]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/dgrp/dgrp_specproc.c
staging: dgrp: using vmalloc needs to include vmalloc.h
[karo-tx-linux.git] / drivers / staging / dgrp / dgrp_specproc.c
1 /*
2  *
3  * Copyright 1999 Digi International (www.digi.com)
4  *     James Puzzo  <jamesp at digi dot com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
13  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14  * PURPOSE.  See the GNU General Public License for more details.
15  *
16  */
17
18 /*
19  *
20  *  Filename:
21  *
22  *     dgrp_specproc.c
23  *
24  *  Description:
25  *
26  *     Handle the "config" proc entry for the linux realport device driver
27  *     and provide slots for the "net" and "mon" devices
28  *
29  *  Author:
30  *
31  *     James A. Puzzo
32  *
33  */
34
35 #include <linux/module.h>
36 #include <linux/tty.h>
37 #include <linux/sched.h>
38 #include <linux/cred.h>
39 #include <linux/proc_fs.h>
40 #include <linux/ctype.h>
41 #include <linux/seq_file.h>
42 #include <linux/vmalloc.h>
43
44 #include "dgrp_common.h"
45
46 static struct dgrp_proc_entry dgrp_table[];
47 static struct proc_dir_entry *dgrp_proc_dir_entry;
48
49 static int dgrp_add_id(long id);
50 static int dgrp_remove_nd(struct nd_struct *nd);
51 static void unregister_dgrp_device(struct proc_dir_entry *de);
52 static void register_dgrp_device(struct nd_struct *node,
53                                  struct proc_dir_entry *root,
54                                  void (*register_hook)(struct proc_dir_entry *de));
55
56 /* File operation declarations */
57 static int dgrp_gen_proc_open(struct inode *, struct file *);
58 static int dgrp_gen_proc_close(struct inode *, struct file *);
59 static int parse_write_config(char *);
60
61
62 static const struct file_operations dgrp_proc_file_ops = {
63         .owner   = THIS_MODULE,
64         .open    = dgrp_gen_proc_open,
65         .release = dgrp_gen_proc_close,
66 };
67
68 static struct inode_operations proc_inode_ops = {
69         .permission = dgrp_inode_permission
70 };
71
72
73 static void register_proc_table(struct dgrp_proc_entry *,
74                                 struct proc_dir_entry *);
75 static void unregister_proc_table(struct dgrp_proc_entry *,
76                                   struct proc_dir_entry *);
77
78 static struct dgrp_proc_entry dgrp_net_table[];
79 static struct dgrp_proc_entry dgrp_mon_table[];
80 static struct dgrp_proc_entry dgrp_ports_table[];
81 static struct dgrp_proc_entry dgrp_dpa_table[];
82
83 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
84                                  size_t count, loff_t *pos);
85
86 static int nodeinfo_proc_open(struct inode *inode, struct file *file);
87 static int info_proc_open(struct inode *inode, struct file *file);
88 static int config_proc_open(struct inode *inode, struct file *file);
89
90 static struct file_operations config_proc_file_ops = {
91         .owner   = THIS_MODULE,
92         .open    = config_proc_open,
93         .read    = seq_read,
94         .llseek  = seq_lseek,
95         .release = seq_release,
96         .write   = config_proc_write
97 };
98
99 static struct file_operations info_proc_file_ops = {
100         .owner   = THIS_MODULE,
101         .open    = info_proc_open,
102         .read    = seq_read,
103         .llseek  = seq_lseek,
104         .release = seq_release,
105 };
106
107 static struct file_operations nodeinfo_proc_file_ops = {
108         .owner   = THIS_MODULE,
109         .open    = nodeinfo_proc_open,
110         .read    = seq_read,
111         .llseek  = seq_lseek,
112         .release = seq_release,
113 };
114
115 static struct dgrp_proc_entry dgrp_table[] = {
116         {
117                 .id = DGRP_CONFIG,
118                 .name = "config",
119                 .mode = 0644,
120                 .proc_file_ops = &config_proc_file_ops,
121         },
122         {
123                 .id = DGRP_INFO,
124                 .name = "info",
125                 .mode = 0644,
126                 .proc_file_ops = &info_proc_file_ops,
127         },
128         {
129                 .id = DGRP_NODEINFO,
130                 .name = "nodeinfo",
131                 .mode = 0644,
132                 .proc_file_ops = &nodeinfo_proc_file_ops,
133         },
134         {
135                 .id = DGRP_NETDIR,
136                 .name = "net",
137                 .mode = 0500,
138                 .child = dgrp_net_table
139         },
140         {
141                 .id = DGRP_MONDIR,
142                 .name = "mon",
143                 .mode = 0500,
144                 .child = dgrp_mon_table
145         },
146         {
147                 .id = DGRP_PORTSDIR,
148                 .name = "ports",
149                 .mode = 0500,
150                 .child = dgrp_ports_table
151         },
152         {
153                 .id = DGRP_DPADIR,
154                 .name = "dpa",
155                 .mode = 0500,
156                 .child = dgrp_dpa_table
157         }
158 };
159
160 static struct proc_dir_entry *net_entry_pointer;
161 static struct proc_dir_entry *mon_entry_pointer;
162 static struct proc_dir_entry *dpa_entry_pointer;
163 static struct proc_dir_entry *ports_entry_pointer;
164
165 static struct dgrp_proc_entry dgrp_net_table[] = {
166         {0}
167 };
168
169 static struct dgrp_proc_entry dgrp_mon_table[] = {
170         {0}
171 };
172
173 static struct dgrp_proc_entry dgrp_ports_table[] = {
174         {0}
175 };
176
177 static struct dgrp_proc_entry dgrp_dpa_table[] = {
178         {0}
179 };
180
181 void dgrp_unregister_proc(void)
182 {
183         unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
184         net_entry_pointer = NULL;
185         mon_entry_pointer = NULL;
186         dpa_entry_pointer = NULL;
187         ports_entry_pointer = NULL;
188
189         if (dgrp_proc_dir_entry) {
190                 remove_proc_entry(dgrp_proc_dir_entry->name,
191                                   dgrp_proc_dir_entry->parent);
192                 dgrp_proc_dir_entry = NULL;
193         }
194
195 }
196
197 void dgrp_register_proc(void)
198 {
199         /*
200          *      Register /proc/dgrp
201          */
202         dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
203                                           &dgrp_proc_file_ops);
204         register_proc_table(dgrp_table, dgrp_proc_dir_entry);
205 }
206
207 /*
208  * /proc/sys support
209  */
210 static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
211 {
212         if (!de || !de->low_ino)
213                 return 0;
214         if (de->namelen != len)
215                 return 0;
216         return !memcmp(name, de->name, len);
217 }
218
219
220 /*
221  *  Scan the entries in table and add them all to /proc at the position
222  *  referred to by "root"
223  */
224 static void register_proc_table(struct dgrp_proc_entry *table,
225                                 struct proc_dir_entry *root)
226 {
227         struct proc_dir_entry *de;
228         int len;
229         mode_t mode;
230
231         for (; table->id; table++) {
232                 /* Can't do anything without a proc name. */
233                 if (!table->name)
234                         continue;
235
236                 /* Maybe we can't do anything with it... */
237                 if (!table->proc_file_ops &&
238                     !table->child) {
239                         pr_warn("dgrp: Can't register %s\n",
240                                 table->name);
241                         continue;
242                 }
243
244                 len = strlen(table->name);
245                 mode = table->mode;
246
247                 de = NULL;
248                 if (!table->child)
249                         mode |= S_IFREG;
250                 else {
251                         mode |= S_IFDIR;
252                         for (de = root->subdir; de; de = de->next) {
253                                 if (dgrp_proc_match(len, table->name, de))
254                                         break;
255                         }
256                         /* If the subdir exists already, de is non-NULL */
257                 }
258
259                 if (!de) {
260                         de = create_proc_entry(table->name, mode, root);
261                         if (!de)
262                                 continue;
263                         de->data = (void *) table;
264                         if (!table->child) {
265                                 de->proc_iops = &proc_inode_ops;
266                                 if (table->proc_file_ops)
267                                         de->proc_fops = table->proc_file_ops;
268                                 else
269                                         de->proc_fops = &dgrp_proc_file_ops;
270                         }
271                 }
272                 table->de = de;
273                 if (de->mode & S_IFDIR)
274                         register_proc_table(table->child, de);
275
276                 if (table->id == DGRP_NETDIR)
277                         net_entry_pointer = de;
278
279                 if (table->id == DGRP_MONDIR)
280                         mon_entry_pointer = de;
281
282                 if (table->id == DGRP_DPADIR)
283                         dpa_entry_pointer = de;
284
285                 if (table->id == DGRP_PORTSDIR)
286                         ports_entry_pointer = de;
287         }
288 }
289
290 /*
291  * Unregister a /proc sysctl table and any subdirectories.
292  */
293 static void unregister_proc_table(struct dgrp_proc_entry *table,
294                                   struct proc_dir_entry *root)
295 {
296         struct proc_dir_entry *de;
297         struct nd_struct *tmp;
298
299         list_for_each_entry(tmp, &nd_struct_list, list) {
300                 if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
301                         unregister_dgrp_device(tmp->nd_net_de);
302                         dgrp_remove_node_class_sysfs_files(tmp);
303                 }
304
305                 if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
306                         unregister_dgrp_device(tmp->nd_mon_de);
307
308                 if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
309                         unregister_dgrp_device(tmp->nd_dpa_de);
310
311                 if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
312                         unregister_dgrp_device(tmp->nd_ports_de);
313         }
314
315         for (; table->id; table++) {
316                 de = table->de;
317
318                 if (!de)
319                         continue;
320                 if (de->mode & S_IFDIR) {
321                         if (!table->child) {
322                                 pr_alert("dgrp: malformed sysctl tree on free\n");
323                                 continue;
324                         }
325                         unregister_proc_table(table->child, de);
326
327         /* Don't unregister directories which still have entries */
328                         if (de->subdir)
329                                 continue;
330                 }
331
332                 /* Don't unregister proc entries that are still being used.. */
333                 if ((atomic_read(&de->count)) != 1) {
334                         pr_alert("proc entry %s in use, not removing\n",
335                                 de->name);
336                         continue;
337                 }
338
339                 remove_proc_entry(de->name, de->parent);
340                 table->de = NULL;
341         }
342 }
343
344 static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
345 {
346         struct proc_dir_entry *de;
347         struct dgrp_proc_entry *entry;
348         int ret = 0;
349
350         de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
351         if (!de || !de->data) {
352                 ret = -ENXIO;
353                 goto done;
354         }
355
356         entry = (struct dgrp_proc_entry *) de->data;
357         if (!entry) {
358                 ret = -ENXIO;
359                 goto done;
360         }
361
362         down(&entry->excl_sem);
363
364         if (entry->excl_cnt)
365                 ret = -EBUSY;
366         else
367                 entry->excl_cnt++;
368
369         up(&entry->excl_sem);
370
371 done:
372         return ret;
373 }
374
375 static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
376 {
377         struct proc_dir_entry *de;
378         struct dgrp_proc_entry *entry;
379
380         de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
381         if (!de || !de->data)
382                 goto done;
383
384         entry = (struct dgrp_proc_entry *) de->data;
385         if (!entry)
386                 goto done;
387
388         down(&entry->excl_sem);
389
390         if (entry->excl_cnt)
391                 entry->excl_cnt = 0;
392
393         up(&entry->excl_sem);
394
395 done:
396         return 0;
397 }
398
399 static void *config_proc_start(struct seq_file *m, loff_t *pos)
400 {
401         return seq_list_start_head(&nd_struct_list, *pos);
402 }
403
404 static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
405 {
406         return seq_list_next(v, &nd_struct_list, pos);
407 }
408
409 static void config_proc_stop(struct seq_file *m, void *v)
410 {
411 }
412
413 static int config_proc_show(struct seq_file *m, void *v)
414 {
415         struct nd_struct *nd;
416         char tmp_id[4];
417
418         if (v == &nd_struct_list) {
419                 seq_puts(m, "#-----------------------------------------------------------------------------\n");
420                 seq_puts(m, "#                        Avail\n");
421                 seq_puts(m, "# ID  Major  State       Ports\n");
422                 return 0;
423         }
424
425         nd = list_entry(v, struct nd_struct, list);
426
427         ID_TO_CHAR(nd->nd_ID, tmp_id);
428
429         seq_printf(m, "  %-2.2s  %-5ld  %-10.10s  %-5d\n",
430                    tmp_id,
431                    nd->nd_major,
432                    ND_STATE_STR(nd->nd_state),
433                    nd->nd_chan_count);
434
435         return 0;
436 }
437
438 static const struct seq_operations proc_config_ops = {
439         .start = config_proc_start,
440         .next  = config_proc_next,
441         .stop  = config_proc_stop,
442         .show  = config_proc_show
443 };
444
445 static int config_proc_open(struct inode *inode, struct file *file)
446 {
447         return seq_open(file, &proc_config_ops);
448 }
449
450
451 /*
452  *  When writing configuration information, each "record" (i.e. each
453  *  write) is treated as an independent request.  See the "parse"
454  *  description for more details.
455  */
456 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
457                                  size_t count, loff_t *pos)
458 {
459         ssize_t retval;
460         char *inbuf, *sp;
461         char *line, *ldelim;
462
463         if (count > 32768)
464                 return -EINVAL;
465
466         inbuf = sp = vzalloc(count + 1);
467         if (!inbuf)
468                 return -ENOMEM;
469
470         if (copy_from_user(inbuf, buffer, count)) {
471                 retval = -EFAULT;
472                 goto done;
473         }
474
475         inbuf[count] = 0;
476
477         ldelim = "\n";
478
479         line = strpbrk(sp, ldelim);
480         while (line) {
481                 *line = 0;
482                 retval = parse_write_config(sp);
483                 if (retval)
484                         goto done;
485
486                 sp = line + 1;
487                 line = strpbrk(sp, ldelim);
488         }
489
490         retval = count;
491 done:
492         vfree(inbuf);
493         return retval;
494 }
495
496 /*
497  *  ------------------------------------------------------------------------
498  *
499  *  The following are the functions to parse input
500  *
501  *  ------------------------------------------------------------------------
502  */
503 static inline char *skip_past_ws(const char *str)
504 {
505         while ((*str) && !isspace(*str))
506                 ++str;
507
508         return skip_spaces(str);
509 }
510
511 static int parse_id(char **c, char *cID)
512 {
513         int tmp = **c;
514
515         if (isalnum(tmp) || (tmp == '_'))
516                 cID[0] = tmp;
517         else
518                 return -EINVAL;
519
520         (*c)++; tmp = **c;
521
522         if (isalnum(tmp) || (tmp == '_')) {
523                 cID[1] = tmp;
524                 (*c)++;
525         } else
526                 cID[1] = 0;
527
528         return 0;
529 }
530
531 static int parse_add_config(char *buf)
532 {
533         char *c = buf;
534         int  retval;
535         char cID[2];
536         long ID;
537
538         c = skip_past_ws(c);
539
540         retval = parse_id(&c, cID);
541         if (retval < 0)
542                 return retval;
543
544         ID = CHAR_TO_ID(cID);
545
546         c = skip_past_ws(c);
547
548         return dgrp_add_id(ID);
549 }
550
551 static int parse_del_config(char *buf)
552 {
553         char *c = buf;
554         int  retval;
555         struct nd_struct *nd;
556         char cID[2];
557         long ID;
558         long major;
559
560         c = skip_past_ws(c);
561
562         retval = parse_id(&c, cID);
563         if (retval < 0)
564                 return retval;
565
566         ID = CHAR_TO_ID(cID);
567
568         c = skip_past_ws(c);
569
570         retval = kstrtol(c, 10, &major);
571         if (retval)
572                 return retval;
573
574         nd = nd_struct_get(major);
575         if (!nd)
576                 return -EINVAL;
577
578         if ((nd->nd_major != major) || (nd->nd_ID != ID))
579                 return -EINVAL;
580
581         return dgrp_remove_nd(nd);
582 }
583
584 static int parse_chg_config(char *buf)
585 {
586         return -EINVAL;
587 }
588
589 /*
590  *  The passed character buffer represents a single configuration request.
591  *  If the first character is a "+", it is parsed as a request to add a
592  *     PortServer
593  *  If the first character is a "-", it is parsed as a request to delete a
594  *     PortServer
595  *  If the first character is a "*", it is parsed as a request to change a
596  *     PortServer
597  *  Any other character (including whitespace) causes the record to be
598  *     ignored.
599  */
600 static int parse_write_config(char *buf)
601 {
602         int retval;
603
604         switch (buf[0]) {
605         case '+':
606                 retval = parse_add_config(buf);
607                 break;
608         case '-':
609                 retval = parse_del_config(buf);
610                 break;
611         case '*':
612                 retval = parse_chg_config(buf);
613                 break;
614         default:
615                 retval = -EINVAL;
616         }
617
618         return retval;
619 }
620
621 static int info_proc_show(struct seq_file *m, void *v)
622 {
623         seq_printf(m, "version: %s\n", DIGI_VERSION);
624         seq_puts(m, "register_with_sysfs: 1\n");
625         seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
626                    dgrp_rawreadok, dgrp_rawreadok);
627         seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
628                    dgrp_poll_tick, dgrp_poll_tick);
629
630         return 0;
631 }
632
633 static int info_proc_open(struct inode *inode, struct file *file)
634 {
635         return single_open(file, info_proc_show, NULL);
636 }
637
638
639 static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
640 {
641         return seq_list_start_head(&nd_struct_list, *pos);
642 }
643
644 static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
645 {
646         return seq_list_next(v, &nd_struct_list, pos);
647 }
648
649 static void nodeinfo_stop(struct seq_file *m, void *v)
650 {
651 }
652
653 static int nodeinfo_show(struct seq_file *m, void *v)
654 {
655         struct nd_struct *nd;
656         char hwver[8];
657         char swver[8];
658         char tmp_id[4];
659
660         if (v == &nd_struct_list) {
661                 seq_puts(m, "#-----------------------------------------------------------------------------\n");
662                 seq_puts(m, "#                 HW       HW   SW\n");
663                 seq_puts(m, "# ID  State       Version  ID   Version  Description\n");
664                 return 0;
665         }
666
667         nd = list_entry(v, struct nd_struct, list);
668
669         ID_TO_CHAR(nd->nd_ID, tmp_id);
670
671         if (nd->nd_state == NS_READY) {
672                 sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
673                         nd->nd_hw_ver & 0xff);
674                 sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
675                         nd->nd_sw_ver & 0xff);
676                 seq_printf(m, "  %-2.2s  %-10.10s  %-7.7s  %-3d  %-7.7s  %-35.35s\n",
677                            tmp_id,
678                            ND_STATE_STR(nd->nd_state),
679                            hwver,
680                            nd->nd_hw_id,
681                            swver,
682                            nd->nd_ps_desc);
683
684         } else {
685                 seq_printf(m, "  %-2.2s  %-10.10s\n",
686                            tmp_id,
687                            ND_STATE_STR(nd->nd_state));
688         }
689
690         return 0;
691 }
692
693
694 static const struct seq_operations nodeinfo_ops = {
695         .start = nodeinfo_start,
696         .next  = nodeinfo_next,
697         .stop  = nodeinfo_stop,
698         .show  = nodeinfo_show
699 };
700
701 static int nodeinfo_proc_open(struct inode *inode, struct file *file)
702 {
703         return seq_open(file, &nodeinfo_ops);
704 }
705
706 /**
707  * dgrp_add_id() -- creates new nd struct and adds it to list
708  * @id: id of device to add
709  */
710 static int dgrp_add_id(long id)
711 {
712         struct nd_struct *nd;
713         int ret;
714         int i;
715
716         nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
717         if (!nd)
718                 return -ENOMEM;
719
720         nd->nd_major = 0;
721         nd->nd_ID = id;
722
723         spin_lock_init(&nd->nd_lock);
724
725         init_waitqueue_head(&nd->nd_tx_waitq);
726         init_waitqueue_head(&nd->nd_mon_wqueue);
727         init_waitqueue_head(&nd->nd_dpa_wqueue);
728         for (i = 0; i < SEQ_MAX; i++)
729                 init_waitqueue_head(&nd->nd_seq_wque[i]);
730
731         /* setup the structures to get the major number */
732         ret = dgrp_tty_init(nd);
733         if (ret)
734                 goto error_out;
735
736         nd->nd_major = nd->nd_serial_ttdriver->major;
737
738         ret = nd_struct_add(nd);
739         if (ret)
740                 goto error_out;
741
742         register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
743         register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
744         register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
745         register_dgrp_device(nd, ports_entry_pointer,
746                               dgrp_register_ports_hook);
747
748         return 0;
749
750 error_out:
751         kfree(nd);
752         return ret;
753
754 }
755
756 static int dgrp_remove_nd(struct nd_struct *nd)
757 {
758         int ret;
759
760         /* Check to see if the selected structure is in use */
761         if (nd->nd_tty_ref_cnt)
762                 return -EBUSY;
763
764         if (nd->nd_net_de) {
765                 unregister_dgrp_device(nd->nd_net_de);
766                 dgrp_remove_node_class_sysfs_files(nd);
767         }
768
769         if (nd->nd_mon_de)
770                 unregister_dgrp_device(nd->nd_mon_de);
771
772         if (nd->nd_ports_de)
773                 unregister_dgrp_device(nd->nd_ports_de);
774
775         if (nd->nd_dpa_de)
776                 unregister_dgrp_device(nd->nd_dpa_de);
777
778         dgrp_tty_uninit(nd);
779
780         ret = nd_struct_del(nd);
781         if (ret)
782                 return ret;
783
784         kfree(nd);
785         return 0;
786 }
787
788 static void register_dgrp_device(struct nd_struct *node,
789                                  struct proc_dir_entry *root,
790                                  void (*register_hook)(struct proc_dir_entry *de))
791 {
792         char buf[3];
793         struct proc_dir_entry *de;
794
795         ID_TO_CHAR(node->nd_ID, buf);
796
797         de = create_proc_entry(buf, 0600 | S_IFREG, root);
798         if (!de)
799                 return;
800
801         de->data = (void *) node;
802
803         if (register_hook)
804                 register_hook(de);
805
806 }
807
808 static void unregister_dgrp_device(struct proc_dir_entry *de)
809 {
810         if (!de)
811                 return;
812
813         /* Don't unregister proc entries that are still being used.. */
814         if ((atomic_read(&de->count)) != 1) {
815                 pr_alert("%s - proc entry %s in use. Not removing.\n",
816                          __func__, de->name);
817                 return;
818         }
819
820         remove_proc_entry(de->name, de->parent);
821         de = NULL;
822 }