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