18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Sysctl interface for parport devices.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Authors: David Campbell
58c2ecf20Sopenharmony_ci *          Tim Waugh <tim@cyberelk.demon.co.uk>
68c2ecf20Sopenharmony_ci *          Philip Blundell <philb@gnu.org>
78c2ecf20Sopenharmony_ci *          Andrea Arcangeli
88c2ecf20Sopenharmony_ci *          Riccardo Facchetti <fizban@tin.it>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * based on work by Grant Guenther <grant@torque.net>
118c2ecf20Sopenharmony_ci *              and Philip Blundell
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * Cleaned up include files - Russell King <linux@arm.uk.linux.org>
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/errno.h>
208c2ecf20Sopenharmony_ci#include <linux/kernel.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/parport.h>
238c2ecf20Sopenharmony_ci#include <linux/ctype.h>
248c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
258c2ecf20Sopenharmony_ci#include <linux/device.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define PARPORT_MIN_TIMESLICE_VALUE 1ul
328c2ecf20Sopenharmony_ci#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ)
338c2ecf20Sopenharmony_ci#define PARPORT_MIN_SPINTIME_VALUE 1
348c2ecf20Sopenharmony_ci#define PARPORT_MAX_SPINTIME_VALUE 1000
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int do_active_device(struct ctl_table *table, int write,
378c2ecf20Sopenharmony_ci		      void *result, size_t *lenp, loff_t *ppos)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct parport *port = (struct parport *)table->extra1;
408c2ecf20Sopenharmony_ci	char buffer[256];
418c2ecf20Sopenharmony_ci	struct pardevice *dev;
428c2ecf20Sopenharmony_ci	int len = 0;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (write)		/* can't happen anyway */
458c2ecf20Sopenharmony_ci		return -EACCES;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (*ppos) {
488c2ecf20Sopenharmony_ci		*lenp = 0;
498c2ecf20Sopenharmony_ci		return 0;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	for (dev = port->devices; dev ; dev = dev->next) {
538c2ecf20Sopenharmony_ci		if(dev == port->cad) {
548c2ecf20Sopenharmony_ci			len += sprintf(buffer, "%s\n", dev->name);
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if(!len) {
598c2ecf20Sopenharmony_ci		len += sprintf(buffer, "%s\n", "none");
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (len > *lenp)
638c2ecf20Sopenharmony_ci		len = *lenp;
648c2ecf20Sopenharmony_ci	else
658c2ecf20Sopenharmony_ci		*lenp = len;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	*ppos += len;
688c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
698c2ecf20Sopenharmony_ci	return 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
738c2ecf20Sopenharmony_cistatic int do_autoprobe(struct ctl_table *table, int write,
748c2ecf20Sopenharmony_ci			void *result, size_t *lenp, loff_t *ppos)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	struct parport_device_info *info = table->extra2;
778c2ecf20Sopenharmony_ci	const char *str;
788c2ecf20Sopenharmony_ci	char buffer[256];
798c2ecf20Sopenharmony_ci	int len = 0;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (write) /* permissions stop this */
828c2ecf20Sopenharmony_ci		return -EACCES;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (*ppos) {
858c2ecf20Sopenharmony_ci		*lenp = 0;
868c2ecf20Sopenharmony_ci		return 0;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if ((str = info->class_name) != NULL)
908c2ecf20Sopenharmony_ci		len += sprintf (buffer + len, "CLASS:%s;\n", str);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if ((str = info->model) != NULL)
938c2ecf20Sopenharmony_ci		len += sprintf (buffer + len, "MODEL:%s;\n", str);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if ((str = info->mfr) != NULL)
968c2ecf20Sopenharmony_ci		len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if ((str = info->description) != NULL)
998c2ecf20Sopenharmony_ci		len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if ((str = info->cmdset) != NULL)
1028c2ecf20Sopenharmony_ci		len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (len > *lenp)
1058c2ecf20Sopenharmony_ci		len = *lenp;
1068c2ecf20Sopenharmony_ci	else
1078c2ecf20Sopenharmony_ci		*lenp = len;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	*ppos += len;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci#endif /* IEEE1284.3 support. */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic int do_hardware_base_addr(struct ctl_table *table, int write,
1178c2ecf20Sopenharmony_ci				 void *result, size_t *lenp, loff_t *ppos)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct parport *port = (struct parport *)table->extra1;
1208c2ecf20Sopenharmony_ci	char buffer[20];
1218c2ecf20Sopenharmony_ci	int len = 0;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (*ppos) {
1248c2ecf20Sopenharmony_ci		*lenp = 0;
1258c2ecf20Sopenharmony_ci		return 0;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (write) /* permissions prevent this anyway */
1298c2ecf20Sopenharmony_ci		return -EACCES;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (len > *lenp)
1348c2ecf20Sopenharmony_ci		len = *lenp;
1358c2ecf20Sopenharmony_ci	else
1368c2ecf20Sopenharmony_ci		*lenp = len;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	*ppos += len;
1398c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int do_hardware_irq(struct ctl_table *table, int write,
1448c2ecf20Sopenharmony_ci			   void *result, size_t *lenp, loff_t *ppos)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct parport *port = (struct parport *)table->extra1;
1478c2ecf20Sopenharmony_ci	char buffer[20];
1488c2ecf20Sopenharmony_ci	int len = 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (*ppos) {
1518c2ecf20Sopenharmony_ci		*lenp = 0;
1528c2ecf20Sopenharmony_ci		return 0;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (write) /* permissions prevent this anyway */
1568c2ecf20Sopenharmony_ci		return -EACCES;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	len += sprintf (buffer, "%d\n", port->irq);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (len > *lenp)
1618c2ecf20Sopenharmony_ci		len = *lenp;
1628c2ecf20Sopenharmony_ci	else
1638c2ecf20Sopenharmony_ci		*lenp = len;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	*ppos += len;
1668c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
1678c2ecf20Sopenharmony_ci	return 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int do_hardware_dma(struct ctl_table *table, int write,
1718c2ecf20Sopenharmony_ci			   void *result, size_t *lenp, loff_t *ppos)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct parport *port = (struct parport *)table->extra1;
1748c2ecf20Sopenharmony_ci	char buffer[20];
1758c2ecf20Sopenharmony_ci	int len = 0;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (*ppos) {
1788c2ecf20Sopenharmony_ci		*lenp = 0;
1798c2ecf20Sopenharmony_ci		return 0;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (write) /* permissions prevent this anyway */
1838c2ecf20Sopenharmony_ci		return -EACCES;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	len += sprintf (buffer, "%d\n", port->dma);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (len > *lenp)
1888c2ecf20Sopenharmony_ci		len = *lenp;
1898c2ecf20Sopenharmony_ci	else
1908c2ecf20Sopenharmony_ci		*lenp = len;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	*ppos += len;
1938c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int do_hardware_modes(struct ctl_table *table, int write,
1988c2ecf20Sopenharmony_ci			     void *result, size_t *lenp, loff_t *ppos)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct parport *port = (struct parport *)table->extra1;
2018c2ecf20Sopenharmony_ci	char buffer[40];
2028c2ecf20Sopenharmony_ci	int len = 0;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (*ppos) {
2058c2ecf20Sopenharmony_ci		*lenp = 0;
2068c2ecf20Sopenharmony_ci		return 0;
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (write) /* permissions prevent this anyway */
2108c2ecf20Sopenharmony_ci		return -EACCES;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	{
2138c2ecf20Sopenharmony_ci#define printmode(x)							\
2148c2ecf20Sopenharmony_cido {									\
2158c2ecf20Sopenharmony_ci	if (port->modes & PARPORT_MODE_##x)				\
2168c2ecf20Sopenharmony_ci		len += sprintf(buffer + len, "%s%s", f++ ? "," : "", #x); \
2178c2ecf20Sopenharmony_ci} while (0)
2188c2ecf20Sopenharmony_ci		int f = 0;
2198c2ecf20Sopenharmony_ci		printmode(PCSPP);
2208c2ecf20Sopenharmony_ci		printmode(TRISTATE);
2218c2ecf20Sopenharmony_ci		printmode(COMPAT);
2228c2ecf20Sopenharmony_ci		printmode(EPP);
2238c2ecf20Sopenharmony_ci		printmode(ECP);
2248c2ecf20Sopenharmony_ci		printmode(DMA);
2258c2ecf20Sopenharmony_ci#undef printmode
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci	buffer[len++] = '\n';
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (len > *lenp)
2308c2ecf20Sopenharmony_ci		len = *lenp;
2318c2ecf20Sopenharmony_ci	else
2328c2ecf20Sopenharmony_ci		*lenp = len;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	*ppos += len;
2358c2ecf20Sopenharmony_ci	memcpy(result, buffer, len);
2368c2ecf20Sopenharmony_ci	return 0;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci#define PARPORT_PORT_DIR(CHILD) { .procname = NULL, .mode = 0555, .child = CHILD }
2408c2ecf20Sopenharmony_ci#define PARPORT_PARPORT_DIR(CHILD) { .procname = "parport", \
2418c2ecf20Sopenharmony_ci                                     .mode = 0555, .child = CHILD }
2428c2ecf20Sopenharmony_ci#define PARPORT_DEV_DIR(CHILD) { .procname = "dev", .mode = 0555, .child = CHILD }
2438c2ecf20Sopenharmony_ci#define PARPORT_DEVICES_ROOT_DIR  {  .procname = "devices", \
2448c2ecf20Sopenharmony_ci                                    .mode = 0555, .child = NULL }
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic const unsigned long parport_min_timeslice_value =
2478c2ecf20Sopenharmony_ciPARPORT_MIN_TIMESLICE_VALUE;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic const unsigned long parport_max_timeslice_value =
2508c2ecf20Sopenharmony_ciPARPORT_MAX_TIMESLICE_VALUE;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic const  int parport_min_spintime_value =
2538c2ecf20Sopenharmony_ciPARPORT_MIN_SPINTIME_VALUE;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic const int parport_max_spintime_value =
2568c2ecf20Sopenharmony_ciPARPORT_MAX_SPINTIME_VALUE;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistruct parport_sysctl_table {
2608c2ecf20Sopenharmony_ci	struct ctl_table_header *sysctl_header;
2618c2ecf20Sopenharmony_ci	struct ctl_table vars[12];
2628c2ecf20Sopenharmony_ci	struct ctl_table device_dir[2];
2638c2ecf20Sopenharmony_ci	struct ctl_table port_dir[2];
2648c2ecf20Sopenharmony_ci	struct ctl_table parport_dir[2];
2658c2ecf20Sopenharmony_ci	struct ctl_table dev_dir[2];
2668c2ecf20Sopenharmony_ci};
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic const struct parport_sysctl_table parport_sysctl_template = {
2698c2ecf20Sopenharmony_ci	.sysctl_header = NULL,
2708c2ecf20Sopenharmony_ci        {
2718c2ecf20Sopenharmony_ci		{
2728c2ecf20Sopenharmony_ci			.procname	= "spintime",
2738c2ecf20Sopenharmony_ci			.data		= NULL,
2748c2ecf20Sopenharmony_ci			.maxlen		= sizeof(int),
2758c2ecf20Sopenharmony_ci			.mode		= 0644,
2768c2ecf20Sopenharmony_ci			.proc_handler	= proc_dointvec_minmax,
2778c2ecf20Sopenharmony_ci			.extra1		= (void*) &parport_min_spintime_value,
2788c2ecf20Sopenharmony_ci			.extra2		= (void*) &parport_max_spintime_value
2798c2ecf20Sopenharmony_ci		},
2808c2ecf20Sopenharmony_ci		{
2818c2ecf20Sopenharmony_ci			.procname	= "base-addr",
2828c2ecf20Sopenharmony_ci			.data		= NULL,
2838c2ecf20Sopenharmony_ci			.maxlen		= 0,
2848c2ecf20Sopenharmony_ci			.mode		= 0444,
2858c2ecf20Sopenharmony_ci			.proc_handler	= do_hardware_base_addr
2868c2ecf20Sopenharmony_ci		},
2878c2ecf20Sopenharmony_ci		{
2888c2ecf20Sopenharmony_ci			.procname	= "irq",
2898c2ecf20Sopenharmony_ci			.data		= NULL,
2908c2ecf20Sopenharmony_ci			.maxlen		= 0,
2918c2ecf20Sopenharmony_ci			.mode		= 0444,
2928c2ecf20Sopenharmony_ci			.proc_handler	= do_hardware_irq
2938c2ecf20Sopenharmony_ci		},
2948c2ecf20Sopenharmony_ci		{
2958c2ecf20Sopenharmony_ci			.procname	= "dma",
2968c2ecf20Sopenharmony_ci			.data		= NULL,
2978c2ecf20Sopenharmony_ci			.maxlen		= 0,
2988c2ecf20Sopenharmony_ci			.mode		= 0444,
2998c2ecf20Sopenharmony_ci			.proc_handler	= do_hardware_dma
3008c2ecf20Sopenharmony_ci		},
3018c2ecf20Sopenharmony_ci		{
3028c2ecf20Sopenharmony_ci			.procname	= "modes",
3038c2ecf20Sopenharmony_ci			.data		= NULL,
3048c2ecf20Sopenharmony_ci			.maxlen		= 0,
3058c2ecf20Sopenharmony_ci			.mode		= 0444,
3068c2ecf20Sopenharmony_ci			.proc_handler	= do_hardware_modes
3078c2ecf20Sopenharmony_ci		},
3088c2ecf20Sopenharmony_ci		PARPORT_DEVICES_ROOT_DIR,
3098c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
3108c2ecf20Sopenharmony_ci		{
3118c2ecf20Sopenharmony_ci			.procname	= "autoprobe",
3128c2ecf20Sopenharmony_ci			.data		= NULL,
3138c2ecf20Sopenharmony_ci			.maxlen		= 0,
3148c2ecf20Sopenharmony_ci			.mode		= 0444,
3158c2ecf20Sopenharmony_ci			.proc_handler	= do_autoprobe
3168c2ecf20Sopenharmony_ci		},
3178c2ecf20Sopenharmony_ci		{
3188c2ecf20Sopenharmony_ci			.procname	= "autoprobe0",
3198c2ecf20Sopenharmony_ci			.data		= NULL,
3208c2ecf20Sopenharmony_ci			.maxlen		= 0,
3218c2ecf20Sopenharmony_ci			.mode		= 0444,
3228c2ecf20Sopenharmony_ci			.proc_handler	= do_autoprobe
3238c2ecf20Sopenharmony_ci		},
3248c2ecf20Sopenharmony_ci		{
3258c2ecf20Sopenharmony_ci			.procname	= "autoprobe1",
3268c2ecf20Sopenharmony_ci			.data		= NULL,
3278c2ecf20Sopenharmony_ci			.maxlen		= 0,
3288c2ecf20Sopenharmony_ci			.mode		= 0444,
3298c2ecf20Sopenharmony_ci			.proc_handler	= do_autoprobe
3308c2ecf20Sopenharmony_ci		},
3318c2ecf20Sopenharmony_ci		{
3328c2ecf20Sopenharmony_ci			.procname	= "autoprobe2",
3338c2ecf20Sopenharmony_ci			.data		= NULL,
3348c2ecf20Sopenharmony_ci			.maxlen		= 0,
3358c2ecf20Sopenharmony_ci			.mode		= 0444,
3368c2ecf20Sopenharmony_ci			.proc_handler	= do_autoprobe
3378c2ecf20Sopenharmony_ci		},
3388c2ecf20Sopenharmony_ci		{
3398c2ecf20Sopenharmony_ci			.procname	= "autoprobe3",
3408c2ecf20Sopenharmony_ci			.data		= NULL,
3418c2ecf20Sopenharmony_ci			.maxlen		= 0,
3428c2ecf20Sopenharmony_ci			.mode		= 0444,
3438c2ecf20Sopenharmony_ci			.proc_handler	= do_autoprobe
3448c2ecf20Sopenharmony_ci		},
3458c2ecf20Sopenharmony_ci#endif /* IEEE 1284 support */
3468c2ecf20Sopenharmony_ci		{}
3478c2ecf20Sopenharmony_ci	},
3488c2ecf20Sopenharmony_ci	{
3498c2ecf20Sopenharmony_ci		{
3508c2ecf20Sopenharmony_ci			.procname	= "active",
3518c2ecf20Sopenharmony_ci			.data		= NULL,
3528c2ecf20Sopenharmony_ci			.maxlen		= 0,
3538c2ecf20Sopenharmony_ci			.mode		= 0444,
3548c2ecf20Sopenharmony_ci			.proc_handler	= do_active_device
3558c2ecf20Sopenharmony_ci		},
3568c2ecf20Sopenharmony_ci		{}
3578c2ecf20Sopenharmony_ci	},
3588c2ecf20Sopenharmony_ci	{
3598c2ecf20Sopenharmony_ci		PARPORT_PORT_DIR(NULL),
3608c2ecf20Sopenharmony_ci		{}
3618c2ecf20Sopenharmony_ci	},
3628c2ecf20Sopenharmony_ci	{
3638c2ecf20Sopenharmony_ci		PARPORT_PARPORT_DIR(NULL),
3648c2ecf20Sopenharmony_ci		{}
3658c2ecf20Sopenharmony_ci	},
3668c2ecf20Sopenharmony_ci	{
3678c2ecf20Sopenharmony_ci		PARPORT_DEV_DIR(NULL),
3688c2ecf20Sopenharmony_ci		{}
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci};
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistruct parport_device_sysctl_table
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct ctl_table_header *sysctl_header;
3758c2ecf20Sopenharmony_ci	struct ctl_table vars[2];
3768c2ecf20Sopenharmony_ci	struct ctl_table device_dir[2];
3778c2ecf20Sopenharmony_ci	struct ctl_table devices_root_dir[2];
3788c2ecf20Sopenharmony_ci	struct ctl_table port_dir[2];
3798c2ecf20Sopenharmony_ci	struct ctl_table parport_dir[2];
3808c2ecf20Sopenharmony_ci	struct ctl_table dev_dir[2];
3818c2ecf20Sopenharmony_ci};
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic const struct parport_device_sysctl_table
3848c2ecf20Sopenharmony_ciparport_device_sysctl_template = {
3858c2ecf20Sopenharmony_ci	.sysctl_header = NULL,
3868c2ecf20Sopenharmony_ci	{
3878c2ecf20Sopenharmony_ci		{
3888c2ecf20Sopenharmony_ci			.procname 	= "timeslice",
3898c2ecf20Sopenharmony_ci			.data		= NULL,
3908c2ecf20Sopenharmony_ci			.maxlen		= sizeof(unsigned long),
3918c2ecf20Sopenharmony_ci			.mode		= 0644,
3928c2ecf20Sopenharmony_ci			.proc_handler	= proc_doulongvec_ms_jiffies_minmax,
3938c2ecf20Sopenharmony_ci			.extra1		= (void*) &parport_min_timeslice_value,
3948c2ecf20Sopenharmony_ci			.extra2		= (void*) &parport_max_timeslice_value
3958c2ecf20Sopenharmony_ci		},
3968c2ecf20Sopenharmony_ci	},
3978c2ecf20Sopenharmony_ci	{
3988c2ecf20Sopenharmony_ci		{
3998c2ecf20Sopenharmony_ci			.procname	= NULL,
4008c2ecf20Sopenharmony_ci			.data		= NULL,
4018c2ecf20Sopenharmony_ci			.maxlen		= 0,
4028c2ecf20Sopenharmony_ci			.mode		= 0555,
4038c2ecf20Sopenharmony_ci			.child		= NULL
4048c2ecf20Sopenharmony_ci		},
4058c2ecf20Sopenharmony_ci		{}
4068c2ecf20Sopenharmony_ci	},
4078c2ecf20Sopenharmony_ci	{
4088c2ecf20Sopenharmony_ci		PARPORT_DEVICES_ROOT_DIR,
4098c2ecf20Sopenharmony_ci		{}
4108c2ecf20Sopenharmony_ci	},
4118c2ecf20Sopenharmony_ci	{
4128c2ecf20Sopenharmony_ci		PARPORT_PORT_DIR(NULL),
4138c2ecf20Sopenharmony_ci		{}
4148c2ecf20Sopenharmony_ci	},
4158c2ecf20Sopenharmony_ci	{
4168c2ecf20Sopenharmony_ci		PARPORT_PARPORT_DIR(NULL),
4178c2ecf20Sopenharmony_ci		{}
4188c2ecf20Sopenharmony_ci	},
4198c2ecf20Sopenharmony_ci	{
4208c2ecf20Sopenharmony_ci		PARPORT_DEV_DIR(NULL),
4218c2ecf20Sopenharmony_ci		{}
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci};
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistruct parport_default_sysctl_table
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct ctl_table_header *sysctl_header;
4288c2ecf20Sopenharmony_ci	struct ctl_table vars[3];
4298c2ecf20Sopenharmony_ci	struct ctl_table default_dir[2];
4308c2ecf20Sopenharmony_ci	struct ctl_table parport_dir[2];
4318c2ecf20Sopenharmony_ci	struct ctl_table dev_dir[2];
4328c2ecf20Sopenharmony_ci};
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_cistatic struct parport_default_sysctl_table
4358c2ecf20Sopenharmony_ciparport_default_sysctl_table = {
4368c2ecf20Sopenharmony_ci	.sysctl_header	= NULL,
4378c2ecf20Sopenharmony_ci	{
4388c2ecf20Sopenharmony_ci		{
4398c2ecf20Sopenharmony_ci			.procname	= "timeslice",
4408c2ecf20Sopenharmony_ci			.data		= &parport_default_timeslice,
4418c2ecf20Sopenharmony_ci			.maxlen		= sizeof(parport_default_timeslice),
4428c2ecf20Sopenharmony_ci			.mode		= 0644,
4438c2ecf20Sopenharmony_ci			.proc_handler	= proc_doulongvec_ms_jiffies_minmax,
4448c2ecf20Sopenharmony_ci			.extra1		= (void*) &parport_min_timeslice_value,
4458c2ecf20Sopenharmony_ci			.extra2		= (void*) &parport_max_timeslice_value
4468c2ecf20Sopenharmony_ci		},
4478c2ecf20Sopenharmony_ci		{
4488c2ecf20Sopenharmony_ci			.procname	= "spintime",
4498c2ecf20Sopenharmony_ci			.data		= &parport_default_spintime,
4508c2ecf20Sopenharmony_ci			.maxlen		= sizeof(parport_default_spintime),
4518c2ecf20Sopenharmony_ci			.mode		= 0644,
4528c2ecf20Sopenharmony_ci			.proc_handler	= proc_dointvec_minmax,
4538c2ecf20Sopenharmony_ci			.extra1		= (void*) &parport_min_spintime_value,
4548c2ecf20Sopenharmony_ci			.extra2		= (void*) &parport_max_spintime_value
4558c2ecf20Sopenharmony_ci		},
4568c2ecf20Sopenharmony_ci		{}
4578c2ecf20Sopenharmony_ci	},
4588c2ecf20Sopenharmony_ci	{
4598c2ecf20Sopenharmony_ci		{
4608c2ecf20Sopenharmony_ci			.procname	= "default",
4618c2ecf20Sopenharmony_ci			.mode		= 0555,
4628c2ecf20Sopenharmony_ci			.child		= parport_default_sysctl_table.vars
4638c2ecf20Sopenharmony_ci		},
4648c2ecf20Sopenharmony_ci		{}
4658c2ecf20Sopenharmony_ci	},
4668c2ecf20Sopenharmony_ci	{
4678c2ecf20Sopenharmony_ci		PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
4688c2ecf20Sopenharmony_ci		{}
4698c2ecf20Sopenharmony_ci	},
4708c2ecf20Sopenharmony_ci	{
4718c2ecf20Sopenharmony_ci		PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
4728c2ecf20Sopenharmony_ci		{}
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci};
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ciint parport_proc_register(struct parport *port)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct parport_sysctl_table *t;
4808c2ecf20Sopenharmony_ci	int i;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
4838c2ecf20Sopenharmony_ci	if (t == NULL)
4848c2ecf20Sopenharmony_ci		return -ENOMEM;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	t->device_dir[0].extra1 = port;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++)
4898c2ecf20Sopenharmony_ci		t->vars[i].extra1 = port;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	t->vars[0].data = &port->spintime;
4928c2ecf20Sopenharmony_ci	t->vars[5].child = t->device_dir;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++)
4958c2ecf20Sopenharmony_ci		t->vars[6 + i].extra2 = &port->probe_info[i];
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	t->port_dir[0].procname = port->name;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	t->port_dir[0].child = t->vars;
5008c2ecf20Sopenharmony_ci	t->parport_dir[0].child = t->port_dir;
5018c2ecf20Sopenharmony_ci	t->dev_dir[0].child = t->parport_dir;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	t->sysctl_header = register_sysctl_table(t->dev_dir);
5048c2ecf20Sopenharmony_ci	if (t->sysctl_header == NULL) {
5058c2ecf20Sopenharmony_ci		kfree(t);
5068c2ecf20Sopenharmony_ci		t = NULL;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci	port->sysctl_table = t;
5098c2ecf20Sopenharmony_ci	return 0;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ciint parport_proc_unregister(struct parport *port)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	if (port->sysctl_table) {
5158c2ecf20Sopenharmony_ci		struct parport_sysctl_table *t = port->sysctl_table;
5168c2ecf20Sopenharmony_ci		port->sysctl_table = NULL;
5178c2ecf20Sopenharmony_ci		unregister_sysctl_table(t->sysctl_header);
5188c2ecf20Sopenharmony_ci		kfree(t);
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci	return 0;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ciint parport_device_proc_register(struct pardevice *device)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct parport_device_sysctl_table *t;
5268c2ecf20Sopenharmony_ci	struct parport * port = device->port;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
5298c2ecf20Sopenharmony_ci	if (t == NULL)
5308c2ecf20Sopenharmony_ci		return -ENOMEM;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	t->dev_dir[0].child = t->parport_dir;
5338c2ecf20Sopenharmony_ci	t->parport_dir[0].child = t->port_dir;
5348c2ecf20Sopenharmony_ci	t->port_dir[0].procname = port->name;
5358c2ecf20Sopenharmony_ci	t->port_dir[0].child = t->devices_root_dir;
5368c2ecf20Sopenharmony_ci	t->devices_root_dir[0].child = t->device_dir;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	t->device_dir[0].procname = device->name;
5398c2ecf20Sopenharmony_ci	t->device_dir[0].child = t->vars;
5408c2ecf20Sopenharmony_ci	t->vars[0].data = &device->timeslice;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	t->sysctl_header = register_sysctl_table(t->dev_dir);
5438c2ecf20Sopenharmony_ci	if (t->sysctl_header == NULL) {
5448c2ecf20Sopenharmony_ci		kfree(t);
5458c2ecf20Sopenharmony_ci		t = NULL;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci	device->sysctl_table = t;
5488c2ecf20Sopenharmony_ci	return 0;
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ciint parport_device_proc_unregister(struct pardevice *device)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	if (device->sysctl_table) {
5548c2ecf20Sopenharmony_ci		struct parport_device_sysctl_table *t = device->sysctl_table;
5558c2ecf20Sopenharmony_ci		device->sysctl_table = NULL;
5568c2ecf20Sopenharmony_ci		unregister_sysctl_table(t->sysctl_header);
5578c2ecf20Sopenharmony_ci		kfree(t);
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	return 0;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_cistatic int __init parport_default_proc_register(void)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	int ret;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	parport_default_sysctl_table.sysctl_header =
5678c2ecf20Sopenharmony_ci		register_sysctl_table(parport_default_sysctl_table.dev_dir);
5688c2ecf20Sopenharmony_ci	if (!parport_default_sysctl_table.sysctl_header)
5698c2ecf20Sopenharmony_ci		return -ENOMEM;
5708c2ecf20Sopenharmony_ci	ret = parport_bus_init();
5718c2ecf20Sopenharmony_ci	if (ret) {
5728c2ecf20Sopenharmony_ci		unregister_sysctl_table(parport_default_sysctl_table.
5738c2ecf20Sopenharmony_ci					sysctl_header);
5748c2ecf20Sopenharmony_ci		return ret;
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci	return 0;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic void __exit parport_default_proc_unregister(void)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	if (parport_default_sysctl_table.sysctl_header) {
5828c2ecf20Sopenharmony_ci		unregister_sysctl_table(parport_default_sysctl_table.
5838c2ecf20Sopenharmony_ci					sysctl_header);
5848c2ecf20Sopenharmony_ci		parport_default_sysctl_table.sysctl_header = NULL;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci	parport_bus_exit();
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci#else /* no sysctl or no procfs*/
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ciint parport_proc_register(struct parport *pp)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	return 0;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ciint parport_proc_unregister(struct parport *pp)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	return 0;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ciint parport_device_proc_register(struct pardevice *device)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	return 0;
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ciint parport_device_proc_unregister(struct pardevice *device)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	return 0;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic int __init parport_default_proc_register (void)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	return parport_bus_init();
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic void __exit parport_default_proc_unregister (void)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	parport_bus_exit();
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci#endif
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cisubsys_initcall(parport_default_proc_register)
6238c2ecf20Sopenharmony_cimodule_exit(parport_default_proc_unregister)
624