598 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Sysctl interface for parport devices.3 * 4 * Authors: David Campbell5 * Tim Waugh <tim@cyberelk.demon.co.uk>6 * Philip Blundell <philb@gnu.org>7 * Andrea Arcangeli8 * Riccardo Facchetti <fizban@tin.it>9 *10 * based on work by Grant Guenther <grant@torque.net>11 * and Philip Blundell12 *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 134#define PARPORT_MAX_SPINTIME_VALUE 100035 36static int do_active_device(const 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 += scnprintf(buffer, sizeof(buffer), "%s\n", dev->name);55 }56 }57 58 if(!len) {59 len += scnprintf(buffer, sizeof(buffer), "%s\n", "none");60 }61 62 if (len > *lenp)63 len = *lenp;64 else65 *lenp = len;66 67 *ppos += len;68 memcpy(result, buffer, len);69 return 0;70}71 72#ifdef CONFIG_PARPORT_128473static int do_autoprobe(const 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 += scnprintf (buffer + len, sizeof(buffer) - len, "CLASS:%s;\n", str);91 92 if ((str = info->model) != NULL)93 len += scnprintf (buffer + len, sizeof(buffer) - len, "MODEL:%s;\n", str);94 95 if ((str = info->mfr) != NULL)96 len += scnprintf (buffer + len, sizeof(buffer) - len, "MANUFACTURER:%s;\n", str);97 98 if ((str = info->description) != NULL)99 len += scnprintf (buffer + len, sizeof(buffer) - len, "DESCRIPTION:%s;\n", str);100 101 if ((str = info->cmdset) != NULL)102 len += scnprintf (buffer + len, sizeof(buffer) - len, "COMMAND SET:%s;\n", str);103 104 if (len > *lenp)105 len = *lenp;106 else107 *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(const 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[64];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 += scnprintf (buffer, sizeof(buffer), "%lu\t%lu\n", port->base, port->base_hi);132 133 if (len > *lenp)134 len = *lenp;135 else136 *lenp = len;137 138 *ppos += len;139 memcpy(result, buffer, len);140 return 0;141}142 143static int do_hardware_irq(const 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 += scnprintf (buffer, sizeof(buffer), "%d\n", port->irq);159 160 if (len > *lenp)161 len = *lenp;162 else163 *lenp = len;164 165 *ppos += len;166 memcpy(result, buffer, len);167 return 0;168}169 170static int do_hardware_dma(const 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 += scnprintf (buffer, sizeof(buffer), "%d\n", port->dma);186 187 if (len > *lenp)188 len = *lenp;189 else190 *lenp = len;191 192 *ppos += len;193 memcpy(result, buffer, len);194 return 0;195}196 197static int do_hardware_modes(const 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 += scnprintf(buffer + len, sizeof(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 printmode226 }227 buffer[len++] = '\n';228 229 if (len > *lenp)230 len = *lenp;231 else232 *lenp = len;233 234 *ppos += len;235 memcpy(result, buffer, len);236 return 0;237}238 239static const unsigned long parport_min_timeslice_value =240PARPORT_MIN_TIMESLICE_VALUE;241 242static const unsigned long parport_max_timeslice_value =243PARPORT_MAX_TIMESLICE_VALUE;244 245static const int parport_min_spintime_value =246PARPORT_MIN_SPINTIME_VALUE;247 248static const int parport_max_spintime_value =249PARPORT_MAX_SPINTIME_VALUE;250 251 252struct parport_sysctl_table {253 struct ctl_table_header *port_header;254 struct ctl_table_header *devices_header;255#ifdef CONFIG_PARPORT_1284256 struct ctl_table vars[10];257#else258 struct ctl_table vars[5];259#endif /* IEEE 1284 support */260 struct ctl_table device_dir[1];261};262 263static const struct parport_sysctl_table parport_sysctl_template = {264 .port_header = NULL,265 .devices_header = NULL,266 {267 {268 .procname = "spintime",269 .data = NULL,270 .maxlen = sizeof(int),271 .mode = 0644,272 .proc_handler = proc_dointvec_minmax,273 .extra1 = (void*) &parport_min_spintime_value,274 .extra2 = (void*) &parport_max_spintime_value275 },276 {277 .procname = "base-addr",278 .data = NULL,279 .maxlen = 0,280 .mode = 0444,281 .proc_handler = do_hardware_base_addr282 },283 {284 .procname = "irq",285 .data = NULL,286 .maxlen = 0,287 .mode = 0444,288 .proc_handler = do_hardware_irq289 },290 {291 .procname = "dma",292 .data = NULL,293 .maxlen = 0,294 .mode = 0444,295 .proc_handler = do_hardware_dma296 },297 {298 .procname = "modes",299 .data = NULL,300 .maxlen = 0,301 .mode = 0444,302 .proc_handler = do_hardware_modes303 },304#ifdef CONFIG_PARPORT_1284305 {306 .procname = "autoprobe",307 .data = NULL,308 .maxlen = 0,309 .mode = 0444,310 .proc_handler = do_autoprobe311 },312 {313 .procname = "autoprobe0",314 .data = NULL,315 .maxlen = 0,316 .mode = 0444,317 .proc_handler = do_autoprobe318 },319 {320 .procname = "autoprobe1",321 .data = NULL,322 .maxlen = 0,323 .mode = 0444,324 .proc_handler = do_autoprobe325 },326 {327 .procname = "autoprobe2",328 .data = NULL,329 .maxlen = 0,330 .mode = 0444,331 .proc_handler = do_autoprobe332 },333 {334 .procname = "autoprobe3",335 .data = NULL,336 .maxlen = 0,337 .mode = 0444,338 .proc_handler = do_autoprobe339 },340#endif /* IEEE 1284 support */341 },342 {343 {344 .procname = "active",345 .data = NULL,346 .maxlen = 0,347 .mode = 0444,348 .proc_handler = do_active_device349 },350 },351};352 353struct parport_device_sysctl_table354{355 struct ctl_table_header *sysctl_header;356 struct ctl_table vars[1];357 struct ctl_table device_dir[1];358};359 360static const struct parport_device_sysctl_table361parport_device_sysctl_template = {362 .sysctl_header = NULL,363 {364 {365 .procname = "timeslice",366 .data = NULL,367 .maxlen = sizeof(unsigned long),368 .mode = 0644,369 .proc_handler = proc_doulongvec_ms_jiffies_minmax,370 .extra1 = (void*) &parport_min_timeslice_value,371 .extra2 = (void*) &parport_max_timeslice_value372 },373 },374 {375 {376 .procname = NULL,377 .data = NULL,378 .maxlen = 0,379 .mode = 0555,380 },381 }382};383 384struct parport_default_sysctl_table385{386 struct ctl_table_header *sysctl_header;387 struct ctl_table vars[2];388};389 390static struct parport_default_sysctl_table391parport_default_sysctl_table = {392 .sysctl_header = NULL,393 {394 {395 .procname = "timeslice",396 .data = &parport_default_timeslice,397 .maxlen = sizeof(parport_default_timeslice),398 .mode = 0644,399 .proc_handler = proc_doulongvec_ms_jiffies_minmax,400 .extra1 = (void*) &parport_min_timeslice_value,401 .extra2 = (void*) &parport_max_timeslice_value402 },403 {404 .procname = "spintime",405 .data = &parport_default_spintime,406 .maxlen = sizeof(parport_default_spintime),407 .mode = 0644,408 .proc_handler = proc_dointvec_minmax,409 .extra1 = (void*) &parport_min_spintime_value,410 .extra2 = (void*) &parport_max_spintime_value411 },412 }413};414 415int parport_proc_register(struct parport *port)416{417 struct parport_sysctl_table *t;418 char *tmp_dir_path;419 int i, err = 0;420 421 t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);422 if (t == NULL)423 return -ENOMEM;424 425 t->device_dir[0].extra1 = port;426 427 t->vars[0].data = &port->spintime;428 for (i = 0; i < 5; i++) {429 t->vars[i].extra1 = port;430#ifdef CONFIG_PARPORT_1284431 t->vars[5 + i].extra2 = &port->probe_info[i];432#endif /* IEEE 1284 support */433 }434 435 tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices", port->name);436 if (!tmp_dir_path) {437 err = -ENOMEM;438 goto exit_free_t;439 }440 441 t->devices_header = register_sysctl(tmp_dir_path, t->device_dir);442 if (t->devices_header == NULL) {443 err = -ENOENT;444 goto exit_free_tmp_dir_path;445 }446 447 kfree(tmp_dir_path);448 449 tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s", port->name);450 if (!tmp_dir_path) {451 err = -ENOMEM;452 goto unregister_devices_h;453 }454 455 t->port_header = register_sysctl(tmp_dir_path, t->vars);456 if (t->port_header == NULL) {457 err = -ENOENT;458 goto unregister_devices_h;459 }460 461 port->sysctl_table = t;462 463 kfree(tmp_dir_path);464 return 0;465 466unregister_devices_h:467 unregister_sysctl_table(t->devices_header);468 469exit_free_tmp_dir_path:470 kfree(tmp_dir_path);471 472exit_free_t:473 kfree(t);474 return err;475}476 477int parport_proc_unregister(struct parport *port)478{479 if (port->sysctl_table) {480 struct parport_sysctl_table *t = port->sysctl_table;481 port->sysctl_table = NULL;482 unregister_sysctl_table(t->devices_header);483 unregister_sysctl_table(t->port_header);484 kfree(t);485 }486 return 0;487}488 489int parport_device_proc_register(struct pardevice *device)490{491 struct parport_device_sysctl_table *t;492 struct parport * port = device->port;493 char *tmp_dir_path;494 int err = 0;495 496 t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);497 if (t == NULL)498 return -ENOMEM;499 500 /* Allocate a buffer for two paths: dev/parport/PORT/devices/DEVICE. */501 tmp_dir_path = kasprintf(GFP_KERNEL, "dev/parport/%s/devices/%s", port->name, device->name);502 if (!tmp_dir_path) {503 err = -ENOMEM;504 goto exit_free_t;505 }506 507 t->vars[0].data = &device->timeslice;508 509 t->sysctl_header = register_sysctl(tmp_dir_path, t->vars);510 if (t->sysctl_header == NULL) {511 kfree(t);512 t = NULL;513 }514 device->sysctl_table = t;515 516 kfree(tmp_dir_path);517 return 0;518 519exit_free_t:520 kfree(t);521 522 return err;523}524 525int parport_device_proc_unregister(struct pardevice *device)526{527 if (device->sysctl_table) {528 struct parport_device_sysctl_table *t = device->sysctl_table;529 device->sysctl_table = NULL;530 unregister_sysctl_table(t->sysctl_header);531 kfree(t);532 }533 return 0;534}535 536static int __init parport_default_proc_register(void)537{538 int ret;539 540 parport_default_sysctl_table.sysctl_header =541 register_sysctl("dev/parport/default", parport_default_sysctl_table.vars);542 if (!parport_default_sysctl_table.sysctl_header)543 return -ENOMEM;544 ret = parport_bus_init();545 if (ret) {546 unregister_sysctl_table(parport_default_sysctl_table.547 sysctl_header);548 return ret;549 }550 return 0;551}552 553static void __exit parport_default_proc_unregister(void)554{555 if (parport_default_sysctl_table.sysctl_header) {556 unregister_sysctl_table(parport_default_sysctl_table.557 sysctl_header);558 parport_default_sysctl_table.sysctl_header = NULL;559 }560 parport_bus_exit();561}562 563#else /* no sysctl or no procfs*/564 565int parport_proc_register(struct parport *pp)566{567 return 0;568}569 570int parport_proc_unregister(struct parport *pp)571{572 return 0;573}574 575int parport_device_proc_register(struct pardevice *device)576{577 return 0;578}579 580int parport_device_proc_unregister(struct pardevice *device)581{582 return 0;583}584 585static int __init parport_default_proc_register (void)586{587 return parport_bus_init();588}589 590static void __exit parport_default_proc_unregister (void)591{592 parport_bus_exit();593}594#endif595 596subsys_initcall(parport_default_proc_register)597module_exit(parport_default_proc_unregister)598