linux/drivers/parport/procfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Sysctl interface for parport devices.
   3 * 
   4 * Authors: David Campbell
   5 *          Tim Waugh <tim@cyberelk.demon.co.uk>
   6 *          Philip Blundell <philb@gnu.org>
   7 *          Andrea Arcangeli
   8 *          Riccardo Facchetti <fizban@tin.it>
   9 *
  10 * based on work by Grant Guenther <grant@torque.net>
  11 *              and Philip Blundell
  12 *
  13 * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
  14 */
  15
  16#include <linux/string.h>
  17#include <linux/init.h>
  18#include <linux/module.h>
  19#include <linux/errno.h>
  20#include <linux/kernel.h>
  21#include <linux/slab.h>
  22#include <linux/parport.h>
  23#include <linux/ctype.h>
  24#include <linux/sysctl.h>
  25#include <linux/device.h>
  26
  27#include <linux/uaccess.h>
  28
  29#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
  30
  31#define PARPORT_MIN_TIMESLICE_VALUE 1ul 
  32#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ)
  33#define PARPORT_MIN_SPINTIME_VALUE 1
  34#define PARPORT_MAX_SPINTIME_VALUE 1000
  35
  36static int do_active_device(struct ctl_table *table, int write,
  37                      void *result, size_t *lenp, loff_t *ppos)
  38{
  39        struct parport *port = (struct parport *)table->extra1;
  40        char buffer[256];
  41        struct pardevice *dev;
  42        int len = 0;
  43
  44        if (write)              /* can't happen anyway */
  45                return -EACCES;
  46
  47        if (*ppos) {
  48                *lenp = 0;
  49                return 0;
  50        }
  51        
  52        for (dev = port->devices; dev ; dev = dev->next) {
  53                if(dev == port->cad) {
  54                        len += sprintf(buffer, "%s\n", dev->name);
  55                }
  56        }
  57
  58        if(!len) {
  59                len += sprintf(buffer, "%s\n", "none");
  60        }
  61
  62        if (len > *lenp)
  63                len = *lenp;
  64        else
  65                *lenp = len;
  66
  67        *ppos += len;
  68        memcpy(result, buffer, len);
  69        return 0;
  70}
  71
  72#ifdef CONFIG_PARPORT_1284
  73static int do_autoprobe(struct ctl_table *table, int write,
  74                        void *result, size_t *lenp, loff_t *ppos)
  75{
  76        struct parport_device_info *info = table->extra2;
  77        const char *str;
  78        char buffer[256];
  79        int len = 0;
  80
  81        if (write) /* permissions stop this */
  82                return -EACCES;
  83
  84        if (*ppos) {
  85                *lenp = 0;
  86                return 0;
  87        }
  88        
  89        if ((str = info->class_name) != NULL)
  90                len += sprintf (buffer + len, "CLASS:%s;\n", str);
  91
  92        if ((str = info->model) != NULL)
  93                len += sprintf (buffer + len, "MODEL:%s;\n", str);
  94
  95        if ((str = info->mfr) != NULL)
  96                len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
  97
  98        if ((str = info->description) != NULL)
  99                len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
 100
 101        if ((str = info->cmdset) != NULL)
 102                len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
 103
 104        if (len > *lenp)
 105                len = *lenp;
 106        else
 107                *lenp = len;
 108
 109        *ppos += len;
 110
 111        memcpy(result, buffer, len);
 112        return 0;
 113}
 114#endif /* IEEE1284.3 support. */
 115
 116static int do_hardware_base_addr(struct ctl_table *table, int write,
 117                                 void *result, size_t *lenp, loff_t *ppos)
 118{
 119        struct parport *port = (struct parport *)table->extra1;
 120        char buffer[20];
 121        int len = 0;
 122
 123        if (*ppos) {
 124                *lenp = 0;
 125                return 0;
 126        }
 127
 128        if (write) /* permissions prevent this anyway */
 129                return -EACCES;
 130
 131        len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi);
 132
 133        if (len > *lenp)
 134                len = *lenp;
 135        else
 136                *lenp = len;
 137
 138        *ppos += len;
 139        memcpy(result, buffer, len);
 140        return 0;
 141}
 142
 143static int do_hardware_irq(struct ctl_table *table, int write,
 144                           void *result, size_t *lenp, loff_t *ppos)
 145{
 146        struct parport *port = (struct parport *)table->extra1;
 147        char buffer[20];
 148        int len = 0;
 149
 150        if (*ppos) {
 151                *lenp = 0;
 152                return 0;
 153        }
 154
 155        if (write) /* permissions prevent this anyway */
 156                return -EACCES;
 157
 158        len += sprintf (buffer, "%d\n", port->irq);
 159
 160        if (len > *lenp)
 161                len = *lenp;
 162        else
 163                *lenp = len;
 164
 165        *ppos += len;
 166        memcpy(result, buffer, len);
 167        return 0;
 168}
 169
 170static int do_hardware_dma(struct ctl_table *table, int write,
 171                           void *result, size_t *lenp, loff_t *ppos)
 172{
 173        struct parport *port = (struct parport *)table->extra1;
 174        char buffer[20];
 175        int len = 0;
 176
 177        if (*ppos) {
 178                *lenp = 0;
 179                return 0;
 180        }
 181
 182        if (write) /* permissions prevent this anyway */
 183                return -EACCES;
 184
 185        len += sprintf (buffer, "%d\n", port->dma);
 186
 187        if (len > *lenp)
 188                len = *lenp;
 189        else
 190                *lenp = len;
 191
 192        *ppos += len;
 193        memcpy(result, buffer, len);
 194        return 0;
 195}
 196
 197static int do_hardware_modes(struct ctl_table *table, int write,
 198                             void *result, size_t *lenp, loff_t *ppos)
 199{
 200        struct parport *port = (struct parport *)table->extra1;
 201        char buffer[40];
 202        int len = 0;
 203
 204        if (*ppos) {
 205                *lenp = 0;
 206                return 0;
 207        }
 208
 209        if (write) /* permissions prevent this anyway */
 210                return -EACCES;
 211
 212        {
 213#define printmode(x)                                                    \
 214do {                                                                    \
 215        if (port->modes & PARPORT_MODE_##x)                             \
 216                len += sprintf(buffer + len, "%s%s", f++ ? "," : "", #x); \
 217} while (0)
 218                int f = 0;
 219                printmode(PCSPP);
 220                printmode(TRISTATE);
 221                printmode(COMPAT);
 222                printmode(EPP);
 223                printmode(ECP);
 224                printmode(DMA);
 225#undef printmode
 226        }
 227        buffer[len++] = '\n';
 228
 229        if (len > *lenp)
 230                len = *lenp;
 231        else
 232                *lenp = len;
 233
 234        *ppos += len;
 235        memcpy(result, buffer, len);
 236        return 0;
 237}
 238
 239#define PARPORT_PORT_DIR(CHILD) { .procname = NULL, .mode = 0555, .child = CHILD }
 240#define PARPORT_PARPORT_DIR(CHILD) { .procname = "parport", \
 241                                     .mode = 0555, .child = CHILD }
 242#define PARPORT_DEV_DIR(CHILD) { .procname = "dev", .mode = 0555, .child = CHILD }
 243#define PARPORT_DEVICES_ROOT_DIR  {  .procname = "devices", \
 244                                    .mode = 0555, .child = NULL }
 245
 246static const unsigned long parport_min_timeslice_value =
 247PARPORT_MIN_TIMESLICE_VALUE;
 248
 249static const unsigned long parport_max_timeslice_value =
 250PARPORT_MAX_TIMESLICE_VALUE;
 251
 252static const  int parport_min_spintime_value =
 253PARPORT_MIN_SPINTIME_VALUE;
 254
 255static const int parport_max_spintime_value =
 256PARPORT_MAX_SPINTIME_VALUE;
 257
 258
 259struct parport_sysctl_table {
 260        struct ctl_table_header *sysctl_header;
 261        struct ctl_table vars[12];
 262        struct ctl_table device_dir[2];
 263        struct ctl_table port_dir[2];
 264        struct ctl_table parport_dir[2];
 265        struct ctl_table dev_dir[2];
 266};
 267
 268static const struct parport_sysctl_table parport_sysctl_template = {
 269        .sysctl_header = NULL,
 270        {
 271                {
 272                        .procname       = "spintime",
 273                        .data           = NULL,
 274                        .maxlen         = sizeof(int),
 275                        .mode           = 0644,
 276                        .proc_handler   = proc_dointvec_minmax,
 277                        .extra1         = (void*) &parport_min_spintime_value,
 278                        .extra2         = (void*) &parport_max_spintime_value
 279                },
 280                {
 281                        .procname       = "base-addr",
 282                        .data           = NULL,
 283                        .maxlen         = 0,
 284                        .mode           = 0444,
 285                        .proc_handler   = do_hardware_base_addr
 286                },
 287                {
 288                        .procname       = "irq",
 289                        .data           = NULL,
 290                        .maxlen         = 0,
 291                        .mode           = 0444,
 292                        .proc_handler   = do_hardware_irq
 293                },
 294                {
 295                        .procname       = "dma",
 296                        .data           = NULL,
 297                        .maxlen         = 0,
 298                        .mode           = 0444,
 299                        .proc_handler   = do_hardware_dma
 300                },
 301                {
 302                        .procname       = "modes",
 303                        .data           = NULL,
 304                        .maxlen         = 0,
 305                        .mode           = 0444,
 306                        .proc_handler   = do_hardware_modes
 307                },
 308                PARPORT_DEVICES_ROOT_DIR,
 309#ifdef CONFIG_PARPORT_1284
 310                {
 311                        .procname       = "autoprobe",
 312                        .data           = NULL,
 313                        .maxlen         = 0,
 314                        .mode           = 0444,
 315                        .proc_handler   = do_autoprobe
 316                },
 317                {
 318                        .procname       = "autoprobe0",
 319                        .data           = NULL,
 320                        .maxlen         = 0,
 321                        .mode           = 0444,
 322                        .proc_handler   = do_autoprobe
 323                },
 324                {
 325                        .procname       = "autoprobe1",
 326                        .data           = NULL,
 327                        .maxlen         = 0,
 328                        .mode           = 0444,
 329                        .proc_handler   = do_autoprobe
 330                },
 331                {
 332                        .procname       = "autoprobe2",
 333                        .data           = NULL,
 334                        .maxlen         = 0,
 335                        .mode           = 0444,
 336                        .proc_handler   = do_autoprobe
 337                },
 338                {
 339                        .procname       = "autoprobe3",
 340                        .data           = NULL,
 341                        .maxlen         = 0,
 342                        .mode           = 0444,
 343                        .proc_handler   = do_autoprobe
 344                },
 345#endif /* IEEE 1284 support */
 346                {}
 347        },
 348        {
 349                {
 350                        .procname       = "active",
 351                        .data           = NULL,
 352                        .maxlen         = 0,
 353                        .mode           = 0444,
 354                        .proc_handler   = do_active_device
 355                },
 356                {}
 357        },
 358        {
 359                PARPORT_PORT_DIR(NULL),
 360                {}
 361        },
 362        {
 363                PARPORT_PARPORT_DIR(NULL),
 364                {}
 365        },
 366        {
 367                PARPORT_DEV_DIR(NULL),
 368                {}
 369        }
 370};
 371
 372struct parport_device_sysctl_table
 373{
 374        struct ctl_table_header *sysctl_header;
 375        struct ctl_table vars[2];
 376        struct ctl_table device_dir[2];
 377        struct ctl_table devices_root_dir[2];
 378        struct ctl_table port_dir[2];
 379        struct ctl_table parport_dir[2];
 380        struct ctl_table dev_dir[2];
 381};
 382
 383static const struct parport_device_sysctl_table
 384parport_device_sysctl_template = {
 385        .sysctl_header = NULL,
 386        {
 387                {
 388                        .procname       = "timeslice",
 389                        .data           = NULL,
 390                        .maxlen         = sizeof(unsigned long),
 391                        .mode           = 0644,
 392                        .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
 393                        .extra1         = (void*) &parport_min_timeslice_value,
 394                        .extra2         = (void*) &parport_max_timeslice_value
 395                },
 396        },
 397        {
 398                {
 399                        .procname       = NULL,
 400                        .data           = NULL,
 401                        .maxlen         = 0,
 402                        .mode           = 0555,
 403                        .child          = NULL
 404                },
 405                {}
 406        },
 407        {
 408                PARPORT_DEVICES_ROOT_DIR,
 409                {}
 410        },
 411        {
 412                PARPORT_PORT_DIR(NULL),
 413                {}
 414        },
 415        {
 416                PARPORT_PARPORT_DIR(NULL),
 417                {}
 418        },
 419        {
 420                PARPORT_DEV_DIR(NULL),
 421                {}
 422        }
 423};
 424
 425struct parport_default_sysctl_table
 426{
 427        struct ctl_table_header *sysctl_header;
 428        struct ctl_table vars[3];
 429        struct ctl_table default_dir[2];
 430        struct ctl_table parport_dir[2];
 431        struct ctl_table dev_dir[2];
 432};
 433
 434static struct parport_default_sysctl_table
 435parport_default_sysctl_table = {
 436        .sysctl_header  = NULL,
 437        {
 438                {
 439                        .procname       = "timeslice",
 440                        .data           = &parport_default_timeslice,
 441                        .maxlen         = sizeof(parport_default_timeslice),
 442                        .mode           = 0644,
 443                        .proc_handler   = proc_doulongvec_ms_jiffies_minmax,
 444                        .extra1         = (void*) &parport_min_timeslice_value,
 445                        .extra2         = (void*) &parport_max_timeslice_value
 446                },
 447                {
 448                        .procname       = "spintime",
 449                        .data           = &parport_default_spintime,
 450                        .maxlen         = sizeof(parport_default_spintime),
 451                        .mode           = 0644,
 452                        .proc_handler   = proc_dointvec_minmax,
 453                        .extra1         = (void*) &parport_min_spintime_value,
 454                        .extra2         = (void*) &parport_max_spintime_value
 455                },
 456                {}
 457        },
 458        {
 459                {
 460                        .procname       = "default",
 461                        .mode           = 0555,
 462                        .child          = parport_default_sysctl_table.vars
 463                },
 464                {}
 465        },
 466        {
 467                PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
 468                {}
 469        },
 470        {
 471                PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
 472                {}
 473        }
 474};
 475
 476
 477int parport_proc_register(struct parport *port)
 478{
 479        struct parport_sysctl_table *t;
 480        int i;
 481
 482        t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
 483        if (t == NULL)
 484                return -ENOMEM;
 485
 486        t->device_dir[0].extra1 = port;
 487
 488        for (i = 0; i < 5; i++)
 489                t->vars[i].extra1 = port;
 490
 491        t->vars[0].data = &port->spintime;
 492        t->vars[5].child = t->device_dir;
 493        
 494        for (i = 0; i < 5; i++)
 495                t->vars[6 + i].extra2 = &port->probe_info[i];
 496
 497        t->port_dir[0].procname = port->name;
 498
 499        t->port_dir[0].child = t->vars;
 500        t->parport_dir[0].child = t->port_dir;
 501        t->dev_dir[0].child = t->parport_dir;
 502
 503        t->sysctl_header = register_sysctl_table(t->dev_dir);
 504        if (t->sysctl_header == NULL) {
 505                kfree(t);
 506                t = NULL;
 507        }
 508        port->sysctl_table = t;
 509        return 0;
 510}
 511
 512int parport_proc_unregister(struct parport *port)
 513{
 514        if (port->sysctl_table) {
 515                struct parport_sysctl_table *t = port->sysctl_table;
 516                port->sysctl_table = NULL;
 517                unregister_sysctl_table(t->sysctl_header);
 518                kfree(t);
 519        }
 520        return 0;
 521}
 522
 523int parport_device_proc_register(struct pardevice *device)
 524{
 525        struct parport_device_sysctl_table *t;
 526        struct parport * port = device->port;
 527        
 528        t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
 529        if (t == NULL)
 530                return -ENOMEM;
 531
 532        t->dev_dir[0].child = t->parport_dir;
 533        t->parport_dir[0].child = t->port_dir;
 534        t->port_dir[0].procname = port->name;
 535        t->port_dir[0].child = t->devices_root_dir;
 536        t->devices_root_dir[0].child = t->device_dir;
 537
 538        t->device_dir[0].procname = device->name;
 539        t->device_dir[0].child = t->vars;
 540        t->vars[0].data = &device->timeslice;
 541
 542        t->sysctl_header = register_sysctl_table(t->dev_dir);
 543        if (t->sysctl_header == NULL) {
 544                kfree(t);
 545                t = NULL;
 546        }
 547        device->sysctl_table = t;
 548        return 0;
 549}
 550
 551int parport_device_proc_unregister(struct pardevice *device)
 552{
 553        if (device->sysctl_table) {
 554                struct parport_device_sysctl_table *t = device->sysctl_table;
 555                device->sysctl_table = NULL;
 556                unregister_sysctl_table(t->sysctl_header);
 557                kfree(t);
 558        }
 559        return 0;
 560}
 561
 562static int __init parport_default_proc_register(void)
 563{
 564        int ret;
 565
 566        parport_default_sysctl_table.sysctl_header =
 567                register_sysctl_table(parport_default_sysctl_table.dev_dir);
 568        if (!parport_default_sysctl_table.sysctl_header)
 569                return -ENOMEM;
 570        ret = parport_bus_init();
 571        if (ret) {
 572                unregister_sysctl_table(parport_default_sysctl_table.
 573                                        sysctl_header);
 574                return ret;
 575        }
 576        return 0;
 577}
 578
 579static void __exit parport_default_proc_unregister(void)
 580{
 581        if (parport_default_sysctl_table.sysctl_header) {
 582                unregister_sysctl_table(parport_default_sysctl_table.
 583                                        sysctl_header);
 584                parport_default_sysctl_table.sysctl_header = NULL;
 585        }
 586        parport_bus_exit();
 587}
 588
 589#else /* no sysctl or no procfs*/
 590
 591int parport_proc_register(struct parport *pp)
 592{
 593        return 0;
 594}
 595
 596int parport_proc_unregister(struct parport *pp)
 597{
 598        return 0;
 599}
 600
 601int parport_device_proc_register(struct pardevice *device)
 602{
 603        return 0;
 604}
 605
 606int parport_device_proc_unregister(struct pardevice *device)
 607{
 608        return 0;
 609}
 610
 611static int __init parport_default_proc_register (void)
 612{
 613        return parport_bus_init();
 614}
 615
 616static void __exit parport_default_proc_unregister (void)
 617{
 618        parport_bus_exit();
 619}
 620#endif
 621
 622subsys_initcall(parport_default_proc_register)
 623module_exit(parport_default_proc_unregister)
 624