| @@ -680,9 +680,12 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime, · 679 unmodified lines |
| 680 | bool is_input) | 680 | bool is_input) |
| 681 | { | 681 | { |
| 682 | char *newbuf, *oldbuf; | 682 | char *newbuf, *oldbuf; |
| | 683 | unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; |
| 683 | | 684 | |
| 684 | if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) | 685 | if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) |
| 685 | return -EINVAL; | 686 | return -EINVAL; |
| | 687 | if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0) |
| | 688 | return -EINVAL; |
| 686 | if (params->avail_min < 1 || params->avail_min > params->buffer_size) | 689 | if (params->avail_min < 1 || params->avail_min > params->buffer_size) |
| 687 | return -EINVAL; | 690 | return -EINVAL; |
| 688 | if (params->buffer_size != runtime->buffer_size) { | 691 | if (params->buffer_size != runtime->buffer_size) { |
| @@ -720,8 +723,24 @@ EXPORT_SYMBOL(snd_rawmidi_output_params); · 31 unmodified lines |
| 720 | int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, | 723 | int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, |
| 721 | struct snd_rawmidi_params *params) | 724 | struct snd_rawmidi_params *params) |
| 722 | { | 725 | { |
| | 726 | unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK; |
| | 727 | unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK; |
| | 728 | int err; |
| | 729 | |
| | 730 | if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) |
| | 731 | return -EINVAL; |
| | 732 | else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) |
| | 733 | return -EINVAL; |
| | 734 | if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) |
| | 735 | return -EINVAL; |
| 723 | snd_rawmidi_drain_input(substream); | 736 | snd_rawmidi_drain_input(substream); |
| 724 | return resize_runtime_buffer(substream->runtime, params, true); | 737 | err = resize_runtime_buffer(substream->runtime, params, true); |
| | 738 | if (err < 0) |
| | 739 | return err; |
| | 740 | |
| | 741 | substream->framing = framing; |
| | 742 | substream->clock_type = clock_type; |
| | 743 | return 0; |
| 725 | } | 744 | } |
| 726 | EXPORT_SYMBOL(snd_rawmidi_input_params); | 745 | EXPORT_SYMBOL(snd_rawmidi_input_params); |
| 727 | | 746 | |
| @@ -963,6 +982,62 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card, · 235 unmodified lines |
| 963 | return -ENOIOCTLCMD; | 982 | return -ENOIOCTLCMD; |
| 964 | } | 983 | } |
| 965 | | 984 | |
| | 985 | static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream, |
| | 986 | const unsigned char *buffer, int src_count, const struct timespec64 *tstamp) |
| | 987 | { |
| | 988 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
| | 989 | struct snd_rawmidi_framing_tstamp *dest_ptr; |
| | 990 | struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec }; |
| | 991 | int dest_frames = 0; |
| | 992 | int orig_count = src_count; |
| | 993 | int frame_size = sizeof(struct snd_rawmidi_framing_tstamp); |
| | 994 | |
| | 995 | BUILD_BUG_ON(frame_size != 0x20); |
| | 996 | if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0)) |
| | 997 | return -EINVAL; |
| | 998 | |
| | 999 | while (src_count > 0) { |
| | 1000 | if ((int)(runtime->buffer_size - runtime->avail) < frame_size) { |
| | 1001 | runtime->xruns += src_count; |
| | 1002 | break; |
| | 1003 | } |
| | 1004 | if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH) |
| | 1005 | frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH; |
| | 1006 | else { |
| | 1007 | frame.length = src_count; |
| | 1008 | memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH); |
| | 1009 | } |
| | 1010 | memcpy(frame.data, buffer, frame.length); |
| | 1011 | buffer += frame.length; |
| | 1012 | src_count -= frame.length; |
| | 1013 | dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr); |
| | 1014 | *dest_ptr = frame; |
| | 1015 | runtime->avail += frame_size; |
| | 1016 | runtime->hw_ptr += frame_size; |
| | 1017 | runtime->hw_ptr %= runtime->buffer_size; |
| | 1018 | dest_frames++; |
| | 1019 | } |
| | 1020 | return orig_count - src_count; |
| | 1021 | } |
| | 1022 | |
| | 1023 | static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream) |
| | 1024 | { |
| | 1025 | struct timespec64 ts64 = {0, 0}; |
| | 1026 | |
| | 1027 | switch (substream->clock_type) { |
| | 1028 | case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW: |
| | 1029 | ktime_get_raw_ts64(&ts64); |
| | 1030 | break; |
| | 1031 | case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC: |
| | 1032 | ktime_get_ts64(&ts64); |
| | 1033 | break; |
| | 1034 | case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME: |
| | 1035 | ktime_get_real_ts64(&ts64); |
| | 1036 | break; |
| | 1037 | } |
| | 1038 | return ts64; |
| | 1039 | } |
| | 1040 | |
| 966 | /** | 1041 | /** |
| 967 | * snd_rawmidi_receive - receive the input data from the device | 1042 | * snd_rawmidi_receive - receive the input data from the device |
| 968 | * @substream: the rawmidi substream | 1043 | * @substream: the rawmidi substream |
| @@ -977,6 +1052,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, · 8 unmodified lines |
| 977 | const unsigned char *buffer, int count) | 1052 | const unsigned char *buffer, int count) |
| 978 | { | 1053 | { |
| 979 | unsigned long flags; | 1054 | unsigned long flags; |
| | 1055 | struct timespec64 ts64 = get_framing_tstamp(substream); |
| 980 | int result = 0, count1; | 1056 | int result = 0, count1; |
| 981 | struct snd_rawmidi_runtime *runtime = substream->runtime; | 1057 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
| 982 | | 1058 | |
| @@ -987,8 +1063,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, · 4 unmodified lines |
| 987 | "snd_rawmidi_receive: input is not active!!!\n"); | 1063 | "snd_rawmidi_receive: input is not active!!!\n"); |
| 988 | return -EINVAL; | 1064 | return -EINVAL; |
| 989 | } | 1065 | } |
| | 1066 | |
| 990 | spin_lock_irqsave(&runtime->lock, flags); | 1067 | spin_lock_irqsave(&runtime->lock, flags); |
| 991 | if (count == 1) { /* special case, faster code */ | 1068 | if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { |
| | 1069 | result = receive_with_tstamp_framing(substream, buffer, count, &ts64); |
| | 1070 | } else if (count == 1) { /* special case, faster code */ |
| 992 | substream->bytes++; | 1071 | substream->bytes++; |
| 993 | if (runtime->avail < runtime->buffer_size) { | 1072 | if (runtime->avail < runtime->buffer_size) { |
| 994 | runtime->buffer[runtime->hw_ptr++] = buffer[0]; | 1073 | runtime->buffer[runtime->hw_ptr++] = buffer[0]; |
| @@ -1541,6 +1620,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, · 546 unmodified lines |
| 1541 | struct snd_rawmidi_substream *substream; | 1620 | struct snd_rawmidi_substream *substream; |
| 1542 | struct snd_rawmidi_runtime *runtime; | 1621 | struct snd_rawmidi_runtime *runtime; |
| 1543 | unsigned long buffer_size, avail, xruns; | 1622 | unsigned long buffer_size, avail, xruns; |
| | 1623 | unsigned int clock_type; |
| | 1624 | static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" }; |
| 1544 | | 1625 | |
| 1545 | rmidi = entry->private_data; | 1626 | rmidi = entry->private_data; |
| 1546 | snd_iprintf(buffer, "%s\n\n", rmidi->name); | 1627 | snd_iprintf(buffer, "%s\n\n", rmidi->name); |
| @@ -1596,6 +1677,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, · 49 unmodified lines |
| 1596 | " Avail : %lu\n" | 1677 | " Avail : %lu\n" |
| 1597 | " Overruns : %lu\n", | 1678 | " Overruns : %lu\n", |
| 1598 | buffer_size, avail, xruns); | 1679 | buffer_size, avail, xruns); |
| | 1680 | if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { |
| | 1681 | clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT; |
| | 1682 | if (!snd_BUG_ON(clock_type >= sizeof(clock_names))) |
| | 1683 | snd_iprintf(buffer, |
| | 1684 | " Framing : tstamp\n" |
| | 1685 | " Clock type : %s\n", |
| | 1686 | clock_names[clock_type]); |
| | 1687 | } |
| 1599 | } | 1688 | } |
| 1600 | } | 1689 | } |
| 1601 | } | 1690 | } |