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 proc_dir_entry
*dgrp_proc_dir_entry
;
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
));
56 /* File operation declarations */
57 static int parse_write_config(char *);
60 static struct inode_operations proc_inode_ops
= {
61 .permission
= dgrp_inode_permission
65 static ssize_t
dgrp_config_proc_write(struct file
*file
,
66 const char __user
*buffer
,
67 size_t count
, loff_t
*pos
);
69 static int dgrp_nodeinfo_proc_open(struct inode
*inode
, struct file
*file
);
70 static int dgrp_info_proc_open(struct inode
*inode
, struct file
*file
);
71 static int dgrp_config_proc_open(struct inode
*inode
, struct file
*file
);
73 static struct file_operations config_proc_file_ops
= {
75 .open
= dgrp_config_proc_open
,
78 .release
= seq_release
,
79 .write
= dgrp_config_proc_write
,
82 static struct file_operations info_proc_file_ops
= {
84 .open
= dgrp_info_proc_open
,
87 .release
= single_release
,
90 static struct file_operations nodeinfo_proc_file_ops
= {
92 .open
= dgrp_nodeinfo_proc_open
,
95 .release
= seq_release
,
98 static struct proc_dir_entry
*net_entry_pointer
;
99 static struct proc_dir_entry
*mon_entry_pointer
;
100 static struct proc_dir_entry
*dpa_entry_pointer
;
101 static struct proc_dir_entry
*ports_entry_pointer
;
103 void dgrp_unregister_proc(void)
105 net_entry_pointer
= NULL
;
106 mon_entry_pointer
= NULL
;
107 dpa_entry_pointer
= NULL
;
108 ports_entry_pointer
= NULL
;
110 if (dgrp_proc_dir_entry
) {
111 struct nd_struct
*nd
;
112 list_for_each_entry(nd
, &nd_struct_list
, list
) {
114 unregister_dgrp_device(nd
->nd_net_de
);
115 dgrp_remove_node_class_sysfs_files(nd
);
119 unregister_dgrp_device(nd
->nd_mon_de
);
122 unregister_dgrp_device(nd
->nd_dpa_de
);
125 unregister_dgrp_device(nd
->nd_ports_de
);
127 remove_proc_entry("dgrp/config", NULL
);
128 remove_proc_entry("dgrp/info", NULL
);
129 remove_proc_entry("dgrp/nodeinfo", NULL
);
130 remove_proc_entry("dgrp/net", NULL
);
131 remove_proc_entry("dgrp/mon", NULL
);
132 remove_proc_entry("dgrp/dpa", NULL
);
133 remove_proc_entry("dgrp/ports", NULL
);
134 remove_proc_entry("dgrp", NULL
);
135 dgrp_proc_dir_entry
= NULL
;
139 void dgrp_register_proc(void)
141 struct proc_dir_entry
*de
;
143 * Register /proc/dgrp
145 dgrp_proc_dir_entry
= proc_mkdir("dgrp", NULL
);
146 if (!dgrp_proc_dir_entry
)
148 de
= create_proc_entry("dgrp/config", 0644, NULL
);
150 de
->proc_fops
= &config_proc_file_ops
;
151 de
->proc_iops
= &proc_inode_ops
;
153 de
= create_proc_entry("dgrp/info", 0644, NULL
);
155 de
->proc_fops
= &info_proc_file_ops
;
156 de
->proc_iops
= &proc_inode_ops
;
158 de
= create_proc_entry("dgrp/nodeinfo", 0644, NULL
);
160 de
->proc_fops
= &nodeinfo_proc_file_ops
;
161 de
->proc_iops
= &proc_inode_ops
;
163 net_entry_pointer
= proc_mkdir_mode("dgrp/net", 0500, NULL
);
164 mon_entry_pointer
= proc_mkdir_mode("dgrp/mon", 0500, NULL
);
165 dpa_entry_pointer
= proc_mkdir_mode("dgrp/dpa", 0500, NULL
);
166 ports_entry_pointer
= proc_mkdir_mode("dgrp/ports", 0500, NULL
);
169 static void *dgrp_config_proc_start(struct seq_file
*m
, loff_t
*pos
)
171 return seq_list_start_head(&nd_struct_list
, *pos
);
174 static void *dgrp_config_proc_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
176 return seq_list_next(v
, &nd_struct_list
, pos
);
179 static void dgrp_config_proc_stop(struct seq_file
*m
, void *v
)
183 static int dgrp_config_proc_show(struct seq_file
*m
, void *v
)
185 struct nd_struct
*nd
;
188 if (v
== &nd_struct_list
) {
189 seq_puts(m
, "#-----------------------------------------------------------------------------\n");
190 seq_puts(m
, "# Avail\n");
191 seq_puts(m
, "# ID Major State Ports\n");
195 nd
= list_entry(v
, struct nd_struct
, list
);
197 ID_TO_CHAR(nd
->nd_ID
, tmp_id
);
199 seq_printf(m
, " %-2.2s %-5ld %-10.10s %-5d\n",
202 ND_STATE_STR(nd
->nd_state
),
208 static const struct seq_operations proc_config_ops
= {
209 .start
= dgrp_config_proc_start
,
210 .next
= dgrp_config_proc_next
,
211 .stop
= dgrp_config_proc_stop
,
212 .show
= dgrp_config_proc_show
,
215 static int dgrp_config_proc_open(struct inode
*inode
, struct file
*file
)
217 return seq_open(file
, &proc_config_ops
);
222 * When writing configuration information, each "record" (i.e. each
223 * write) is treated as an independent request. See the "parse"
224 * description for more details.
226 static ssize_t
dgrp_config_proc_write(struct file
*file
,
227 const char __user
*buffer
,
228 size_t count
, loff_t
*pos
)
237 inbuf
= sp
= vzalloc(count
+ 1);
241 if (copy_from_user(inbuf
, buffer
, count
)) {
250 line
= strpbrk(sp
, ldelim
);
253 retval
= parse_write_config(sp
);
258 line
= strpbrk(sp
, ldelim
);
268 * ------------------------------------------------------------------------
270 * The following are the functions to parse input
272 * ------------------------------------------------------------------------
274 static inline char *skip_past_ws(const char *str
)
276 while ((*str
) && !isspace(*str
))
279 return skip_spaces(str
);
282 static int parse_id(char **c
, char *cID
)
286 if (isalnum(tmp
) || (tmp
== '_'))
293 if (isalnum(tmp
) || (tmp
== '_')) {
302 static int parse_add_config(char *buf
)
311 retval
= parse_id(&c
, cID
);
315 ID
= CHAR_TO_ID(cID
);
319 return dgrp_add_id(ID
);
322 static int parse_del_config(char *buf
)
326 struct nd_struct
*nd
;
333 retval
= parse_id(&c
, cID
);
337 ID
= CHAR_TO_ID(cID
);
341 retval
= kstrtol(c
, 10, &major
);
345 nd
= nd_struct_get(major
);
349 if ((nd
->nd_major
!= major
) || (nd
->nd_ID
!= ID
))
352 return dgrp_remove_nd(nd
);
355 static int parse_chg_config(char *buf
)
361 * The passed character buffer represents a single configuration request.
362 * If the first character is a "+", it is parsed as a request to add a
364 * If the first character is a "-", it is parsed as a request to delete a
366 * If the first character is a "*", it is parsed as a request to change a
368 * Any other character (including whitespace) causes the record to be
371 static int parse_write_config(char *buf
)
377 retval
= parse_add_config(buf
);
380 retval
= parse_del_config(buf
);
383 retval
= parse_chg_config(buf
);
392 static int dgrp_info_proc_show(struct seq_file
*m
, void *v
)
394 seq_printf(m
, "version: %s\n", DIGI_VERSION
);
395 seq_puts(m
, "register_with_sysfs: 1\n");
396 seq_printf(m
, "pollrate: 0x%08x\t(%d)\n",
397 dgrp_poll_tick
, dgrp_poll_tick
);
402 static int dgrp_info_proc_open(struct inode
*inode
, struct file
*file
)
404 return single_open(file
, dgrp_info_proc_show
, NULL
);
408 static void *dgrp_nodeinfo_start(struct seq_file
*m
, loff_t
*pos
)
410 return seq_list_start_head(&nd_struct_list
, *pos
);
413 static void *dgrp_nodeinfo_next(struct seq_file
*p
, void *v
, loff_t
*pos
)
415 return seq_list_next(v
, &nd_struct_list
, pos
);
418 static void dgrp_nodeinfo_stop(struct seq_file
*m
, void *v
)
422 static int dgrp_nodeinfo_show(struct seq_file
*m
, void *v
)
424 struct nd_struct
*nd
;
429 if (v
== &nd_struct_list
) {
430 seq_puts(m
, "#-----------------------------------------------------------------------------\n");
431 seq_puts(m
, "# HW HW SW\n");
432 seq_puts(m
, "# ID State Version ID Version Description\n");
436 nd
= list_entry(v
, struct nd_struct
, list
);
438 ID_TO_CHAR(nd
->nd_ID
, tmp_id
);
440 if (nd
->nd_state
== NS_READY
) {
441 sprintf(hwver
, "%d.%d", (nd
->nd_hw_ver
>> 8) & 0xff,
442 nd
->nd_hw_ver
& 0xff);
443 sprintf(swver
, "%d.%d", (nd
->nd_sw_ver
>> 8) & 0xff,
444 nd
->nd_sw_ver
& 0xff);
445 seq_printf(m
, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
447 ND_STATE_STR(nd
->nd_state
),
454 seq_printf(m
, " %-2.2s %-10.10s\n",
456 ND_STATE_STR(nd
->nd_state
));
463 static const struct seq_operations nodeinfo_ops
= {
464 .start
= dgrp_nodeinfo_start
,
465 .next
= dgrp_nodeinfo_next
,
466 .stop
= dgrp_nodeinfo_stop
,
467 .show
= dgrp_nodeinfo_show
,
470 static int dgrp_nodeinfo_proc_open(struct inode
*inode
, struct file
*file
)
472 return seq_open(file
, &nodeinfo_ops
);
476 * dgrp_add_id() -- creates new nd struct and adds it to list
477 * @id: id of device to add
479 static int dgrp_add_id(long id
)
481 struct nd_struct
*nd
;
485 nd
= kzalloc(sizeof(struct nd_struct
), GFP_KERNEL
);
492 spin_lock_init(&nd
->nd_lock
);
494 init_waitqueue_head(&nd
->nd_tx_waitq
);
495 init_waitqueue_head(&nd
->nd_mon_wqueue
);
496 init_waitqueue_head(&nd
->nd_dpa_wqueue
);
497 for (i
= 0; i
< SEQ_MAX
; i
++)
498 init_waitqueue_head(&nd
->nd_seq_wque
[i
]);
500 /* setup the structures to get the major number */
501 ret
= dgrp_tty_init(nd
);
505 nd
->nd_major
= nd
->nd_serial_ttdriver
->major
;
507 ret
= nd_struct_add(nd
);
511 register_dgrp_device(nd
, net_entry_pointer
, dgrp_register_net_hook
);
512 register_dgrp_device(nd
, mon_entry_pointer
, dgrp_register_mon_hook
);
513 register_dgrp_device(nd
, dpa_entry_pointer
, dgrp_register_dpa_hook
);
514 register_dgrp_device(nd
, ports_entry_pointer
,
515 dgrp_register_ports_hook
);
519 /* FIXME this guy should free the tty driver stored in nd and destroy
520 * all channel ports */
527 static int dgrp_remove_nd(struct nd_struct
*nd
)
531 /* Check to see if the selected structure is in use */
532 if (nd
->nd_tty_ref_cnt
)
536 unregister_dgrp_device(nd
->nd_net_de
);
537 dgrp_remove_node_class_sysfs_files(nd
);
540 unregister_dgrp_device(nd
->nd_mon_de
);
542 unregister_dgrp_device(nd
->nd_ports_de
);
544 unregister_dgrp_device(nd
->nd_dpa_de
);
548 ret
= nd_struct_del(nd
);
556 static void register_dgrp_device(struct nd_struct
*node
,
557 struct proc_dir_entry
*root
,
558 void (*register_hook
)(struct proc_dir_entry
*de
))
561 struct proc_dir_entry
*de
;
563 ID_TO_CHAR(node
->nd_ID
, buf
);
565 de
= create_proc_entry(buf
, 0600 | S_IFREG
, root
);
569 de
->data
= (void *) node
;
576 static void unregister_dgrp_device(struct proc_dir_entry
*de
)
581 /* Don't unregister proc entries that are still being used.. */
582 if ((atomic_read(&de
->count
)) != 1) {
583 pr_alert("%s - proc entry %s in use. Not removing.\n",
588 remove_proc_entry(de
->name
, de
->parent
);