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