162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Sysctl interface for parport devices. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: David Campbell 562306a36Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> 662306a36Sopenharmony_ci * Philip Blundell <philb@gnu.org> 762306a36Sopenharmony_ci * Andrea Arcangeli 862306a36Sopenharmony_ci * Riccardo Facchetti <fizban@tin.it> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * based on work by Grant Guenther <grant@torque.net> 1162306a36Sopenharmony_ci * and Philip Blundell 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Cleaned up include files - Russell King <linux@arm.uk.linux.org> 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/errno.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/parport.h> 2362306a36Sopenharmony_ci#include <linux/ctype.h> 2462306a36Sopenharmony_ci#include <linux/sysctl.h> 2562306a36Sopenharmony_ci#include <linux/device.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <linux/uaccess.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define PARPORT_MIN_TIMESLICE_VALUE 1ul 3262306a36Sopenharmony_ci#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ) 3362306a36Sopenharmony_ci#define PARPORT_MIN_SPINTIME_VALUE 1 3462306a36Sopenharmony_ci#define PARPORT_MAX_SPINTIME_VALUE 1000 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * PARPORT_BASE_* is the size of the known parts of the sysctl path 3762306a36Sopenharmony_ci * in dev/partport/%s/devices/%s. "dev/parport/"(12), "/devices/"(9 3862306a36Sopenharmony_ci * and null char(1). 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci#define PARPORT_BASE_PATH_SIZE 13 4162306a36Sopenharmony_ci#define PARPORT_BASE_DEVICES_PATH_SIZE 22 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int do_active_device(struct ctl_table *table, int write, 4462306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct parport *port = (struct parport *)table->extra1; 4762306a36Sopenharmony_ci char buffer[256]; 4862306a36Sopenharmony_ci struct pardevice *dev; 4962306a36Sopenharmony_ci int len = 0; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (write) /* can't happen anyway */ 5262306a36Sopenharmony_ci return -EACCES; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (*ppos) { 5562306a36Sopenharmony_ci *lenp = 0; 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci for (dev = port->devices; dev ; dev = dev->next) { 6062306a36Sopenharmony_ci if(dev == port->cad) { 6162306a36Sopenharmony_ci len += sprintf(buffer, "%s\n", dev->name); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if(!len) { 6662306a36Sopenharmony_ci len += sprintf(buffer, "%s\n", "none"); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (len > *lenp) 7062306a36Sopenharmony_ci len = *lenp; 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci *lenp = len; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *ppos += len; 7562306a36Sopenharmony_ci memcpy(result, buffer, len); 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 8062306a36Sopenharmony_cistatic int do_autoprobe(struct ctl_table *table, int write, 8162306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci struct parport_device_info *info = table->extra2; 8462306a36Sopenharmony_ci const char *str; 8562306a36Sopenharmony_ci char buffer[256]; 8662306a36Sopenharmony_ci int len = 0; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (write) /* permissions stop this */ 8962306a36Sopenharmony_ci return -EACCES; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (*ppos) { 9262306a36Sopenharmony_ci *lenp = 0; 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if ((str = info->class_name) != NULL) 9762306a36Sopenharmony_ci len += sprintf (buffer + len, "CLASS:%s;\n", str); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if ((str = info->model) != NULL) 10062306a36Sopenharmony_ci len += sprintf (buffer + len, "MODEL:%s;\n", str); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if ((str = info->mfr) != NULL) 10362306a36Sopenharmony_ci len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if ((str = info->description) != NULL) 10662306a36Sopenharmony_ci len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if ((str = info->cmdset) != NULL) 10962306a36Sopenharmony_ci len += sprintf (buffer + len, "COMMAND SET:%s;\n", str); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (len > *lenp) 11262306a36Sopenharmony_ci len = *lenp; 11362306a36Sopenharmony_ci else 11462306a36Sopenharmony_ci *lenp = len; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci *ppos += len; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci memcpy(result, buffer, len); 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci#endif /* IEEE1284.3 support. */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int do_hardware_base_addr(struct ctl_table *table, int write, 12462306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct parport *port = (struct parport *)table->extra1; 12762306a36Sopenharmony_ci char buffer[20]; 12862306a36Sopenharmony_ci int len = 0; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (*ppos) { 13162306a36Sopenharmony_ci *lenp = 0; 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (write) /* permissions prevent this anyway */ 13662306a36Sopenharmony_ci return -EACCES; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (len > *lenp) 14162306a36Sopenharmony_ci len = *lenp; 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci *lenp = len; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci *ppos += len; 14662306a36Sopenharmony_ci memcpy(result, buffer, len); 14762306a36Sopenharmony_ci return 0; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int do_hardware_irq(struct ctl_table *table, int write, 15162306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct parport *port = (struct parport *)table->extra1; 15462306a36Sopenharmony_ci char buffer[20]; 15562306a36Sopenharmony_ci int len = 0; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci if (*ppos) { 15862306a36Sopenharmony_ci *lenp = 0; 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (write) /* permissions prevent this anyway */ 16362306a36Sopenharmony_ci return -EACCES; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci len += sprintf (buffer, "%d\n", port->irq); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (len > *lenp) 16862306a36Sopenharmony_ci len = *lenp; 16962306a36Sopenharmony_ci else 17062306a36Sopenharmony_ci *lenp = len; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci *ppos += len; 17362306a36Sopenharmony_ci memcpy(result, buffer, len); 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int do_hardware_dma(struct ctl_table *table, int write, 17862306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci struct parport *port = (struct parport *)table->extra1; 18162306a36Sopenharmony_ci char buffer[20]; 18262306a36Sopenharmony_ci int len = 0; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (*ppos) { 18562306a36Sopenharmony_ci *lenp = 0; 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (write) /* permissions prevent this anyway */ 19062306a36Sopenharmony_ci return -EACCES; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci len += sprintf (buffer, "%d\n", port->dma); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (len > *lenp) 19562306a36Sopenharmony_ci len = *lenp; 19662306a36Sopenharmony_ci else 19762306a36Sopenharmony_ci *lenp = len; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci *ppos += len; 20062306a36Sopenharmony_ci memcpy(result, buffer, len); 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int do_hardware_modes(struct ctl_table *table, int write, 20562306a36Sopenharmony_ci void *result, size_t *lenp, loff_t *ppos) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct parport *port = (struct parport *)table->extra1; 20862306a36Sopenharmony_ci char buffer[40]; 20962306a36Sopenharmony_ci int len = 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (*ppos) { 21262306a36Sopenharmony_ci *lenp = 0; 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (write) /* permissions prevent this anyway */ 21762306a36Sopenharmony_ci return -EACCES; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci { 22062306a36Sopenharmony_ci#define printmode(x) \ 22162306a36Sopenharmony_cido { \ 22262306a36Sopenharmony_ci if (port->modes & PARPORT_MODE_##x) \ 22362306a36Sopenharmony_ci len += sprintf(buffer + len, "%s%s", f++ ? "," : "", #x); \ 22462306a36Sopenharmony_ci} while (0) 22562306a36Sopenharmony_ci int f = 0; 22662306a36Sopenharmony_ci printmode(PCSPP); 22762306a36Sopenharmony_ci printmode(TRISTATE); 22862306a36Sopenharmony_ci printmode(COMPAT); 22962306a36Sopenharmony_ci printmode(EPP); 23062306a36Sopenharmony_ci printmode(ECP); 23162306a36Sopenharmony_ci printmode(DMA); 23262306a36Sopenharmony_ci#undef printmode 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci buffer[len++] = '\n'; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (len > *lenp) 23762306a36Sopenharmony_ci len = *lenp; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci *lenp = len; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci *ppos += len; 24262306a36Sopenharmony_ci memcpy(result, buffer, len); 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic const unsigned long parport_min_timeslice_value = 24762306a36Sopenharmony_ciPARPORT_MIN_TIMESLICE_VALUE; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic const unsigned long parport_max_timeslice_value = 25062306a36Sopenharmony_ciPARPORT_MAX_TIMESLICE_VALUE; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic const int parport_min_spintime_value = 25362306a36Sopenharmony_ciPARPORT_MIN_SPINTIME_VALUE; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic const int parport_max_spintime_value = 25662306a36Sopenharmony_ciPARPORT_MAX_SPINTIME_VALUE; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistruct parport_sysctl_table { 26062306a36Sopenharmony_ci struct ctl_table_header *port_header; 26162306a36Sopenharmony_ci struct ctl_table_header *devices_header; 26262306a36Sopenharmony_ci struct ctl_table vars[12]; 26362306a36Sopenharmony_ci struct ctl_table device_dir[2]; 26462306a36Sopenharmony_ci}; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic const struct parport_sysctl_table parport_sysctl_template = { 26762306a36Sopenharmony_ci .port_header = NULL, 26862306a36Sopenharmony_ci .devices_header = NULL, 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci { 27162306a36Sopenharmony_ci .procname = "spintime", 27262306a36Sopenharmony_ci .data = NULL, 27362306a36Sopenharmony_ci .maxlen = sizeof(int), 27462306a36Sopenharmony_ci .mode = 0644, 27562306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 27662306a36Sopenharmony_ci .extra1 = (void*) &parport_min_spintime_value, 27762306a36Sopenharmony_ci .extra2 = (void*) &parport_max_spintime_value 27862306a36Sopenharmony_ci }, 27962306a36Sopenharmony_ci { 28062306a36Sopenharmony_ci .procname = "base-addr", 28162306a36Sopenharmony_ci .data = NULL, 28262306a36Sopenharmony_ci .maxlen = 0, 28362306a36Sopenharmony_ci .mode = 0444, 28462306a36Sopenharmony_ci .proc_handler = do_hardware_base_addr 28562306a36Sopenharmony_ci }, 28662306a36Sopenharmony_ci { 28762306a36Sopenharmony_ci .procname = "irq", 28862306a36Sopenharmony_ci .data = NULL, 28962306a36Sopenharmony_ci .maxlen = 0, 29062306a36Sopenharmony_ci .mode = 0444, 29162306a36Sopenharmony_ci .proc_handler = do_hardware_irq 29262306a36Sopenharmony_ci }, 29362306a36Sopenharmony_ci { 29462306a36Sopenharmony_ci .procname = "dma", 29562306a36Sopenharmony_ci .data = NULL, 29662306a36Sopenharmony_ci .maxlen = 0, 29762306a36Sopenharmony_ci .mode = 0444, 29862306a36Sopenharmony_ci .proc_handler = do_hardware_dma 29962306a36Sopenharmony_ci }, 30062306a36Sopenharmony_ci { 30162306a36Sopenharmony_ci .procname = "modes", 30262306a36Sopenharmony_ci .data = NULL, 30362306a36Sopenharmony_ci .maxlen = 0, 30462306a36Sopenharmony_ci .mode = 0444, 30562306a36Sopenharmony_ci .proc_handler = do_hardware_modes 30662306a36Sopenharmony_ci }, 30762306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 30862306a36Sopenharmony_ci { 30962306a36Sopenharmony_ci .procname = "autoprobe", 31062306a36Sopenharmony_ci .data = NULL, 31162306a36Sopenharmony_ci .maxlen = 0, 31262306a36Sopenharmony_ci .mode = 0444, 31362306a36Sopenharmony_ci .proc_handler = do_autoprobe 31462306a36Sopenharmony_ci }, 31562306a36Sopenharmony_ci { 31662306a36Sopenharmony_ci .procname = "autoprobe0", 31762306a36Sopenharmony_ci .data = NULL, 31862306a36Sopenharmony_ci .maxlen = 0, 31962306a36Sopenharmony_ci .mode = 0444, 32062306a36Sopenharmony_ci .proc_handler = do_autoprobe 32162306a36Sopenharmony_ci }, 32262306a36Sopenharmony_ci { 32362306a36Sopenharmony_ci .procname = "autoprobe1", 32462306a36Sopenharmony_ci .data = NULL, 32562306a36Sopenharmony_ci .maxlen = 0, 32662306a36Sopenharmony_ci .mode = 0444, 32762306a36Sopenharmony_ci .proc_handler = do_autoprobe 32862306a36Sopenharmony_ci }, 32962306a36Sopenharmony_ci { 33062306a36Sopenharmony_ci .procname = "autoprobe2", 33162306a36Sopenharmony_ci .data = NULL, 33262306a36Sopenharmony_ci .maxlen = 0, 33362306a36Sopenharmony_ci .mode = 0444, 33462306a36Sopenharmony_ci .proc_handler = do_autoprobe 33562306a36Sopenharmony_ci }, 33662306a36Sopenharmony_ci { 33762306a36Sopenharmony_ci .procname = "autoprobe3", 33862306a36Sopenharmony_ci .data = NULL, 33962306a36Sopenharmony_ci .maxlen = 0, 34062306a36Sopenharmony_ci .mode = 0444, 34162306a36Sopenharmony_ci .proc_handler = do_autoprobe 34262306a36Sopenharmony_ci }, 34362306a36Sopenharmony_ci#endif /* IEEE 1284 support */ 34462306a36Sopenharmony_ci {} 34562306a36Sopenharmony_ci }, 34662306a36Sopenharmony_ci { 34762306a36Sopenharmony_ci { 34862306a36Sopenharmony_ci .procname = "active", 34962306a36Sopenharmony_ci .data = NULL, 35062306a36Sopenharmony_ci .maxlen = 0, 35162306a36Sopenharmony_ci .mode = 0444, 35262306a36Sopenharmony_ci .proc_handler = do_active_device 35362306a36Sopenharmony_ci }, 35462306a36Sopenharmony_ci {} 35562306a36Sopenharmony_ci }, 35662306a36Sopenharmony_ci}; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistruct parport_device_sysctl_table 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct ctl_table_header *sysctl_header; 36162306a36Sopenharmony_ci struct ctl_table vars[2]; 36262306a36Sopenharmony_ci struct ctl_table device_dir[2]; 36362306a36Sopenharmony_ci struct ctl_table devices_root_dir[2]; 36462306a36Sopenharmony_ci struct ctl_table port_dir[2]; 36562306a36Sopenharmony_ci struct ctl_table parport_dir[2]; 36662306a36Sopenharmony_ci struct ctl_table dev_dir[2]; 36762306a36Sopenharmony_ci}; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic const struct parport_device_sysctl_table 37062306a36Sopenharmony_ciparport_device_sysctl_template = { 37162306a36Sopenharmony_ci .sysctl_header = NULL, 37262306a36Sopenharmony_ci { 37362306a36Sopenharmony_ci { 37462306a36Sopenharmony_ci .procname = "timeslice", 37562306a36Sopenharmony_ci .data = NULL, 37662306a36Sopenharmony_ci .maxlen = sizeof(unsigned long), 37762306a36Sopenharmony_ci .mode = 0644, 37862306a36Sopenharmony_ci .proc_handler = proc_doulongvec_ms_jiffies_minmax, 37962306a36Sopenharmony_ci .extra1 = (void*) &parport_min_timeslice_value, 38062306a36Sopenharmony_ci .extra2 = (void*) &parport_max_timeslice_value 38162306a36Sopenharmony_ci }, 38262306a36Sopenharmony_ci {} 38362306a36Sopenharmony_ci }, 38462306a36Sopenharmony_ci { 38562306a36Sopenharmony_ci { 38662306a36Sopenharmony_ci .procname = NULL, 38762306a36Sopenharmony_ci .data = NULL, 38862306a36Sopenharmony_ci .maxlen = 0, 38962306a36Sopenharmony_ci .mode = 0555, 39062306a36Sopenharmony_ci }, 39162306a36Sopenharmony_ci {} 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistruct parport_default_sysctl_table 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct ctl_table_header *sysctl_header; 39862306a36Sopenharmony_ci struct ctl_table vars[3]; 39962306a36Sopenharmony_ci struct ctl_table default_dir[2]; 40062306a36Sopenharmony_ci struct ctl_table parport_dir[2]; 40162306a36Sopenharmony_ci struct ctl_table dev_dir[2]; 40262306a36Sopenharmony_ci}; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic struct parport_default_sysctl_table 40562306a36Sopenharmony_ciparport_default_sysctl_table = { 40662306a36Sopenharmony_ci .sysctl_header = NULL, 40762306a36Sopenharmony_ci { 40862306a36Sopenharmony_ci { 40962306a36Sopenharmony_ci .procname = "timeslice", 41062306a36Sopenharmony_ci .data = &parport_default_timeslice, 41162306a36Sopenharmony_ci .maxlen = sizeof(parport_default_timeslice), 41262306a36Sopenharmony_ci .mode = 0644, 41362306a36Sopenharmony_ci .proc_handler = proc_doulongvec_ms_jiffies_minmax, 41462306a36Sopenharmony_ci .extra1 = (void*) &parport_min_timeslice_value, 41562306a36Sopenharmony_ci .extra2 = (void*) &parport_max_timeslice_value 41662306a36Sopenharmony_ci }, 41762306a36Sopenharmony_ci { 41862306a36Sopenharmony_ci .procname = "spintime", 41962306a36Sopenharmony_ci .data = &parport_default_spintime, 42062306a36Sopenharmony_ci .maxlen = sizeof(parport_default_spintime), 42162306a36Sopenharmony_ci .mode = 0644, 42262306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 42362306a36Sopenharmony_ci .extra1 = (void*) &parport_min_spintime_value, 42462306a36Sopenharmony_ci .extra2 = (void*) &parport_max_spintime_value 42562306a36Sopenharmony_ci }, 42662306a36Sopenharmony_ci {} 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci}; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ciint parport_proc_register(struct parport *port) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct parport_sysctl_table *t; 43362306a36Sopenharmony_ci char *tmp_dir_path; 43462306a36Sopenharmony_ci size_t tmp_path_len, port_name_len; 43562306a36Sopenharmony_ci int bytes_written, i, err = 0; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL); 43862306a36Sopenharmony_ci if (t == NULL) 43962306a36Sopenharmony_ci return -ENOMEM; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci t->device_dir[0].extra1 = port; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci t->vars[0].data = &port->spintime; 44462306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 44562306a36Sopenharmony_ci t->vars[i].extra1 = port; 44662306a36Sopenharmony_ci t->vars[5 + i].extra2 = &port->probe_info[i]; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN); 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * Allocate a buffer for two paths: dev/parport/PORT and dev/parport/PORT/devices. 45262306a36Sopenharmony_ci * We calculate for the second as that will give us enough for the first. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci tmp_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len; 45562306a36Sopenharmony_ci tmp_dir_path = kzalloc(tmp_path_len, GFP_KERNEL); 45662306a36Sopenharmony_ci if (!tmp_dir_path) { 45762306a36Sopenharmony_ci err = -ENOMEM; 45862306a36Sopenharmony_ci goto exit_free_t; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci bytes_written = snprintf(tmp_dir_path, tmp_path_len, 46262306a36Sopenharmony_ci "dev/parport/%s/devices", port->name); 46362306a36Sopenharmony_ci if (tmp_path_len <= bytes_written) { 46462306a36Sopenharmony_ci err = -ENOENT; 46562306a36Sopenharmony_ci goto exit_free_tmp_dir_path; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci t->devices_header = register_sysctl(tmp_dir_path, t->device_dir); 46862306a36Sopenharmony_ci if (t->devices_header == NULL) { 46962306a36Sopenharmony_ci err = -ENOENT; 47062306a36Sopenharmony_ci goto exit_free_tmp_dir_path; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci tmp_path_len = PARPORT_BASE_PATH_SIZE + port_name_len; 47462306a36Sopenharmony_ci bytes_written = snprintf(tmp_dir_path, tmp_path_len, 47562306a36Sopenharmony_ci "dev/parport/%s", port->name); 47662306a36Sopenharmony_ci if (tmp_path_len <= bytes_written) { 47762306a36Sopenharmony_ci err = -ENOENT; 47862306a36Sopenharmony_ci goto unregister_devices_h; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci t->port_header = register_sysctl(tmp_dir_path, t->vars); 48262306a36Sopenharmony_ci if (t->port_header == NULL) { 48362306a36Sopenharmony_ci err = -ENOENT; 48462306a36Sopenharmony_ci goto unregister_devices_h; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci port->sysctl_table = t; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci kfree(tmp_dir_path); 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciunregister_devices_h: 49362306a36Sopenharmony_ci unregister_sysctl_table(t->devices_header); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ciexit_free_tmp_dir_path: 49662306a36Sopenharmony_ci kfree(tmp_dir_path); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciexit_free_t: 49962306a36Sopenharmony_ci kfree(t); 50062306a36Sopenharmony_ci return err; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint parport_proc_unregister(struct parport *port) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci if (port->sysctl_table) { 50662306a36Sopenharmony_ci struct parport_sysctl_table *t = port->sysctl_table; 50762306a36Sopenharmony_ci port->sysctl_table = NULL; 50862306a36Sopenharmony_ci unregister_sysctl_table(t->devices_header); 50962306a36Sopenharmony_ci unregister_sysctl_table(t->port_header); 51062306a36Sopenharmony_ci kfree(t); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ciint parport_device_proc_register(struct pardevice *device) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci int bytes_written, err = 0; 51862306a36Sopenharmony_ci struct parport_device_sysctl_table *t; 51962306a36Sopenharmony_ci struct parport * port = device->port; 52062306a36Sopenharmony_ci size_t port_name_len, device_name_len, tmp_dir_path_len; 52162306a36Sopenharmony_ci char *tmp_dir_path; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL); 52462306a36Sopenharmony_ci if (t == NULL) 52562306a36Sopenharmony_ci return -ENOMEM; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci port_name_len = strnlen(port->name, PARPORT_NAME_MAX_LEN); 52862306a36Sopenharmony_ci device_name_len = strnlen(device->name, PATH_MAX); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* Allocate a buffer for two paths: dev/parport/PORT/devices/DEVICE. */ 53162306a36Sopenharmony_ci tmp_dir_path_len = PARPORT_BASE_DEVICES_PATH_SIZE + port_name_len + device_name_len; 53262306a36Sopenharmony_ci tmp_dir_path = kzalloc(tmp_dir_path_len, GFP_KERNEL); 53362306a36Sopenharmony_ci if (!tmp_dir_path) { 53462306a36Sopenharmony_ci err = -ENOMEM; 53562306a36Sopenharmony_ci goto exit_free_t; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci bytes_written = snprintf(tmp_dir_path, tmp_dir_path_len, "dev/parport/%s/devices/%s", 53962306a36Sopenharmony_ci port->name, device->name); 54062306a36Sopenharmony_ci if (tmp_dir_path_len <= bytes_written) { 54162306a36Sopenharmony_ci err = -ENOENT; 54262306a36Sopenharmony_ci goto exit_free_path; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci t->vars[0].data = &device->timeslice; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci t->sysctl_header = register_sysctl(tmp_dir_path, t->vars); 54862306a36Sopenharmony_ci if (t->sysctl_header == NULL) { 54962306a36Sopenharmony_ci kfree(t); 55062306a36Sopenharmony_ci t = NULL; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci device->sysctl_table = t; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci kfree(tmp_dir_path); 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciexit_free_path: 55862306a36Sopenharmony_ci kfree(tmp_dir_path); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ciexit_free_t: 56162306a36Sopenharmony_ci kfree(t); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return err; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ciint parport_device_proc_unregister(struct pardevice *device) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci if (device->sysctl_table) { 56962306a36Sopenharmony_ci struct parport_device_sysctl_table *t = device->sysctl_table; 57062306a36Sopenharmony_ci device->sysctl_table = NULL; 57162306a36Sopenharmony_ci unregister_sysctl_table(t->sysctl_header); 57262306a36Sopenharmony_ci kfree(t); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int __init parport_default_proc_register(void) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci int ret; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci parport_default_sysctl_table.sysctl_header = 58262306a36Sopenharmony_ci register_sysctl("dev/parport/default", parport_default_sysctl_table.vars); 58362306a36Sopenharmony_ci if (!parport_default_sysctl_table.sysctl_header) 58462306a36Sopenharmony_ci return -ENOMEM; 58562306a36Sopenharmony_ci ret = parport_bus_init(); 58662306a36Sopenharmony_ci if (ret) { 58762306a36Sopenharmony_ci unregister_sysctl_table(parport_default_sysctl_table. 58862306a36Sopenharmony_ci sysctl_header); 58962306a36Sopenharmony_ci return ret; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic void __exit parport_default_proc_unregister(void) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci if (parport_default_sysctl_table.sysctl_header) { 59762306a36Sopenharmony_ci unregister_sysctl_table(parport_default_sysctl_table. 59862306a36Sopenharmony_ci sysctl_header); 59962306a36Sopenharmony_ci parport_default_sysctl_table.sysctl_header = NULL; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci parport_bus_exit(); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#else /* no sysctl or no procfs*/ 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ciint parport_proc_register(struct parport *pp) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ciint parport_proc_unregister(struct parport *pp) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci return 0; 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ciint parport_device_proc_register(struct pardevice *device) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ciint parport_device_proc_unregister(struct pardevice *device) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int __init parport_default_proc_register (void) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci return parport_bus_init(); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic void __exit parport_default_proc_unregister (void) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci parport_bus_exit(); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci#endif 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cisubsys_initcall(parport_default_proc_register) 63862306a36Sopenharmony_cimodule_exit(parport_default_proc_unregister) 639