1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Universal MIDI Packet (UMP) support 4 */ 5 6 #include <linux/list.h> 7 #include <linux/slab.h> 8 #include <linux/module.h> 9 #include <linux/export.h> 10 #include <linux/mm.h> 11 #include <sound/core.h> 12 #include <sound/rawmidi.h> 13 #include <sound/ump.h> 14 #include <sound/ump_convert.h> 15 16 #define ump_err(ump, fmt, args...) dev_err((ump)->core.dev, fmt, ##args) 17 #define ump_warn(ump, fmt, args...) dev_warn((ump)->core.dev, fmt, ##args) 18 #define ump_info(ump, fmt, args...) dev_info((ump)->core.dev, fmt, ##args) 19 #define ump_dbg(ump, fmt, args...) dev_dbg((ump)->core.dev, fmt, ##args) 20 21 static int snd_ump_dev_register(struct snd_rawmidi *rmidi); 22 static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi); 23 static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, 24 void __user *argp); 25 static void snd_ump_proc_read(struct snd_info_entry *entry, 26 struct snd_info_buffer *buffer); 27 static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream); 28 static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream); 29 static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream, 30 int up); 31 static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream); 32 33 static void ump_handle_stream_msg(struct snd_ump_endpoint *ump, 34 const u32 *buf, int size); 35 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) 36 static int process_legacy_output(struct snd_ump_endpoint *ump, 37 u32 *buffer, int count); 38 static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, 39 int words); 40 static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump); 41 static void update_legacy_names(struct snd_ump_endpoint *ump); 42 #else 43 static inline int process_legacy_output(struct snd_ump_endpoint *ump, 44 u32 *buffer, int count) 45 { 46 return 0; 47 } 48 static inline void process_legacy_input(struct snd_ump_endpoint *ump, 49 const u32 *src, int words) 50 { 51 } 52 static inline void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump) 53 { 54 } 55 static inline void update_legacy_names(struct snd_ump_endpoint *ump) 56 { 57 } 58 #endif 59 60 /* copy a string safely with stripping non-printable letters */ 61 static void safe_copy_string(void *dst, size_t max_dst_size, 62 const void *src, size_t max_src_size) 63 { 64 const unsigned char *s = src; 65 unsigned char *d = dst; 66 67 if (!max_dst_size--) 68 return; 69 for (s = src; max_dst_size && *s && max_src_size--; s++) { 70 if (!isascii(*s) || !isprint(*s)) 71 continue; 72 *d++ = *s; 73 max_dst_size--; 74 } 75 *d = 0; 76 } 77 78 /* append a string safely with stripping non-printable letters */ 79 static void safe_append_string(void *dst, size_t max_dst_size, 80 const void *src, size_t max_src_size) 81 { 82 unsigned char *d = dst; 83 size_t len = strlen(d); 84 85 safe_copy_string(d + len, max_dst_size - len, src, max_src_size); 86 } 87 88 static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = { 89 .dev_register = snd_ump_dev_register, 90 .dev_unregister = snd_ump_dev_unregister, 91 .ioctl = snd_ump_ioctl, 92 .proc_read = snd_ump_proc_read, 93 }; 94 95 static const struct snd_rawmidi_ops snd_ump_rawmidi_input_ops = { 96 .open = snd_ump_rawmidi_open, 97 .close = snd_ump_rawmidi_close, 98 .trigger = snd_ump_rawmidi_trigger, 99 }; 100 101 static const struct snd_rawmidi_ops snd_ump_rawmidi_output_ops = { 102 .open = snd_ump_rawmidi_open, 103 .close = snd_ump_rawmidi_close, 104 .trigger = snd_ump_rawmidi_trigger, 105 .drain = snd_ump_rawmidi_drain, 106 }; 107 108 static void snd_ump_endpoint_free(struct snd_rawmidi *rmidi) 109 { 110 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); 111 struct snd_ump_block *fb; 112 113 while (!list_empty(&ump->block_list)) { 114 fb = list_first_entry(&ump->block_list, struct snd_ump_block, 115 list); 116 list_del(&fb->list); 117 if (fb->private_free) 118 fb->private_free(fb); 119 kfree(fb); 120 } 121 122 if (ump->private_free) 123 ump->private_free(ump); 124 125 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) 126 kfree(ump->out_cvts); 127 #endif 128 } 129 130 /** 131 * snd_ump_endpoint_new - create a UMP Endpoint object 132 * @card: the card instance 133 * @id: the id string for rawmidi 134 * @device: the device index for rawmidi 135 * @output: 1 for enabling output 136 * @input: 1 for enabling input 137 * @ump_ret: the pointer to store the new UMP instance 138 * 139 * Creates a new UMP Endpoint object. A UMP Endpoint is tied with one rawmidi 140 * instance with one input and/or one output rawmidi stream (either uni- 141 * or bi-directional). A UMP Endpoint may contain one or multiple UMP Blocks 142 * that consist of one or multiple UMP Groups. 143 * 144 * Use snd_rawmidi_set_ops() to set the operators to the new instance. 145 * Unlike snd_rawmidi_new(), this function sets up the info_flags by itself 146 * depending on the given @output and @input. 147 * 148 * The device has SNDRV_RAWMIDI_INFO_UMP flag set and a different device 149 * file ("umpCxDx") than a standard MIDI 1.x device ("midiCxDx") is 150 * created. 151 * 152 * Return: Zero if successful, or a negative error code on failure. 153 */ 154 int snd_ump_endpoint_new(struct snd_card *card, char *id, int device, 155 int output, int input, 156 struct snd_ump_endpoint **ump_ret) 157 { 158 unsigned int info_flags = SNDRV_RAWMIDI_INFO_UMP; 159 struct snd_ump_endpoint *ump; 160 int err; 161 162 if (input) 163 info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 164 if (output) 165 info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 166 if (input && output) 167 info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; 168 169 ump = kzalloc(sizeof(*ump), GFP_KERNEL); 170 if (!ump) 171 return -ENOMEM; 172 INIT_LIST_HEAD(&ump->block_list); 173 mutex_init(&ump->open_mutex); 174 init_waitqueue_head(&ump->stream_wait); 175 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) 176 spin_lock_init(&ump->legacy_locks[0]); 177 spin_lock_init(&ump->legacy_locks[1]); 178 #endif 179 err = snd_rawmidi_init(&ump->core, card, id, device, 180 output, input, info_flags); 181 if (err < 0) { 182 snd_rawmidi_free(&ump->core); 183 return err; 184 } 185 186 ump->info.card = card->number; 187 ump->info.device = device; 188 189 ump->core.private_free = snd_ump_endpoint_free; 190 ump->core.ops = &snd_ump_rawmidi_ops; 191 if (input) 192 snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_INPUT, 193 &snd_ump_rawmidi_input_ops); 194 if (output) 195 snd_rawmidi_set_ops(&ump->core, SNDRV_RAWMIDI_STREAM_OUTPUT, 196 &snd_ump_rawmidi_output_ops); 197 198 ump_dbg(ump, "Created a UMP EP #%d (%s)\n", device, id); 199 *ump_ret = ump; 200 return 0; 201 } 202 EXPORT_SYMBOL_GPL(snd_ump_endpoint_new); 203 204 /* 205 * Device register / unregister hooks; 206 * do nothing, placeholders for avoiding the default rawmidi handling 207 */ 208 209 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 210 static void snd_ump_dev_seq_free(struct snd_seq_device *device) 211 { 212 struct snd_ump_endpoint *ump = device->private_data; 213 214 ump->seq_dev = NULL; 215 } 216 #endif 217 218 static int snd_ump_dev_register(struct snd_rawmidi *rmidi) 219 { 220 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 221 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); 222 int err; 223 224 err = snd_seq_device_new(ump->core.card, ump->core.device, 225 SNDRV_SEQ_DEV_ID_UMP, 0, &ump->seq_dev); 226 if (err < 0) 227 return err; 228 ump->seq_dev->private_data = ump; 229 ump->seq_dev->private_free = snd_ump_dev_seq_free; 230 snd_device_register(ump->core.card, ump->seq_dev); 231 #endif 232 return 0; 233 } 234 235 static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi) 236 { 237 return 0; 238 } 239 240 static struct snd_ump_block * 241 snd_ump_get_block(struct snd_ump_endpoint *ump, unsigned char id) 242 { 243 struct snd_ump_block *fb; 244 245 list_for_each_entry(fb, &ump->block_list, list) { 246 if (fb->info.block_id == id) 247 return fb; 248 } 249 return NULL; 250 } 251 252 /* 253 * rawmidi ops for UMP endpoint 254 */ 255 static int snd_ump_rawmidi_open(struct snd_rawmidi_substream *substream) 256 { 257 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); 258 int dir = substream->stream; 259 int err; 260 261 if (ump->substreams[dir]) 262 return -EBUSY; 263 err = ump->ops->open(ump, dir); 264 if (err < 0) 265 return err; 266 ump->substreams[dir] = substream; 267 return 0; 268 } 269 270 static int snd_ump_rawmidi_close(struct snd_rawmidi_substream *substream) 271 { 272 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); 273 int dir = substream->stream; 274 275 ump->substreams[dir] = NULL; 276 ump->ops->close(ump, dir); 277 return 0; 278 } 279 280 static void snd_ump_rawmidi_trigger(struct snd_rawmidi_substream *substream, 281 int up) 282 { 283 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); 284 int dir = substream->stream; 285 286 ump->ops->trigger(ump, dir, up); 287 } 288 289 static void snd_ump_rawmidi_drain(struct snd_rawmidi_substream *substream) 290 { 291 struct snd_ump_endpoint *ump = rawmidi_to_ump(substream->rmidi); 292 293 if (ump->ops->drain) 294 ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT); 295 } 296 297 /* number of 32bit words per message type */ 298 static unsigned char ump_packet_words[0x10] = { 299 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4 300 }; 301 302 /** 303 * snd_ump_receive_ump_val - parse the UMP packet data 304 * @ump: UMP endpoint 305 * @val: UMP packet data 306 * 307 * The data is copied onto ump->input_buf[]. 308 * When a full packet is completed, returns the number of words (from 1 to 4). 309 * OTOH, if the packet is incomplete, returns 0. 310 */ 311 int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val) 312 { 313 int words; 314 315 if (!ump->input_pending) 316 ump->input_pending = ump_packet_words[ump_message_type(val)]; 317 318 ump->input_buf[ump->input_buf_head++] = val; 319 ump->input_pending--; 320 if (!ump->input_pending) { 321 words = ump->input_buf_head; 322 ump->input_buf_head = 0; 323 return words; 324 } 325 return 0; 326 } 327 EXPORT_SYMBOL_GPL(snd_ump_receive_ump_val); 328 329 /** 330 * snd_ump_receive - transfer UMP packets from the device 331 * @ump: the UMP endpoint 332 * @buffer: the buffer pointer to transfer 333 * @count: byte size to transfer 334 * 335 * Called from the driver to submit the received UMP packets from the device 336 * to user-space. It's essentially a wrapper of rawmidi_receive(). 337 * The data to receive is in CPU-native endianness. 338 */ 339 int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count) 340 { 341 struct snd_rawmidi_substream *substream; 342 const u32 *p = buffer; 343 int n, words = count >> 2; 344 345 while (words--) { 346 n = snd_ump_receive_ump_val(ump, *p++); 347 if (!n) 348 continue; 349 ump_handle_stream_msg(ump, ump->input_buf, n); 350 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 351 if (ump->seq_ops) 352 ump->seq_ops->input_receive(ump, ump->input_buf, n); 353 #endif 354 process_legacy_input(ump, ump->input_buf, n); 355 } 356 357 substream = ump->substreams[SNDRV_RAWMIDI_STREAM_INPUT]; 358 if (!substream) 359 return 0; 360 return snd_rawmidi_receive(substream, (const char *)buffer, count); 361 } 362 EXPORT_SYMBOL_GPL(snd_ump_receive); 363 364 /** 365 * snd_ump_transmit - transmit UMP packets 366 * @ump: the UMP endpoint 367 * @buffer: the buffer pointer to transfer 368 * @count: byte size to transfer 369 * 370 * Called from the driver to obtain the UMP packets from user-space to the 371 * device. It's essentially a wrapper of rawmidi_transmit(). 372 * The data to transmit is in CPU-native endianness. 373 */ 374 int snd_ump_transmit(struct snd_ump_endpoint *ump, u32 *buffer, int count) 375 { 376 struct snd_rawmidi_substream *substream = 377 ump->substreams[SNDRV_RAWMIDI_STREAM_OUTPUT]; 378 int err; 379 380 if (!substream) 381 return -ENODEV; 382 err = snd_rawmidi_transmit(substream, (char *)buffer, count); 383 /* received either data or an error? */ 384 if (err) 385 return err; 386 return process_legacy_output(ump, buffer, count); 387 } 388 EXPORT_SYMBOL_GPL(snd_ump_transmit); 389 390 /** 391 * snd_ump_block_new - Create a UMP block 392 * @ump: UMP object 393 * @blk: block ID number to create 394 * @direction: direction (in/out/bidirection) 395 * @first_group: the first group ID (0-based) 396 * @num_groups: the number of groups in this block 397 * @blk_ret: the pointer to store the resultant block object 398 */ 399 int snd_ump_block_new(struct snd_ump_endpoint *ump, unsigned int blk, 400 unsigned int direction, unsigned int first_group, 401 unsigned int num_groups, struct snd_ump_block **blk_ret) 402 { 403 struct snd_ump_block *fb, *p; 404 405 if (blk >= SNDRV_UMP_MAX_BLOCKS) 406 return -EINVAL; 407 408 if (snd_ump_get_block(ump, blk)) 409 return -EBUSY; 410 411 fb = kzalloc(sizeof(*fb), GFP_KERNEL); 412 if (!fb) 413 return -ENOMEM; 414 415 fb->ump = ump; 416 fb->info.card = ump->info.card; 417 fb->info.device = ump->info.device; 418 fb->info.block_id = blk; 419 if (blk >= ump->info.num_blocks) 420 ump->info.num_blocks = blk + 1; 421 fb->info.direction = direction; 422 fb->info.active = 1; 423 fb->info.first_group = first_group; 424 fb->info.num_groups = num_groups; 425 /* fill the default name, may be overwritten to a better name */ 426 snprintf(fb->info.name, sizeof(fb->info.name), "Group %u-%u", 427 first_group + 1, first_group + num_groups); 428 429 /* put the entry in the ordered list */ 430 list_for_each_entry(p, &ump->block_list, list) { 431 if (p->info.block_id > blk) { 432 list_add_tail(&fb->list, &p->list); 433 goto added; 434 } 435 } 436 list_add_tail(&fb->list, &ump->block_list); 437 438 added: 439 ump_dbg(ump, "Created a UMP Block #%d (%s)\n", blk, fb->info.name); 440 *blk_ret = fb; 441 return 0; 442 } 443 EXPORT_SYMBOL_GPL(snd_ump_block_new); 444 445 static int snd_ump_ioctl_block(struct snd_ump_endpoint *ump, 446 struct snd_ump_block_info __user *argp) 447 { 448 struct snd_ump_block *fb; 449 unsigned char id; 450 451 if (get_user(id, &argp->block_id)) 452 return -EFAULT; 453 fb = snd_ump_get_block(ump, id); 454 if (!fb) 455 return -ENOENT; 456 if (copy_to_user(argp, &fb->info, sizeof(fb->info))) 457 return -EFAULT; 458 return 0; 459 } 460 461 /* 462 * Handle UMP-specific ioctls; called from snd_rawmidi_ioctl() 463 */ 464 static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd, 465 void __user *argp) 466 { 467 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); 468 469 switch (cmd) { 470 case SNDRV_UMP_IOCTL_ENDPOINT_INFO: 471 if (copy_to_user(argp, &ump->info, sizeof(ump->info))) 472 return -EFAULT; 473 return 0; 474 case SNDRV_UMP_IOCTL_BLOCK_INFO: 475 return snd_ump_ioctl_block(ump, argp); 476 default: 477 ump_dbg(ump, "rawmidi: unknown command = 0x%x\n", cmd); 478 return -ENOTTY; 479 } 480 } 481 482 static const char *ump_direction_string(int dir) 483 { 484 switch (dir) { 485 case SNDRV_UMP_DIR_INPUT: 486 return "input"; 487 case SNDRV_UMP_DIR_OUTPUT: 488 return "output"; 489 case SNDRV_UMP_DIR_BIDIRECTION: 490 return "bidirection"; 491 default: 492 return "unknown"; 493 } 494 } 495 496 static const char *ump_ui_hint_string(int dir) 497 { 498 switch (dir) { 499 case SNDRV_UMP_BLOCK_UI_HINT_RECEIVER: 500 return "receiver"; 501 case SNDRV_UMP_BLOCK_UI_HINT_SENDER: 502 return "sender"; 503 case SNDRV_UMP_BLOCK_UI_HINT_BOTH: 504 return "both"; 505 default: 506 return "unknown"; 507 } 508 } 509 510 /* Additional proc file output */ 511 static void snd_ump_proc_read(struct snd_info_entry *entry, 512 struct snd_info_buffer *buffer) 513 { 514 struct snd_rawmidi *rmidi = entry->private_data; 515 struct snd_ump_endpoint *ump = rawmidi_to_ump(rmidi); 516 struct snd_ump_block *fb; 517 518 snd_iprintf(buffer, "EP Name: %s\n", ump->info.name); 519 snd_iprintf(buffer, "EP Product ID: %s\n", ump->info.product_id); 520 snd_iprintf(buffer, "UMP Version: 0x%04x\n", ump->info.version); 521 snd_iprintf(buffer, "Protocol Caps: 0x%08x\n", ump->info.protocol_caps); 522 snd_iprintf(buffer, "Protocol: 0x%08x\n", ump->info.protocol); 523 if (ump->info.version) { 524 snd_iprintf(buffer, "Manufacturer ID: 0x%08x\n", 525 ump->info.manufacturer_id); 526 snd_iprintf(buffer, "Family ID: 0x%04x\n", ump->info.family_id); 527 snd_iprintf(buffer, "Model ID: 0x%04x\n", ump->info.model_id); 528 snd_iprintf(buffer, "SW Revision: 0x%4phN\n", ump->info.sw_revision); 529 } 530 snd_iprintf(buffer, "Static Blocks: %s\n", 531 (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No"); 532 snd_iprintf(buffer, "Num Blocks: %d\n\n", ump->info.num_blocks); 533 534 list_for_each_entry(fb, &ump->block_list, list) { 535 snd_iprintf(buffer, "Block %d (%s)\n", fb->info.block_id, 536 fb->info.name); 537 snd_iprintf(buffer, " Direction: %s\n", 538 ump_direction_string(fb->info.direction)); 539 snd_iprintf(buffer, " Active: %s\n", 540 fb->info.active ? "Yes" : "No"); 541 snd_iprintf(buffer, " Groups: %d-%d\n", 542 fb->info.first_group + 1, 543 fb->info.first_group + fb->info.num_groups); 544 snd_iprintf(buffer, " Is MIDI1: %s%s\n", 545 (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) ? "Yes" : "No", 546 (fb->info.flags & SNDRV_UMP_BLOCK_IS_LOWSPEED) ? " (Low Speed)" : ""); 547 if (ump->info.version) { 548 snd_iprintf(buffer, " MIDI-CI Version: %d\n", 549 fb->info.midi_ci_version); 550 snd_iprintf(buffer, " Sysex8 Streams: %d\n", 551 fb->info.sysex8_streams); 552 snd_iprintf(buffer, " UI Hint: %s\n", 553 ump_ui_hint_string(fb->info.ui_hint)); 554 } 555 snd_iprintf(buffer, "\n"); 556 } 557 } 558 559 /* update dir_bits and active flag for all groups in the client */ 560 void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump) 561 { 562 struct snd_ump_block *fb; 563 struct snd_ump_group *group; 564 int i; 565 566 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { 567 group = &ump->groups[i]; 568 *group->name = 0; 569 group->dir_bits = 0; 570 group->active = 0; 571 group->group = i; 572 group->valid = false; 573 group->is_midi1 = false; 574 } 575 576 list_for_each_entry(fb, &ump->block_list, list) { 577 if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS) 578 break; 579 group = &ump->groups[fb->info.first_group]; 580 for (i = 0; i < fb->info.num_groups; i++, group++) { 581 group->valid = true; 582 if (fb->info.active) 583 group->active = 1; 584 if (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1) 585 group->is_midi1 = true; 586 switch (fb->info.direction) { 587 case SNDRV_UMP_DIR_INPUT: 588 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT); 589 break; 590 case SNDRV_UMP_DIR_OUTPUT: 591 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT); 592 break; 593 case SNDRV_UMP_DIR_BIDIRECTION: 594 group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) | 595 (1 << SNDRV_RAWMIDI_STREAM_OUTPUT); 596 break; 597 } 598 if (!*fb->info.name) 599 continue; 600 if (*group->name) 601 strlcat(group->name, ", ", sizeof(group->name)); 602 safe_append_string(group->name, sizeof(group->name), 603 fb->info.name, sizeof(fb->info.name)); 604 } 605 } 606 } 607 EXPORT_SYMBOL_GPL(snd_ump_update_group_attrs); 608 609 /* 610 * UMP endpoint and function block handling 611 */ 612 613 /* open / close UMP streams for the internal stream msg communication */ 614 static int ump_request_open(struct snd_ump_endpoint *ump) 615 { 616 return snd_rawmidi_kernel_open(&ump->core, 0, 617 SNDRV_RAWMIDI_LFLG_OUTPUT, 618 &ump->stream_rfile); 619 } 620 621 static void ump_request_close(struct snd_ump_endpoint *ump) 622 { 623 snd_rawmidi_kernel_release(&ump->stream_rfile); 624 } 625 626 /* request a command and wait for the given response; 627 * @req1 and @req2 are u32 commands 628 * @reply is the expected UMP stream status 629 */ 630 static int ump_req_msg(struct snd_ump_endpoint *ump, u32 req1, u32 req2, 631 u32 reply) 632 { 633 u32 buf[4]; 634 635 ump_dbg(ump, "%s: request %08x %08x, wait-for %08x\n", 636 __func__, req1, req2, reply); 637 memset(buf, 0, sizeof(buf)); 638 buf[0] = req1; 639 buf[1] = req2; 640 ump->stream_finished = 0; 641 ump->stream_wait_for = reply; 642 snd_rawmidi_kernel_write(ump->stream_rfile.output, 643 (unsigned char *)&buf, 16); 644 wait_event_timeout(ump->stream_wait, ump->stream_finished, 645 msecs_to_jiffies(500)); 646 if (!READ_ONCE(ump->stream_finished)) { 647 ump_dbg(ump, "%s: request timed out\n", __func__); 648 return -ETIMEDOUT; 649 } 650 ump->stream_finished = 0; 651 ump_dbg(ump, "%s: reply: %08x %08x %08x %08x\n", 652 __func__, buf[0], buf[1], buf[2], buf[3]); 653 return 0; 654 } 655 656 /* append the received letters via UMP packet to the given string buffer; 657 * return 1 if the full string is received or 0 to continue 658 */ 659 static int ump_append_string(struct snd_ump_endpoint *ump, char *dest, 660 int maxsize, const u32 *buf, int offset) 661 { 662 unsigned char format; 663 int c; 664 665 format = ump_stream_message_format(buf[0]); 666 if (format == UMP_STREAM_MSG_FORMAT_SINGLE || 667 format == UMP_STREAM_MSG_FORMAT_START) { 668 c = 0; 669 } else { 670 c = strlen(dest); 671 if (c >= maxsize - 1) 672 return 1; 673 } 674 675 for (; offset < 16; offset++) { 676 dest[c] = buf[offset / 4] >> (3 - (offset % 4)) * 8; 677 if (!dest[c]) 678 break; 679 if (++c >= maxsize - 1) 680 break; 681 } 682 dest[c] = 0; 683 return (format == UMP_STREAM_MSG_FORMAT_SINGLE || 684 format == UMP_STREAM_MSG_FORMAT_END); 685 } 686 687 /* Choose the default protocol */ 688 static void choose_default_protocol(struct snd_ump_endpoint *ump) 689 { 690 if (ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK) 691 return; 692 if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2) 693 ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2; 694 else 695 ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1; 696 } 697 698 /* notify the EP info/name change to sequencer */ 699 static void seq_notify_ep_change(struct snd_ump_endpoint *ump) 700 { 701 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 702 if (ump->parsed && ump->seq_ops && ump->seq_ops->notify_ep_change) 703 ump->seq_ops->notify_ep_change(ump); 704 #endif 705 } 706 707 /* handle EP info stream message; update the UMP attributes */ 708 static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump, 709 const union snd_ump_stream_msg *buf) 710 { 711 ump->info.version = (buf->ep_info.ump_version_major << 8) | 712 buf->ep_info.ump_version_minor; 713 ump->info.num_blocks = buf->ep_info.num_function_blocks; 714 if (ump->info.num_blocks > SNDRV_UMP_MAX_BLOCKS) { 715 ump_info(ump, "Invalid function blocks %d, fallback to 1\n", 716 ump->info.num_blocks); 717 ump->info.num_blocks = 1; 718 } 719 720 if (buf->ep_info.static_function_block) 721 ump->info.flags |= SNDRV_UMP_EP_INFO_STATIC_BLOCKS; 722 723 ump->info.protocol_caps = (buf->ep_info.protocol << 8) | 724 buf->ep_info.jrts; 725 726 ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n", 727 ump->info.version, ump->info.num_blocks, ump->info.protocol_caps); 728 729 ump->info.protocol &= ump->info.protocol_caps; 730 choose_default_protocol(ump); 731 seq_notify_ep_change(ump); 732 733 return 1; /* finished */ 734 } 735 736 /* handle EP device info stream message; update the UMP attributes */ 737 static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump, 738 const union snd_ump_stream_msg *buf) 739 { 740 ump->info.manufacturer_id = buf->device_info.manufacture_id & 0x7f7f7f; 741 ump->info.family_id = (buf->device_info.family_msb << 8) | 742 buf->device_info.family_lsb; 743 ump->info.model_id = (buf->device_info.model_msb << 8) | 744 buf->device_info.model_lsb; 745 ump->info.sw_revision[0] = (buf->device_info.sw_revision >> 24) & 0x7f; 746 ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f; 747 ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f; 748 ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f; 749 ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%4phN\n", 750 ump->info.manufacturer_id, 751 ump->info.family_id, 752 ump->info.model_id, 753 ump->info.sw_revision); 754 seq_notify_ep_change(ump); 755 return 1; /* finished */ 756 } 757 758 /* set up the core rawmidi name from UMP EP name string */ 759 static void ump_set_rawmidi_name(struct snd_ump_endpoint *ump) 760 { 761 safe_copy_string(ump->core.name, sizeof(ump->core.name), 762 ump->info.name, sizeof(ump->info.name)); 763 } 764 765 /* handle EP name stream message; update the UMP name string */ 766 static int ump_handle_ep_name_msg(struct snd_ump_endpoint *ump, 767 const union snd_ump_stream_msg *buf) 768 { 769 int ret; 770 771 ret = ump_append_string(ump, ump->info.name, sizeof(ump->info.name), 772 buf->raw, 2); 773 if (ret && ump->parsed) { 774 ump_set_rawmidi_name(ump); 775 ump_legacy_set_rawmidi_name(ump); 776 seq_notify_ep_change(ump); 777 } 778 779 return ret; 780 } 781 782 /* handle EP product id stream message; update the UMP product_id string */ 783 static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump, 784 const union snd_ump_stream_msg *buf) 785 { 786 int ret; 787 788 ret = ump_append_string(ump, ump->info.product_id, 789 sizeof(ump->info.product_id), 790 buf->raw, 2); 791 if (ret) 792 seq_notify_ep_change(ump); 793 return ret; 794 } 795 796 /* notify the protocol change to sequencer */ 797 static void seq_notify_protocol(struct snd_ump_endpoint *ump) 798 { 799 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 800 if (ump->seq_ops && ump->seq_ops->switch_protocol) 801 ump->seq_ops->switch_protocol(ump); 802 #endif /* CONFIG_SND_SEQUENCER */ 803 } 804 805 /** 806 * snd_ump_switch_protocol - switch MIDI protocol 807 * @ump: UMP endpoint 808 * @protocol: protocol to switch to 809 * 810 * Returns 1 if the protocol is actually switched, 0 if unchanged 811 */ 812 int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol) 813 { 814 unsigned int type; 815 816 protocol &= ump->info.protocol_caps; 817 if (protocol == ump->info.protocol) 818 return 0; 819 820 type = protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK; 821 if (type != SNDRV_UMP_EP_INFO_PROTO_MIDI1 && 822 type != SNDRV_UMP_EP_INFO_PROTO_MIDI2) 823 return 0; 824 825 ump->info.protocol = protocol; 826 ump_dbg(ump, "New protocol = %x (caps = %x)\n", 827 protocol, ump->info.protocol_caps); 828 seq_notify_protocol(ump); 829 return 1; 830 } 831 EXPORT_SYMBOL_GPL(snd_ump_switch_protocol); 832 833 /* handle EP stream config message; update the UMP protocol */ 834 static int ump_handle_stream_cfg_msg(struct snd_ump_endpoint *ump, 835 const union snd_ump_stream_msg *buf) 836 { 837 unsigned int protocol = 838 (buf->stream_cfg.protocol << 8) | buf->stream_cfg.jrts; 839 840 snd_ump_switch_protocol(ump, protocol); 841 return 1; /* finished */ 842 } 843 844 /* Extract Function Block info from UMP packet */ 845 static void fill_fb_info(struct snd_ump_endpoint *ump, 846 struct snd_ump_block_info *info, 847 const union snd_ump_stream_msg *buf) 848 { 849 info->direction = buf->fb_info.direction; 850 info->ui_hint = buf->fb_info.ui_hint; 851 info->first_group = buf->fb_info.first_group; 852 info->num_groups = buf->fb_info.num_groups; 853 if (buf->fb_info.midi_10 < 2) 854 info->flags = buf->fb_info.midi_10; 855 else 856 info->flags = SNDRV_UMP_BLOCK_IS_MIDI1 | SNDRV_UMP_BLOCK_IS_LOWSPEED; 857 info->active = buf->fb_info.active; 858 info->midi_ci_version = buf->fb_info.midi_ci_version; 859 info->sysex8_streams = buf->fb_info.sysex8_streams; 860 861 ump_dbg(ump, "FB %d: dir=%d, active=%d, first_gp=%d, num_gp=%d, midici=%d, sysex8=%d, flags=0x%x\n", 862 info->block_id, info->direction, info->active, 863 info->first_group, info->num_groups, info->midi_ci_version, 864 info->sysex8_streams, info->flags); 865 866 if ((info->flags & SNDRV_UMP_BLOCK_IS_MIDI1) && info->num_groups != 1) { 867 info->num_groups = 1; 868 ump_dbg(ump, "FB %d: corrected groups to 1 for MIDI1\n", 869 info->block_id); 870 } 871 } 872 873 /* check whether the FB info gets updated by the current message */ 874 static bool is_fb_info_updated(struct snd_ump_endpoint *ump, 875 struct snd_ump_block *fb, 876 const union snd_ump_stream_msg *buf) 877 { 878 char tmpbuf[offsetof(struct snd_ump_block_info, name)]; 879 880 if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) { 881 ump_info(ump, "Skipping static FB info update (blk#%d)\n", 882 fb->info.block_id); 883 return 0; 884 } 885 886 memcpy(tmpbuf, &fb->info, sizeof(tmpbuf)); 887 fill_fb_info(ump, (struct snd_ump_block_info *)tmpbuf, buf); 888 return memcmp(&fb->info, tmpbuf, sizeof(tmpbuf)) != 0; 889 } 890 891 /* notify the FB info/name change to sequencer */ 892 static void seq_notify_fb_change(struct snd_ump_endpoint *ump, 893 struct snd_ump_block *fb) 894 { 895 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 896 if (ump->seq_ops && ump->seq_ops->notify_fb_change) 897 ump->seq_ops->notify_fb_change(ump, fb); 898 #endif 899 } 900 901 /* handle FB info message; update FB info if the block is present */ 902 static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump, 903 const union snd_ump_stream_msg *buf) 904 { 905 unsigned char blk; 906 struct snd_ump_block *fb; 907 908 blk = buf->fb_info.function_block_id; 909 fb = snd_ump_get_block(ump, blk); 910 911 /* complain only if updated after parsing */ 912 if (!fb && ump->parsed) { 913 ump_info(ump, "Function Block Info Update for non-existing block %d\n", 914 blk); 915 return -ENODEV; 916 } 917 918 /* When updated after the initial parse, check the FB info update */ 919 if (ump->parsed && !is_fb_info_updated(ump, fb, buf)) 920 return 1; /* no content change */ 921 922 if (fb) { 923 fill_fb_info(ump, &fb->info, buf); 924 if (ump->parsed) { 925 snd_ump_update_group_attrs(ump); 926 update_legacy_names(ump); 927 seq_notify_fb_change(ump, fb); 928 } 929 } 930 931 return 1; /* finished */ 932 } 933 934 /* handle FB name message; update the FB name string */ 935 static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump, 936 const union snd_ump_stream_msg *buf) 937 { 938 unsigned char blk; 939 struct snd_ump_block *fb; 940 int ret; 941 942 blk = buf->fb_name.function_block_id; 943 fb = snd_ump_get_block(ump, blk); 944 if (!fb) 945 return -ENODEV; 946 947 if (ump->parsed && 948 (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS)) { 949 ump_dbg(ump, "Skipping static FB name update (blk#%d)\n", 950 fb->info.block_id); 951 return 0; 952 } 953 954 ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name), 955 buf->raw, 3); 956 /* notify the FB name update to sequencer, too */ 957 if (ret > 0 && ump->parsed) { 958 snd_ump_update_group_attrs(ump); 959 update_legacy_names(ump); 960 seq_notify_fb_change(ump, fb); 961 } 962 return ret; 963 } 964 965 static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk) 966 { 967 struct snd_ump_block *fb; 968 unsigned char direction, first_group, num_groups; 969 const union snd_ump_stream_msg *buf = 970 (const union snd_ump_stream_msg *)ump->input_buf; 971 u32 msg; 972 int err; 973 974 /* query the FB info once */ 975 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) | 976 (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_INFO; 977 err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_INFO); 978 if (err < 0) { 979 ump_dbg(ump, "Unable to get FB info for block %d\n", blk); 980 return err; 981 } 982 983 /* the last input must be the FB info */ 984 if (buf->fb_info.status != UMP_STREAM_MSG_STATUS_FB_INFO) { 985 ump_dbg(ump, "Inconsistent input: 0x%x\n", *buf->raw); 986 return -EINVAL; 987 } 988 989 direction = buf->fb_info.direction; 990 first_group = buf->fb_info.first_group; 991 num_groups = buf->fb_info.num_groups; 992 993 err = snd_ump_block_new(ump, blk, direction, first_group, num_groups, 994 &fb); 995 if (err < 0) 996 return err; 997 998 fill_fb_info(ump, &fb->info, buf); 999 1000 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_FB_DISCOVERY, 0) | 1001 (blk << 8) | UMP_STREAM_MSG_REQUEST_FB_NAME; 1002 err = ump_req_msg(ump, msg, 0, UMP_STREAM_MSG_STATUS_FB_NAME); 1003 if (err) 1004 ump_dbg(ump, "Unable to get UMP FB name string #%d\n", blk); 1005 1006 return 0; 1007 } 1008 1009 /* handle stream messages, called from snd_ump_receive() */ 1010 static void ump_handle_stream_msg(struct snd_ump_endpoint *ump, 1011 const u32 *buf, int size) 1012 { 1013 const union snd_ump_stream_msg *msg; 1014 unsigned int status; 1015 int ret; 1016 1017 /* UMP stream message suppressed (for gadget UMP)? */ 1018 if (ump->no_process_stream) 1019 return; 1020 1021 BUILD_BUG_ON(sizeof(*msg) != 16); 1022 ump_dbg(ump, "Stream msg: %08x %08x %08x %08x\n", 1023 buf[0], buf[1], buf[2], buf[3]); 1024 1025 if (size != 4 || ump_message_type(*buf) != UMP_MSG_TYPE_STREAM) 1026 return; 1027 1028 msg = (const union snd_ump_stream_msg *)buf; 1029 status = ump_stream_message_status(*buf); 1030 switch (status) { 1031 case UMP_STREAM_MSG_STATUS_EP_INFO: 1032 ret = ump_handle_ep_info_msg(ump, msg); 1033 break; 1034 case UMP_STREAM_MSG_STATUS_DEVICE_INFO: 1035 ret = ump_handle_device_info_msg(ump, msg); 1036 break; 1037 case UMP_STREAM_MSG_STATUS_EP_NAME: 1038 ret = ump_handle_ep_name_msg(ump, msg); 1039 break; 1040 case UMP_STREAM_MSG_STATUS_PRODUCT_ID: 1041 ret = ump_handle_product_id_msg(ump, msg); 1042 break; 1043 case UMP_STREAM_MSG_STATUS_STREAM_CFG: 1044 ret = ump_handle_stream_cfg_msg(ump, msg); 1045 break; 1046 case UMP_STREAM_MSG_STATUS_FB_INFO: 1047 ret = ump_handle_fb_info_msg(ump, msg); 1048 break; 1049 case UMP_STREAM_MSG_STATUS_FB_NAME: 1050 ret = ump_handle_fb_name_msg(ump, msg); 1051 break; 1052 default: 1053 return; 1054 } 1055 1056 /* when the message has been processed fully, wake up */ 1057 if (ret > 0 && ump->stream_wait_for == status) { 1058 WRITE_ONCE(ump->stream_finished, 1); 1059 wake_up(&ump->stream_wait); 1060 } 1061 } 1062 1063 /** 1064 * snd_ump_parse_endpoint - parse endpoint and create function blocks 1065 * @ump: UMP object 1066 * 1067 * Returns 0 for successful parse, -ENODEV if device doesn't respond 1068 * (or the query is unsupported), or other error code for serious errors. 1069 */ 1070 int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump) 1071 { 1072 int blk, err; 1073 u32 msg; 1074 1075 if (!(ump->core.info_flags & SNDRV_RAWMIDI_INFO_DUPLEX)) 1076 return -ENODEV; 1077 1078 err = ump_request_open(ump); 1079 if (err < 0) { 1080 ump_dbg(ump, "Unable to open rawmidi device: %d\n", err); 1081 return err; 1082 } 1083 1084 /* Check Endpoint Information */ 1085 msg = ump_stream_compose(UMP_STREAM_MSG_STATUS_EP_DISCOVERY, 0) | 1086 0x0101; /* UMP version 1.1 */ 1087 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_INFO, 1088 UMP_STREAM_MSG_STATUS_EP_INFO); 1089 if (err < 0) { 1090 ump_dbg(ump, "Unable to get UMP EP info\n"); 1091 goto error; 1092 } 1093 1094 /* Request Endpoint Device Info */ 1095 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_DEVICE_INFO, 1096 UMP_STREAM_MSG_STATUS_DEVICE_INFO); 1097 if (err < 0) 1098 ump_dbg(ump, "Unable to get UMP EP device info\n"); 1099 1100 /* Request Endpoint Name */ 1101 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_EP_NAME, 1102 UMP_STREAM_MSG_STATUS_EP_NAME); 1103 if (err < 0) 1104 ump_dbg(ump, "Unable to get UMP EP name string\n"); 1105 1106 ump_set_rawmidi_name(ump); 1107 1108 /* Request Endpoint Product ID */ 1109 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_PRODUCT_ID, 1110 UMP_STREAM_MSG_STATUS_PRODUCT_ID); 1111 if (err < 0) 1112 ump_dbg(ump, "Unable to get UMP EP product ID string\n"); 1113 1114 /* Get the current stream configuration */ 1115 err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_STREAM_CFG, 1116 UMP_STREAM_MSG_STATUS_STREAM_CFG); 1117 if (err < 0) 1118 ump_dbg(ump, "Unable to get UMP EP stream config\n"); 1119 1120 /* If no protocol is set by some reason, assume the valid one */ 1121 choose_default_protocol(ump); 1122 1123 /* Query and create blocks from Function Blocks */ 1124 for (blk = 0; blk < ump->info.num_blocks; blk++) { 1125 err = create_block_from_fb_info(ump, blk); 1126 if (err < 0) 1127 continue; 1128 } 1129 1130 /* initialize group attributions */ 1131 snd_ump_update_group_attrs(ump); 1132 1133 error: 1134 ump->parsed = true; 1135 ump_request_close(ump); 1136 if (err == -ETIMEDOUT) 1137 err = -ENODEV; 1138 return err; 1139 } 1140 EXPORT_SYMBOL_GPL(snd_ump_parse_endpoint); 1141 1142 #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) 1143 /* 1144 * Legacy rawmidi support 1145 */ 1146 static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) 1147 { 1148 struct snd_ump_endpoint *ump = substream->rmidi->private_data; 1149 int dir = substream->stream; 1150 int group = ump->legacy_mapping[substream->number]; 1151 int err; 1152 1153 guard(mutex)(&ump->open_mutex); 1154 if (ump->legacy_substreams[dir][group]) 1155 return -EBUSY; 1156 if (!ump->groups[group].active) 1157 return -ENODEV; 1158 if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { 1159 if (!ump->legacy_out_opens) { 1160 err = snd_rawmidi_kernel_open(&ump->core, 0, 1161 SNDRV_RAWMIDI_LFLG_OUTPUT | 1162 SNDRV_RAWMIDI_LFLG_APPEND, 1163 &ump->legacy_out_rfile); 1164 if (err < 0) 1165 return err; 1166 } 1167 ump->legacy_out_opens++; 1168 snd_ump_convert_reset(&ump->out_cvts[group]); 1169 } 1170 guard(spinlock_irq)(&ump->legacy_locks[dir]); 1171 ump->legacy_substreams[dir][group] = substream; 1172 return 0; 1173 } 1174 1175 static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) 1176 { 1177 struct snd_ump_endpoint *ump = substream->rmidi->private_data; 1178 int dir = substream->stream; 1179 int group = ump->legacy_mapping[substream->number]; 1180 1181 guard(mutex)(&ump->open_mutex); 1182 scoped_guard(spinlock_irq, &ump->legacy_locks[dir]) 1183 ump->legacy_substreams[dir][group] = NULL; 1184 if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { 1185 if (!--ump->legacy_out_opens) 1186 snd_rawmidi_kernel_release(&ump->legacy_out_rfile); 1187 } 1188 return 0; 1189 } 1190 1191 static void snd_ump_legacy_trigger(struct snd_rawmidi_substream *substream, 1192 int up) 1193 { 1194 struct snd_ump_endpoint *ump = substream->rmidi->private_data; 1195 int dir = substream->stream; 1196 1197 ump->ops->trigger(ump, dir, up); 1198 } 1199 1200 static void snd_ump_legacy_drain(struct snd_rawmidi_substream *substream) 1201 { 1202 struct snd_ump_endpoint *ump = substream->rmidi->private_data; 1203 1204 if (ump->ops->drain) 1205 ump->ops->drain(ump, SNDRV_RAWMIDI_STREAM_OUTPUT); 1206 } 1207 1208 static int snd_ump_legacy_dev_register(struct snd_rawmidi *rmidi) 1209 { 1210 /* dummy, just for avoiding create superfluous seq clients */ 1211 return 0; 1212 } 1213 1214 static const struct snd_rawmidi_ops snd_ump_legacy_input_ops = { 1215 .open = snd_ump_legacy_open, 1216 .close = snd_ump_legacy_close, 1217 .trigger = snd_ump_legacy_trigger, 1218 }; 1219 1220 static const struct snd_rawmidi_ops snd_ump_legacy_output_ops = { 1221 .open = snd_ump_legacy_open, 1222 .close = snd_ump_legacy_close, 1223 .trigger = snd_ump_legacy_trigger, 1224 .drain = snd_ump_legacy_drain, 1225 }; 1226 1227 static const struct snd_rawmidi_global_ops snd_ump_legacy_ops = { 1228 .dev_register = snd_ump_legacy_dev_register, 1229 }; 1230 1231 static int process_legacy_output(struct snd_ump_endpoint *ump, 1232 u32 *buffer, int count) 1233 { 1234 struct snd_rawmidi_substream *substream; 1235 struct ump_cvt_to_ump *ctx; 1236 const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT; 1237 unsigned int protocol; 1238 unsigned char c; 1239 int group, size = 0; 1240 1241 if (!ump->out_cvts || !ump->legacy_out_opens) 1242 return 0; 1243 1244 guard(spinlock_irqsave)(&ump->legacy_locks[dir]); 1245 for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) { 1246 substream = ump->legacy_substreams[dir][group]; 1247 if (!substream) 1248 continue; 1249 ctx = &ump->out_cvts[group]; 1250 protocol = ump->info.protocol; 1251 if ((protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) && 1252 ump->groups[group].is_midi1) 1253 protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1; 1254 while (!ctx->ump_bytes && 1255 snd_rawmidi_transmit(substream, &c, 1) > 0) 1256 snd_ump_convert_to_ump(ctx, group, protocol, c); 1257 if (ctx->ump_bytes && ctx->ump_bytes <= count) { 1258 size = ctx->ump_bytes; 1259 memcpy(buffer, ctx->ump, size); 1260 ctx->ump_bytes = 0; 1261 break; 1262 } 1263 } 1264 return size; 1265 } 1266 1267 static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, 1268 int words) 1269 { 1270 struct snd_rawmidi_substream *substream; 1271 unsigned char buf[16]; 1272 unsigned char group; 1273 const int dir = SNDRV_RAWMIDI_STREAM_INPUT; 1274 int size; 1275 1276 size = snd_ump_convert_from_ump(src, buf, &group); 1277 if (size <= 0) 1278 return; 1279 guard(spinlock_irqsave)(&ump->legacy_locks[dir]); 1280 substream = ump->legacy_substreams[dir][group]; 1281 if (substream) 1282 snd_rawmidi_receive(substream, buf, size); 1283 } 1284 1285 /* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */ 1286 static int fill_legacy_mapping(struct snd_ump_endpoint *ump) 1287 { 1288 struct snd_ump_block *fb; 1289 unsigned int group_maps = 0; 1290 int i, num; 1291 1292 if (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) { 1293 list_for_each_entry(fb, &ump->block_list, list) { 1294 for (i = 0; i < fb->info.num_groups; i++) 1295 group_maps |= 1U << (fb->info.first_group + i); 1296 } 1297 if (!group_maps) 1298 ump_info(ump, "No UMP Group is found in FB\n"); 1299 } 1300 1301 /* use all groups for non-static case */ 1302 if (!group_maps) 1303 group_maps = (1U << SNDRV_UMP_MAX_GROUPS) - 1; 1304 1305 num = 0; 1306 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) 1307 if (group_maps & (1U << i)) 1308 ump->legacy_mapping[num++] = i; 1309 1310 return num; 1311 } 1312 1313 static void update_legacy_substreams(struct snd_ump_endpoint *ump, 1314 struct snd_rawmidi *rmidi, int dir) 1315 { 1316 struct snd_rawmidi_substream *s; 1317 const char *name; 1318 int idx; 1319 1320 list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { 1321 idx = ump->legacy_mapping[s->number]; 1322 name = ump->groups[idx].name; 1323 if (!*name) 1324 name = ump->core.name; 1325 scnprintf(s->name, sizeof(s->name), "Group %d (%.16s)%s", 1326 idx + 1, name, 1327 ump->groups[idx].active ? "" : " [Inactive]"); 1328 s->inactive = !ump->groups[idx].active; 1329 } 1330 } 1331 1332 static void update_legacy_names(struct snd_ump_endpoint *ump) 1333 { 1334 struct snd_rawmidi *rmidi = ump->legacy_rmidi; 1335 1336 update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT); 1337 update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT); 1338 } 1339 1340 static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump) 1341 { 1342 struct snd_rawmidi *rmidi = ump->legacy_rmidi; 1343 1344 snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)", 1345 ump->core.name); 1346 } 1347 1348 int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, 1349 char *id, int device) 1350 { 1351 struct snd_rawmidi *rmidi; 1352 bool input, output; 1353 int err, num; 1354 1355 ump->out_cvts = kcalloc(SNDRV_UMP_MAX_GROUPS, 1356 sizeof(*ump->out_cvts), GFP_KERNEL); 1357 if (!ump->out_cvts) 1358 return -ENOMEM; 1359 1360 num = fill_legacy_mapping(ump); 1361 1362 input = ump->core.info_flags & SNDRV_RAWMIDI_INFO_INPUT; 1363 output = ump->core.info_flags & SNDRV_RAWMIDI_INFO_OUTPUT; 1364 err = snd_rawmidi_new(ump->core.card, id, device, 1365 output ? num : 0, input ? num : 0, 1366 &rmidi); 1367 if (err < 0) { 1368 kfree(ump->out_cvts); 1369 return err; 1370 } 1371 1372 if (input) 1373 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 1374 &snd_ump_legacy_input_ops); 1375 if (output) 1376 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 1377 &snd_ump_legacy_output_ops); 1378 rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP; 1379 rmidi->ops = &snd_ump_legacy_ops; 1380 rmidi->private_data = ump; 1381 ump->legacy_rmidi = rmidi; 1382 ump_legacy_set_rawmidi_name(ump); 1383 update_legacy_names(ump); 1384 1385 snd_rawmidi_tie_devices(rmidi, &ump->core); 1386 1387 ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id); 1388 return 0; 1389 } 1390 EXPORT_SYMBOL_GPL(snd_ump_attach_legacy_rawmidi); 1391 #endif /* CONFIG_SND_UMP_LEGACY_RAWMIDI */ 1392 1393 MODULE_DESCRIPTION("Universal MIDI Packet (UMP) Core Driver"); 1394 MODULE_LICENSE("GPL"); 1395