1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* ALSA sequencer binding for UMP device */ 3 4 #include <linux/init.h> 5 #include <linux/slab.h> 6 #include <linux/errno.h> 7 #include <linux/mutex.h> 8 #include <linux/string.h> 9 #include <linux/module.h> 10 #include <asm/byteorder.h> 11 #include <sound/core.h> 12 #include <sound/ump.h> 13 #include <sound/seq_kernel.h> 14 #include <sound/seq_device.h> 15 #include "seq_clientmgr.h" 16 #include "seq_system.h" 17 18 struct seq_ump_client; 19 struct seq_ump_group; 20 21 enum { 22 STR_IN = SNDRV_RAWMIDI_STREAM_INPUT, 23 STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT 24 }; 25 26 /* object per UMP group; corresponding to a sequencer port */ 27 struct seq_ump_group { 28 int group; /* group index (0-based) */ 29 unsigned int dir_bits; /* directions */ 30 bool active; /* activeness */ 31 bool valid; /* valid group (referred by blocks) */ 32 char name[64]; /* seq port name */ 33 }; 34 35 /* context for UMP input parsing, per EP */ 36 struct seq_ump_input_buffer { 37 unsigned char len; /* total length in words */ 38 unsigned char pending; /* pending words */ 39 unsigned char type; /* parsed UMP packet type */ 40 unsigned char group; /* parsed UMP packet group */ 41 u32 buf[4]; /* incoming UMP packet */ 42 }; 43 44 /* sequencer client, per UMP EP (rawmidi) */ 45 struct seq_ump_client { 46 struct snd_ump_endpoint *ump; /* assigned endpoint */ 47 int seq_client; /* sequencer client id */ 48 int opened[2]; /* current opens for each direction */ 49 struct snd_rawmidi_file out_rfile; /* rawmidi for output */ 50 struct seq_ump_input_buffer input; /* input parser context */ 51 struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */ 52 void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */ 53 struct work_struct group_notify_work; /* FB change notification */ 54 }; 55 56 /* number of 32bit words for each UMP message type */ 57 static unsigned char ump_packet_words[0x10] = { 58 1, 1, 1, 2, 2, 4, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4 59 }; 60 61 /* conversion between UMP group and seq port; 62 * assume the port number is equal with UMP group number (1-based) 63 */ 64 static unsigned char ump_group_to_seq_port(unsigned char group) 65 { 66 return group + 1; 67 } 68 69 /* process the incoming rawmidi stream */ 70 static void seq_ump_input_receive(struct snd_ump_endpoint *ump, 71 const u32 *val, int words) 72 { 73 struct seq_ump_client *client = ump->seq_client; 74 struct snd_seq_ump_event ev = {}; 75 76 if (!client->opened[STR_IN]) 77 return; 78 79 if (ump_is_groupless_msg(ump_message_type(*val))) 80 ev.source.port = 0; /* UMP EP port */ 81 else 82 ev.source.port = ump_group_to_seq_port(ump_message_group(*val)); 83 ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS; 84 ev.flags = SNDRV_SEQ_EVENT_UMP; 85 memcpy(ev.ump, val, words << 2); 86 snd_seq_kernel_client_dispatch(client->seq_client, 87 (struct snd_seq_event *)&ev, 88 true, 0); 89 } 90 91 /* process an input sequencer event; only deal with UMP types */ 92 static int seq_ump_process_event(struct snd_seq_event *ev, int direct, 93 void *private_data, int atomic, int hop) 94 { 95 struct seq_ump_client *client = private_data; 96 struct snd_rawmidi_substream *substream; 97 struct snd_seq_ump_event *ump_ev; 98 unsigned char type; 99 int len; 100 101 substream = client->out_rfile.output; 102 if (!substream) 103 return -ENODEV; 104 if (!snd_seq_ev_is_ump(ev)) 105 return 0; /* invalid event, skip */ 106 ump_ev = (struct snd_seq_ump_event *)ev; 107 type = ump_message_type(ump_ev->ump[0]); 108 len = ump_packet_words[type]; 109 if (len > 4) 110 return 0; // invalid - skip 111 snd_rawmidi_kernel_write(substream, ev->data.raw8.d, len << 2); 112 return 0; 113 } 114 115 /* open the rawmidi */ 116 static int seq_ump_client_open(struct seq_ump_client *client, int dir) 117 { 118 struct snd_ump_endpoint *ump = client->ump; 119 int err = 0; 120 121 mutex_lock(&ump->open_mutex); 122 if (dir == STR_OUT && !client->opened[dir]) { 123 err = snd_rawmidi_kernel_open(&ump->core, 0, 124 SNDRV_RAWMIDI_LFLG_OUTPUT | 125 SNDRV_RAWMIDI_LFLG_APPEND, 126 &client->out_rfile); 127 if (err < 0) 128 goto unlock; 129 } 130 client->opened[dir]++; 131 unlock: 132 mutex_unlock(&ump->open_mutex); 133 return err; 134 } 135 136 /* close the rawmidi */ 137 static int seq_ump_client_close(struct seq_ump_client *client, int dir) 138 { 139 struct snd_ump_endpoint *ump = client->ump; 140 141 mutex_lock(&ump->open_mutex); 142 if (!--client->opened[dir]) 143 if (dir == STR_OUT) 144 snd_rawmidi_kernel_release(&client->out_rfile); 145 mutex_unlock(&ump->open_mutex); 146 return 0; 147 } 148 149 /* sequencer subscription ops for each client */ 150 static int seq_ump_subscribe(void *pdata, struct snd_seq_port_subscribe *info) 151 { 152 struct seq_ump_client *client = pdata; 153 154 return seq_ump_client_open(client, STR_IN); 155 } 156 157 static int seq_ump_unsubscribe(void *pdata, struct snd_seq_port_subscribe *info) 158 { 159 struct seq_ump_client *client = pdata; 160 161 return seq_ump_client_close(client, STR_IN); 162 } 163 164 static int seq_ump_use(void *pdata, struct snd_seq_port_subscribe *info) 165 { 166 struct seq_ump_client *client = pdata; 167 168 return seq_ump_client_open(client, STR_OUT); 169 } 170 171 static int seq_ump_unuse(void *pdata, struct snd_seq_port_subscribe *info) 172 { 173 struct seq_ump_client *client = pdata; 174 175 return seq_ump_client_close(client, STR_OUT); 176 } 177 178 /* fill port_info from the given UMP EP and group info */ 179 static void fill_port_info(struct snd_seq_port_info *port, 180 struct seq_ump_client *client, 181 struct seq_ump_group *group) 182 { 183 unsigned int rawmidi_info = client->ump->core.info_flags; 184 185 port->addr.client = client->seq_client; 186 port->addr.port = ump_group_to_seq_port(group->group); 187 port->capability = 0; 188 if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) 189 port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | 190 SNDRV_SEQ_PORT_CAP_SYNC_WRITE | 191 SNDRV_SEQ_PORT_CAP_SUBS_WRITE; 192 if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) 193 port->capability |= SNDRV_SEQ_PORT_CAP_READ | 194 SNDRV_SEQ_PORT_CAP_SYNC_READ | 195 SNDRV_SEQ_PORT_CAP_SUBS_READ; 196 if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX) 197 port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; 198 if (group->dir_bits & (1 << STR_IN)) 199 port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; 200 if (group->dir_bits & (1 << STR_OUT)) 201 port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; 202 port->ump_group = group->group + 1; 203 if (!group->active) 204 port->capability |= SNDRV_SEQ_PORT_CAP_INACTIVE; 205 port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | 206 SNDRV_SEQ_PORT_TYPE_MIDI_UMP | 207 SNDRV_SEQ_PORT_TYPE_HARDWARE | 208 SNDRV_SEQ_PORT_TYPE_PORT; 209 port->midi_channels = 16; 210 if (*group->name) 211 snprintf(port->name, sizeof(port->name), "Group %d (%.53s)", 212 group->group + 1, group->name); 213 else 214 sprintf(port->name, "Group %d", group->group + 1); 215 } 216 217 /* skip non-existing group for static blocks */ 218 static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *group) 219 { 220 return !group->valid && 221 (client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS); 222 } 223 224 /* create a new sequencer port per UMP group */ 225 static int seq_ump_group_init(struct seq_ump_client *client, int group_index) 226 { 227 struct seq_ump_group *group = &client->groups[group_index]; 228 struct snd_seq_port_info *port; 229 struct snd_seq_port_callback pcallbacks; 230 int err; 231 232 if (skip_group(client, group)) 233 return 0; 234 235 port = kzalloc(sizeof(*port), GFP_KERNEL); 236 if (!port) { 237 err = -ENOMEM; 238 goto error; 239 } 240 241 fill_port_info(port, client, group); 242 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; 243 memset(&pcallbacks, 0, sizeof(pcallbacks)); 244 pcallbacks.owner = THIS_MODULE; 245 pcallbacks.private_data = client; 246 pcallbacks.subscribe = seq_ump_subscribe; 247 pcallbacks.unsubscribe = seq_ump_unsubscribe; 248 pcallbacks.use = seq_ump_use; 249 pcallbacks.unuse = seq_ump_unuse; 250 pcallbacks.event_input = seq_ump_process_event; 251 port->kernel = &pcallbacks; 252 err = snd_seq_kernel_client_ctl(client->seq_client, 253 SNDRV_SEQ_IOCTL_CREATE_PORT, 254 port); 255 error: 256 kfree(port); 257 return err; 258 } 259 260 /* update the sequencer ports; called from notify_fb_change callback */ 261 static void update_port_infos(struct seq_ump_client *client) 262 { 263 struct snd_seq_port_info *old, *new; 264 int i, err; 265 266 old = kzalloc(sizeof(*old), GFP_KERNEL); 267 new = kzalloc(sizeof(*new), GFP_KERNEL); 268 if (!old || !new) 269 goto error; 270 271 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { 272 if (skip_group(client, &client->groups[i])) 273 continue; 274 275 old->addr.client = client->seq_client; 276 old->addr.port = i; 277 err = snd_seq_kernel_client_ctl(client->seq_client, 278 SNDRV_SEQ_IOCTL_GET_PORT_INFO, 279 old); 280 if (err < 0) 281 goto error; 282 fill_port_info(new, client, &client->groups[i]); 283 if (old->capability == new->capability && 284 !strcmp(old->name, new->name)) 285 continue; 286 err = snd_seq_kernel_client_ctl(client->seq_client, 287 SNDRV_SEQ_IOCTL_SET_PORT_INFO, 288 new); 289 if (err < 0) 290 goto error; 291 /* notify to system port */ 292 snd_seq_system_client_ev_port_change(client->seq_client, i); 293 } 294 error: 295 kfree(new); 296 kfree(old); 297 } 298 299 /* update dir_bits and active flag for all groups in the client */ 300 static void update_group_attrs(struct seq_ump_client *client) 301 { 302 struct snd_ump_block *fb; 303 struct seq_ump_group *group; 304 int i; 305 306 for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { 307 group = &client->groups[i]; 308 *group->name = 0; 309 group->dir_bits = 0; 310 group->active = 0; 311 group->group = i; 312 group->valid = false; 313 } 314 315 list_for_each_entry(fb, &client->ump->block_list, list) { 316 if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS) 317 break; 318 group = &client->groups[fb->info.first_group]; 319 for (i = 0; i < fb->info.num_groups; i++, group++) { 320 group->valid = true; 321 if (fb->info.active) 322 group->active = 1; 323 switch (fb->info.direction) { 324 case SNDRV_UMP_DIR_INPUT: 325 group->dir_bits |= (1 << STR_IN); 326 break; 327 case SNDRV_UMP_DIR_OUTPUT: 328 group->dir_bits |= (1 << STR_OUT); 329 break; 330 case SNDRV_UMP_DIR_BIDIRECTION: 331 group->dir_bits |= (1 << STR_OUT) | (1 << STR_IN); 332 break; 333 } 334 if (!*fb->info.name) 335 continue; 336 if (!*group->name) { 337 /* store the first matching name */ 338 strscpy(group->name, fb->info.name, 339 sizeof(group->name)); 340 } else { 341 /* when overlapping, concat names */ 342 strlcat(group->name, ", ", sizeof(group->name)); 343 strlcat(group->name, fb->info.name, 344 sizeof(group->name)); 345 } 346 } 347 } 348 } 349 350 /* create a UMP Endpoint port */ 351 static int create_ump_endpoint_port(struct seq_ump_client *client) 352 { 353 struct snd_seq_port_info *port; 354 struct snd_seq_port_callback pcallbacks; 355 unsigned int rawmidi_info = client->ump->core.info_flags; 356 int err; 357 358 port = kzalloc(sizeof(*port), GFP_KERNEL); 359 if (!port) 360 return -ENOMEM; 361 362 port->addr.client = client->seq_client; 363 port->addr.port = 0; /* fixed */ 364 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; 365 port->capability = SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT; 366 if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { 367 port->capability |= SNDRV_SEQ_PORT_CAP_READ | 368 SNDRV_SEQ_PORT_CAP_SYNC_READ | 369 SNDRV_SEQ_PORT_CAP_SUBS_READ; 370 port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; 371 } 372 if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { 373 port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | 374 SNDRV_SEQ_PORT_CAP_SYNC_WRITE | 375 SNDRV_SEQ_PORT_CAP_SUBS_WRITE; 376 port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; 377 } 378 if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX) 379 port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; 380 port->ump_group = 0; /* no associated group, no conversion */ 381 port->type = SNDRV_SEQ_PORT_TYPE_MIDI_UMP | 382 SNDRV_SEQ_PORT_TYPE_HARDWARE | 383 SNDRV_SEQ_PORT_TYPE_PORT; 384 port->midi_channels = 16; 385 strcpy(port->name, "MIDI 2.0"); 386 memset(&pcallbacks, 0, sizeof(pcallbacks)); 387 pcallbacks.owner = THIS_MODULE; 388 pcallbacks.private_data = client; 389 if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { 390 pcallbacks.subscribe = seq_ump_subscribe; 391 pcallbacks.unsubscribe = seq_ump_unsubscribe; 392 } 393 if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { 394 pcallbacks.use = seq_ump_use; 395 pcallbacks.unuse = seq_ump_unuse; 396 pcallbacks.event_input = seq_ump_process_event; 397 } 398 port->kernel = &pcallbacks; 399 err = snd_seq_kernel_client_ctl(client->seq_client, 400 SNDRV_SEQ_IOCTL_CREATE_PORT, 401 port); 402 kfree(port); 403 return err; 404 } 405 406 /* release the client resources */ 407 static void seq_ump_client_free(struct seq_ump_client *client) 408 { 409 cancel_work_sync(&client->group_notify_work); 410 411 if (client->seq_client >= 0) 412 snd_seq_delete_kernel_client(client->seq_client); 413 414 client->ump->seq_ops = NULL; 415 client->ump->seq_client = NULL; 416 417 kfree(client); 418 } 419 420 /* update the MIDI version for the given client */ 421 static void setup_client_midi_version(struct seq_ump_client *client) 422 { 423 struct snd_seq_client *cptr; 424 425 cptr = snd_seq_kernel_client_get(client->seq_client); 426 if (!cptr) 427 return; 428 if (client->ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) 429 cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_2_0; 430 else 431 cptr->midi_version = SNDRV_SEQ_CLIENT_UMP_MIDI_1_0; 432 snd_seq_kernel_client_put(cptr); 433 } 434 435 /* set up client's group_filter bitmap */ 436 static void setup_client_group_filter(struct seq_ump_client *client) 437 { 438 struct snd_seq_client *cptr; 439 unsigned int filter; 440 int p; 441 442 cptr = snd_seq_kernel_client_get(client->seq_client); 443 if (!cptr) 444 return; 445 filter = ~(1U << 0); /* always allow groupless messages */ 446 for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { 447 if (client->groups[p].active) 448 filter &= ~(1U << (p + 1)); 449 } 450 cptr->group_filter = filter; 451 snd_seq_kernel_client_put(cptr); 452 } 453 454 /* UMP group change notification */ 455 static void handle_group_notify(struct work_struct *work) 456 { 457 struct seq_ump_client *client = 458 container_of(work, struct seq_ump_client, group_notify_work); 459 460 update_group_attrs(client); 461 update_port_infos(client); 462 setup_client_group_filter(client); 463 } 464 465 /* UMP FB change notification */ 466 static int seq_ump_notify_fb_change(struct snd_ump_endpoint *ump, 467 struct snd_ump_block *fb) 468 { 469 struct seq_ump_client *client = ump->seq_client; 470 471 if (!client) 472 return -ENODEV; 473 schedule_work(&client->group_notify_work); 474 return 0; 475 } 476 477 /* UMP protocol change notification; just update the midi_version field */ 478 static int seq_ump_switch_protocol(struct snd_ump_endpoint *ump) 479 { 480 if (!ump->seq_client) 481 return -ENODEV; 482 setup_client_midi_version(ump->seq_client); 483 return 0; 484 } 485 486 static const struct snd_seq_ump_ops seq_ump_ops = { 487 .input_receive = seq_ump_input_receive, 488 .notify_fb_change = seq_ump_notify_fb_change, 489 .switch_protocol = seq_ump_switch_protocol, 490 }; 491 492 /* create a sequencer client and ports for the given UMP endpoint */ 493 static int snd_seq_ump_probe(struct device *_dev) 494 { 495 struct snd_seq_device *dev = to_seq_dev(_dev); 496 struct snd_ump_endpoint *ump = dev->private_data; 497 struct snd_card *card = dev->card; 498 struct seq_ump_client *client; 499 struct snd_ump_block *fb; 500 struct snd_seq_client *cptr; 501 int p, err; 502 503 client = kzalloc(sizeof(*client), GFP_KERNEL); 504 if (!client) 505 return -ENOMEM; 506 507 INIT_WORK(&client->group_notify_work, handle_group_notify); 508 client->ump = ump; 509 510 client->seq_client = 511 snd_seq_create_kernel_client(card, ump->core.device, 512 ump->core.name); 513 if (client->seq_client < 0) { 514 err = client->seq_client; 515 goto error; 516 } 517 518 client->ump_info[0] = &ump->info; 519 list_for_each_entry(fb, &ump->block_list, list) 520 client->ump_info[fb->info.block_id + 1] = &fb->info; 521 522 setup_client_midi_version(client); 523 update_group_attrs(client); 524 525 for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { 526 err = seq_ump_group_init(client, p); 527 if (err < 0) 528 goto error; 529 } 530 531 setup_client_group_filter(client); 532 533 err = create_ump_endpoint_port(client); 534 if (err < 0) 535 goto error; 536 537 cptr = snd_seq_kernel_client_get(client->seq_client); 538 if (!cptr) { 539 err = -EINVAL; 540 goto error; 541 } 542 cptr->ump_info = client->ump_info; 543 snd_seq_kernel_client_put(cptr); 544 545 ump->seq_client = client; 546 ump->seq_ops = &seq_ump_ops; 547 return 0; 548 549 error: 550 seq_ump_client_free(client); 551 return err; 552 } 553 554 /* remove a sequencer client */ 555 static int snd_seq_ump_remove(struct device *_dev) 556 { 557 struct snd_seq_device *dev = to_seq_dev(_dev); 558 struct snd_ump_endpoint *ump = dev->private_data; 559 560 if (ump->seq_client) 561 seq_ump_client_free(ump->seq_client); 562 return 0; 563 } 564 565 static struct snd_seq_driver seq_ump_driver = { 566 .driver = { 567 .name = KBUILD_MODNAME, 568 .probe = snd_seq_ump_probe, 569 .remove = snd_seq_ump_remove, 570 }, 571 .id = SNDRV_SEQ_DEV_ID_UMP, 572 .argsize = 0, 573 }; 574 575 module_snd_seq_driver(seq_ump_driver); 576 577 MODULE_DESCRIPTION("ALSA sequencer client for UMP rawmidi"); 578 MODULE_LICENSE("GPL"); 579