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