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/slab.h>
41 #include <linux/ctype.h>
42 #include <linux/seq_file.h>
43 #include <linux/uaccess.h>
44 #include <linux/vmalloc.h>
46 #include "dgrp_common.h"
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 struct proc_dir_entry *add_proc_file(struct nd_struct *node,
53 struct proc_dir_entry *root,
54 const struct file_operations *fops);
56 /* File operation declarations */
57 static int parse_write_config(char *);
59 static ssize_t dgrp_config_proc_write(struct file *file,
60 const char __user *buffer,
61 size_t count, loff_t *pos);
63 static int dgrp_nodeinfo_proc_open(struct inode *inode, struct file *file);
64 static int dgrp_info_proc_open(struct inode *inode, struct file *file);
65 static int dgrp_config_proc_open(struct inode *inode, struct file *file);
67 static const struct file_operations config_proc_file_ops = {
69 .open = dgrp_config_proc_open,
72 .release = seq_release,
73 .write = dgrp_config_proc_write,
76 static const struct file_operations info_proc_file_ops = {
78 .open = dgrp_info_proc_open,
81 .release = single_release,
84 static const struct file_operations nodeinfo_proc_file_ops = {
86 .open = dgrp_nodeinfo_proc_open,
89 .release = seq_release,
92 static struct proc_dir_entry *net_entry_pointer;
93 static struct proc_dir_entry *mon_entry_pointer;
94 static struct proc_dir_entry *dpa_entry_pointer;
95 static struct proc_dir_entry *ports_entry_pointer;
97 static void remove_files(struct nd_struct *nd)
100 ID_TO_CHAR(nd->nd_ID, buf);
101 dgrp_remove_node_class_sysfs_files(nd);
103 remove_proc_entry(buf, net_entry_pointer);
105 remove_proc_entry(buf, mon_entry_pointer);
107 remove_proc_entry(buf, dpa_entry_pointer);
109 remove_proc_entry(buf, ports_entry_pointer);
112 void dgrp_unregister_proc(void)
114 net_entry_pointer = NULL;
115 mon_entry_pointer = NULL;
116 dpa_entry_pointer = NULL;
117 ports_entry_pointer = NULL;
119 if (dgrp_proc_dir_entry) {
120 struct nd_struct *nd;
121 list_for_each_entry(nd, &nd_struct_list, list)
123 remove_proc_entry("dgrp/config", NULL);
124 remove_proc_entry("dgrp/info", NULL);
125 remove_proc_entry("dgrp/nodeinfo", NULL);
126 remove_proc_entry("dgrp/net", NULL);
127 remove_proc_entry("dgrp/mon", NULL);
128 remove_proc_entry("dgrp/dpa", NULL);
129 remove_proc_entry("dgrp/ports", NULL);
130 remove_proc_entry("dgrp", NULL);
131 dgrp_proc_dir_entry = NULL;
135 void dgrp_register_proc(void)
138 * Register /proc/dgrp
140 dgrp_proc_dir_entry = proc_mkdir("dgrp", NULL);
141 if (!dgrp_proc_dir_entry)
143 proc_create("dgrp/config", 0644, NULL, &config_proc_file_ops);
144 proc_create("dgrp/info", 0644, NULL, &info_proc_file_ops);
145 proc_create("dgrp/nodeinfo", 0644, NULL, &nodeinfo_proc_file_ops);
146 net_entry_pointer = proc_mkdir_mode("dgrp/net", 0500, NULL);
147 mon_entry_pointer = proc_mkdir_mode("dgrp/mon", 0500, NULL);
148 dpa_entry_pointer = proc_mkdir_mode("dgrp/dpa", 0500, NULL);
149 ports_entry_pointer = proc_mkdir_mode("dgrp/ports", 0500, NULL);
152 static void *dgrp_config_proc_start(struct seq_file *m, loff_t *pos)
154 return seq_list_start_head(&nd_struct_list, *pos);
157 static void *dgrp_config_proc_next(struct seq_file *p, void *v, loff_t *pos)
159 return seq_list_next(v, &nd_struct_list, pos);
162 static void dgrp_config_proc_stop(struct seq_file *m, void *v)
166 static int dgrp_config_proc_show(struct seq_file *m, void *v)
168 struct nd_struct *nd;
171 if (v == &nd_struct_list) {
172 seq_puts(m, "#-----------------------------------------------------------------------------\n");
173 seq_puts(m, "# Avail\n");
174 seq_puts(m, "# ID Major State Ports\n");
178 nd = list_entry(v, struct nd_struct, list);
180 ID_TO_CHAR(nd->nd_ID, tmp_id);
182 seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n",
185 ND_STATE_STR(nd->nd_state),
191 static const struct seq_operations proc_config_ops = {
192 .start = dgrp_config_proc_start,
193 .next = dgrp_config_proc_next,
194 .stop = dgrp_config_proc_stop,
195 .show = dgrp_config_proc_show,
198 static int dgrp_config_proc_open(struct inode *inode, struct file *file)
200 return seq_open(file, &proc_config_ops);
205 * When writing configuration information, each "record" (i.e. each
206 * write) is treated as an independent request. See the "parse"
207 * description for more details.
209 static ssize_t dgrp_config_proc_write(struct file *file,
210 const char __user *buffer,
211 size_t count, loff_t *pos)
220 inbuf = sp = vzalloc(count + 1);
224 if (copy_from_user(inbuf, buffer, count)) {
233 line = strpbrk(sp, ldelim);
236 retval = parse_write_config(sp);
241 line = strpbrk(sp, ldelim);
251 * ------------------------------------------------------------------------
253 * The following are the functions to parse input
255 * ------------------------------------------------------------------------
257 static inline char *skip_past_ws(const char *str)
259 while ((*str) && !isspace(*str))
262 return skip_spaces(str);
265 static int parse_id(char **c, char *cID)
269 if (isalnum(tmp) || (tmp == '_'))
276 if (isalnum(tmp) || (tmp == '_')) {
285 static int parse_add_config(char *buf)
294 retval = parse_id(&c, cID);
298 ID = CHAR_TO_ID(cID);
302 return dgrp_add_id(ID);
305 static int parse_del_config(char *buf)
309 struct nd_struct *nd;
316 retval = parse_id(&c, cID);
320 ID = CHAR_TO_ID(cID);
324 retval = kstrtol(c, 10, &major);
328 nd = nd_struct_get(major);
332 if ((nd->nd_major != major) || (nd->nd_ID != ID))
335 return dgrp_remove_nd(nd);
338 static int parse_chg_config(char *buf)
344 * The passed character buffer represents a single configuration request.
345 * If the first character is a "+", it is parsed as a request to add a
347 * If the first character is a "-", it is parsed as a request to delete a
349 * If the first character is a "*", it is parsed as a request to change a
351 * Any other character (including whitespace) causes the record to be
354 static int parse_write_config(char *buf)
360 retval = parse_add_config(buf);
363 retval = parse_del_config(buf);
366 retval = parse_chg_config(buf);
375 static int dgrp_info_proc_show(struct seq_file *m, void *v)
377 seq_printf(m, "version: %s\n", DIGI_VERSION);
378 seq_puts(m, "register_with_sysfs: 1\n");
379 seq_printf(m, "pollrate: 0x%08x\t(%d)\n",
380 dgrp_poll_tick, dgrp_poll_tick);
385 static int dgrp_info_proc_open(struct inode *inode, struct file *file)
387 return single_open(file, dgrp_info_proc_show, NULL);
391 static void *dgrp_nodeinfo_start(struct seq_file *m, loff_t *pos)
393 return seq_list_start_head(&nd_struct_list, *pos);
396 static void *dgrp_nodeinfo_next(struct seq_file *p, void *v, loff_t *pos)
398 return seq_list_next(v, &nd_struct_list, pos);
401 static void dgrp_nodeinfo_stop(struct seq_file *m, void *v)
405 static int dgrp_nodeinfo_show(struct seq_file *m, void *v)
407 struct nd_struct *nd;
412 if (v == &nd_struct_list) {
413 seq_puts(m, "#-----------------------------------------------------------------------------\n");
414 seq_puts(m, "# HW HW SW\n");
415 seq_puts(m, "# ID State Version ID Version Description\n");
419 nd = list_entry(v, struct nd_struct, list);
421 ID_TO_CHAR(nd->nd_ID, tmp_id);
423 if (nd->nd_state == NS_READY) {
424 sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff,
425 nd->nd_hw_ver & 0xff);
426 sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff,
427 nd->nd_sw_ver & 0xff);
428 seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n",
430 ND_STATE_STR(nd->nd_state),
437 seq_printf(m, " %-2.2s %-10.10s\n",
439 ND_STATE_STR(nd->nd_state));
446 static const struct seq_operations nodeinfo_ops = {
447 .start = dgrp_nodeinfo_start,
448 .next = dgrp_nodeinfo_next,
449 .stop = dgrp_nodeinfo_stop,
450 .show = dgrp_nodeinfo_show,
453 static int dgrp_nodeinfo_proc_open(struct inode *inode, struct file *file)
455 return seq_open(file, &nodeinfo_ops);
459 * dgrp_add_id() -- creates new nd struct and adds it to list
460 * @id: id of device to add
462 static int dgrp_add_id(long id)
464 struct nd_struct *nd;
468 nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL);
475 spin_lock_init(&nd->nd_lock);
477 init_waitqueue_head(&nd->nd_tx_waitq);
478 init_waitqueue_head(&nd->nd_mon_wqueue);
479 init_waitqueue_head(&nd->nd_dpa_wqueue);
480 sema_init(&nd->nd_mon_semaphore, 1);
481 sema_init(&nd->nd_net_semaphore, 1);
482 spin_lock_init(&nd->nd_dpa_lock);
483 nd->nd_state = NS_CLOSED;
484 for (i = 0; i < SEQ_MAX; i++)
485 init_waitqueue_head(&nd->nd_seq_wque[i]);
487 /* setup the structures to get the major number */
488 ret = dgrp_tty_init(nd);
492 nd->nd_major = nd->nd_serial_ttdriver->major;
494 ret = nd_struct_add(nd);
498 dgrp_create_node_class_sysfs_files(nd);
499 nd->nd_net_de = add_proc_file(nd, net_entry_pointer, &dgrp_net_ops);
500 nd->nd_mon_de = add_proc_file(nd, mon_entry_pointer, &dgrp_mon_ops);
501 nd->nd_dpa_de = add_proc_file(nd, dpa_entry_pointer, &dgrp_dpa_ops);
502 nd->nd_ports_de = add_proc_file(nd, ports_entry_pointer,
506 /* FIXME this guy should free the tty driver stored in nd and destroy
507 * all channel ports */
514 static int dgrp_remove_nd(struct nd_struct *nd)
518 /* Check to see if the selected structure is in use */
519 if (nd->nd_tty_ref_cnt)
526 ret = nd_struct_del(nd);
534 static struct proc_dir_entry *add_proc_file(struct nd_struct *node,
535 struct proc_dir_entry *root,
536 const struct file_operations *fops)
539 ID_TO_CHAR(node->nd_ID, buf);
540 return proc_create_data(buf, 0600, root, fops, node);