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