diff options
-rw-r--r-- | sound/firewire/amdtp-stream.c | 80 | ||||
-rw-r--r-- | sound/firewire/amdtp-stream.h | 6 |
2 files changed, 81 insertions, 5 deletions
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 646e8e390773..a03b37bdc274 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | /* isochronous header parameters */ | 28 | /* isochronous header parameters */ |
29 | #define ISO_DATA_LENGTH_SHIFT 16 | 29 | #define ISO_DATA_LENGTH_SHIFT 16 |
30 | #define TAG_NO_CIP_HEADER 0 | ||
30 | #define TAG_CIP 1 | 31 | #define TAG_CIP 1 |
31 | 32 | ||
32 | /* common isochronous packet header parameters */ | 33 | /* common isochronous packet header parameters */ |
@@ -234,11 +235,15 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters); | |||
234 | unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) | 235 | unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s) |
235 | { | 236 | { |
236 | unsigned int multiplier = 1; | 237 | unsigned int multiplier = 1; |
238 | unsigned int header_size = 0; | ||
237 | 239 | ||
238 | if (s->flags & CIP_JUMBO_PAYLOAD) | 240 | if (s->flags & CIP_JUMBO_PAYLOAD) |
239 | multiplier = 5; | 241 | multiplier = 5; |
242 | if (!(s->flags & CIP_NO_HEADER)) | ||
243 | header_size = 8; | ||
240 | 244 | ||
241 | return 8 + s->syt_interval * s->data_block_quadlets * 4 * multiplier; | 245 | return header_size + |
246 | s->syt_interval * s->data_block_quadlets * 4 * multiplier; | ||
242 | } | 247 | } |
243 | EXPORT_SYMBOL(amdtp_stream_get_max_payload); | 248 | EXPORT_SYMBOL(amdtp_stream_get_max_payload); |
244 | 249 | ||
@@ -380,7 +385,7 @@ static int queue_packet(struct amdtp_stream *s, unsigned int header_length, | |||
380 | goto end; | 385 | goto end; |
381 | 386 | ||
382 | p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL); | 387 | p.interrupt = IS_ALIGNED(s->packet_index + 1, INTERRUPT_INTERVAL); |
383 | p.tag = TAG_CIP; | 388 | p.tag = s->tag; |
384 | p.header_length = header_length; | 389 | p.header_length = header_length; |
385 | if (payload_length > 0) | 390 | if (payload_length > 0) |
386 | p.payload_length = payload_length; | 391 | p.payload_length = payload_length; |
@@ -457,6 +462,34 @@ static int handle_out_packet(struct amdtp_stream *s, | |||
457 | return 0; | 462 | return 0; |
458 | } | 463 | } |
459 | 464 | ||
465 | static int handle_out_packet_without_header(struct amdtp_stream *s, | ||
466 | unsigned int payload_length, unsigned int cycle, | ||
467 | unsigned int index) | ||
468 | { | ||
469 | __be32 *buffer; | ||
470 | unsigned int syt; | ||
471 | unsigned int data_blocks; | ||
472 | unsigned int pcm_frames; | ||
473 | struct snd_pcm_substream *pcm; | ||
474 | |||
475 | buffer = s->buffer.packets[s->packet_index].buffer; | ||
476 | syt = calculate_syt(s, cycle); | ||
477 | data_blocks = calculate_data_blocks(s, syt); | ||
478 | pcm_frames = s->process_data_blocks(s, buffer, data_blocks, &syt); | ||
479 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
480 | |||
481 | payload_length = data_blocks * 4 * s->data_block_quadlets; | ||
482 | if (queue_out_packet(s, payload_length) < 0) | ||
483 | return -EIO; | ||
484 | |||
485 | pcm = ACCESS_ONCE(s->pcm); | ||
486 | if (pcm && pcm_frames > 0) | ||
487 | update_pcm_pointers(s, pcm, pcm_frames); | ||
488 | |||
489 | /* No need to return the number of handled data blocks. */ | ||
490 | return 0; | ||
491 | } | ||
492 | |||
460 | static int handle_in_packet(struct amdtp_stream *s, | 493 | static int handle_in_packet(struct amdtp_stream *s, |
461 | unsigned int payload_length, unsigned int cycle, | 494 | unsigned int payload_length, unsigned int cycle, |
462 | unsigned int index) | 495 | unsigned int index) |
@@ -573,6 +606,30 @@ end: | |||
573 | return 0; | 606 | return 0; |
574 | } | 607 | } |
575 | 608 | ||
609 | static int handle_in_packet_without_header(struct amdtp_stream *s, | ||
610 | unsigned int payload_quadlets, unsigned int cycle, | ||
611 | unsigned int index) | ||
612 | { | ||
613 | __be32 *buffer; | ||
614 | unsigned int data_blocks; | ||
615 | struct snd_pcm_substream *pcm; | ||
616 | unsigned int pcm_frames; | ||
617 | |||
618 | buffer = s->buffer.packets[s->packet_index].buffer; | ||
619 | data_blocks = payload_quadlets / s->data_block_quadlets; | ||
620 | pcm_frames = s->process_data_blocks(s, buffer, data_blocks, NULL); | ||
621 | s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; | ||
622 | |||
623 | if (queue_in_packet(s) < 0) | ||
624 | return -EIO; | ||
625 | |||
626 | pcm = ACCESS_ONCE(s->pcm); | ||
627 | if (pcm && pcm_frames > 0) | ||
628 | update_pcm_pointers(s, pcm, pcm_frames); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
576 | /* | 633 | /* |
577 | * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On | 634 | * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On |
578 | * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent | 635 | * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent |
@@ -616,7 +673,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 tstamp, | |||
616 | 673 | ||
617 | for (i = 0; i < packets; ++i) { | 674 | for (i = 0; i < packets; ++i) { |
618 | cycle = increment_cycle_count(cycle, 1); | 675 | cycle = increment_cycle_count(cycle, 1); |
619 | if (handle_out_packet(s, 0, cycle, i) < 0) { | 676 | if (s->handle_packet(s, 0, cycle, i) < 0) { |
620 | s->packet_index = -1; | 677 | s->packet_index = -1; |
621 | amdtp_stream_pcm_abort(s); | 678 | amdtp_stream_pcm_abort(s); |
622 | return; | 679 | return; |
@@ -663,7 +720,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp, | |||
663 | break; | 720 | break; |
664 | } | 721 | } |
665 | 722 | ||
666 | if (handle_in_packet(s, payload_length, cycle, i) < 0) | 723 | if (s->handle_packet(s, payload_length, cycle, i) < 0) |
667 | break; | 724 | break; |
668 | } | 725 | } |
669 | 726 | ||
@@ -699,10 +756,18 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, | |||
699 | packets = header_length / IN_PACKET_HEADER_SIZE; | 756 | packets = header_length / IN_PACKET_HEADER_SIZE; |
700 | cycle = decrement_cycle_count(cycle, packets); | 757 | cycle = decrement_cycle_count(cycle, packets); |
701 | context->callback.sc = in_stream_callback; | 758 | context->callback.sc = in_stream_callback; |
759 | if (s->flags & CIP_NO_HEADER) | ||
760 | s->handle_packet = handle_in_packet_without_header; | ||
761 | else | ||
762 | s->handle_packet = handle_in_packet; | ||
702 | } else { | 763 | } else { |
703 | packets = header_length / 4; | 764 | packets = header_length / 4; |
704 | cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets); | 765 | cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets); |
705 | context->callback.sc = out_stream_callback; | 766 | context->callback.sc = out_stream_callback; |
767 | if (s->flags & CIP_NO_HEADER) | ||
768 | s->handle_packet = handle_out_packet_without_header; | ||
769 | else | ||
770 | s->handle_packet = handle_out_packet; | ||
706 | } | 771 | } |
707 | 772 | ||
708 | s->start_cycle = cycle; | 773 | s->start_cycle = cycle; |
@@ -782,6 +847,11 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) | |||
782 | 847 | ||
783 | amdtp_stream_update(s); | 848 | amdtp_stream_update(s); |
784 | 849 | ||
850 | if (s->flags & CIP_NO_HEADER) | ||
851 | s->tag = TAG_NO_CIP_HEADER; | ||
852 | else | ||
853 | s->tag = TAG_CIP; | ||
854 | |||
785 | s->packet_index = 0; | 855 | s->packet_index = 0; |
786 | do { | 856 | do { |
787 | if (s->direction == AMDTP_IN_STREAM) | 857 | if (s->direction == AMDTP_IN_STREAM) |
@@ -794,7 +864,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) | |||
794 | 864 | ||
795 | /* NOTE: TAG1 matches CIP. This just affects in stream. */ | 865 | /* NOTE: TAG1 matches CIP. This just affects in stream. */ |
796 | tag = FW_ISO_CONTEXT_MATCH_TAG1; | 866 | tag = FW_ISO_CONTEXT_MATCH_TAG1; |
797 | if (s->flags & CIP_EMPTY_WITH_TAG0) | 867 | if ((s->flags & CIP_EMPTY_WITH_TAG0) || (s->flags & CIP_NO_HEADER)) |
798 | tag |= FW_ISO_CONTEXT_MATCH_TAG0; | 868 | tag |= FW_ISO_CONTEXT_MATCH_TAG0; |
799 | 869 | ||
800 | s->callbacked = false; | 870 | s->callbacked = false; |
diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index a31dfd849821..2bd4de4c7bb7 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h | |||
@@ -31,6 +31,7 @@ | |||
31 | * allows 5 times as large as IEC 61883-6 defines. | 31 | * allows 5 times as large as IEC 61883-6 defines. |
32 | * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include | 32 | * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include |
33 | * valid EOH. | 33 | * valid EOH. |
34 | * @CIP_NO_HEADERS: a lack of headers in packets | ||
34 | */ | 35 | */ |
35 | enum cip_flags { | 36 | enum cip_flags { |
36 | CIP_NONBLOCKING = 0x00, | 37 | CIP_NONBLOCKING = 0x00, |
@@ -42,6 +43,7 @@ enum cip_flags { | |||
42 | CIP_EMPTY_HAS_WRONG_DBC = 0x20, | 43 | CIP_EMPTY_HAS_WRONG_DBC = 0x20, |
43 | CIP_JUMBO_PAYLOAD = 0x40, | 44 | CIP_JUMBO_PAYLOAD = 0x40, |
44 | CIP_HEADER_WITHOUT_EOH = 0x80, | 45 | CIP_HEADER_WITHOUT_EOH = 0x80, |
46 | CIP_NO_HEADER = 0x100, | ||
45 | }; | 47 | }; |
46 | 48 | ||
47 | /** | 49 | /** |
@@ -104,6 +106,10 @@ struct amdtp_stream { | |||
104 | struct fw_iso_context *context; | 106 | struct fw_iso_context *context; |
105 | struct iso_packets_buffer buffer; | 107 | struct iso_packets_buffer buffer; |
106 | int packet_index; | 108 | int packet_index; |
109 | int tag; | ||
110 | int (*handle_packet)(struct amdtp_stream *s, | ||
111 | unsigned int payload_quadlets, unsigned int cycle, | ||
112 | unsigned int index); | ||
107 | 113 | ||
108 | /* For CIP headers. */ | 114 | /* For CIP headers. */ |
109 | unsigned int source_node_id_field; | 115 | unsigned int source_node_id_field; |