Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / parport / procfs.c
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
36 static 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
73 static 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
116 static 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
143 static 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
170 static 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
197 static 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)                                                    \
214 do {                                                                    \
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 static const unsigned long parport_min_timeslice_value =
240 PARPORT_MIN_TIMESLICE_VALUE;
241
242 static const unsigned long parport_max_timeslice_value =
243 PARPORT_MAX_TIMESLICE_VALUE;
244
245 static const  int parport_min_spintime_value =
246 PARPORT_MIN_SPINTIME_VALUE;
247
248 static const int parport_max_spintime_value =
249 PARPORT_MAX_SPINTIME_VALUE;
250
251
252 struct parport_sysctl_table {
253         struct ctl_table_header *port_header;
254         struct ctl_table_header *devices_header;
255 #ifdef CONFIG_PARPORT_1284
256         struct ctl_table vars[10];
257 #else
258         struct ctl_table vars[5];
259 #endif /* IEEE 1284 support */
260         struct ctl_table device_dir[1];
261 };
262
263 static 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_value
275                 },
276                 {
277                         .procname       = "base-addr",
278                         .data           = NULL,
279                         .maxlen         = 0,
280                         .mode           = 0444,
281                         .proc_handler   = do_hardware_base_addr
282                 },
283                 {
284                         .procname       = "irq",
285                         .data           = NULL,
286                         .maxlen         = 0,
287                         .mode           = 0444,
288                         .proc_handler   = do_hardware_irq
289                 },
290                 {
291                         .procname       = "dma",
292                         .data           = NULL,
293                         .maxlen         = 0,
294                         .mode           = 0444,
295                         .proc_handler   = do_hardware_dma
296                 },
297                 {
298                         .procname       = "modes",
299                         .data           = NULL,
300                         .maxlen         = 0,
301                         .mode           = 0444,
302                         .proc_handler   = do_hardware_modes
303                 },
304 #ifdef CONFIG_PARPORT_1284
305                 {
306                         .procname       = "autoprobe",
307                         .data           = NULL,
308                         .maxlen         = 0,
309                         .mode           = 0444,
310                         .proc_handler   = do_autoprobe
311                 },
312                 {
313                         .procname       = "autoprobe0",
314                         .data           = NULL,
315                         .maxlen         = 0,
316                         .mode           = 0444,
317                         .proc_handler   = do_autoprobe
318                 },
319                 {
320                         .procname       = "autoprobe1",
321                         .data           = NULL,
322                         .maxlen         = 0,
323                         .mode           = 0444,
324                         .proc_handler   = do_autoprobe
325                 },
326                 {
327                         .procname       = "autoprobe2",
328                         .data           = NULL,
329                         .maxlen         = 0,
330                         .mode           = 0444,
331                         .proc_handler   = do_autoprobe
332                 },
333                 {
334                         .procname       = "autoprobe3",
335                         .data           = NULL,
336                         .maxlen         = 0,
337                         .mode           = 0444,
338                         .proc_handler   = do_autoprobe
339                 },
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_device
349                 },
350         },
351 };
352
353 struct parport_device_sysctl_table
354 {
355         struct ctl_table_header *sysctl_header;
356         struct ctl_table vars[1];
357         struct ctl_table device_dir[1];
358 };
359
360 static const struct parport_device_sysctl_table
361 parport_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_value
372                 },
373         },
374         {
375                 {
376                         .procname       = NULL,
377                         .data           = NULL,
378                         .maxlen         = 0,
379                         .mode           = 0555,
380                 },
381         }
382 };
383
384 struct parport_default_sysctl_table
385 {
386         struct ctl_table_header *sysctl_header;
387         struct ctl_table vars[2];
388 };
389
390 static struct parport_default_sysctl_table
391 parport_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_value
402                 },
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_value
411                 },
412         }
413 };
414
415 int 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_1284
431                 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
466 unregister_devices_h:
467         unregister_sysctl_table(t->devices_header);
468
469 exit_free_tmp_dir_path:
470         kfree(tmp_dir_path);
471
472 exit_free_t:
473         kfree(t);
474         return err;
475 }
476
477 int 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
489 int 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
519 exit_free_t:
520         kfree(t);
521
522         return err;
523 }
524
525 int 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
536 static 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
553 static 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
565 int parport_proc_register(struct parport *pp)
566 {
567         return 0;
568 }
569
570 int parport_proc_unregister(struct parport *pp)
571 {
572         return 0;
573 }
574
575 int parport_device_proc_register(struct pardevice *device)
576 {
577         return 0;
578 }
579
580 int parport_device_proc_unregister(struct pardevice *device)
581 {
582         return 0;
583 }
584
585 static int __init parport_default_proc_register (void)
586 {
587         return parport_bus_init();
588 }
589
590 static void __exit parport_default_proc_unregister (void)
591 {
592         parport_bus_exit();
593 }
594 #endif
595
596 subsys_initcall(parport_default_proc_register)
597 module_exit(parport_default_proc_unregister)