| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Abstract layer for MIDI v1.0 stream |
|---|
| 3 | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
|---|
| 4 | | - * |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | | - * |
|---|
| 20 | 5 | */ |
|---|
| 21 | 6 | |
|---|
| 22 | 7 | #include <sound/core.h> |
|---|
| .. | .. |
|---|
| 50 | 35 | MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device."); |
|---|
| 51 | 36 | #endif /* CONFIG_SND_OSSEMUL */ |
|---|
| 52 | 37 | |
|---|
| 53 | | -static int snd_rawmidi_free(struct snd_rawmidi *rawmidi); |
|---|
| 38 | +static int snd_rawmidi_free(struct snd_rawmidi *rmidi); |
|---|
| 54 | 39 | static int snd_rawmidi_dev_free(struct snd_device *device); |
|---|
| 55 | 40 | static int snd_rawmidi_dev_register(struct snd_device *device); |
|---|
| 56 | 41 | static int snd_rawmidi_dev_disconnect(struct snd_device *device); |
|---|
| .. | .. |
|---|
| 64 | 49 | dev_warn(&(rmidi)->dev, fmt, ##args) |
|---|
| 65 | 50 | #define rmidi_dbg(rmidi, fmt, args...) \ |
|---|
| 66 | 51 | dev_dbg(&(rmidi)->dev, fmt, ##args) |
|---|
| 52 | + |
|---|
| 53 | +struct snd_rawmidi_status32 { |
|---|
| 54 | + s32 stream; |
|---|
| 55 | + s32 tstamp_sec; /* Timestamp */ |
|---|
| 56 | + s32 tstamp_nsec; |
|---|
| 57 | + u32 avail; /* available bytes */ |
|---|
| 58 | + u32 xruns; /* count of overruns since last status (in bytes) */ |
|---|
| 59 | + unsigned char reserved[16]; /* reserved for future use */ |
|---|
| 60 | +}; |
|---|
| 61 | + |
|---|
| 62 | +#define SNDRV_RAWMIDI_IOCTL_STATUS32 _IOWR('W', 0x20, struct snd_rawmidi_status32) |
|---|
| 63 | + |
|---|
| 64 | +struct snd_rawmidi_status64 { |
|---|
| 65 | + int stream; |
|---|
| 66 | + u8 rsvd[4]; /* alignment */ |
|---|
| 67 | + s64 tstamp_sec; /* Timestamp */ |
|---|
| 68 | + s64 tstamp_nsec; |
|---|
| 69 | + size_t avail; /* available bytes */ |
|---|
| 70 | + size_t xruns; /* count of overruns since last status (in bytes) */ |
|---|
| 71 | + unsigned char reserved[16]; /* reserved for future use */ |
|---|
| 72 | +}; |
|---|
| 73 | + |
|---|
| 74 | +#define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64) |
|---|
| 67 | 75 | |
|---|
| 68 | 76 | static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) |
|---|
| 69 | 77 | { |
|---|
| .. | .. |
|---|
| 262 | 270 | { |
|---|
| 263 | 271 | struct snd_rawmidi_substream *substream; |
|---|
| 264 | 272 | struct snd_rawmidi_str *s = &rmidi->streams[stream]; |
|---|
| 265 | | - static unsigned int info_flags[2] = { |
|---|
| 273 | + static const unsigned int info_flags[2] = { |
|---|
| 266 | 274 | [SNDRV_RAWMIDI_STREAM_OUTPUT] = SNDRV_RAWMIDI_INFO_OUTPUT, |
|---|
| 267 | 275 | [SNDRV_RAWMIDI_STREAM_INPUT] = SNDRV_RAWMIDI_INFO_INPUT, |
|---|
| 268 | 276 | }; |
|---|
| .. | .. |
|---|
| 403 | 411 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) |
|---|
| 404 | 412 | return -EINVAL; /* invalid combination */ |
|---|
| 405 | 413 | |
|---|
| 406 | | - err = nonseekable_open(inode, file); |
|---|
| 414 | + err = stream_open(inode, file); |
|---|
| 407 | 415 | if (err < 0) |
|---|
| 408 | 416 | return err; |
|---|
| 409 | 417 | |
|---|
| .. | .. |
|---|
| 718 | 726 | EXPORT_SYMBOL(snd_rawmidi_input_params); |
|---|
| 719 | 727 | |
|---|
| 720 | 728 | static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, |
|---|
| 721 | | - struct snd_rawmidi_status *status) |
|---|
| 729 | + struct snd_rawmidi_status64 *status) |
|---|
| 722 | 730 | { |
|---|
| 723 | 731 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
|---|
| 724 | 732 | |
|---|
| .. | .. |
|---|
| 731 | 739 | } |
|---|
| 732 | 740 | |
|---|
| 733 | 741 | static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, |
|---|
| 734 | | - struct snd_rawmidi_status *status) |
|---|
| 742 | + struct snd_rawmidi_status64 *status) |
|---|
| 735 | 743 | { |
|---|
| 736 | 744 | struct snd_rawmidi_runtime *runtime = substream->runtime; |
|---|
| 737 | 745 | |
|---|
| .. | .. |
|---|
| 742 | 750 | status->xruns = runtime->xruns; |
|---|
| 743 | 751 | runtime->xruns = 0; |
|---|
| 744 | 752 | spin_unlock_irq(&runtime->lock); |
|---|
| 753 | + return 0; |
|---|
| 754 | +} |
|---|
| 755 | + |
|---|
| 756 | +static int snd_rawmidi_ioctl_status32(struct snd_rawmidi_file *rfile, |
|---|
| 757 | + struct snd_rawmidi_status32 __user *argp) |
|---|
| 758 | +{ |
|---|
| 759 | + int err = 0; |
|---|
| 760 | + struct snd_rawmidi_status32 __user *status = argp; |
|---|
| 761 | + struct snd_rawmidi_status32 status32; |
|---|
| 762 | + struct snd_rawmidi_status64 status64; |
|---|
| 763 | + |
|---|
| 764 | + if (copy_from_user(&status32, argp, |
|---|
| 765 | + sizeof(struct snd_rawmidi_status32))) |
|---|
| 766 | + return -EFAULT; |
|---|
| 767 | + |
|---|
| 768 | + switch (status32.stream) { |
|---|
| 769 | + case SNDRV_RAWMIDI_STREAM_OUTPUT: |
|---|
| 770 | + if (rfile->output == NULL) |
|---|
| 771 | + return -EINVAL; |
|---|
| 772 | + err = snd_rawmidi_output_status(rfile->output, &status64); |
|---|
| 773 | + break; |
|---|
| 774 | + case SNDRV_RAWMIDI_STREAM_INPUT: |
|---|
| 775 | + if (rfile->input == NULL) |
|---|
| 776 | + return -EINVAL; |
|---|
| 777 | + err = snd_rawmidi_input_status(rfile->input, &status64); |
|---|
| 778 | + break; |
|---|
| 779 | + default: |
|---|
| 780 | + return -EINVAL; |
|---|
| 781 | + } |
|---|
| 782 | + if (err < 0) |
|---|
| 783 | + return err; |
|---|
| 784 | + |
|---|
| 785 | + status32 = (struct snd_rawmidi_status32) { |
|---|
| 786 | + .stream = status64.stream, |
|---|
| 787 | + .tstamp_sec = status64.tstamp_sec, |
|---|
| 788 | + .tstamp_nsec = status64.tstamp_nsec, |
|---|
| 789 | + .avail = status64.avail, |
|---|
| 790 | + .xruns = status64.xruns, |
|---|
| 791 | + }; |
|---|
| 792 | + |
|---|
| 793 | + if (copy_to_user(status, &status32, sizeof(*status))) |
|---|
| 794 | + return -EFAULT; |
|---|
| 795 | + |
|---|
| 796 | + return 0; |
|---|
| 797 | +} |
|---|
| 798 | + |
|---|
| 799 | +static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile, |
|---|
| 800 | + struct snd_rawmidi_status64 __user *argp) |
|---|
| 801 | +{ |
|---|
| 802 | + int err = 0; |
|---|
| 803 | + struct snd_rawmidi_status64 status; |
|---|
| 804 | + |
|---|
| 805 | + if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status64))) |
|---|
| 806 | + return -EFAULT; |
|---|
| 807 | + |
|---|
| 808 | + switch (status.stream) { |
|---|
| 809 | + case SNDRV_RAWMIDI_STREAM_OUTPUT: |
|---|
| 810 | + if (rfile->output == NULL) |
|---|
| 811 | + return -EINVAL; |
|---|
| 812 | + err = snd_rawmidi_output_status(rfile->output, &status); |
|---|
| 813 | + break; |
|---|
| 814 | + case SNDRV_RAWMIDI_STREAM_INPUT: |
|---|
| 815 | + if (rfile->input == NULL) |
|---|
| 816 | + return -EINVAL; |
|---|
| 817 | + err = snd_rawmidi_input_status(rfile->input, &status); |
|---|
| 818 | + break; |
|---|
| 819 | + default: |
|---|
| 820 | + return -EINVAL; |
|---|
| 821 | + } |
|---|
| 822 | + if (err < 0) |
|---|
| 823 | + return err; |
|---|
| 824 | + if (copy_to_user(argp, &status, |
|---|
| 825 | + sizeof(struct snd_rawmidi_status64))) |
|---|
| 826 | + return -EFAULT; |
|---|
| 745 | 827 | return 0; |
|---|
| 746 | 828 | } |
|---|
| 747 | 829 | |
|---|
| .. | .. |
|---|
| 791 | 873 | return -EINVAL; |
|---|
| 792 | 874 | } |
|---|
| 793 | 875 | } |
|---|
| 794 | | - case SNDRV_RAWMIDI_IOCTL_STATUS: |
|---|
| 795 | | - { |
|---|
| 796 | | - int err = 0; |
|---|
| 797 | | - struct snd_rawmidi_status status; |
|---|
| 798 | | - |
|---|
| 799 | | - if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status))) |
|---|
| 800 | | - return -EFAULT; |
|---|
| 801 | | - switch (status.stream) { |
|---|
| 802 | | - case SNDRV_RAWMIDI_STREAM_OUTPUT: |
|---|
| 803 | | - if (rfile->output == NULL) |
|---|
| 804 | | - return -EINVAL; |
|---|
| 805 | | - err = snd_rawmidi_output_status(rfile->output, &status); |
|---|
| 806 | | - break; |
|---|
| 807 | | - case SNDRV_RAWMIDI_STREAM_INPUT: |
|---|
| 808 | | - if (rfile->input == NULL) |
|---|
| 809 | | - return -EINVAL; |
|---|
| 810 | | - err = snd_rawmidi_input_status(rfile->input, &status); |
|---|
| 811 | | - break; |
|---|
| 812 | | - default: |
|---|
| 813 | | - return -EINVAL; |
|---|
| 814 | | - } |
|---|
| 815 | | - if (err < 0) |
|---|
| 816 | | - return err; |
|---|
| 817 | | - if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status))) |
|---|
| 818 | | - return -EFAULT; |
|---|
| 819 | | - return 0; |
|---|
| 820 | | - } |
|---|
| 876 | + case SNDRV_RAWMIDI_IOCTL_STATUS32: |
|---|
| 877 | + return snd_rawmidi_ioctl_status32(rfile, argp); |
|---|
| 878 | + case SNDRV_RAWMIDI_IOCTL_STATUS64: |
|---|
| 879 | + return snd_rawmidi_ioctl_status64(rfile, argp); |
|---|
| 821 | 880 | case SNDRV_RAWMIDI_IOCTL_DROP: |
|---|
| 822 | 881 | { |
|---|
| 823 | 882 | int val; |
|---|
| .. | .. |
|---|
| 1271 | 1330 | } |
|---|
| 1272 | 1331 | EXPORT_SYMBOL(snd_rawmidi_transmit); |
|---|
| 1273 | 1332 | |
|---|
| 1333 | +/** |
|---|
| 1334 | + * snd_rawmidi_proceed - Discard the all pending bytes and proceed |
|---|
| 1335 | + * @substream: rawmidi substream |
|---|
| 1336 | + * |
|---|
| 1337 | + * Return: the number of discarded bytes |
|---|
| 1338 | + */ |
|---|
| 1339 | +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) |
|---|
| 1340 | +{ |
|---|
| 1341 | + struct snd_rawmidi_runtime *runtime = substream->runtime; |
|---|
| 1342 | + unsigned long flags; |
|---|
| 1343 | + int count = 0; |
|---|
| 1344 | + |
|---|
| 1345 | + spin_lock_irqsave(&runtime->lock, flags); |
|---|
| 1346 | + if (runtime->avail < runtime->buffer_size) { |
|---|
| 1347 | + count = runtime->buffer_size - runtime->avail; |
|---|
| 1348 | + __snd_rawmidi_transmit_ack(substream, count); |
|---|
| 1349 | + } |
|---|
| 1350 | + spin_unlock_irqrestore(&runtime->lock, flags); |
|---|
| 1351 | + return count; |
|---|
| 1352 | +} |
|---|
| 1353 | +EXPORT_SYMBOL(snd_rawmidi_proceed); |
|---|
| 1354 | + |
|---|
| 1274 | 1355 | static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, |
|---|
| 1275 | 1356 | const unsigned char __user *userbuf, |
|---|
| 1276 | 1357 | const unsigned char *kernelbuf, |
|---|
| .. | .. |
|---|
| 1584 | 1665 | { |
|---|
| 1585 | 1666 | struct snd_rawmidi *rmidi; |
|---|
| 1586 | 1667 | int err; |
|---|
| 1587 | | - static struct snd_device_ops ops = { |
|---|
| 1668 | + static const struct snd_device_ops ops = { |
|---|
| 1588 | 1669 | .dev_free = snd_rawmidi_dev_free, |
|---|
| 1589 | 1670 | .dev_register = snd_rawmidi_dev_register, |
|---|
| 1590 | 1671 | .dev_disconnect = snd_rawmidi_dev_disconnect, |
|---|
| .. | .. |
|---|
| 1655 | 1736 | |
|---|
| 1656 | 1737 | snd_info_free_entry(rmidi->proc_entry); |
|---|
| 1657 | 1738 | rmidi->proc_entry = NULL; |
|---|
| 1658 | | - mutex_lock(®ister_mutex); |
|---|
| 1659 | 1739 | if (rmidi->ops && rmidi->ops->dev_unregister) |
|---|
| 1660 | 1740 | rmidi->ops->dev_unregister(rmidi); |
|---|
| 1661 | | - mutex_unlock(®ister_mutex); |
|---|
| 1662 | 1741 | |
|---|
| 1663 | 1742 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); |
|---|
| 1664 | 1743 | snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); |
|---|