1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /**
3  * \file rawmidi/ump.c
4  * \brief Universal MIDI Protocol (UMP) Interface
5  */
6 
7 #include "rawmidi_local.h"
8 #include "ump_local.h"
9 
get_rawmidi_flags(snd_ump_t *ump)10 static int get_rawmidi_flags(snd_ump_t *ump)
11 {
12 	snd_rawmidi_info_t info;
13 	int err;
14 
15 	err = snd_rawmidi_info(ump->rawmidi, &info);
16 	if (err < 0)
17 		return err;
18 	if (!(info.flags & SNDRV_RAWMIDI_INFO_UMP))
19 		return -EINVAL;
20 	ump->flags = info.flags;
21 	return 0;
22 }
23 
24 /**
25  * \brief Opens a new connection to the UMP interface.
26  * \param inputp Returned input handle (NULL if not wanted)
27  * \param outputp Returned output handle (NULL if not wanted)
28  * \param name ASCII identifier of the UMP handle
29  * \param mode Open mode
30  * \return 0 on success otherwise a negative error code
31  *
32  * Opens a new connection to the UMP interface specified with
33  * an ASCII identifier and mode.
34  */
snd_ump_open(snd_ump_t **inputp, snd_ump_t **outputp, const char *name, int mode)35 int snd_ump_open(snd_ump_t **inputp, snd_ump_t **outputp, const char *name,
36 		 int mode)
37 {
38 	snd_ump_t *input = NULL, *output = NULL;
39 	int err;
40 
41 	if (inputp)
42 		*inputp = NULL;
43 	if (outputp)
44 		*outputp = NULL;
45 	if (!inputp && !outputp)
46 		return -EINVAL;
47 
48 	err = -ENOMEM;
49 	if (inputp) {
50 		input = calloc(1, sizeof(*input));
51 		if (!input)
52 			goto error;
53 		input->is_input = 1;
54 	}
55 	if (outputp) {
56 		output = calloc(1, sizeof(*output));
57 		if (!output)
58 			goto error;
59 	}
60 
61 	err = snd_rawmidi_open(input ? &input->rawmidi : NULL,
62 			       output ? &output->rawmidi : NULL,
63 			       name, mode | _SND_RAWMIDI_OPEN_UMP);
64 	if (err < 0)
65 		goto error;
66 
67 	if (input) {
68 		err = get_rawmidi_flags(input);
69 		if (err < 0)
70 			goto error;
71 	}
72 	if (output) {
73 		err = get_rawmidi_flags(output);
74 		if (err < 0)
75 			goto error;
76 	}
77 
78 	if (inputp)
79 		*inputp = input;
80 	if (outputp)
81 		*outputp = output;
82 
83 	return 0;
84 
85  error:
86 	if (input) {
87 		if (input->rawmidi)
88 			snd_rawmidi_close(input->rawmidi);
89 		free(input);
90 	}
91 	if (output) {
92 		if (output->rawmidi)
93 			snd_rawmidi_close(output->rawmidi);
94 		free(output);
95 	}
96 	return err;
97 }
98 
99 /**
100  * \brief close UMP handle
101  * \param ump UMP handle
102  * \return 0 on success otherwise a negative error code
103  *
104  * Closes the specified UMP handle and frees all associated
105  * resources.
106  */
snd_ump_close(snd_ump_t *ump)107 int snd_ump_close(snd_ump_t *ump)
108 {
109 	int err;
110 
111 	err = snd_rawmidi_close(ump->rawmidi);
112 	free(ump);
113 	return err;
114 }
115 
116 /**
117  * \brief get RawMidi instance associated with the UMP handle
118  * \param ump UMP handle
119  * \return the associated RawMidi handle
120  *
121  * Returns the associated RawMidi instance with the given UMP handle
122  */
snd_ump_rawmidi(snd_ump_t *ump)123 snd_rawmidi_t *snd_ump_rawmidi(snd_ump_t *ump)
124 {
125 	return ump->rawmidi;
126 }
127 
128 /**
129  * \brief get identifier of UMP handle
130  * \param ump UMP handle
131  * \return ascii identifier of UMP handle
132  *
133  * Returns the ASCII identifier of given UMP handle. It's the same
134  * identifier specified in snd_ump_open().
135  */
snd_ump_name(snd_ump_t *ump)136 const char *snd_ump_name(snd_ump_t *ump)
137 {
138 	return snd_rawmidi_name(ump->rawmidi);
139 }
140 
141 /**
142  * \brief get count of poll descriptors for UMP handle
143  * \param ump UMP handle
144  * \return count of poll descriptors
145  */
snd_ump_poll_descriptors_count(snd_ump_t *ump)146 int snd_ump_poll_descriptors_count(snd_ump_t *ump)
147 {
148 	return snd_rawmidi_poll_descriptors_count(ump->rawmidi);
149 }
150 
151 /**
152  * \brief get poll descriptors
153  * \param ump UMP handle
154  * \param pfds array of poll descriptors
155  * \param space space in the poll descriptor array
156  * \return count of filled descriptors
157  */
snd_ump_poll_descriptors(snd_ump_t *ump, struct pollfd *pfds, unsigned int space)158 int snd_ump_poll_descriptors(snd_ump_t *ump, struct pollfd *pfds,
159 			     unsigned int space)
160 {
161 	return snd_rawmidi_poll_descriptors(ump->rawmidi, pfds, space);
162 }
163 
164 /**
165  * \brief get returned events from poll descriptors
166  * \param ump UMP handle
167  * \param pfds array of poll descriptors
168  * \param nfds count of poll descriptors
169  * \param revents returned events
170  * \return zero if success, otherwise a negative error code
171  */
snd_ump_poll_descriptors_revents(snd_ump_t *ump, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)172 int snd_ump_poll_descriptors_revents(snd_ump_t *ump, struct pollfd *pfds,
173 				     unsigned int nfds, unsigned short *revents)
174 {
175 	return snd_rawmidi_poll_descriptors_revents(ump->rawmidi, pfds, nfds,
176 						    revents);
177 }
178 
179 /**
180  * \brief set nonblock mode
181  * \param ump UMP handle
182  * \param nonblock 0 = block, 1 = nonblock mode
183  * \return 0 on success otherwise a negative error code
184  *
185  * The nonblock mode cannot be used when the stream is in
186  * #SND_RAWMIDI_APPEND state.
187  */
snd_ump_nonblock(snd_ump_t *ump, int nonblock)188 int snd_ump_nonblock(snd_ump_t *ump, int nonblock)
189 {
190 	return snd_rawmidi_nonblock(ump->rawmidi, nonblock);
191 }
192 
193 /**
194  * \brief get information about associated RawMidi handle
195  * \param ump UMP handle
196  * \param info pointer to a snd_rawmidi_info_t structure to be filled
197  * \return 0 on success otherwise a negative error code
198  */
snd_ump_rawmidi_info(snd_ump_t *ump, snd_rawmidi_info_t *info)199 int snd_ump_rawmidi_info(snd_ump_t *ump, snd_rawmidi_info_t *info)
200 {
201 	return snd_rawmidi_info(ump->rawmidi, info);
202 }
203 
204 /**
205  * \brief set parameters about associated RawMidi stream
206  * \param ump UMP handle
207  * \param params pointer to a snd_rawmidi_params_t structure to be filled
208  * \return 0 on success otherwise a negative error code
209  */
snd_ump_rawmidi_params(snd_ump_t *ump, snd_rawmidi_params_t *params)210 int snd_ump_rawmidi_params(snd_ump_t *ump, snd_rawmidi_params_t *params)
211 {
212 	return snd_rawmidi_params(ump->rawmidi, params);
213 }
214 
215 /**
216  * \brief get current parameters about associated RawMidi stream
217  * \param ump UMP handle
218  * \param params pointer to a snd_rawmidi_params_t structure to be filled
219  * \return 0 on success otherwise a negative error code
220  */
snd_ump_rawmidi_params_current(snd_ump_t *ump, snd_rawmidi_params_t *params)221 int snd_ump_rawmidi_params_current(snd_ump_t *ump, snd_rawmidi_params_t *params)
222 {
223 	return snd_rawmidi_params_current(ump->rawmidi, params);
224 }
225 
226 /**
227  * \brief get status of associated RawMidi stream
228  * \param ump UMP handle
229  * \param status pointer to a snd_rawmidi_status_t structure to be filled
230  * \return 0 on success otherwise a negative error code
231  */
snd_ump_rawmidi_status(snd_ump_t *ump, snd_rawmidi_status_t *status)232 int snd_ump_rawmidi_status(snd_ump_t *ump, snd_rawmidi_status_t *status)
233 {
234 	return snd_rawmidi_status(ump->rawmidi, status);
235 }
236 
237 /**
238  * \brief drop all packets in the rawmidi I/O ring buffer immediately
239  * \param ump UMP handle
240  * \return 0 on success otherwise a negative error code
241  */
snd_ump_drop(snd_ump_t *ump)242 int snd_ump_drop(snd_ump_t *ump)
243 {
244 	return snd_rawmidi_drop(ump->rawmidi);
245 }
246 
247 /**
248  * \brief drain all packets in the UMP I/O ring buffer
249  * \param ump UMP handle
250  * \return 0 on success otherwise a negative error code
251  *
252  * Waits until all MIDI packets are not drained (sent) to the
253  * hardware device.
254  */
snd_ump_drain(snd_ump_t *ump)255 int snd_ump_drain(snd_ump_t *ump)
256 {
257 	return snd_rawmidi_drain(ump->rawmidi);
258 }
259 
260 /**
261  * \brief write UMP packets to UMP stream
262  * \param ump UMP handle
263  * \param buffer buffer containing UMP packets
264  * \param size output buffer size in bytes
265  */
snd_ump_write(snd_ump_t *ump, const void *buffer, size_t size)266 ssize_t snd_ump_write(snd_ump_t *ump, const void *buffer, size_t size)
267 {
268 	if (ump->is_input)
269 		return -EINVAL;
270 	return snd_rawmidi_write(ump->rawmidi, buffer, size);
271 }
272 
273 /**
274  * \brief read UMP packets from UMP stream
275  * \param ump UMP handle
276  * \param buffer buffer to store the input MIDI bytes
277  * \param size input buffer size in bytes
278  * \retval count of UMP packet in bytes otherwise a negative error code
279  */
snd_ump_read(snd_ump_t *ump, void *buffer, size_t size)280 ssize_t snd_ump_read(snd_ump_t *ump, void *buffer, size_t size)
281 {
282 	if (!ump->is_input)
283 		return -EINVAL;
284 	return snd_rawmidi_read(ump->rawmidi, buffer, size);
285 }
286 
287 /**
288  * \brief read UMP packets from UMP stream with timestamp
289  * \param ump UMP handle
290  * \param[out] tstamp timestamp for the returned UMP packets
291  * \param buffer buffer to store the input UMP packets
292  * \param size input buffer size in bytes
293  * \retval count of UMP packet in bytes otherwise a negative error code
294  */
snd_ump_tread(snd_ump_t *ump, struct timespec *tstamp, void *buffer, size_t size)295 ssize_t snd_ump_tread(snd_ump_t *ump, struct timespec *tstamp, void *buffer,
296 		      size_t size)
297 {
298 	if (!ump->is_input)
299 		return -EINVAL;
300 	return snd_rawmidi_tread(ump->rawmidi, tstamp, buffer, size);
301 }
302 
303 /**
304  * \brief get size of the snd_ump_endpoint_info_t structure in bytes
305  * \return size of the snd_ump_endpoint_info_t structure in bytes
306  */
snd_ump_endpoint_info_sizeof(void)307 size_t snd_ump_endpoint_info_sizeof(void)
308 {
309 	return sizeof(snd_ump_endpoint_info_t);
310 }
311 
312 /**
313  * \brief allocate the snd_ump_endpoint_info_t structure
314  * \param info returned pointer
315  * \return 0 on success otherwise a negative error code if fails
316  *
317  * Allocates a new snd_rawmidi_status_t structure using the standard
318  * malloc C library function.
319  */
snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info)320 int snd_ump_endpoint_info_malloc(snd_ump_endpoint_info_t **info)
321 {
322 	*info = calloc(1, sizeof(snd_ump_endpoint_info_t));
323 	if (!*info)
324 		return -ENOMEM;
325 	return 0;
326 }
327 
328 /**
329  * \brief frees the snd_ump_endpoint_info_t structure
330  * \param info pointer to the snd_ump_endpoint_info_t structure to free
331  *
332  * Frees the given snd_ump_endpoint_info_t structure using the standard
333  * free C library function.
334  */
snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)335 void snd_ump_endpoint_info_free(snd_ump_endpoint_info_t *info)
336 {
337 	free(info);
338 }
339 
340 /**
341  * \brief copy one snd_ump_endpoint_info_t structure to another
342  * \param dst destination snd_ump_endpoint_info_t structure
343  * \param src source snd_ump_endpoint_info_t structure
344  */
snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst, const snd_ump_endpoint_info_t *src)345 void snd_ump_endpoint_info_copy(snd_ump_endpoint_info_t *dst,
346 				const snd_ump_endpoint_info_t *src)
347 {
348 	*dst = *src;
349 }
350 
351 /**
352  * \brief get card number of UMP endpoint
353  * \param info pointer to a snd_ump_endpoint_info_t structure
354  * \return the card number of the given UMP endpoint
355  */
snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info)356 int snd_ump_endpoint_info_get_card(const snd_ump_endpoint_info_t *info)
357 {
358 	return info->card;
359 }
360 
361 /**
362  * \brief get device number of UMP endpoint
363  * \param info pointer to a snd_ump_endpoint_info_t structure
364  * \return the device number of the given UMP endpoint
365  */
snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info)366 int snd_ump_endpoint_info_get_device(const snd_ump_endpoint_info_t *info)
367 {
368 	return info->device;
369 }
370 
371 /**
372  * \brief get UMP endpoint info flags
373  * \param info pointer to a snd_ump_endpoint_info_t structure
374  * \return UMP endpoint flag bits
375  */
snd_ump_endpoint_info_get_flags(const snd_ump_endpoint_info_t *info)376 unsigned int snd_ump_endpoint_info_get_flags(const snd_ump_endpoint_info_t *info)
377 {
378 	return info->flags;
379 }
380 
381 /**
382  * \brief get UMP endpoint protocol capability bits
383  * \param info pointer to a snd_ump_endpoint_info_t structure
384  * \return UMP endpoint protocol capability bits
385  */
snd_ump_endpoint_info_get_protocol_caps(const snd_ump_endpoint_info_t *info)386 unsigned int snd_ump_endpoint_info_get_protocol_caps(const snd_ump_endpoint_info_t *info)
387 {
388 	return info->protocol_caps;
389 }
390 
391 /**
392  * \brief get the current UMP endpoint protocol
393  * \param info pointer to a snd_ump_endpoint_info_t structure
394  * \return UMP endpoint protocol bits
395  */
snd_ump_endpoint_info_get_protocol(const snd_ump_endpoint_info_t *info)396 unsigned int snd_ump_endpoint_info_get_protocol(const snd_ump_endpoint_info_t *info)
397 {
398 	return info->protocol;
399 }
400 
401 /**
402  * \brief get the number of UMP blocks belonging to the endpoint
403  * \param info pointer to a snd_ump_endpoint_info_t structure
404  * \return number of UMP blocks
405  */
snd_ump_endpoint_info_get_num_blocks(const snd_ump_endpoint_info_t *info)406 unsigned int snd_ump_endpoint_info_get_num_blocks(const snd_ump_endpoint_info_t *info)
407 {
408 	return info->num_blocks;
409 }
410 
411 /**
412  * \brief get UMP version number
413  * \param info pointer to a snd_ump_endpoint_info_t structure
414  * \return UMP version number
415  */
snd_ump_endpoint_info_get_version(const snd_ump_endpoint_info_t *info)416 unsigned int snd_ump_endpoint_info_get_version(const snd_ump_endpoint_info_t *info)
417 {
418 	return info->version;
419 }
420 
421 /**
422  * \brief get UMP manufacturer ID
423  * \param info pointer to a snd_ump_endpoint_info_t structure
424  * \return UMP manufacturer ID
425  */
snd_ump_endpoint_info_get_manufacturer_id(const snd_ump_endpoint_info_t *info)426 unsigned int snd_ump_endpoint_info_get_manufacturer_id(const snd_ump_endpoint_info_t *info)
427 {
428 	return info->manufacturer_id;
429 }
430 
431 /**
432  * \brief get UMP family ID
433  * \param info pointer to a snd_ump_endpoint_info_t structure
434  * \return UMP family ID
435  */
snd_ump_endpoint_info_get_family_id(const snd_ump_endpoint_info_t *info)436 unsigned int snd_ump_endpoint_info_get_family_id(const snd_ump_endpoint_info_t *info)
437 {
438 	return info->family_id;
439 }
440 
441 /**
442  * \brief get UMP model ID
443  * \param info pointer to a snd_ump_endpoint_info_t structure
444  * \return UMP model ID
445  */
snd_ump_endpoint_info_get_model_id(const snd_ump_endpoint_info_t *info)446 unsigned int snd_ump_endpoint_info_get_model_id(const snd_ump_endpoint_info_t *info)
447 {
448 	return info->model_id;
449 }
450 
451 /**
452  * \brief get UMP software revision
453  * \param info pointer to a snd_ump_endpoint_info_t structure
454  * \return UMP software revision
455  */
snd_ump_endpoint_info_get_sw_revision(const snd_ump_endpoint_info_t *info)456 const unsigned char *snd_ump_endpoint_info_get_sw_revision(const snd_ump_endpoint_info_t *info)
457 {
458 	return info->sw_revision;
459 }
460 
461 /**
462  * \brief get UMP endpoint name string
463  * \param info pointer to a snd_ump_endpoint_info_t structure
464  * \return UMP endpoint name string
465  */
snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info)466 const char *snd_ump_endpoint_info_get_name(const snd_ump_endpoint_info_t *info)
467 {
468 	return (const char *)info->name;
469 }
470 
471 /**
472  * \brief get UMP endpoint product ID string
473  * \param info pointer to a snd_ump_endpoint_info_t structure
474  * \return UMP endpoint product ID string
475  */
snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info)476 const char *snd_ump_endpoint_info_get_product_id(const snd_ump_endpoint_info_t *info)
477 {
478 	return (const char *)info->product_id;
479 }
480 
481 /**
482  * \brief get endpoint information about UMP handle
483  * \param ump UMP handle
484  * \param info pointer to a snd_ump_endpoint_info_t structure to be filled
485  * \return 0 on success otherwise a negative error code
486  */
snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info)487 int snd_ump_endpoint_info(snd_ump_t *ump, snd_ump_endpoint_info_t *info)
488 {
489 	return _snd_rawmidi_ump_endpoint_info(ump->rawmidi, info);
490 }
491 
492 /**
493  * \brief get size of the snd_ump_block_info_t structure in bytes
494  * \return size of the snd_ump_block_info_t structure in bytes
495  */
snd_ump_block_info_sizeof(void)496 size_t snd_ump_block_info_sizeof(void)
497 {
498 	return sizeof(snd_ump_block_info_t);
499 }
500 
501 /**
502  * \brief allocate the snd_ump_block_info_t structure
503  * \param info returned pointer
504  * \return 0 on success otherwise a negative error code if fails
505  *
506  * Allocates a new snd_ump_block_info_t structure using the standard
507  * malloc C library function.
508  */
snd_ump_block_info_malloc(snd_ump_block_info_t **info)509 int snd_ump_block_info_malloc(snd_ump_block_info_t **info)
510 {
511 	*info = calloc(1, sizeof(snd_ump_block_info_t));
512 	if (!*info)
513 		return -ENOMEM;
514 	return 0;
515 }
516 
517 /**
518  * \brief frees the snd_ump_block_info_t structure
519  * \param info pointer to the snd_ump_block_info_t structure to free
520  *
521  * Frees the given snd_ump_block_info_t structure using the standard
522  * free C library function.
523  */
snd_ump_block_info_free(snd_ump_block_info_t *info)524 void snd_ump_block_info_free(snd_ump_block_info_t *info)
525 {
526 	free(info);
527 }
528 
529 /**
530  * \brief copy one snd_ump_block_info_t structure to another
531  * \param dst destination snd_ump_block_info_t structure
532  * \param src source snd_ump_block_info_t structure
533  */
snd_ump_block_info_copy(snd_ump_block_info_t *dst, const snd_ump_block_info_t *src)534 void snd_ump_block_info_copy(snd_ump_block_info_t *dst,
535 			     const snd_ump_block_info_t *src)
536 {
537 	*dst = *src;
538 }
539 
540 /**
541  * \brief get card number of UMP block
542  * \param info pointer to a snd_ump_block_info_t structure
543  * \return the card number of the given UMP block
544  */
snd_ump_block_info_get_card(const snd_ump_block_info_t *info)545 int snd_ump_block_info_get_card(const snd_ump_block_info_t *info)
546 {
547 	return info->card;
548 }
549 
550 /**
551  * \brief get device number of UMP block
552  * \param info pointer to a snd_ump_block_info_t structure
553  * \return the device number of the given UMP block
554  */
snd_ump_block_info_get_device(const snd_ump_block_info_t *info)555 int snd_ump_block_info_get_device(const snd_ump_block_info_t *info)
556 {
557 	return info->device;
558 }
559 
560 /**
561  * \brief get UMP block ID
562  * \param info pointer to a snd_ump_block_info_t structure
563  * \return ID number of the given UMP block
564  */
snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)565 unsigned int snd_ump_block_info_get_block_id(const snd_ump_block_info_t *info)
566 {
567 	return info->block_id;
568 }
569 
570 /**
571  * \brief set UMP block ID for query
572  * \param info pointer to a snd_ump_block_info_t structure
573  * \param id the ID number for query
574  */
snd_ump_block_info_set_block_id(snd_ump_block_info_t *info, unsigned int id)575 void snd_ump_block_info_set_block_id(snd_ump_block_info_t *info,
576 				     unsigned int id)
577 {
578 	info->block_id = id;
579 }
580 
581 /**
582  * \brief get UMP block activeness
583  * \param info pointer to a snd_ump_block_info_t structure
584  * \return 1 if the block is active or 0 if inactive
585  */
snd_ump_block_info_get_active(const snd_ump_block_info_t *info)586 unsigned int snd_ump_block_info_get_active(const snd_ump_block_info_t *info)
587 {
588 	return info->active;
589 }
590 
591 /**
592  * \brief get UMP block information flags
593  * \param info pointer to a snd_ump_block_info_t structure
594  * \return info flag bits for the given UMP block
595  */
snd_ump_block_info_get_flags(const snd_ump_block_info_t *info)596 unsigned int snd_ump_block_info_get_flags(const snd_ump_block_info_t *info)
597 {
598 	return info->flags;
599 }
600 
601 /**
602  * \brief get UMP block direction
603  * \param info pointer to a snd_ump_block_info_t structure
604  * \return direction of UMP block (input,output,bidirectional)
605  */
snd_ump_block_info_get_direction(const snd_ump_block_info_t *info)606 unsigned int snd_ump_block_info_get_direction(const snd_ump_block_info_t *info)
607 {
608 	return info->direction;
609 }
610 
611 /**
612  * \brief get first UMP group ID belonging to the block
613  * \param info pointer to a snd_ump_block_info_t structure
614  * \return the first UMP group ID belonging to the block
615  */
snd_ump_block_info_get_first_group(const snd_ump_block_info_t *info)616 unsigned int snd_ump_block_info_get_first_group(const snd_ump_block_info_t *info)
617 {
618 	return info->first_group;
619 }
620 
621 /**
622  * \brief get number of UMP groups belonging to the block
623  * \param info pointer to a snd_ump_block_info_t structure
624  * \return the number of UMP groups belonging to the block
625  */
snd_ump_block_info_get_num_groups(const snd_ump_block_info_t *info)626 unsigned int snd_ump_block_info_get_num_groups(const snd_ump_block_info_t *info)
627 {
628 	return info->num_groups;
629 }
630 
631 /**
632  * \brief get MIDI-CI version number
633  * \param info pointer to a snd_ump_block_info_t structure
634  * \return MIDI-CI version number
635  */
snd_ump_block_info_get_midi_ci_version(const snd_ump_block_info_t *info)636 unsigned int snd_ump_block_info_get_midi_ci_version(const snd_ump_block_info_t *info)
637 {
638 	return info->midi_ci_version;
639 }
640 
641 /**
642  * \brief get number of supported SysEx8 streams
643  * \param info pointer to a snd_ump_block_info_t structure
644  * \return number of supported SysEx8 streams
645  */
snd_ump_block_info_get_sysex8_streams(const snd_ump_block_info_t *info)646 unsigned int snd_ump_block_info_get_sysex8_streams(const snd_ump_block_info_t *info)
647 {
648 	return info->sysex8_streams;
649 }
650 
651 /**
652  * \brief get UI hint of the given UMP block
653  * \param info pointer to a snd_ump_block_info_t structure
654  * \return the hint bits
655  */
snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info)656 unsigned int snd_ump_block_info_get_ui_hint(const snd_ump_block_info_t *info)
657 {
658 	return info->ui_hint;
659 }
660 
661 /**
662  * \brief get the name string of UMP block
663  * \param info pointer to a snd_ump_block_info_t structure
664  * \return the name string of UMP block
665  */
snd_ump_block_info_get_name(const snd_ump_block_info_t *info)666 const char *snd_ump_block_info_get_name(const snd_ump_block_info_t *info)
667 {
668 	return (const char *)info->name;
669 }
670 
671 /**
672  * \brief get UMP block information
673  * \param ump UMP handle
674  * \param info pointer to a snd_ump_block_info_t structure
675  * \return 0 on success otherwise a negative error code
676  *
677  * The caller should fill the block ID to query at first via
678  * snd_ump_block_info_set_block_id().
679  */
snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info)680 int snd_ump_block_info(snd_ump_t *ump, snd_ump_block_info_t *info)
681 {
682 	return _snd_rawmidi_ump_block_info(ump->rawmidi, info);
683 }
684 
685 /*
686  * UMP sysex helpers
687  */
expand_sysex_data(const uint32_t *data, uint8_t *buf, size_t maxlen, unsigned char bytes, int offset)688 static int expand_sysex_data(const uint32_t *data, uint8_t *buf,
689 			     size_t maxlen, unsigned char bytes, int offset)
690 {
691 	int size = 0;
692 
693 	for (; bytes; bytes--, size++) {
694 		if (!maxlen)
695 			break;
696 		buf[size] = (*data >> offset) & 0x7f;
697 		if (!offset) {
698 			offset = 24;
699 			data++;
700 		} else {
701 			offset -= 8;
702 		}
703 	}
704 
705 	return size;
706 }
707 
expand_sysex7(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)708 static int expand_sysex7(const uint32_t *ump, uint8_t *buf, size_t maxlen,
709 			 size_t *filled)
710 {
711 	unsigned char status;
712 	unsigned char bytes;
713 
714 	*filled = 0;
715 	if (!maxlen)
716 		return 0;
717 
718 	status = snd_ump_sysex_msg_status(ump);
719 	bytes = snd_ump_sysex_msg_length(ump);
720 	if (bytes > 6)
721 		return 0; // invalid - skip
722 
723 	*filled = expand_sysex_data(ump, buf, maxlen, bytes, 8);
724 	return (status == SND_UMP_SYSEX_STATUS_SINGLE ||
725 		status == SND_UMP_SYSEX_STATUS_END);
726 }
727 
expand_sysex8(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)728 static int expand_sysex8(const uint32_t *ump, uint8_t *buf, size_t maxlen,
729 			  size_t *filled)
730 {
731 	unsigned char status;
732 	unsigned char bytes;
733 
734 	*filled = 0;
735 	if (!maxlen)
736 		return 0;
737 
738 	status = snd_ump_sysex_msg_status(ump);
739 	if (status > SND_UMP_SYSEX_STATUS_END)
740 		return 0; // unsupported, skip
741 	bytes = snd_ump_sysex_msg_length(ump);
742 	if (!bytes || bytes > 14)
743 		return 0; // skip
744 
745 	*filled = expand_sysex_data(ump, buf, maxlen, bytes - 1, 0);
746 	return (status == SND_UMP_SYSEX_STATUS_SINGLE ||
747 		status == SND_UMP_SYSEX_STATUS_END);
748 }
749 
750 /**
751  * \brief fill sysex byte from a UMP packet
752  * \param ump UMP packet pointer
753  * \param buf buffer point to fill sysex bytes
754  * \param maxlen max buffer size in bytes
755  * \param filled the size of filled sysex bytes on the buffer
756  * \return 1 if the sysex finished, otherwise 0
757  */
snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen, size_t *filled)758 int snd_ump_msg_sysex_expand(const uint32_t *ump, uint8_t *buf, size_t maxlen,
759 			     size_t *filled)
760 {
761 	switch (snd_ump_msg_type(ump)) {
762 	case SND_UMP_MSG_TYPE_DATA:
763 		return expand_sysex7(ump, buf, maxlen, filled);
764 	case SND_UMP_MSG_TYPE_EXTENDED_DATA:
765 		return expand_sysex8(ump, buf, maxlen, filled);
766 	default:
767 		return -EINVAL;
768 	}
769 }
770