linux/sound/core/ump.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Universal MIDI Packet (UMP) support
 */

#include <linux/list.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/export.h>
#include <linux/mm.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/ump.h>
#include <sound/ump_convert.h>

#define ump_err(ump, fmt, args...)
#define ump_warn(ump, fmt, args...)
#define ump_info(ump, fmt, args...)
#define ump_dbg(ump, fmt, args...)

static int snd_ump_dev_register(struct snd_rawmidi *rmidi);
static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi);
static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
			  void __user *argp);
static void snd_ump_proc_read(struct snd_info_entry *entry,
			      struct snd_info_buffer *buffer);
static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream);
static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream);
static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
				    int up);
static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream);

static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
				  const u32 *buf, int size);
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
static int process_legacy_output(struct snd_ump_endpoint *ump,
				 u32 *buffer, int count);
static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
				 int words);
#else
static inline int process_legacy_output(struct snd_ump_endpoint *ump,
					u32 *buffer, int count)
{
	return 0;
}
static inline void process_legacy_input(struct snd_ump_endpoint *ump,
					const u32 *src, int words)
{
}
#endif

static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops =;

static const struct snd_rawmidi_ops snd_ump_rawmidi_input_ops =;

static const struct snd_rawmidi_ops snd_ump_rawmidi_output_ops =;

static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi)
{}

/**
 * snd_ump_endpoint_new - create a UMP Endpoint object
 * @card: the card instance
 * @id: the id string for rawmidi
 * @device: the device index for rawmidi
 * @output: 1 for enabling output
 * @input: 1 for enabling input
 * @ump_ret: the pointer to store the new UMP instance
 *
 * Creates a new UMP Endpoint object. A UMP Endpoint is tied with one rawmidi
 * instance with one input and/or one output rawmidi stream (either uni-
 * or bi-directional). A UMP Endpoint may contain one or multiple UMP Blocks
 * that consist of one or multiple UMP Groups.
 *
 * Use snd_rawmidi_set_ops() to set the operators to the new instance.
 * Unlike snd_rawmidi_new(), this function sets up the info_flags by itself
 * depending on the given @output and @input.
 *
 * The device has SNDRV_RAWMIDI_INFO_UMP flag set and a different device
 * file ("umpCxDx") than a standard MIDI 1.x device ("midiCxDx") is
 * created.
 *
 * Return: Zero if successful, or a negative error code on failure.
 */
int snd_ump_endpoint_new(struct snd_card *card, char *id, int device,
			 int output, int input,
			 struct snd_ump_endpoint **ump_ret)
{}
EXPORT_SYMBOL_GPL();

/*
 * Device register / unregister hooks;
 *  do nothing, placeholders for avoiding the default rawmidi handling
 */

#if IS_ENABLED(CONFIG_SND_SEQUENCER)
static void snd_ump_dev_seq_free(struct snd_seq_device *device)
{}
#endif

static int snd_ump_dev_register(struct snd_rawmidi *rmidi)
{}

static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi)
{}

static struct snd_ump_block *
snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id)
{}

/*
 * rawmidi ops for UMP endpoint
 */
static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream)
{}

static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream)
{}

static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream,
				    int up)
{}

static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream)
{}

/* number of 32bit words per message type */
static unsigned char ump_packet_words[0x10] =;

/**
 * snd_ump_receive_ump_val - parse the UMP packet data
 * @ump: UMP endpoint
 * @val: UMP packet data
 *
 * The data is copied onto ump->input_buf[].
 * When a full packet is completed, returns the number of words (from 1 to 4).
 * OTOH, if the packet is incomplete, returns 0.
 */
int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_ump_receive - transfer UMP packets from the device
 * @ump: the UMP endpoint
 * @buffer: the buffer pointer to transfer
 * @count: byte size to transfer
 *
 * Called from the driver to submit the received UMP packets from the device
 * to user-space.  It's essentially a wrapper of rawmidi_receive().
 * The data to receive is in CPU-native endianness.
 */
int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_ump_transmit - transmit UMP packets
 * @ump: the UMP endpoint
 * @buffer: the buffer pointer to transfer
 * @count: byte size to transfer
 *
 * Called from the driver to obtain the UMP packets from user-space to the
 * device.  It's essentially a wrapper of rawmidi_transmit().
 * The data to transmit is in CPU-native endianness.
 */
int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count)
{}
EXPORT_SYMBOL_GPL();

/**
 * snd_ump_block_new - Create a UMP block
 * @ump: UMP object
 * @blk: block ID number to create
 * @direction: direction (in/out/bidirection)
 * @first_group: the first group ID (0-based)
 * @num_groups: the number of groups in this block
 * @blk_ret: the pointer to store the resultant block object
 */
int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk,
		      unsigned int direction, unsigned int first_group,
		      unsigned int num_groups, struct snd_ump_block **blk_ret)
{}
EXPORT_SYMBOL_GPL();

static int snd_ump_ioctl_block(struct snd_ump_endpoint *ump,
			       struct snd_ump_block_info __user *argp)
{}

/*
 * Handle UMP-specific ioctls; called from snd_rawmidi_ioctl()
 */
static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
			  void __user *argp)
{}

static const char *ump_direction_string(int dir)
{}

static const char *ump_ui_hint_string(int dir)
{}

/* Additional proc file output */
static void snd_ump_proc_read(struct snd_info_entry *entry,
			      struct snd_info_buffer *buffer)
{}

/* update dir_bits and active flag for all groups in the client */
void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
{}
EXPORT_SYMBOL_GPL();

/*
 * UMP endpoint and function block handling
 */

/* open / close UMP streams for the internal stream msg communication */
static int ump_request_open(struct snd_ump_endpoint *ump)
{}

static void ump_request_close(struct snd_ump_endpoint *ump)
{}

/* request a command and wait for the given response;
 * @req1 and @req2 are u32 commands
 * @reply is the expected UMP stream status
 */
static int ump_req_msg(struct snd_ump_endpoint *ump, u32 req1, u32 req2,
		       u32 reply)
{}

/* append the received letters via UMP packet to the given string buffer;
 * return 1 if the full string is received or 0 to continue
 */
static int ump_append_string(struct snd_ump_endpoint *ump, char *dest,
			     int maxsize, const u32 *buf, int offset)
{}

/* Choose the default protocol */
static void choose_default_protocol(struct snd_ump_endpoint *ump)
{}

/* handle EP info stream message; update the UMP attributes */
static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
				  const union snd_ump_stream_msg *buf)
{}

/* handle EP device info stream message; update the UMP attributes */
static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
				      const union snd_ump_stream_msg *buf)
{}

/* handle EP name stream message; update the UMP name string */
static int ump_handle_ep_name_msg(struct snd_ump_endpoint *ump,
				  const union snd_ump_stream_msg *buf)
{}

/* handle EP product id stream message; update the UMP product_id string */
static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump,
				     const union snd_ump_stream_msg *buf)
{}

/* notify the protocol change to sequencer */
static void seq_notify_protocol(struct snd_ump_endpoint *ump)
{}

/**
 * snd_ump_switch_protocol - switch MIDI protocol
 * @ump: UMP endpoint
 * @protocol: protocol to switch to
 *
 * Returns 1 if the protocol is actually switched, 0 if unchanged
 */
int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol)
{}
EXPORT_SYMBOL_GPL();

/* handle EP stream config message; update the UMP protocol */
static int ump_handle_stream_cfg_msg(struct snd_ump_endpoint *ump,
				     const union snd_ump_stream_msg *buf)
{}

/* Extract Function Block info from UMP packet */
static void fill_fb_info(struct snd_ump_endpoint *ump,
			 struct snd_ump_block_info *info,
			 const union snd_ump_stream_msg *buf)
{}

/* check whether the FB info gets updated by the current message */
static bool is_fb_info_updated(struct snd_ump_endpoint *ump,
			       struct snd_ump_block *fb,
			       const union snd_ump_stream_msg *buf)
{}

/* notify the FB info/name change to sequencer */
static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
				 struct snd_ump_block *fb)
{}

/* handle FB info message; update FB info if the block is present */
static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
				  const union snd_ump_stream_msg *buf)
{}

/* handle FB name message; update the FB name string */
static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
				  const union snd_ump_stream_msg *buf)
{}

static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk)
{}

/* handle stream messages, called from snd_ump_receive() */
static void ump_handle_stream_msg(struct snd_ump_endpoint *ump,
				  const u32 *buf, int size)
{}

/**
 * snd_ump_parse_endpoint - parse endpoint and create function blocks
 * @ump: UMP object
 *
 * Returns 0 for successful parse, -ENODEV if device doesn't respond
 * (or the query is unsupported), or other error code for serious errors.
 */
int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
{}
EXPORT_SYMBOL_GPL();

#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
/*
 * Legacy rawmidi support
 */
static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
{}

static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream)
{}

static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream,
				   int up)
{}

static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream)
{}

static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi)
{}

static const struct snd_rawmidi_ops snd_ump_legacy_input_ops =;

static const struct snd_rawmidi_ops snd_ump_legacy_output_ops =;

static const struct snd_rawmidi_global_ops snd_ump_legacy_ops =;

static int process_legacy_output(struct snd_ump_endpoint *ump,
				 u32 *buffer, int count)
{}

static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
				 int words)
{}

/* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */
static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
{}

static void fill_substream_names(struct snd_ump_endpoint *ump,
				 struct snd_rawmidi *rmidi, int dir)
{}

int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
				  char *id, int device)
{}
EXPORT_SYMBOL_GPL();
#endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */

MODULE_DESCRIPTION();
MODULE_LICENSE();