Root/drivers/parport/procfs.c

1/* Sysctl interface for parport devices.
2 *
3 * Authors: David Campbell
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/init.h>
17#include <linux/module.h>
18#include <linux/errno.h>
19#include <linux/kernel.h>
20#include <linux/slab.h>
21#include <linux/parport.h>
22#include <linux/ctype.h>
23#include <linux/sysctl.h>
24
25#include <asm/uaccess.h>
26
27#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
28
29#define PARPORT_MIN_TIMESLICE_VALUE 1ul
30#define PARPORT_MAX_TIMESLICE_VALUE ((unsigned long) HZ)
31#define PARPORT_MIN_SPINTIME_VALUE 1
32#define PARPORT_MAX_SPINTIME_VALUE 1000
33
34static int do_active_device(ctl_table *table, int write,
35              void __user *result, size_t *lenp, loff_t *ppos)
36{
37    struct parport *port = (struct parport *)table->extra1;
38    char buffer[256];
39    struct pardevice *dev;
40    int len = 0;
41
42    if (write) /* can't happen anyway */
43        return -EACCES;
44
45    if (*ppos) {
46        *lenp = 0;
47        return 0;
48    }
49    
50    for (dev = port->devices; dev ; dev = dev->next) {
51        if(dev == port->cad) {
52            len += sprintf(buffer, "%s\n", dev->name);
53        }
54    }
55
56    if(!len) {
57        len += sprintf(buffer, "%s\n", "none");
58    }
59
60    if (len > *lenp)
61        len = *lenp;
62    else
63        *lenp = len;
64
65    *ppos += len;
66
67    return copy_to_user(result, buffer, len) ? -EFAULT : 0;
68}
69
70#ifdef CONFIG_PARPORT_1284
71static int do_autoprobe(ctl_table *table, int write,
72            void __user *result, size_t *lenp, loff_t *ppos)
73{
74    struct parport_device_info *info = table->extra2;
75    const char *str;
76    char buffer[256];
77    int len = 0;
78
79    if (write) /* permissions stop this */
80        return -EACCES;
81
82    if (*ppos) {
83        *lenp = 0;
84        return 0;
85    }
86    
87    if ((str = info->class_name) != NULL)
88        len += sprintf (buffer + len, "CLASS:%s;\n", str);
89
90    if ((str = info->model) != NULL)
91        len += sprintf (buffer + len, "MODEL:%s;\n", str);
92
93    if ((str = info->mfr) != NULL)
94        len += sprintf (buffer + len, "MANUFACTURER:%s;\n", str);
95
96    if ((str = info->description) != NULL)
97        len += sprintf (buffer + len, "DESCRIPTION:%s;\n", str);
98
99    if ((str = info->cmdset) != NULL)
100        len += sprintf (buffer + len, "COMMAND SET:%s;\n", str);
101
102    if (len > *lenp)
103        len = *lenp;
104    else
105        *lenp = len;
106
107    *ppos += len;
108
109    return copy_to_user (result, buffer, len) ? -EFAULT : 0;
110}
111#endif /* IEEE1284.3 support. */
112
113static int do_hardware_base_addr (ctl_table *table, int write,
114                  void __user *result,
115                  size_t *lenp, loff_t *ppos)
116{
117    struct parport *port = (struct parport *)table->extra1;
118    char buffer[20];
119    int len = 0;
120
121    if (*ppos) {
122        *lenp = 0;
123        return 0;
124    }
125
126    if (write) /* permissions prevent this anyway */
127        return -EACCES;
128
129    len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi);
130
131    if (len > *lenp)
132        len = *lenp;
133    else
134        *lenp = len;
135
136    *ppos += len;
137
138    return copy_to_user(result, buffer, len) ? -EFAULT : 0;
139}
140
141static int do_hardware_irq (ctl_table *table, int write,
142                void __user *result,
143                size_t *lenp, loff_t *ppos)
144{
145    struct parport *port = (struct parport *)table->extra1;
146    char buffer[20];
147    int len = 0;
148
149    if (*ppos) {
150        *lenp = 0;
151        return 0;
152    }
153
154    if (write) /* permissions prevent this anyway */
155        return -EACCES;
156
157    len += sprintf (buffer, "%d\n", port->irq);
158
159    if (len > *lenp)
160        len = *lenp;
161    else
162        *lenp = len;
163
164    *ppos += len;
165
166    return copy_to_user(result, buffer, len) ? -EFAULT : 0;
167}
168
169static int do_hardware_dma (ctl_table *table, int write,
170                void __user *result,
171                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
194    return copy_to_user(result, buffer, len) ? -EFAULT : 0;
195}
196
197static int do_hardware_modes (ctl_table *table, int write,
198                  void __user *result,
199                  size_t *lenp, loff_t *ppos)
200{
201    struct parport *port = (struct parport *)table->extra1;
202    char buffer[40];
203    int len = 0;
204
205    if (*ppos) {
206        *lenp = 0;
207        return 0;
208    }
209
210    if (write) /* permissions prevent this anyway */
211        return -EACCES;
212
213    {
214#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
215        int f = 0;
216        printmode(PCSPP);
217        printmode(TRISTATE);
218        printmode(COMPAT);
219        printmode(EPP);
220        printmode(ECP);
221        printmode(DMA);
222#undef printmode
223    }
224    buffer[len++] = '\n';
225
226    if (len > *lenp)
227        len = *lenp;
228    else
229        *lenp = len;
230
231    *ppos += len;
232
233    return copy_to_user(result, buffer, len) ? -EFAULT : 0;
234}
235
236#define PARPORT_PORT_DIR(CHILD) { .procname = NULL, .mode = 0555, .child = CHILD }
237#define PARPORT_PARPORT_DIR(CHILD) { .procname = "parport", \
238                                     .mode = 0555, .child = CHILD }
239#define PARPORT_DEV_DIR(CHILD) { .procname = "dev", .mode = 0555, .child = CHILD }
240#define PARPORT_DEVICES_ROOT_DIR { .procname = "devices", \
241                                    .mode = 0555, .child = NULL }
242
243static const unsigned long parport_min_timeslice_value =
244PARPORT_MIN_TIMESLICE_VALUE;
245
246static const unsigned long parport_max_timeslice_value =
247PARPORT_MAX_TIMESLICE_VALUE;
248
249static const int parport_min_spintime_value =
250PARPORT_MIN_SPINTIME_VALUE;
251
252static const int parport_max_spintime_value =
253PARPORT_MAX_SPINTIME_VALUE;
254
255
256struct parport_sysctl_table {
257    struct ctl_table_header *sysctl_header;
258    ctl_table vars[12];
259    ctl_table device_dir[2];
260    ctl_table port_dir[2];
261    ctl_table parport_dir[2];
262    ctl_table dev_dir[2];
263};
264
265static const struct parport_sysctl_table parport_sysctl_template = {
266    .sysctl_header = NULL,
267        {
268        {
269            .procname = "spintime",
270            .data = NULL,
271            .maxlen = sizeof(int),
272            .mode = 0644,
273            .proc_handler = proc_dointvec_minmax,
274            .extra1 = (void*) &parport_min_spintime_value,
275            .extra2 = (void*) &parport_max_spintime_value
276        },
277        {
278            .procname = "base-addr",
279            .data = NULL,
280            .maxlen = 0,
281            .mode = 0444,
282            .proc_handler = do_hardware_base_addr
283        },
284        {
285            .procname = "irq",
286            .data = NULL,
287            .maxlen = 0,
288            .mode = 0444,
289            .proc_handler = do_hardware_irq
290        },
291        {
292            .procname = "dma",
293            .data = NULL,
294            .maxlen = 0,
295            .mode = 0444,
296            .proc_handler = do_hardware_dma
297        },
298        {
299            .procname = "modes",
300            .data = NULL,
301            .maxlen = 0,
302            .mode = 0444,
303            .proc_handler = do_hardware_modes
304        },
305        PARPORT_DEVICES_ROOT_DIR,
306#ifdef CONFIG_PARPORT_1284
307        {
308            .procname = "autoprobe",
309            .data = NULL,
310            .maxlen = 0,
311            .mode = 0444,
312            .proc_handler = do_autoprobe
313        },
314        {
315            .procname = "autoprobe0",
316            .data = NULL,
317            .maxlen = 0,
318            .mode = 0444,
319            .proc_handler = do_autoprobe
320        },
321        {
322            .procname = "autoprobe1",
323            .data = NULL,
324            .maxlen = 0,
325            .mode = 0444,
326            .proc_handler = do_autoprobe
327        },
328        {
329            .procname = "autoprobe2",
330            .data = NULL,
331            .maxlen = 0,
332            .mode = 0444,
333            .proc_handler = do_autoprobe
334        },
335        {
336            .procname = "autoprobe3",
337            .data = NULL,
338            .maxlen = 0,
339            .mode = 0444,
340            .proc_handler = do_autoprobe
341        },
342#endif /* IEEE 1284 support */
343        {}
344    },
345    {
346        {
347            .procname = "active",
348            .data = NULL,
349            .maxlen = 0,
350            .mode = 0444,
351            .proc_handler = do_active_device
352        },
353        {}
354    },
355    {
356        PARPORT_PORT_DIR(NULL),
357        {}
358    },
359    {
360        PARPORT_PARPORT_DIR(NULL),
361        {}
362    },
363    {
364        PARPORT_DEV_DIR(NULL),
365        {}
366    }
367};
368
369struct parport_device_sysctl_table
370{
371    struct ctl_table_header *sysctl_header;
372    ctl_table vars[2];
373    ctl_table device_dir[2];
374    ctl_table devices_root_dir[2];
375    ctl_table port_dir[2];
376    ctl_table parport_dir[2];
377    ctl_table dev_dir[2];
378};
379
380static const struct parport_device_sysctl_table
381parport_device_sysctl_template = {
382    .sysctl_header = NULL,
383    {
384        {
385            .procname = "timeslice",
386            .data = NULL,
387            .maxlen = sizeof(unsigned long),
388            .mode = 0644,
389            .proc_handler = proc_doulongvec_ms_jiffies_minmax,
390            .extra1 = (void*) &parport_min_timeslice_value,
391            .extra2 = (void*) &parport_max_timeslice_value
392        },
393    },
394    {
395        {
396            .procname = NULL,
397            .data = NULL,
398            .maxlen = 0,
399            .mode = 0555,
400            .child = NULL
401        },
402        {}
403    },
404    {
405        PARPORT_DEVICES_ROOT_DIR,
406        {}
407    },
408    {
409        PARPORT_PORT_DIR(NULL),
410        {}
411    },
412    {
413        PARPORT_PARPORT_DIR(NULL),
414        {}
415    },
416    {
417        PARPORT_DEV_DIR(NULL),
418        {}
419    }
420};
421
422struct parport_default_sysctl_table
423{
424    struct ctl_table_header *sysctl_header;
425    ctl_table vars[3];
426        ctl_table default_dir[2];
427    ctl_table parport_dir[2];
428    ctl_table dev_dir[2];
429};
430
431static struct parport_default_sysctl_table
432parport_default_sysctl_table = {
433    .sysctl_header = NULL,
434    {
435        {
436            .procname = "timeslice",
437            .data = &parport_default_timeslice,
438            .maxlen = sizeof(parport_default_timeslice),
439            .mode = 0644,
440            .proc_handler = proc_doulongvec_ms_jiffies_minmax,
441            .extra1 = (void*) &parport_min_timeslice_value,
442            .extra2 = (void*) &parport_max_timeslice_value
443        },
444        {
445            .procname = "spintime",
446            .data = &parport_default_spintime,
447            .maxlen = sizeof(parport_default_spintime),
448            .mode = 0644,
449            .proc_handler = proc_dointvec_minmax,
450            .extra1 = (void*) &parport_min_spintime_value,
451            .extra2 = (void*) &parport_max_spintime_value
452        },
453        {}
454    },
455    {
456        {
457            .procname = "default",
458            .mode = 0555,
459            .child = parport_default_sysctl_table.vars
460        },
461        {}
462    },
463    {
464        PARPORT_PARPORT_DIR(parport_default_sysctl_table.default_dir),
465        {}
466    },
467    {
468        PARPORT_DEV_DIR(parport_default_sysctl_table.parport_dir),
469        {}
470    }
471};
472
473
474int parport_proc_register(struct parport *port)
475{
476    struct parport_sysctl_table *t;
477    int i;
478
479    t = kmalloc(sizeof(*t), GFP_KERNEL);
480    if (t == NULL)
481        return -ENOMEM;
482    memcpy(t, &parport_sysctl_template, sizeof(*t));
483
484    t->device_dir[0].extra1 = port;
485
486    for (i = 0; i < 5; i++)
487        t->vars[i].extra1 = port;
488
489    t->vars[0].data = &port->spintime;
490    t->vars[5].child = t->device_dir;
491    
492    for (i = 0; i < 5; i++)
493        t->vars[6 + i].extra2 = &port->probe_info[i];
494
495    t->port_dir[0].procname = port->name;
496
497    t->port_dir[0].child = t->vars;
498    t->parport_dir[0].child = t->port_dir;
499    t->dev_dir[0].child = t->parport_dir;
500
501    t->sysctl_header = register_sysctl_table(t->dev_dir);
502    if (t->sysctl_header == NULL) {
503        kfree(t);
504        t = NULL;
505    }
506    port->sysctl_table = t;
507    return 0;
508}
509
510int parport_proc_unregister(struct parport *port)
511{
512    if (port->sysctl_table) {
513        struct parport_sysctl_table *t = port->sysctl_table;
514        port->sysctl_table = NULL;
515        unregister_sysctl_table(t->sysctl_header);
516        kfree(t);
517    }
518    return 0;
519}
520
521int parport_device_proc_register(struct pardevice *device)
522{
523    struct parport_device_sysctl_table *t;
524    struct parport * port = device->port;
525    
526    t = kmalloc(sizeof(*t), GFP_KERNEL);
527    if (t == NULL)
528        return -ENOMEM;
529    memcpy(t, &parport_device_sysctl_template, sizeof(*t));
530
531    t->dev_dir[0].child = t->parport_dir;
532    t->parport_dir[0].child = t->port_dir;
533    t->port_dir[0].procname = port->name;
534    t->port_dir[0].child = t->devices_root_dir;
535    t->devices_root_dir[0].child = t->device_dir;
536
537    t->device_dir[0].procname = device->name;
538    t->device_dir[0].child = t->vars;
539    t->vars[0].data = &device->timeslice;
540
541    t->sysctl_header = register_sysctl_table(t->dev_dir);
542    if (t->sysctl_header == NULL) {
543        kfree(t);
544        t = NULL;
545    }
546    device->sysctl_table = t;
547    return 0;
548}
549
550int parport_device_proc_unregister(struct pardevice *device)
551{
552    if (device->sysctl_table) {
553        struct parport_device_sysctl_table *t = device->sysctl_table;
554        device->sysctl_table = NULL;
555        unregister_sysctl_table(t->sysctl_header);
556        kfree(t);
557    }
558    return 0;
559}
560
561static int __init parport_default_proc_register(void)
562{
563    parport_default_sysctl_table.sysctl_header =
564        register_sysctl_table(parport_default_sysctl_table.dev_dir);
565    return 0;
566}
567
568static void __exit parport_default_proc_unregister(void)
569{
570    if (parport_default_sysctl_table.sysctl_header) {
571        unregister_sysctl_table(parport_default_sysctl_table.
572                    sysctl_header);
573        parport_default_sysctl_table.sysctl_header = NULL;
574    }
575}
576
577#else /* no sysctl or no procfs*/
578
579int parport_proc_register(struct parport *pp)
580{
581    return 0;
582}
583
584int parport_proc_unregister(struct parport *pp)
585{
586    return 0;
587}
588
589int parport_device_proc_register(struct pardevice *device)
590{
591    return 0;
592}
593
594int parport_device_proc_unregister(struct pardevice *device)
595{
596    return 0;
597}
598
599static int __init parport_default_proc_register (void)
600{
601    return 0;
602}
603
604static void __exit parport_default_proc_unregister (void)
605{
606}
607#endif
608
609module_init(parport_default_proc_register)
610module_exit(parport_default_proc_unregister)
611

Archive Download this file



interactive