3 * Copyright 1999 Digi International (www.digi.com)
4 * James Puzzo <jamesp at digi dot com>
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)
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.
26 * Handle the "config" proc entry for the linux realport device driver
27 * and provide slots for the "net" and "mon" devices
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>
45 #include "dgrp_common.h"
47 static struct dgrp_proc_entry dgrp_table
[];
48 static struct proc_dir_entry
*dgrp_proc_dir_entry
;
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
));
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 *);
63 static const struct file_operations dgrp_proc_file_ops
= {
65 .open
= dgrp_gen_proc_open
,
66 .release
= dgrp_gen_proc_close
,
69 static struct inode_operations proc_inode_ops
= {
70 .permission
= dgrp_inode_permission
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
*);
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
[];
84 static ssize_t
dgrp_config_proc_write(struct file
*file
,
85 const char __user
*buffer
,
86 size_t count
, loff_t
*pos
);
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
);
92 static struct file_operations config_proc_file_ops
= {
94 .open
= dgrp_config_proc_open
,
97 .release
= seq_release
,
98 .write
= dgrp_config_proc_write
,
101 static struct file_operations info_proc_file_ops
= {
102 .owner
= THIS_MODULE
,
103 .open
= dgrp_info_proc_open
,
106 .release
= single_release
,
109 static struct file_operations nodeinfo_proc_file_ops
= {
110 .owner
= THIS_MODULE
,
111 .open
= dgrp_nodeinfo_proc_open
,
114 .release
= seq_release
,
117 static struct dgrp_proc_entry dgrp_table
[] = {
122 .proc_file_ops
= &config_proc_file_ops
,
128 .proc_file_ops
= &info_proc_file_ops
,
134 .proc_file_ops
= &nodeinfo_proc_file_ops
,
140 .child
= dgrp_net_table
146 .child
= dgrp_mon_table
152 .child
= dgrp_ports_table
158 .child
= dgrp_dpa_table
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
;
167 static struct dgrp_proc_entry dgrp_net_table
[] = {
171 static struct dgrp_proc_entry dgrp_mon_table
[] = {
175 static struct dgrp_proc_entry dgrp_ports_table
[] = {
179 static struct dgrp_proc_entry dgrp_dpa_table
[] = {
183 void dgrp_unregister_proc(void)
185 net_entry_pointer
= NULL
;
186 mon_entry_pointer
= NULL
;
187 dpa_entry_pointer
= NULL
;
188 ports_entry_pointer
= NULL
;
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
;
199 void dgrp_register_proc(void)
202 * Register /proc/dgrp
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
);
212 static int dgrp_proc_match(int len
, const char *name
, struct proc_dir_entry
*de
)
214 if (!de
|| !de
->low_ino
)
216 if (de
->namelen
!= len
)
218 return !memcmp(name
, de
->name
, len
);
223 * Scan the entries in table and add them all to /proc at the position
224 * referred to by "root"
226 static void register_proc_table(struct dgrp_proc_entry
*table
,
227 struct proc_dir_entry
*root
)
229 struct proc_dir_entry
*de
;
238 for (; table
->id
; table
++) {
239 /* Can't do anything without a proc name. */
243 /* Maybe we can't do anything with it... */
244 if (!table
->proc_file_ops
&&
246 pr_warn("dgrp: Can't register %s\n",
251 len
= strlen(table
->name
);
259 for (de
= root
->subdir
; de
; de
= de
->next
) {
260 if (dgrp_proc_match(len
, table
->name
, de
))
263 /* If the subdir exists already, de is non-NULL */
267 de
= create_proc_entry(table
->name
, mode
, root
);
270 de
->data
= (void *) table
;
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
);
277 rcu_assign_pointer(de
->proc_fops
,
278 &dgrp_proc_file_ops
);
282 if (de
->mode
& S_IFDIR
)
283 register_proc_table(table
->child
, de
);
285 if (table
->id
== DGRP_NETDIR
)
286 net_entry_pointer
= de
;
288 if (table
->id
== DGRP_MONDIR
)
289 mon_entry_pointer
= de
;
291 if (table
->id
== DGRP_DPADIR
)
292 dpa_entry_pointer
= de
;
294 if (table
->id
== DGRP_PORTSDIR
)
295 ports_entry_pointer
= de
;
300 * Unregister a /proc sysctl table and any subdirectories.
302 static void unregister_proc_table(struct dgrp_proc_entry
*table
,
303 struct proc_dir_entry
*root
)
305 struct proc_dir_entry
*de
;
306 struct nd_struct
*tmp
;
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
);
317 if ((table
== dgrp_mon_table
) && (tmp
->nd_mon_de
))
318 unregister_dgrp_device(tmp
->nd_mon_de
);
320 if ((table
== dgrp_dpa_table
) && (tmp
->nd_dpa_de
))
321 unregister_dgrp_device(tmp
->nd_dpa_de
);
323 if ((table
== dgrp_ports_table
) && (tmp
->nd_ports_de
))
324 unregister_dgrp_device(tmp
->nd_ports_de
);
327 for (; table
->id
; table
++) {
332 if (de
->mode
& S_IFDIR
) {
334 pr_alert("dgrp: malformed sysctl tree on free\n");
337 unregister_proc_table(table
->child
, de
);
339 /* Don't unregister directories which still have entries */
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",
351 remove_proc_entry(de
->name
, de
->parent
);
356 static int dgrp_gen_proc_open(struct inode
*inode
, struct file
*file
)
358 struct proc_dir_entry
*de
;
359 struct dgrp_proc_entry
*entry
;
362 de
= (struct proc_dir_entry
*) PDE(file_inode(file
));
363 if (!de
|| !de
->data
) {
368 entry
= (struct dgrp_proc_entry
*) de
->data
;
374 down(&entry
->excl_sem
);
381 up(&entry
->excl_sem
);
387 static int dgrp_gen_proc_close(struct inode
*inode
, struct file
*file
)
389 struct proc_dir_entry
*de
;
390 struct dgrp_proc_entry
*entry
;
392 de
= (struct proc_dir_entry
*) PDE(file_inode(file
));
393 if (!de
|| !de
->data
)
396 entry
= (struct dgrp_proc_entry
*) de
->data
;
400 down(&entry
->excl_sem
);
405 up(&entry
->excl_sem
);
411 static void *dgrp_config_proc_start(struct seq_file
*m
, loff_t
*pos
)
413 return seq_list_start_head(&nd_struct_list
, *pos
);
416 static void *dgrp_config_proc_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
418 return seq_list_next(v
, &nd_struct_list
, pos
);
421 static void dgrp_config_proc_stop(struct seq_file
*m
, void *v
)
425 static int dgrp_config_proc_show(struct seq_file
*m
, void *v
)
427 struct nd_struct
*nd
;
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");
437 nd
= list_entry(v
, struct nd_struct
, list
);
439 ID_TO_CHAR(nd
->nd_ID
, tmp_id
);
441 seq_printf(m
, " %-2.2s %-5ld %-10.10s %-5d\n",
444 ND_STATE_STR(nd
->nd_state
),
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
,
457 static int dgrp_config_proc_open(struct inode
*inode
, struct file
*file
)
459 return seq_open(file
, &proc_config_ops
);
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.
468 static ssize_t
dgrp_config_proc_write(struct file
*file
,
469 const char __user
*buffer
,
470 size_t count
, loff_t
*pos
)
479 inbuf
= sp
= vzalloc(count
+ 1);
483 if (copy_from_user(inbuf
, buffer
, count
)) {
492 line
= strpbrk(sp
, ldelim
);
495 retval
= parse_write_config(sp
);
500 line
= strpbrk(sp
, ldelim
);
510 * ------------------------------------------------------------------------
512 * The following are the functions to parse input
514 * ------------------------------------------------------------------------
516 static inline char *skip_past_ws(const char *str
)
518 while ((*str
) && !isspace(*str
))
521 return skip_spaces(str
);
524 static int parse_id(char **c
, char *cID
)
528 if (isalnum(tmp
) || (tmp
== '_'))
535 if (isalnum(tmp
) || (tmp
== '_')) {
544 static int parse_add_config(char *buf
)
553 retval
= parse_id(&c
, cID
);
557 ID
= CHAR_TO_ID(cID
);
561 return dgrp_add_id(ID
);
564 static int parse_del_config(char *buf
)
568 struct nd_struct
*nd
;
575 retval
= parse_id(&c
, cID
);
579 ID
= CHAR_TO_ID(cID
);
583 retval
= kstrtol(c
, 10, &major
);
587 nd
= nd_struct_get(major
);
591 if ((nd
->nd_major
!= major
) || (nd
->nd_ID
!= ID
))
594 return dgrp_remove_nd(nd
);
597 static int parse_chg_config(char *buf
)
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
606 * If the first character is a "-", it is parsed as a request to delete a
608 * If the first character is a "*", it is parsed as a request to change a
610 * Any other character (including whitespace) causes the record to be
613 static int parse_write_config(char *buf
)
619 retval
= parse_add_config(buf
);
622 retval
= parse_del_config(buf
);
625 retval
= parse_chg_config(buf
);
634 static int dgrp_info_proc_show(struct seq_file
*m
, void *v
)
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
);
644 static int dgrp_info_proc_open(struct inode
*inode
, struct file
*file
)
646 return single_open(file
, dgrp_info_proc_show
, NULL
);
650 static void *dgrp_nodeinfo_start(struct seq_file
*m
, loff_t
*pos
)
652 return seq_list_start_head(&nd_struct_list
, *pos
);
655 static void *dgrp_nodeinfo_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
657 return seq_list_next(v
, &nd_struct_list
, pos
);
660 static void dgrp_nodeinfo_stop(struct seq_file
*m
, void *v
)
664 static int dgrp_nodeinfo_show(struct seq_file
*m
, void *v
)
666 struct nd_struct
*nd
;
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");
678 nd
= list_entry(v
, struct nd_struct
, list
);
680 ID_TO_CHAR(nd
->nd_ID
, tmp_id
);
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",
689 ND_STATE_STR(nd
->nd_state
),
696 seq_printf(m
, " %-2.2s %-10.10s\n",
698 ND_STATE_STR(nd
->nd_state
));
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
,
712 static int dgrp_nodeinfo_proc_open(struct inode
*inode
, struct file
*file
)
714 return seq_open(file
, &nodeinfo_ops
);
718 * dgrp_add_id() -- creates new nd struct and adds it to list
719 * @id: id of device to add
721 static int dgrp_add_id(long id
)
723 struct nd_struct
*nd
;
727 nd
= kzalloc(sizeof(struct nd_struct
), GFP_KERNEL
);
734 spin_lock_init(&nd
->nd_lock
);
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
]);
742 /* setup the structures to get the major number */
743 ret
= dgrp_tty_init(nd
);
747 nd
->nd_major
= nd
->nd_serial_ttdriver
->major
;
749 ret
= nd_struct_add(nd
);
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
);
761 /* FIXME this guy should free the tty driver stored in nd and destroy
762 * all channel ports */
769 static int dgrp_remove_nd(struct nd_struct
*nd
)
773 /* Check to see if the selected structure is in use */
774 if (nd
->nd_tty_ref_cnt
)
778 unregister_dgrp_device(nd
->nd_net_de
);
779 dgrp_remove_node_class_sysfs_files(nd
);
782 unregister_dgrp_device(nd
->nd_mon_de
);
784 unregister_dgrp_device(nd
->nd_ports_de
);
786 unregister_dgrp_device(nd
->nd_dpa_de
);
790 ret
= nd_struct_del(nd
);
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
))
803 struct proc_dir_entry
*de
;
805 ID_TO_CHAR(node
->nd_ID
, buf
);
807 de
= create_proc_entry(buf
, 0600 | S_IFREG
, root
);
811 de
->data
= (void *) node
;
818 static void unregister_dgrp_device(struct proc_dir_entry
*de
)
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",
830 remove_proc_entry(de
->name
, de
->parent
);