Merge branch 'staging/for_v3.7' into v4l_for_linus
[GitHub/mt8127/android_kernel_alcatel_ttab.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 }