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