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>
43 #include "dgrp_common.h"
45 static struct dgrp_proc_entry dgrp_table[];
46 static struct proc_dir_entry *dgrp_proc_dir_entry;
48 static int dgrp_add_id(long id);
49 static int dgrp_remove_nd(struct nd_struct *nd);
50 static void unregister_dgrp_device(struct proc_dir_entry *de);
51 static void register_dgrp_device(struct nd_struct *node,
52 struct proc_dir_entry *root,
53 void (*register_hook)(struct proc_dir_entry *de));
55 /* File operation declarations */
56 static int dgrp_gen_proc_open(struct inode *, struct file *);
57 static int dgrp_gen_proc_close(struct inode *, struct file *);
58 static int parse_write_config(char *);
61 static const struct file_operations dgrp_proc_file_ops = {
63 .open = dgrp_gen_proc_open,
64 .release = dgrp_gen_proc_close,
67 static struct inode_operations proc_inode_ops = {
68 .permission = dgrp_inode_permission
72 static void register_proc_table(struct dgrp_proc_entry *,
73 struct proc_dir_entry *);
74 static void unregister_proc_table(struct dgrp_proc_entry *,
75 struct proc_dir_entry *);
77 static struct dgrp_proc_entry dgrp_net_table[];
78 static struct dgrp_proc_entry dgrp_mon_table[];
79 static struct dgrp_proc_entry dgrp_ports_table[];
80 static struct dgrp_proc_entry dgrp_dpa_table[];
82 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
83 size_t count, loff_t *pos);
85 static int nodeinfo_proc_open(struct inode *inode, struct file *file);
86 static int info_proc_open(struct inode *inode, struct file *file);
87 static int config_proc_open(struct inode *inode, struct file *file);
89 static struct file_operations config_proc_file_ops = {
91 .open = config_proc_open,
94 .release = seq_release,
95 .write = config_proc_write
98 static struct file_operations info_proc_file_ops = {
100 .open = info_proc_open,
103 .release = seq_release,
106 static struct file_operations nodeinfo_proc_file_ops = {
107 .owner = THIS_MODULE,
108 .open = nodeinfo_proc_open,
111 .release = seq_release,
114 static struct dgrp_proc_entry dgrp_table[] = {
119 .proc_file_ops = &config_proc_file_ops,
125 .proc_file_ops = &info_proc_file_ops,
131 .proc_file_ops = &nodeinfo_proc_file_ops,
137 .child = dgrp_net_table
143 .child = dgrp_mon_table
149 .child = dgrp_ports_table
155 .child = dgrp_dpa_table
159 static struct proc_dir_entry *net_entry_pointer;
160 static struct proc_dir_entry *mon_entry_pointer;
161 static struct proc_dir_entry *dpa_entry_pointer;
162 static struct proc_dir_entry *ports_entry_pointer;
164 static struct dgrp_proc_entry dgrp_net_table[] = {
168 static struct dgrp_proc_entry dgrp_mon_table[] = {
172 static struct dgrp_proc_entry dgrp_ports_table[] = {
176 static struct dgrp_proc_entry dgrp_dpa_table[] = {
180 void dgrp_unregister_proc(void)
182 unregister_proc_table(dgrp_table, dgrp_proc_dir_entry);
183 net_entry_pointer = NULL;
184 mon_entry_pointer = NULL;
185 dpa_entry_pointer = NULL;
186 ports_entry_pointer = NULL;
188 if (dgrp_proc_dir_entry) {
189 remove_proc_entry(dgrp_proc_dir_entry->name,
190 dgrp_proc_dir_entry->parent);
191 dgrp_proc_dir_entry = NULL;
196 void dgrp_register_proc(void)
199 * Register /proc/dgrp
201 dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL,
202 &dgrp_proc_file_ops);
203 register_proc_table(dgrp_table, dgrp_proc_dir_entry);
209 static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de)
211 if (!de || !de->low_ino)
213 if (de->namelen != len)
215 return !memcmp(name, de->name, len);
220 * Scan the entries in table and add them all to /proc at the position
221 * referred to by "root"
223 static void register_proc_table(struct dgrp_proc_entry *table,
224 struct proc_dir_entry *root)
226 struct proc_dir_entry *de;
230 for (; table->id; table++) {
231 /* Can't do anything without a proc name. */
235 /* Maybe we can't do anything with it... */
236 if (!table->proc_file_ops &&
238 pr_warn("dgrp: Can't register %s\n",
243 len = strlen(table->name);
251 for (de = root->subdir; de; de = de->next) {
252 if (dgrp_proc_match(len, table->name, de))
255 /* If the subdir exists already, de is non-NULL */
259 de = create_proc_entry(table->name, mode, root);
262 de->data = (void *) table;
264 de->proc_iops = &proc_inode_ops;
265 if (table->proc_file_ops)
266 de->proc_fops = table->proc_file_ops;
268 de->proc_fops = &dgrp_proc_file_ops;
272 if (de->mode & S_IFDIR)
273 register_proc_table(table->child, de);
275 if (table->id == DGRP_NETDIR)
276 net_entry_pointer = de;
278 if (table->id == DGRP_MONDIR)
279 mon_entry_pointer = de;
281 if (table->id == DGRP_DPADIR)
282 dpa_entry_pointer = de;
284 if (table->id == DGRP_PORTSDIR)
285 ports_entry_pointer = de;
290 * Unregister a /proc sysctl table and any subdirectories.
292 static void unregister_proc_table(struct dgrp_proc_entry *table,
293 struct proc_dir_entry *root)
295 struct proc_dir_entry *de;
296 struct nd_struct *tmp;
298 list_for_each_entry(tmp, &nd_struct_list, list) {
299 if ((table == dgrp_net_table) && (tmp->nd_net_de)) {
300 unregister_dgrp_device(tmp->nd_net_de);
301 dgrp_remove_node_class_sysfs_files(tmp);
304 if ((table == dgrp_mon_table) && (tmp->nd_mon_de))
305 unregister_dgrp_device(tmp->nd_mon_de);
307 if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de))
308 unregister_dgrp_device(tmp->nd_dpa_de);
310 if ((table == dgrp_ports_table) && (tmp->nd_ports_de))
311 unregister_dgrp_device(tmp->nd_ports_de);
314 for (; table->id; table++) {
319 if (de->mode & S_IFDIR) {
321 pr_alert("dgrp: malformed sysctl tree on free\n");
324 unregister_proc_table(table->child, de);
326 /* Don't unregister directories which still have entries */
331 /* Don't unregister proc entries that are still being used.. */
332 if ((atomic_read(&de->count)) != 1) {
333 pr_alert("proc entry %s in use, not removing\n",
338 remove_proc_entry(de->name, de->parent);
343 static int dgrp_gen_proc_open(struct inode *inode, struct file *file)
345 struct proc_dir_entry *de;
346 struct dgrp_proc_entry *entry;
349 de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
350 if (!de || !de->data) {
355 entry = (struct dgrp_proc_entry *) de->data;
361 down(&entry->excl_sem);
368 up(&entry->excl_sem);
374 static int dgrp_gen_proc_close(struct inode *inode, struct file *file)
376 struct proc_dir_entry *de;
377 struct dgrp_proc_entry *entry;
379 de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode);
380 if (!de || !de->data)
383 entry = (struct dgrp_proc_entry *) de->data;
387 down(&entry->excl_sem);
392 up(&entry->excl_sem);
398 static void *config_proc_start(struct seq_file *m, loff_t *pos)
400 return seq_list_start_head(&nd_struct_list, *pos);
403 static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos)
405 return seq_list_next(v, &nd_struct_list, pos);
408 static void config_proc_stop(struct seq_file *m, void *v)
412 static int config_proc_show(struct seq_file *m, void *v)
414 struct nd_struct *nd;
417 if (v == &nd_struct_list) {
418 seq_puts(m, "#-----------------------------------------------------------------------------\n");
419 seq_puts(m, "# Avail\n");
420 seq_puts(m, "# ID Major State Ports\n");
424 nd = list_entry(v, struct nd_struct, list);
426 ID_TO_CHAR(nd->nd_ID, tmp_id);
428 seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n",
431 ND_STATE_STR(nd->nd_state),
437 static const struct seq_operations proc_config_ops = {
438 .start = config_proc_start,
439 .next = config_proc_next,
440 .stop = config_proc_stop,
441 .show = config_proc_show
444 static int config_proc_open(struct inode *inode, struct file *file)
446 return seq_open(file, &proc_config_ops);
451 * When writing configuration information, each "record" (i.e. each
452 * write) is treated as an independent request. See the "parse"
453 * description for more details.
455 static ssize_t config_proc_write(struct file *file, const char __user *buffer,
456 size_t count, loff_t *pos)
465 inbuf = sp = vzalloc(count + 1);
469 if (copy_from_user(inbuf, buffer, count)) {
478 line = strpbrk(sp, ldelim);
481 retval = parse_write_config(sp);
486 line = strpbrk(sp, ldelim);
496 * ------------------------------------------------------------------------
498 * The following are the functions to parse input
500 * ------------------------------------------------------------------------
502 static inline char *skip_past_ws(const char *str)
504 while ((*str) && !isspace(*str))
507 return skip_spaces(str);
510 static int parse_id(char **c, char *cID)
514 if (isalnum(tmp) || (tmp == '_'))
521 if (isalnum(tmp) || (tmp == '_')) {
530 static int parse_add_config(char *buf)
539 retval = parse_id(&c, cID);
543 ID = CHAR_TO_ID(cID);
547 return dgrp_add_id(ID);
550 static int parse_del_config(char *buf)
554 struct nd_struct *nd;
561 retval = parse_id(&c, cID);
565 ID = CHAR_TO_ID(cID);
569 retval = kstrtol(c, 10, &major);
573 nd = nd_struct_get(major);
577 if ((nd->nd_major != major) || (nd->nd_ID != ID))
580 return dgrp_remove_nd(nd);
583 static int parse_chg_config(char *buf)
589 * The passed character buffer represents a single configuration request.
590 * If the first character is a "+", it is parsed as a request to add a
592 * If the first character is a "-", it is parsed as a request to delete a
594 * If the first character is a "*", it is parsed as a request to change a
596 * Any other character (including whitespace) causes the record to be
599 static int parse_write_config(char *buf)
605 retval = parse_add_config(buf);
608 retval = parse_del_config(buf);
611 retval = parse_chg_config(buf);
620 static int info_proc_show(struct seq_file *m, void *v)
622 seq_printf(m, "version: %s\n", DIGI_VERSION);
623 seq_puts(m, "register_with_sysfs: 1\n");
624 seq_printf(m, "rawreadok: 0x%08x\t(%d)\n",
625 dgrp_rawreadok, dgrp_rawreadok);
626 seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
627 dgrp_poll_tick, dgrp_poll_tick);
632 static int info_proc_open(struct inode *inode, struct file *file)
634 return single_open(file, info_proc_show, NULL);
638 static void *nodeinfo_start(struct seq_file *m, loff_t *pos)
640 return seq_list_start_head(&nd_struct_list, *pos);
643 static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
645 return seq_list_next(v, &nd_struct_list, pos);
648 static void nodeinfo_stop(struct seq_file *m, void *v)
652 static int nodeinfo_show(struct seq_file *m, void *v)
654 struct nd_struct *nd;
659 if (v == &nd_struct_list) {
660 seq_puts(m, "#-----------------------------------------------------------------------------\n");
661 seq_puts(m, "# HW HW SW\n");
662 seq_puts(m, "# ID State Version ID Version Description\n");
666 nd = list_entry(v, struct nd_struct, list);
668 ID_TO_CHAR(nd->nd_ID, tmp_id);
670 if (nd->nd_state == NS_READY) {
671 sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
672 nd->nd_hw_ver & 0xff);
673 sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
674 nd->nd_sw_ver & 0xff);
675 seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
677 ND_STATE_STR(nd->nd_state),
684 seq_printf(m, " %-2.2s %-10.10s\n",
686 ND_STATE_STR(nd->nd_state));
693 static const struct seq_operations nodeinfo_ops = {
694 .start = nodeinfo_start,
695 .next = nodeinfo_next,
696 .stop = nodeinfo_stop,
697 .show = nodeinfo_show
700 static int nodeinfo_proc_open(struct inode *inode, struct file *file)
702 return seq_open(file, &nodeinfo_ops);
706 * dgrp_add_id() -- creates new nd struct and adds it to list
707 * @id: id of device to add
709 static int dgrp_add_id(long id)
711 struct nd_struct *nd;
715 nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
722 spin_lock_init(&nd->nd_lock);
724 init_waitqueue_head(&nd->nd_tx_waitq);
725 init_waitqueue_head(&nd->nd_mon_wqueue);
726 init_waitqueue_head(&nd->nd_dpa_wqueue);
727 for (i = 0; i < SEQ_MAX; i++)
728 init_waitqueue_head(&nd->nd_seq_wque[i]);
730 /* setup the structures to get the major number */
731 ret = dgrp_tty_init(nd);
735 nd->nd_major = nd->nd_serial_ttdriver->major;
737 ret = nd_struct_add(nd);
741 register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook);
742 register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook);
743 register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook);
744 register_dgrp_device(nd, ports_entry_pointer,
745 dgrp_register_ports_hook);
755 static int dgrp_remove_nd(struct nd_struct *nd)
759 /* Check to see if the selected structure is in use */
760 if (nd->nd_tty_ref_cnt)
764 unregister_dgrp_device(nd->nd_net_de);
765 dgrp_remove_node_class_sysfs_files(nd);
769 unregister_dgrp_device(nd->nd_mon_de);
772 unregister_dgrp_device(nd->nd_ports_de);
775 unregister_dgrp_device(nd->nd_dpa_de);
779 ret = nd_struct_del(nd);
787 static void register_dgrp_device(struct nd_struct *node,
788 struct proc_dir_entry *root,
789 void (*register_hook)(struct proc_dir_entry *de))
792 struct proc_dir_entry *de;
794 ID_TO_CHAR(node->nd_ID, buf);
796 de = create_proc_entry(buf, 0600 | S_IFREG, root);
800 de->data = (void *) node;
807 static void unregister_dgrp_device(struct proc_dir_entry *de)
812 /* Don't unregister proc entries that are still being used.. */
813 if ((atomic_read(&de->count)) != 1) {
814 pr_alert("%s - proc entry %s in use. Not removing.\n",
819 remove_proc_entry(de->name, de->parent);