.. | .. |
---|
| 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]); |
---|