Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.6-rc3 725 lines 18 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * configfs.c - Implementation of configfs interface to the driver stack 4 * 5 * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG 6 */ 7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9#include <linux/module.h> 10#include <linux/slab.h> 11#include <linux/init.h> 12#include <linux/configfs.h> 13 14#include "most.h" 15 16#define MAX_STRING_SIZE 80 17 18struct mdev_link { 19 struct config_item item; 20 struct list_head list; 21 bool create_link; 22 bool destroy_link; 23 u16 num_buffers; 24 u16 buffer_size; 25 u16 subbuffer_size; 26 u16 packets_per_xact; 27 u16 dbr_size; 28 char datatype[MAX_STRING_SIZE]; 29 char direction[MAX_STRING_SIZE]; 30 char name[MAX_STRING_SIZE]; 31 char device[MAX_STRING_SIZE]; 32 char channel[MAX_STRING_SIZE]; 33 char comp[MAX_STRING_SIZE]; 34 char comp_params[MAX_STRING_SIZE]; 35}; 36 37static struct list_head mdev_link_list; 38 39static int set_cfg_buffer_size(struct mdev_link *link) 40{ 41 return most_set_cfg_buffer_size(link->device, link->channel, 42 link->buffer_size); 43} 44 45static int set_cfg_subbuffer_size(struct mdev_link *link) 46{ 47 return most_set_cfg_subbuffer_size(link->device, link->channel, 48 link->subbuffer_size); 49} 50 51static int set_cfg_dbr_size(struct mdev_link *link) 52{ 53 return most_set_cfg_dbr_size(link->device, link->channel, 54 link->dbr_size); 55} 56 57static int set_cfg_num_buffers(struct mdev_link *link) 58{ 59 return most_set_cfg_num_buffers(link->device, link->channel, 60 link->num_buffers); 61} 62 63static int set_cfg_packets_xact(struct mdev_link *link) 64{ 65 return most_set_cfg_packets_xact(link->device, link->channel, 66 link->packets_per_xact); 67} 68 69static int set_cfg_direction(struct mdev_link *link) 70{ 71 return most_set_cfg_direction(link->device, link->channel, 72 link->direction); 73} 74 75static int set_cfg_datatype(struct mdev_link *link) 76{ 77 return most_set_cfg_datatype(link->device, link->channel, 78 link->datatype); 79} 80 81static int (*set_config_val[])(struct mdev_link *link) = { 82 set_cfg_buffer_size, 83 set_cfg_subbuffer_size, 84 set_cfg_dbr_size, 85 set_cfg_num_buffers, 86 set_cfg_packets_xact, 87 set_cfg_direction, 88 set_cfg_datatype, 89}; 90 91static struct mdev_link *to_mdev_link(struct config_item *item) 92{ 93 return container_of(item, struct mdev_link, item); 94} 95 96static int set_config_and_add_link(struct mdev_link *mdev_link) 97{ 98 int i; 99 int ret; 100 101 for (i = 0; i < ARRAY_SIZE(set_config_val); i++) { 102 ret = set_config_val[i](mdev_link); 103 if (ret < 0 && ret != -ENODEV) { 104 pr_err("Config failed\n"); 105 return ret; 106 } 107 } 108 109 return most_add_link(mdev_link->device, mdev_link->channel, 110 mdev_link->comp, mdev_link->name, 111 mdev_link->comp_params); 112} 113 114static ssize_t mdev_link_create_link_store(struct config_item *item, 115 const char *page, size_t count) 116{ 117 struct mdev_link *mdev_link = to_mdev_link(item); 118 bool tmp; 119 int ret; 120 121 ret = kstrtobool(page, &tmp); 122 if (ret) 123 return ret; 124 if (!tmp) 125 return count; 126 ret = set_config_and_add_link(mdev_link); 127 if (ret && ret != -ENODEV) 128 return ret; 129 list_add_tail(&mdev_link->list, &mdev_link_list); 130 mdev_link->create_link = tmp; 131 mdev_link->destroy_link = false; 132 133 return count; 134} 135 136static ssize_t mdev_link_destroy_link_store(struct config_item *item, 137 const char *page, size_t count) 138{ 139 struct mdev_link *mdev_link = to_mdev_link(item); 140 bool tmp; 141 int ret; 142 143 ret = kstrtobool(page, &tmp); 144 if (ret) 145 return ret; 146 if (!tmp) 147 return count; 148 149 ret = most_remove_link(mdev_link->device, mdev_link->channel, 150 mdev_link->comp); 151 if (ret) 152 return ret; 153 if (!list_empty(&mdev_link_list)) 154 list_del(&mdev_link->list); 155 156 mdev_link->destroy_link = tmp; 157 158 return count; 159} 160 161static ssize_t mdev_link_direction_show(struct config_item *item, char *page) 162{ 163 return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->direction); 164} 165 166static ssize_t mdev_link_direction_store(struct config_item *item, 167 const char *page, size_t count) 168{ 169 struct mdev_link *mdev_link = to_mdev_link(item); 170 171 if (!sysfs_streq(page, "dir_rx") && !sysfs_streq(page, "rx") && 172 !sysfs_streq(page, "dir_tx") && !sysfs_streq(page, "tx")) 173 return -EINVAL; 174 strcpy(mdev_link->direction, page); 175 strim(mdev_link->direction); 176 return count; 177} 178 179static ssize_t mdev_link_datatype_show(struct config_item *item, char *page) 180{ 181 return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->datatype); 182} 183 184static ssize_t mdev_link_datatype_store(struct config_item *item, 185 const char *page, size_t count) 186{ 187 struct mdev_link *mdev_link = to_mdev_link(item); 188 189 if (!sysfs_streq(page, "control") && !sysfs_streq(page, "async") && 190 !sysfs_streq(page, "sync") && !sysfs_streq(page, "isoc") && 191 !sysfs_streq(page, "isoc_avp")) 192 return -EINVAL; 193 strcpy(mdev_link->datatype, page); 194 strim(mdev_link->datatype); 195 return count; 196} 197 198static ssize_t mdev_link_device_show(struct config_item *item, char *page) 199{ 200 return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->device); 201} 202 203static ssize_t mdev_link_device_store(struct config_item *item, 204 const char *page, size_t count) 205{ 206 struct mdev_link *mdev_link = to_mdev_link(item); 207 208 strlcpy(mdev_link->device, page, sizeof(mdev_link->device)); 209 strim(mdev_link->device); 210 return count; 211} 212 213static ssize_t mdev_link_channel_show(struct config_item *item, char *page) 214{ 215 return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->channel); 216} 217 218static ssize_t mdev_link_channel_store(struct config_item *item, 219 const char *page, size_t count) 220{ 221 struct mdev_link *mdev_link = to_mdev_link(item); 222 223 strlcpy(mdev_link->channel, page, sizeof(mdev_link->channel)); 224 strim(mdev_link->channel); 225 return count; 226} 227 228static ssize_t mdev_link_comp_show(struct config_item *item, char *page) 229{ 230 return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->comp); 231} 232 233static ssize_t mdev_link_comp_store(struct config_item *item, 234 const char *page, size_t count) 235{ 236 struct mdev_link *mdev_link = to_mdev_link(item); 237 238 strlcpy(mdev_link->comp, page, sizeof(mdev_link->comp)); 239 strim(mdev_link->comp); 240 return count; 241} 242 243static ssize_t mdev_link_comp_params_show(struct config_item *item, char *page) 244{ 245 return snprintf(page, PAGE_SIZE, "%s\n", 246 to_mdev_link(item)->comp_params); 247} 248 249static ssize_t mdev_link_comp_params_store(struct config_item *item, 250 const char *page, size_t count) 251{ 252 struct mdev_link *mdev_link = to_mdev_link(item); 253 254 strlcpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params)); 255 strim(mdev_link->comp_params); 256 return count; 257} 258 259static ssize_t mdev_link_num_buffers_show(struct config_item *item, char *page) 260{ 261 return snprintf(page, PAGE_SIZE, "%d\n", 262 to_mdev_link(item)->num_buffers); 263} 264 265static ssize_t mdev_link_num_buffers_store(struct config_item *item, 266 const char *page, size_t count) 267{ 268 struct mdev_link *mdev_link = to_mdev_link(item); 269 int ret; 270 271 ret = kstrtou16(page, 0, &mdev_link->num_buffers); 272 if (ret) 273 return ret; 274 return count; 275} 276 277static ssize_t mdev_link_buffer_size_show(struct config_item *item, char *page) 278{ 279 return snprintf(page, PAGE_SIZE, "%d\n", 280 to_mdev_link(item)->buffer_size); 281} 282 283static ssize_t mdev_link_buffer_size_store(struct config_item *item, 284 const char *page, size_t count) 285{ 286 struct mdev_link *mdev_link = to_mdev_link(item); 287 int ret; 288 289 ret = kstrtou16(page, 0, &mdev_link->buffer_size); 290 if (ret) 291 return ret; 292 return count; 293} 294 295static ssize_t mdev_link_subbuffer_size_show(struct config_item *item, 296 char *page) 297{ 298 return snprintf(page, PAGE_SIZE, "%d\n", 299 to_mdev_link(item)->subbuffer_size); 300} 301 302static ssize_t mdev_link_subbuffer_size_store(struct config_item *item, 303 const char *page, size_t count) 304{ 305 struct mdev_link *mdev_link = to_mdev_link(item); 306 int ret; 307 308 ret = kstrtou16(page, 0, &mdev_link->subbuffer_size); 309 if (ret) 310 return ret; 311 return count; 312} 313 314static ssize_t mdev_link_packets_per_xact_show(struct config_item *item, 315 char *page) 316{ 317 return snprintf(page, PAGE_SIZE, "%d\n", 318 to_mdev_link(item)->packets_per_xact); 319} 320 321static ssize_t mdev_link_packets_per_xact_store(struct config_item *item, 322 const char *page, size_t count) 323{ 324 struct mdev_link *mdev_link = to_mdev_link(item); 325 int ret; 326 327 ret = kstrtou16(page, 0, &mdev_link->packets_per_xact); 328 if (ret) 329 return ret; 330 return count; 331} 332 333static ssize_t mdev_link_dbr_size_show(struct config_item *item, char *page) 334{ 335 return snprintf(page, PAGE_SIZE, "%d\n", to_mdev_link(item)->dbr_size); 336} 337 338static ssize_t mdev_link_dbr_size_store(struct config_item *item, 339 const char *page, size_t count) 340{ 341 struct mdev_link *mdev_link = to_mdev_link(item); 342 int ret; 343 344 ret = kstrtou16(page, 0, &mdev_link->dbr_size); 345 if (ret) 346 return ret; 347 return count; 348} 349 350CONFIGFS_ATTR_WO(mdev_link_, create_link); 351CONFIGFS_ATTR_WO(mdev_link_, destroy_link); 352CONFIGFS_ATTR(mdev_link_, device); 353CONFIGFS_ATTR(mdev_link_, channel); 354CONFIGFS_ATTR(mdev_link_, comp); 355CONFIGFS_ATTR(mdev_link_, comp_params); 356CONFIGFS_ATTR(mdev_link_, num_buffers); 357CONFIGFS_ATTR(mdev_link_, buffer_size); 358CONFIGFS_ATTR(mdev_link_, subbuffer_size); 359CONFIGFS_ATTR(mdev_link_, packets_per_xact); 360CONFIGFS_ATTR(mdev_link_, datatype); 361CONFIGFS_ATTR(mdev_link_, direction); 362CONFIGFS_ATTR(mdev_link_, dbr_size); 363 364static struct configfs_attribute *mdev_link_attrs[] = { 365 &mdev_link_attr_create_link, 366 &mdev_link_attr_destroy_link, 367 &mdev_link_attr_device, 368 &mdev_link_attr_channel, 369 &mdev_link_attr_comp, 370 &mdev_link_attr_comp_params, 371 &mdev_link_attr_num_buffers, 372 &mdev_link_attr_buffer_size, 373 &mdev_link_attr_subbuffer_size, 374 &mdev_link_attr_packets_per_xact, 375 &mdev_link_attr_datatype, 376 &mdev_link_attr_direction, 377 &mdev_link_attr_dbr_size, 378 NULL, 379}; 380 381static void mdev_link_release(struct config_item *item) 382{ 383 struct mdev_link *mdev_link = to_mdev_link(item); 384 int ret; 385 386 if (mdev_link->destroy_link) 387 goto free_item; 388 389 ret = most_remove_link(mdev_link->device, mdev_link->channel, 390 mdev_link->comp); 391 if (ret) { 392 pr_err("Removing link failed.\n"); 393 goto free_item; 394 } 395 396 if (!list_empty(&mdev_link_list)) 397 list_del(&mdev_link->list); 398 399free_item: 400 kfree(to_mdev_link(item)); 401} 402 403static struct configfs_item_operations mdev_link_item_ops = { 404 .release = mdev_link_release, 405}; 406 407static const struct config_item_type mdev_link_type = { 408 .ct_item_ops = &mdev_link_item_ops, 409 .ct_attrs = mdev_link_attrs, 410 .ct_owner = THIS_MODULE, 411}; 412 413struct most_common { 414 struct config_group group; 415 struct module *mod; 416 struct configfs_subsystem subsys; 417}; 418 419static struct most_common *to_most_common(struct configfs_subsystem *subsys) 420{ 421 return container_of(subsys, struct most_common, subsys); 422} 423 424static struct config_item *most_common_make_item(struct config_group *group, 425 const char *name) 426{ 427 struct mdev_link *mdev_link; 428 struct most_common *mc = to_most_common(group->cg_subsys); 429 430 mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 431 if (!mdev_link) 432 return ERR_PTR(-ENOMEM); 433 434 if (!try_module_get(mc->mod)) { 435 kfree(mdev_link); 436 return ERR_PTR(-ENOLCK); 437 } 438 config_item_init_type_name(&mdev_link->item, name, 439 &mdev_link_type); 440 441 if (!strcmp(group->cg_item.ci_namebuf, "most_cdev")) 442 strcpy(mdev_link->comp, "cdev"); 443 else if (!strcmp(group->cg_item.ci_namebuf, "most_net")) 444 strcpy(mdev_link->comp, "net"); 445 else if (!strcmp(group->cg_item.ci_namebuf, "most_video")) 446 strcpy(mdev_link->comp, "video"); 447 strcpy(mdev_link->name, name); 448 return &mdev_link->item; 449} 450 451static void most_common_release(struct config_item *item) 452{ 453 struct config_group *group = to_config_group(item); 454 455 kfree(to_most_common(group->cg_subsys)); 456} 457 458static struct configfs_item_operations most_common_item_ops = { 459 .release = most_common_release, 460}; 461 462static void most_common_disconnect(struct config_group *group, 463 struct config_item *item) 464{ 465 struct most_common *mc = to_most_common(group->cg_subsys); 466 467 module_put(mc->mod); 468} 469 470static struct configfs_group_operations most_common_group_ops = { 471 .make_item = most_common_make_item, 472 .disconnect_notify = most_common_disconnect, 473}; 474 475static const struct config_item_type most_common_type = { 476 .ct_item_ops = &most_common_item_ops, 477 .ct_group_ops = &most_common_group_ops, 478 .ct_owner = THIS_MODULE, 479}; 480 481static struct most_common most_cdev = { 482 .subsys = { 483 .su_group = { 484 .cg_item = { 485 .ci_namebuf = "most_cdev", 486 .ci_type = &most_common_type, 487 }, 488 }, 489 }, 490}; 491 492static struct most_common most_net = { 493 .subsys = { 494 .su_group = { 495 .cg_item = { 496 .ci_namebuf = "most_net", 497 .ci_type = &most_common_type, 498 }, 499 }, 500 }, 501}; 502 503static struct most_common most_video = { 504 .subsys = { 505 .su_group = { 506 .cg_item = { 507 .ci_namebuf = "most_video", 508 .ci_type = &most_common_type, 509 }, 510 }, 511 }, 512}; 513 514struct most_snd_grp { 515 struct config_group group; 516 bool create_card; 517 struct list_head list; 518}; 519 520static struct most_snd_grp *to_most_snd_grp(struct config_item *item) 521{ 522 return container_of(to_config_group(item), struct most_snd_grp, group); 523} 524 525static struct config_item *most_snd_grp_make_item(struct config_group *group, 526 const char *name) 527{ 528 struct mdev_link *mdev_link; 529 530 mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL); 531 if (!mdev_link) 532 return ERR_PTR(-ENOMEM); 533 534 config_item_init_type_name(&mdev_link->item, name, &mdev_link_type); 535 mdev_link->create_link = false; 536 strcpy(mdev_link->name, name); 537 strcpy(mdev_link->comp, "sound"); 538 return &mdev_link->item; 539} 540 541static ssize_t most_snd_grp_create_card_store(struct config_item *item, 542 const char *page, size_t count) 543{ 544 struct most_snd_grp *snd_grp = to_most_snd_grp(item); 545 int ret; 546 bool tmp; 547 548 ret = kstrtobool(page, &tmp); 549 if (ret) 550 return ret; 551 if (tmp) { 552 ret = most_cfg_complete("sound"); 553 if (ret) 554 return ret; 555 } 556 snd_grp->create_card = tmp; 557 return count; 558} 559 560CONFIGFS_ATTR_WO(most_snd_grp_, create_card); 561 562static struct configfs_attribute *most_snd_grp_attrs[] = { 563 &most_snd_grp_attr_create_card, 564 NULL, 565}; 566 567static void most_snd_grp_release(struct config_item *item) 568{ 569 struct most_snd_grp *group = to_most_snd_grp(item); 570 571 list_del(&group->list); 572 kfree(group); 573} 574 575static struct configfs_item_operations most_snd_grp_item_ops = { 576 .release = most_snd_grp_release, 577}; 578 579static struct configfs_group_operations most_snd_grp_group_ops = { 580 .make_item = most_snd_grp_make_item, 581}; 582 583static const struct config_item_type most_snd_grp_type = { 584 .ct_item_ops = &most_snd_grp_item_ops, 585 .ct_group_ops = &most_snd_grp_group_ops, 586 .ct_attrs = most_snd_grp_attrs, 587 .ct_owner = THIS_MODULE, 588}; 589 590struct most_sound { 591 struct configfs_subsystem subsys; 592 struct list_head soundcard_list; 593 struct module *mod; 594}; 595 596static struct config_group *most_sound_make_group(struct config_group *group, 597 const char *name) 598{ 599 struct most_snd_grp *most; 600 struct most_sound *ms = container_of(group->cg_subsys, 601 struct most_sound, subsys); 602 603 list_for_each_entry(most, &ms->soundcard_list, list) { 604 if (!most->create_card) { 605 pr_info("adapter configuration still in progress.\n"); 606 return ERR_PTR(-EPROTO); 607 } 608 } 609 if (!try_module_get(ms->mod)) 610 return ERR_PTR(-ENOLCK); 611 most = kzalloc(sizeof(*most), GFP_KERNEL); 612 if (!most) { 613 module_put(ms->mod); 614 return ERR_PTR(-ENOMEM); 615 } 616 config_group_init_type_name(&most->group, name, &most_snd_grp_type); 617 list_add_tail(&most->list, &ms->soundcard_list); 618 return &most->group; 619} 620 621static void most_sound_disconnect(struct config_group *group, 622 struct config_item *item) 623{ 624 struct most_sound *ms = container_of(group->cg_subsys, 625 struct most_sound, subsys); 626 module_put(ms->mod); 627} 628 629static struct configfs_group_operations most_sound_group_ops = { 630 .make_group = most_sound_make_group, 631 .disconnect_notify = most_sound_disconnect, 632}; 633 634static const struct config_item_type most_sound_type = { 635 .ct_group_ops = &most_sound_group_ops, 636 .ct_owner = THIS_MODULE, 637}; 638 639static struct most_sound most_sound_subsys = { 640 .subsys = { 641 .su_group = { 642 .cg_item = { 643 .ci_namebuf = "most_sound", 644 .ci_type = &most_sound_type, 645 }, 646 }, 647 }, 648}; 649 650int most_register_configfs_subsys(struct most_component *c) 651{ 652 int ret; 653 654 if (!strcmp(c->name, "cdev")) { 655 most_cdev.mod = c->mod; 656 ret = configfs_register_subsystem(&most_cdev.subsys); 657 } else if (!strcmp(c->name, "net")) { 658 most_net.mod = c->mod; 659 ret = configfs_register_subsystem(&most_net.subsys); 660 } else if (!strcmp(c->name, "video")) { 661 most_video.mod = c->mod; 662 ret = configfs_register_subsystem(&most_video.subsys); 663 } else if (!strcmp(c->name, "sound")) { 664 most_sound_subsys.mod = c->mod; 665 ret = configfs_register_subsystem(&most_sound_subsys.subsys); 666 } else { 667 return -ENODEV; 668 } 669 670 if (ret) { 671 pr_err("Error %d while registering subsystem %s\n", 672 ret, c->name); 673 } 674 return ret; 675} 676EXPORT_SYMBOL_GPL(most_register_configfs_subsys); 677 678void most_interface_register_notify(const char *mdev) 679{ 680 bool register_snd_card = false; 681 struct mdev_link *mdev_link; 682 683 list_for_each_entry(mdev_link, &mdev_link_list, list) { 684 if (!strcmp(mdev_link->device, mdev)) { 685 set_config_and_add_link(mdev_link); 686 if (!strcmp(mdev_link->comp, "sound")) 687 register_snd_card = true; 688 } 689 } 690 if (register_snd_card) 691 most_cfg_complete("sound"); 692} 693 694void most_deregister_configfs_subsys(struct most_component *c) 695{ 696 if (!strcmp(c->name, "cdev")) 697 configfs_unregister_subsystem(&most_cdev.subsys); 698 else if (!strcmp(c->name, "net")) 699 configfs_unregister_subsystem(&most_net.subsys); 700 else if (!strcmp(c->name, "video")) 701 configfs_unregister_subsystem(&most_video.subsys); 702 else if (!strcmp(c->name, "sound")) 703 configfs_unregister_subsystem(&most_sound_subsys.subsys); 704} 705EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys); 706 707int __init configfs_init(void) 708{ 709 config_group_init(&most_cdev.subsys.su_group); 710 mutex_init(&most_cdev.subsys.su_mutex); 711 712 config_group_init(&most_net.subsys.su_group); 713 mutex_init(&most_net.subsys.su_mutex); 714 715 config_group_init(&most_video.subsys.su_group); 716 mutex_init(&most_video.subsys.su_mutex); 717 718 config_group_init(&most_sound_subsys.subsys.su_group); 719 mutex_init(&most_sound_subsys.subsys.su_mutex); 720 721 INIT_LIST_HEAD(&most_sound_subsys.soundcard_list); 722 INIT_LIST_HEAD(&mdev_link_list); 723 724 return 0; 725}