diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 15:26:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 15:26:52 -0400 |
commit | 3498d13b8090c0b0ef911409fbc503a7c4cca6ef (patch) | |
tree | 254ca00276e863d9fba25707690c66b2a04c49e9 /drivers/staging | |
parent | def7cb8cd4e3258db88050eaaca5438bcc3dafca (diff) | |
parent | 0c57dfcc6c1d037243c2f8fbf62eab3633326ec0 (diff) |
Merge tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull TTY changes from Greg Kroah-Hartman:
"As we skipped the merge window for 3.6-rc1 for the tty tree,
everything is now settled down and working properly, so we are ready
for 3.7-rc1. Here's the patchset, it's big, but the large changes are
removing a firmware file and adding a staging tty driver (it depended
on the tty core changes, so it's going through this tree instead of
the staging tree.)
All of these patches have been in the linux-next tree for a while.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
Fix up more-or-less trivial conflicts in
- drivers/char/pcmcia/synclink_cs.c:
tty NULL dereference fix vs tty_port_cts_enabled() helper function
- drivers/staging/{Kconfig,Makefile}:
add-add conflict (dgrp driver added close to other staging drivers)
- drivers/staging/ipack/devices/ipoctal.c:
"split ipoctal_channel from iopctal" vs "TTY: use tty_port_register_device"
* tag 'tty-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (235 commits)
tty/serial: Add kgdb_nmi driver
tty/serial/amba-pl011: Quiesce interrupts in poll_get_char
tty/serial/amba-pl011: Implement poll_init callback
tty/serial/core: Introduce poll_init callback
kdb: Turn KGDB_KDB=n stubs into static inlines
kdb: Implement disable_nmi command
kernel/debug: Mask KGDB NMI upon entry
serial: pl011: handle corruption at high clock speeds
serial: sccnxp: Make 'default' choice in switch last
serial: sccnxp: Remove mask termios caps for SW flow control
serial: sccnxp: Report actual baudrate back to core
serial: samsung: Add poll_get_char & poll_put_char
Powerpc 8xx CPM_UART setting MAXIDL register proportionaly to baud rate
Powerpc 8xx CPM_UART maxidl should not depend on fifo size
Powerpc 8xx CPM_UART too many interrupts
Powerpc 8xx CPM_UART desynchronisation
serial: set correct baud_base for EXSYS EX-41092 Dual 16950
serial: omap: fix the reciever line error case
8250: blacklist Winbond CIR port
8250_pnp: do pnp probe before legacy probe
...
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/dgrp/Kconfig | 9 | ||||
-rw-r--r-- | drivers/staging/dgrp/Makefile | 12 | ||||
-rw-r--r-- | drivers/staging/dgrp/README | 2 | ||||
-rw-r--r-- | drivers/staging/dgrp/TODO | 13 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_common.c | 200 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_common.h | 208 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_dpa_ops.c | 556 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_driver.c | 110 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_mon_ops.c | 346 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_net_ops.c | 3737 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_ports_ops.c | 170 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_specproc.c | 822 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_sysfs.c | 555 | ||||
-rw-r--r-- | drivers/staging/dgrp/dgrp_tty.c | 3331 | ||||
-rw-r--r-- | drivers/staging/dgrp/digirp.h | 129 | ||||
-rw-r--r-- | drivers/staging/dgrp/drp.h | 693 | ||||
-rw-r--r-- | drivers/staging/ipack/devices/ipoctal.c | 14 | ||||
-rw-r--r-- | drivers/staging/serqt_usb2/serqt_usb2.c | 18 | ||||
-rw-r--r-- | drivers/staging/speakup/serialio.h | 3 |
21 files changed, 10912 insertions, 19 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 0f51a158ef70..d805eef11915 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
@@ -142,4 +142,6 @@ source "drivers/staging/ced1401/Kconfig" | |||
142 | 142 | ||
143 | source "drivers/staging/imx-drm/Kconfig" | 143 | source "drivers/staging/imx-drm/Kconfig" |
144 | 144 | ||
145 | source "drivers/staging/dgrp/Kconfig" | ||
146 | |||
145 | endif # STAGING | 147 | endif # STAGING |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index f4b2bc41f1d1..76e2ebd596ff 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
@@ -63,3 +63,4 @@ obj-$(CONFIG_ZCACHE2) += ramster/ | |||
63 | obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ | 63 | obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ |
64 | obj-$(CONFIG_CED1401) += ced1401/ | 64 | obj-$(CONFIG_CED1401) += ced1401/ |
65 | obj-$(CONFIG_DRM_IMX) += imx-drm/ | 65 | obj-$(CONFIG_DRM_IMX) += imx-drm/ |
66 | obj-$(CONFIG_DGRP) += dgrp/ | ||
diff --git a/drivers/staging/dgrp/Kconfig b/drivers/staging/dgrp/Kconfig new file mode 100644 index 000000000000..39f4bb65ec83 --- /dev/null +++ b/drivers/staging/dgrp/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config DGRP | ||
2 | tristate "Digi Realport driver" | ||
3 | default n | ||
4 | depends on SYSFS | ||
5 | ---help--- | ||
6 | Support for Digi Realport devices. These devices allow you to | ||
7 | access remote serial ports as if they are local tty devices. This | ||
8 | will build the kernel driver, you will still need the userspace | ||
9 | component to make your Realport device work. | ||
diff --git a/drivers/staging/dgrp/Makefile b/drivers/staging/dgrp/Makefile new file mode 100644 index 000000000000..d9c3b88d7162 --- /dev/null +++ b/drivers/staging/dgrp/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | obj-$(CONFIG_DGRP) += dgrp.o | ||
2 | |||
3 | dgrp-y := \ | ||
4 | dgrp_common.o \ | ||
5 | dgrp_dpa_ops.o \ | ||
6 | dgrp_driver.o \ | ||
7 | dgrp_mon_ops.o \ | ||
8 | dgrp_net_ops.o \ | ||
9 | dgrp_ports_ops.o \ | ||
10 | dgrp_specproc.o \ | ||
11 | dgrp_tty.o \ | ||
12 | dgrp_sysfs.o | ||
diff --git a/drivers/staging/dgrp/README b/drivers/staging/dgrp/README new file mode 100644 index 000000000000..1d8aaee270e8 --- /dev/null +++ b/drivers/staging/dgrp/README | |||
@@ -0,0 +1,2 @@ | |||
1 | The user space code to work with this driver is located at | ||
2 | https://github.com/wfp5p/dgrp-utils | ||
diff --git a/drivers/staging/dgrp/TODO b/drivers/staging/dgrp/TODO new file mode 100644 index 000000000000..3ef2611bc6d7 --- /dev/null +++ b/drivers/staging/dgrp/TODO | |||
@@ -0,0 +1,13 @@ | |||
1 | - Use configfs for config stuff. This will require changes to the | ||
2 | user space code. | ||
3 | |||
4 | - dgrp_send() and dgrp_receive() could use some refactoring | ||
5 | |||
6 | - Don't automatically create CHAN_MAX (64) channel array entries for | ||
7 | every device as many devices are going to have much less than 64 | ||
8 | channels. | ||
9 | |||
10 | - The locking needs to be checked. It seems haphazardly done in most | ||
11 | places. | ||
12 | |||
13 | - Check Kconfig dependencies | ||
diff --git a/drivers/staging/dgrp/dgrp_common.c b/drivers/staging/dgrp/dgrp_common.c new file mode 100644 index 000000000000..fce74e7fb834 --- /dev/null +++ b/drivers/staging/dgrp/dgrp_common.c | |||
@@ -0,0 +1,200 @@ | |||
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_common.c | ||
23 | * | ||
24 | * Description: | ||
25 | * | ||
26 | * Definitions of global variables and functions which are either | ||
27 | * shared by the tty, mon, and net drivers; or which cross them | ||
28 | * functionally (like the poller). | ||
29 | * | ||
30 | * Author: | ||
31 | * | ||
32 | * James A. Puzzo | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/errno.h> | ||
37 | #include <linux/tty.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <linux/cred.h> | ||
40 | |||
41 | #include "dgrp_common.h" | ||
42 | |||
43 | /** | ||
44 | * dgrp_carrier -- check for carrier change state and act | ||
45 | * @ch: struct ch_struct * | ||
46 | */ | ||
47 | void dgrp_carrier(struct ch_struct *ch) | ||
48 | { | ||
49 | struct nd_struct *nd; | ||
50 | |||
51 | int virt_carrier = 0; | ||
52 | int phys_carrier = 0; | ||
53 | |||
54 | /* fix case when the tty has already closed. */ | ||
55 | |||
56 | if (!ch) | ||
57 | return; | ||
58 | nd = ch->ch_nd; | ||
59 | if (!nd) | ||
60 | return; | ||
61 | |||
62 | /* | ||
63 | * If we are currently waiting to determine the status of the port, | ||
64 | * we don't yet know the state of the modem lines. As a result, | ||
65 | * we ignore state changes when we are waiting for the modem lines | ||
66 | * to be established. We know, as a result of code in dgrp_net_ops, | ||
67 | * that we will be called again immediately following the reception | ||
68 | * of the status message with the true modem status flags in it. | ||
69 | */ | ||
70 | if (ch->ch_expect & RR_STATUS) | ||
71 | return; | ||
72 | |||
73 | /* | ||
74 | * If CH_HANGUP is set, we gotta keep trying to get all the processes | ||
75 | * that have the port open to close the port. | ||
76 | * So lets just keep sending a hangup every time we get here. | ||
77 | */ | ||
78 | if ((ch->ch_flag & CH_HANGUP) && | ||
79 | (ch->ch_tun.un_open_count > 0)) | ||
80 | tty_hangup(ch->ch_tun.un_tty); | ||
81 | |||
82 | /* | ||
83 | * Compute the effective state of both the physical and virtual | ||
84 | * senses of carrier. | ||
85 | */ | ||
86 | |||
87 | if (ch->ch_s_mlast & DM_CD) | ||
88 | phys_carrier = 1; | ||
89 | |||
90 | if ((ch->ch_s_mlast & DM_CD) || | ||
91 | (ch->ch_digi.digi_flags & DIGI_FORCEDCD) || | ||
92 | (ch->ch_flag & CH_CLOCAL)) | ||
93 | virt_carrier = 1; | ||
94 | |||
95 | /* | ||
96 | * Test for a VIRTUAL carrier transition to HIGH. | ||
97 | * | ||
98 | * The CH_HANGUP condition is intended to prevent any action | ||
99 | * except for close. As a result, we ignore positive carrier | ||
100 | * transitions during CH_HANGUP. | ||
101 | */ | ||
102 | if (((ch->ch_flag & CH_HANGUP) == 0) && | ||
103 | ((ch->ch_flag & CH_VIRT_CD) == 0) && | ||
104 | (virt_carrier == 1)) { | ||
105 | /* | ||
106 | * When carrier rises, wake any threads waiting | ||
107 | * for carrier in the open routine. | ||
108 | */ | ||
109 | nd->nd_tx_work = 1; | ||
110 | |||
111 | if (waitqueue_active(&ch->ch_flag_wait)) | ||
112 | wake_up_interruptible(&ch->ch_flag_wait); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Test for a PHYSICAL transition to low, so long as we aren't | ||
117 | * currently ignoring physical transitions (which is what "virtual | ||
118 | * carrier" indicates). | ||
119 | * | ||
120 | * The transition of the virtual carrier to low really doesn't | ||
121 | * matter... it really only means "ignore carrier state", not | ||
122 | * "make pretend that carrier is there". | ||
123 | */ | ||
124 | if ((virt_carrier == 0) && | ||
125 | ((ch->ch_flag & CH_PHYS_CD) != 0) && | ||
126 | (phys_carrier == 0)) { | ||
127 | /* | ||
128 | * When carrier drops: | ||
129 | * | ||
130 | * Do a Hard Hangup if that is called for. | ||
131 | * | ||
132 | * Drop carrier on all open units. | ||
133 | * | ||
134 | * Flush queues, waking up any task waiting in the | ||
135 | * line discipline. | ||
136 | * | ||
137 | * Send a hangup to the control terminal. | ||
138 | * | ||
139 | * Enable all select calls. | ||
140 | */ | ||
141 | |||
142 | nd->nd_tx_work = 1; | ||
143 | |||
144 | ch->ch_flag &= ~(CH_LOW | CH_EMPTY | CH_DRAIN | CH_INPUT); | ||
145 | |||
146 | if (waitqueue_active(&ch->ch_flag_wait)) | ||
147 | wake_up_interruptible(&ch->ch_flag_wait); | ||
148 | |||
149 | if (ch->ch_tun.un_open_count > 0) | ||
150 | tty_hangup(ch->ch_tun.un_tty); | ||
151 | |||
152 | if (ch->ch_pun.un_open_count > 0) | ||
153 | tty_hangup(ch->ch_pun.un_tty); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Make sure that our cached values reflect the current reality. | ||
158 | */ | ||
159 | if (virt_carrier == 1) | ||
160 | ch->ch_flag |= CH_VIRT_CD; | ||
161 | else | ||
162 | ch->ch_flag &= ~CH_VIRT_CD; | ||
163 | |||
164 | if (phys_carrier == 1) | ||
165 | ch->ch_flag |= CH_PHYS_CD; | ||
166 | else | ||
167 | ch->ch_flag &= ~CH_PHYS_CD; | ||
168 | |||
169 | } | ||
170 | |||
171 | /** | ||
172 | * dgrp_chk_perm() -- check permissions for net device | ||
173 | * @inode: pointer to inode structure for the net communication device | ||
174 | * @op: operation to be tested | ||
175 | * | ||
176 | * The file permissions and ownerships are tested to determine whether | ||
177 | * the operation "op" is permitted on the file pointed to by the inode. | ||
178 | * Returns 0 if the operation is permitted, -EACCESS otherwise | ||
179 | */ | ||
180 | int dgrp_chk_perm(int mode, int op) | ||
181 | { | ||
182 | if (!current_euid()) | ||
183 | mode >>= 6; | ||
184 | else if (in_egroup_p(0)) | ||
185 | mode >>= 3; | ||
186 | |||
187 | if ((mode & op & 0007) == op) | ||
188 | return 0; | ||
189 | |||
190 | if (capable(CAP_SYS_ADMIN)) | ||
191 | return 0; | ||
192 | |||
193 | return -EACCES; | ||
194 | } | ||
195 | |||
196 | /* dgrp_chk_perm wrapper for permission call in struct inode_operations */ | ||
197 | int dgrp_inode_permission(struct inode *inode, int op) | ||
198 | { | ||
199 | return dgrp_chk_perm(inode->i_mode, op); | ||
200 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_common.h b/drivers/staging/dgrp/dgrp_common.h new file mode 100644 index 000000000000..05ff338471ac --- /dev/null +++ b/drivers/staging/dgrp/dgrp_common.h | |||
@@ -0,0 +1,208 @@ | |||
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 | #ifndef __DGRP_COMMON_H | ||
19 | #define __DGRP_COMMON_H | ||
20 | |||
21 | #define DIGI_VERSION "1.9-29" | ||
22 | |||
23 | #include <linux/fs.h> | ||
24 | #include <linux/timer.h> | ||
25 | #include "drp.h" | ||
26 | |||
27 | #define DGRP_TTIME 100 | ||
28 | #define DGRP_RTIME 100 | ||
29 | |||
30 | /************************************************************************ | ||
31 | * All global storage allocation. | ||
32 | ************************************************************************/ | ||
33 | |||
34 | extern int dgrp_rawreadok; /* Allow raw writing of input */ | ||
35 | extern int dgrp_register_cudevices; /* enable legacy cu devices */ | ||
36 | extern int dgrp_register_prdevices; /* enable transparent print devices */ | ||
37 | extern int dgrp_poll_tick; /* Poll interval - in ms */ | ||
38 | |||
39 | extern struct list_head nd_struct_list; | ||
40 | |||
41 | struct dgrp_poll_data { | ||
42 | spinlock_t poll_lock; | ||
43 | struct timer_list timer; | ||
44 | int poll_tick; | ||
45 | ulong poll_round; /* Timer rouding factor */ | ||
46 | long node_active_count; | ||
47 | }; | ||
48 | |||
49 | extern struct dgrp_poll_data dgrp_poll_data; | ||
50 | extern void dgrp_poll_handler(unsigned long arg); | ||
51 | |||
52 | /* from dgrp_mon_ops.c */ | ||
53 | extern void dgrp_register_mon_hook(struct proc_dir_entry *de); | ||
54 | |||
55 | /* from dgrp_tty.c */ | ||
56 | extern int dgrp_tty_init(struct nd_struct *nd); | ||
57 | extern void dgrp_tty_uninit(struct nd_struct *nd); | ||
58 | |||
59 | /* from dgrp_ports_ops.c */ | ||
60 | extern void dgrp_register_ports_hook(struct proc_dir_entry *de); | ||
61 | |||
62 | /* from dgrp_net_ops.c */ | ||
63 | extern void dgrp_register_net_hook(struct proc_dir_entry *de); | ||
64 | |||
65 | /* from dgrp_dpa_ops.c */ | ||
66 | extern void dgrp_register_dpa_hook(struct proc_dir_entry *de); | ||
67 | extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int); | ||
68 | |||
69 | /* from dgrp_sysfs.c */ | ||
70 | extern void dgrp_create_class_sysfs_files(void); | ||
71 | extern void dgrp_remove_class_sysfs_files(void); | ||
72 | |||
73 | extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd); | ||
74 | extern void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd); | ||
75 | |||
76 | extern void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c); | ||
77 | extern void dgrp_remove_tty_sysfs(struct device *c); | ||
78 | |||
79 | /* from dgrp_specproc.c */ | ||
80 | /* | ||
81 | * The list of DGRP entries with r/w capabilities. These | ||
82 | * magic numbers are used for identification purposes. | ||
83 | */ | ||
84 | enum { | ||
85 | DGRP_CONFIG = 1, /* Configure portservers */ | ||
86 | DGRP_NETDIR = 2, /* Directory for "net" devices */ | ||
87 | DGRP_MONDIR = 3, /* Directory for "mon" devices */ | ||
88 | DGRP_PORTSDIR = 4, /* Directory for "ports" devices */ | ||
89 | DGRP_INFO = 5, /* Get info. about the running module */ | ||
90 | DGRP_NODEINFO = 6, /* Get info. about the configured nodes */ | ||
91 | DGRP_DPADIR = 7, /* Directory for the "dpa" devices */ | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Directions for proc handlers | ||
96 | */ | ||
97 | enum { | ||
98 | INBOUND = 1, /* Data being written to kernel */ | ||
99 | OUTBOUND = 2, /* Data being read from the kernel */ | ||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * dgrp_proc_entry: structure for dgrp proc dirs | ||
104 | * @id: ID number associated with this particular entry. Should be | ||
105 | * unique across all of DGRP. | ||
106 | * @name: text name associated with the /proc entry | ||
107 | * @mode: file access permisssions for the /proc entry | ||
108 | * @child: pointer to table describing a subdirectory for this entry | ||
109 | * @de: pointer to directory entry for this object once registered. Used | ||
110 | * to grab the handle of the object for unregistration | ||
111 | * @excl_sem: semaphore to provide exclusive to struct | ||
112 | * @excl_cnt: counter of current accesses | ||
113 | * | ||
114 | * Each entry in a DGRP proc directory is described with a | ||
115 | * dgrp_proc_entry structure. A collection of these | ||
116 | * entries (in an array) represents the members associated | ||
117 | * with a particular /proc directory, and is referred to | ||
118 | * as a table. All tables are terminated by an entry with | ||
119 | * zeros for every member. | ||
120 | */ | ||
121 | struct dgrp_proc_entry { | ||
122 | int id; /* Integer identifier */ | ||
123 | const char *name; /* ASCII identifier */ | ||
124 | mode_t mode; /* File access permissions */ | ||
125 | struct dgrp_proc_entry *child; /* Child pointer */ | ||
126 | |||
127 | /* file ops to use, pass NULL to use default */ | ||
128 | struct file_operations *proc_file_ops; | ||
129 | |||
130 | struct proc_dir_entry *de; /* proc entry pointer */ | ||
131 | struct semaphore excl_sem; /* Protects exclusive access var */ | ||
132 | int excl_cnt; /* Counts number of curr accesses */ | ||
133 | }; | ||
134 | |||
135 | extern void dgrp_unregister_proc(void); | ||
136 | extern void dgrp_register_proc(void); | ||
137 | |||
138 | /*-----------------------------------------------------------------------* | ||
139 | * | ||
140 | * Declarations for common operations: | ||
141 | * | ||
142 | * (either used by more than one of net, mon, or tty, | ||
143 | * or in interrupt context (i.e. the poller)) | ||
144 | * | ||
145 | *-----------------------------------------------------------------------*/ | ||
146 | |||
147 | void dgrp_carrier(struct ch_struct *ch); | ||
148 | extern int dgrp_inode_permission(struct inode *inode, int op); | ||
149 | extern int dgrp_chk_perm(int mode, int op); | ||
150 | |||
151 | |||
152 | /* | ||
153 | * ID manipulation macros (where c1 & c2 are characters, i is | ||
154 | * a long integer, and s is a character array of at least three members | ||
155 | */ | ||
156 | |||
157 | static inline void ID_TO_CHAR(long i, char *s) | ||
158 | { | ||
159 | s[0] = ((i & 0xff00)>>8); | ||
160 | s[1] = (i & 0xff); | ||
161 | s[2] = 0; | ||
162 | } | ||
163 | |||
164 | static inline long CHAR_TO_ID(char *s) | ||
165 | { | ||
166 | return ((s[0] & 0xff) << 8) | (s[1] & 0xff); | ||
167 | } | ||
168 | |||
169 | static inline struct nd_struct *nd_struct_get(long major) | ||
170 | { | ||
171 | struct nd_struct *nd; | ||
172 | |||
173 | list_for_each_entry(nd, &nd_struct_list, list) { | ||
174 | if (major == nd->nd_major) | ||
175 | return nd; | ||
176 | } | ||
177 | |||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | static inline int nd_struct_add(struct nd_struct *entry) | ||
182 | { | ||
183 | struct nd_struct *ptr; | ||
184 | |||
185 | ptr = nd_struct_get(entry->nd_major); | ||
186 | |||
187 | if (ptr) | ||
188 | return -EBUSY; | ||
189 | |||
190 | list_add_tail(&entry->list, &nd_struct_list); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static inline int nd_struct_del(struct nd_struct *entry) | ||
196 | { | ||
197 | struct nd_struct *nd; | ||
198 | |||
199 | nd = nd_struct_get(entry->nd_major); | ||
200 | |||
201 | if (!nd) | ||
202 | return -ENODEV; | ||
203 | |||
204 | list_del(&nd->list); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | #endif /* __DGRP_COMMON_H */ | ||
diff --git a/drivers/staging/dgrp/dgrp_dpa_ops.c b/drivers/staging/dgrp/dgrp_dpa_ops.c new file mode 100644 index 000000000000..49e670915e5c --- /dev/null +++ b/drivers/staging/dgrp/dgrp_dpa_ops.c | |||
@@ -0,0 +1,556 @@ | |||
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_dpa_ops.c | ||
23 | * | ||
24 | * Description: | ||
25 | * | ||
26 | * Handle the file operations required for the "dpa" devices. | ||
27 | * Includes those functions required to register the "dpa" devices | ||
28 | * in "/proc". | ||
29 | * | ||
30 | * Author: | ||
31 | * | ||
32 | * James A. Puzzo | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/proc_fs.h> | ||
38 | #include <linux/tty.h> | ||
39 | #include <linux/poll.h> | ||
40 | #include <linux/cred.h> | ||
41 | #include <linux/sched.h> | ||
42 | #include <linux/ratelimit.h> | ||
43 | #include <asm/unaligned.h> | ||
44 | |||
45 | #include "dgrp_common.h" | ||
46 | |||
47 | /* File operation declarations */ | ||
48 | static int dgrp_dpa_open(struct inode *, struct file *); | ||
49 | static int dgrp_dpa_release(struct inode *, struct file *); | ||
50 | static ssize_t dgrp_dpa_read(struct file *, char __user *, size_t, loff_t *); | ||
51 | static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd, | ||
52 | unsigned long arg); | ||
53 | static unsigned int dgrp_dpa_select(struct file *, struct poll_table_struct *); | ||
54 | |||
55 | static const struct file_operations dpa_ops = { | ||
56 | .owner = THIS_MODULE, | ||
57 | .read = dgrp_dpa_read, | ||
58 | .poll = dgrp_dpa_select, | ||
59 | .unlocked_ioctl = dgrp_dpa_ioctl, | ||
60 | .open = dgrp_dpa_open, | ||
61 | .release = dgrp_dpa_release, | ||
62 | }; | ||
63 | |||
64 | static struct inode_operations dpa_inode_ops = { | ||
65 | .permission = dgrp_inode_permission | ||
66 | }; | ||
67 | |||
68 | |||
69 | |||
70 | struct digi_node { | ||
71 | uint nd_state; /* Node state: 1 = up, 0 = down. */ | ||
72 | uint nd_chan_count; /* Number of channels found */ | ||
73 | uint nd_tx_byte; /* Tx data count */ | ||
74 | uint nd_rx_byte; /* RX data count */ | ||
75 | u8 nd_ps_desc[MAX_DESC_LEN]; /* Description from PS */ | ||
76 | }; | ||
77 | |||
78 | #define DIGI_GETNODE (('d'<<8) | 249) /* get board info */ | ||
79 | |||
80 | |||
81 | struct digi_chan { | ||
82 | uint ch_port; /* Port number to get info on */ | ||
83 | uint ch_open; /* 1 if open, 0 if not */ | ||
84 | uint ch_txcount; /* TX data count */ | ||
85 | uint ch_rxcount; /* RX data count */ | ||
86 | uint ch_s_brate; /* Realport BRATE */ | ||
87 | uint ch_s_estat; /* Realport ELAST */ | ||
88 | uint ch_s_cflag; /* Realport CFLAG */ | ||
89 | uint ch_s_iflag; /* Realport IFLAG */ | ||
90 | uint ch_s_oflag; /* Realport OFLAG */ | ||
91 | uint ch_s_xflag; /* Realport XFLAG */ | ||
92 | uint ch_s_mstat; /* Realport MLAST */ | ||
93 | }; | ||
94 | |||
95 | #define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */ | ||
96 | |||
97 | |||
98 | struct digi_vpd { | ||
99 | int vpd_len; | ||
100 | char vpd_data[VPDSIZE]; | ||
101 | }; | ||
102 | |||
103 | #define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */ | ||
104 | |||
105 | |||
106 | struct digi_debug { | ||
107 | int onoff; | ||
108 | int port; | ||
109 | }; | ||
110 | |||
111 | #define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */ | ||
112 | |||
113 | |||
114 | void dgrp_register_dpa_hook(struct proc_dir_entry *de) | ||
115 | { | ||
116 | struct nd_struct *node = de->data; | ||
117 | |||
118 | de->proc_iops = &dpa_inode_ops; | ||
119 | de->proc_fops = &dpa_ops; | ||
120 | |||
121 | node->nd_dpa_de = de; | ||
122 | spin_lock_init(&node->nd_dpa_lock); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * dgrp_dpa_open -- open the DPA device for a particular PortServer | ||
127 | */ | ||
128 | static int dgrp_dpa_open(struct inode *inode, struct file *file) | ||
129 | { | ||
130 | struct nd_struct *nd; | ||
131 | int rtn = 0; | ||
132 | |||
133 | struct proc_dir_entry *de; | ||
134 | |||
135 | rtn = try_module_get(THIS_MODULE); | ||
136 | if (!rtn) | ||
137 | return -ENXIO; | ||
138 | |||
139 | rtn = 0; | ||
140 | |||
141 | if (!capable(CAP_SYS_ADMIN)) { | ||
142 | rtn = -EPERM; | ||
143 | goto done; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Make sure that the "private_data" field hasn't already been used. | ||
148 | */ | ||
149 | if (file->private_data) { | ||
150 | rtn = -EINVAL; | ||
151 | goto done; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Get the node pointer, and fail if it doesn't exist. | ||
156 | */ | ||
157 | de = PDE(inode); | ||
158 | if (!de) { | ||
159 | rtn = -ENXIO; | ||
160 | goto done; | ||
161 | } | ||
162 | nd = (struct nd_struct *)de->data; | ||
163 | if (!nd) { | ||
164 | rtn = -ENXIO; | ||
165 | goto done; | ||
166 | } | ||
167 | |||
168 | file->private_data = (void *) nd; | ||
169 | |||
170 | /* | ||
171 | * Allocate the DPA buffer. | ||
172 | */ | ||
173 | |||
174 | if (nd->nd_dpa_buf) { | ||
175 | rtn = -EBUSY; | ||
176 | } else { | ||
177 | nd->nd_dpa_buf = kmalloc(DPA_MAX, GFP_KERNEL); | ||
178 | |||
179 | if (!nd->nd_dpa_buf) { | ||
180 | rtn = -ENOMEM; | ||
181 | } else { | ||
182 | nd->nd_dpa_out = 0; | ||
183 | nd->nd_dpa_in = 0; | ||
184 | nd->nd_dpa_lbolt = jiffies; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | done: | ||
189 | |||
190 | if (rtn) | ||
191 | module_put(THIS_MODULE); | ||
192 | return rtn; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * dgrp_dpa_release -- close the DPA device for a particular PortServer | ||
197 | */ | ||
198 | static int dgrp_dpa_release(struct inode *inode, struct file *file) | ||
199 | { | ||
200 | struct nd_struct *nd; | ||
201 | u8 *buf; | ||
202 | unsigned long lock_flags; | ||
203 | |||
204 | /* | ||
205 | * Get the node pointer, and quit if it doesn't exist. | ||
206 | */ | ||
207 | nd = (struct nd_struct *)(file->private_data); | ||
208 | if (!nd) | ||
209 | goto done; | ||
210 | |||
211 | /* | ||
212 | * Free the dpa buffer. | ||
213 | */ | ||
214 | |||
215 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
216 | |||
217 | buf = nd->nd_dpa_buf; | ||
218 | |||
219 | nd->nd_dpa_buf = NULL; | ||
220 | nd->nd_dpa_out = nd->nd_dpa_in; | ||
221 | |||
222 | /* | ||
223 | * Wakeup any thread waiting for buffer space. | ||
224 | */ | ||
225 | |||
226 | if (nd->nd_dpa_flag & DPA_WAIT_SPACE) { | ||
227 | nd->nd_dpa_flag &= ~DPA_WAIT_SPACE; | ||
228 | wake_up_interruptible(&nd->nd_dpa_wqueue); | ||
229 | } | ||
230 | |||
231 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
232 | |||
233 | kfree(buf); | ||
234 | |||
235 | done: | ||
236 | module_put(THIS_MODULE); | ||
237 | file->private_data = NULL; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * dgrp_dpa_read | ||
243 | * | ||
244 | * Copy data from the monitoring buffer to the user, freeing space | ||
245 | * in the monitoring buffer for more messages | ||
246 | */ | ||
247 | static ssize_t dgrp_dpa_read(struct file *file, char __user *buf, size_t count, | ||
248 | loff_t *ppos) | ||
249 | { | ||
250 | struct nd_struct *nd; | ||
251 | int n; | ||
252 | int r; | ||
253 | int offset = 0; | ||
254 | int res = 0; | ||
255 | ssize_t rtn; | ||
256 | unsigned long lock_flags; | ||
257 | |||
258 | /* | ||
259 | * Get the node pointer, and quit if it doesn't exist. | ||
260 | */ | ||
261 | nd = (struct nd_struct *)(file->private_data); | ||
262 | if (!nd) | ||
263 | return -ENXIO; | ||
264 | |||
265 | /* | ||
266 | * Wait for some data to appear in the buffer. | ||
267 | */ | ||
268 | |||
269 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
270 | |||
271 | for (;;) { | ||
272 | n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK; | ||
273 | |||
274 | if (n != 0) | ||
275 | break; | ||
276 | |||
277 | nd->nd_dpa_flag |= DPA_WAIT_DATA; | ||
278 | |||
279 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
280 | |||
281 | /* | ||
282 | * Go to sleep waiting until the condition becomes true. | ||
283 | */ | ||
284 | rtn = wait_event_interruptible(nd->nd_dpa_wqueue, | ||
285 | ((nd->nd_dpa_flag & DPA_WAIT_DATA) == 0)); | ||
286 | |||
287 | if (rtn) | ||
288 | return rtn; | ||
289 | |||
290 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * Read whatever is there. | ||
295 | */ | ||
296 | |||
297 | if (n > count) | ||
298 | n = count; | ||
299 | |||
300 | res = n; | ||
301 | |||
302 | r = DPA_MAX - nd->nd_dpa_out; | ||
303 | |||
304 | if (r <= n) { | ||
305 | |||
306 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
307 | rtn = copy_to_user((void __user *)buf, | ||
308 | nd->nd_dpa_buf + nd->nd_dpa_out, r); | ||
309 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
310 | |||
311 | if (rtn) { | ||
312 | rtn = -EFAULT; | ||
313 | goto done; | ||
314 | } | ||
315 | |||
316 | nd->nd_dpa_out = 0; | ||
317 | n -= r; | ||
318 | offset = r; | ||
319 | } | ||
320 | |||
321 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
322 | rtn = copy_to_user((void __user *)buf + offset, | ||
323 | nd->nd_dpa_buf + nd->nd_dpa_out, n); | ||
324 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
325 | |||
326 | if (rtn) { | ||
327 | rtn = -EFAULT; | ||
328 | goto done; | ||
329 | } | ||
330 | |||
331 | nd->nd_dpa_out += n; | ||
332 | |||
333 | *ppos += res; | ||
334 | |||
335 | rtn = res; | ||
336 | |||
337 | /* | ||
338 | * Wakeup any thread waiting for buffer space. | ||
339 | */ | ||
340 | |||
341 | n = (nd->nd_dpa_in - nd->nd_dpa_out) & DPA_MASK; | ||
342 | |||
343 | if (nd->nd_dpa_flag & DPA_WAIT_SPACE && | ||
344 | (DPA_MAX - n) > DPA_HIGH_WATER) { | ||
345 | nd->nd_dpa_flag &= ~DPA_WAIT_SPACE; | ||
346 | wake_up_interruptible(&nd->nd_dpa_wqueue); | ||
347 | } | ||
348 | |||
349 | done: | ||
350 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
351 | return rtn; | ||
352 | } | ||
353 | |||
354 | static unsigned int dgrp_dpa_select(struct file *file, | ||
355 | struct poll_table_struct *table) | ||
356 | { | ||
357 | unsigned int retval = 0; | ||
358 | struct nd_struct *nd = file->private_data; | ||
359 | |||
360 | if (nd->nd_dpa_out != nd->nd_dpa_in) | ||
361 | retval |= POLLIN | POLLRDNORM; /* Conditionally readable */ | ||
362 | |||
363 | retval |= POLLOUT | POLLWRNORM; /* Always writeable */ | ||
364 | |||
365 | return retval; | ||
366 | } | ||
367 | |||
368 | static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd, | ||
369 | unsigned long arg) | ||
370 | { | ||
371 | |||
372 | struct nd_struct *nd; | ||
373 | struct digi_chan getchan; | ||
374 | struct digi_node getnode; | ||
375 | struct ch_struct *ch; | ||
376 | struct digi_debug setdebug; | ||
377 | struct digi_vpd vpd; | ||
378 | unsigned int port; | ||
379 | void __user *uarg = (void __user *) arg; | ||
380 | |||
381 | nd = file->private_data; | ||
382 | |||
383 | switch (cmd) { | ||
384 | case DIGI_GETCHAN: | ||
385 | if (copy_from_user(&getchan, uarg, sizeof(struct digi_chan))) | ||
386 | return -EFAULT; | ||
387 | |||
388 | port = getchan.ch_port; | ||
389 | |||
390 | if (port < 0 || port > nd->nd_chan_count) | ||
391 | return -EINVAL; | ||
392 | |||
393 | ch = nd->nd_chan + port; | ||
394 | |||
395 | getchan.ch_open = (ch->ch_open_count > 0) ? 1 : 0; | ||
396 | getchan.ch_txcount = ch->ch_txcount; | ||
397 | getchan.ch_rxcount = ch->ch_rxcount; | ||
398 | getchan.ch_s_brate = ch->ch_s_brate; | ||
399 | getchan.ch_s_estat = ch->ch_s_elast; | ||
400 | getchan.ch_s_cflag = ch->ch_s_cflag; | ||
401 | getchan.ch_s_iflag = ch->ch_s_iflag; | ||
402 | getchan.ch_s_oflag = ch->ch_s_oflag; | ||
403 | getchan.ch_s_xflag = ch->ch_s_xflag; | ||
404 | getchan.ch_s_mstat = ch->ch_s_mlast; | ||
405 | |||
406 | if (copy_to_user(uarg, &getchan, sizeof(struct digi_chan))) | ||
407 | return -EFAULT; | ||
408 | break; | ||
409 | |||
410 | |||
411 | case DIGI_GETNODE: | ||
412 | getnode.nd_state = (nd->nd_state & NS_READY) ? 1 : 0; | ||
413 | getnode.nd_chan_count = nd->nd_chan_count; | ||
414 | getnode.nd_tx_byte = nd->nd_tx_byte; | ||
415 | getnode.nd_rx_byte = nd->nd_rx_byte; | ||
416 | |||
417 | memset(&getnode.nd_ps_desc, 0, MAX_DESC_LEN); | ||
418 | strncpy(getnode.nd_ps_desc, nd->nd_ps_desc, MAX_DESC_LEN); | ||
419 | |||
420 | if (copy_to_user(uarg, &getnode, sizeof(struct digi_node))) | ||
421 | return -EFAULT; | ||
422 | break; | ||
423 | |||
424 | |||
425 | case DIGI_SETDEBUG: | ||
426 | if (copy_from_user(&setdebug, uarg, sizeof(struct digi_debug))) | ||
427 | return -EFAULT; | ||
428 | |||
429 | nd->nd_dpa_debug = setdebug.onoff; | ||
430 | nd->nd_dpa_port = setdebug.port; | ||
431 | break; | ||
432 | |||
433 | |||
434 | case DIGI_GETVPD: | ||
435 | if (nd->nd_vpd_len > 0) { | ||
436 | vpd.vpd_len = nd->nd_vpd_len; | ||
437 | memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len); | ||
438 | } else { | ||
439 | vpd.vpd_len = 0; | ||
440 | } | ||
441 | |||
442 | if (copy_to_user(uarg, &vpd, sizeof(struct digi_vpd))) | ||
443 | return -EFAULT; | ||
444 | break; | ||
445 | } | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * dgrp_dpa() -- send data to the device monitor queue | ||
452 | * @nd: pointer to a node structure | ||
453 | * @buf: buffer of data to copy to the monitoring buffer | ||
454 | * @len: number of bytes to transfer to the buffer | ||
455 | * | ||
456 | * Called by the net device routines to send data to the device | ||
457 | * monitor queue. If the device monitor buffer is too full to | ||
458 | * accept the data, it waits until the buffer is ready. | ||
459 | */ | ||
460 | static void dgrp_dpa(struct nd_struct *nd, u8 *buf, int nbuf) | ||
461 | { | ||
462 | int n; | ||
463 | int r; | ||
464 | unsigned long lock_flags; | ||
465 | |||
466 | /* | ||
467 | * Grab DPA lock. | ||
468 | */ | ||
469 | spin_lock_irqsave(&nd->nd_dpa_lock, lock_flags); | ||
470 | |||
471 | /* | ||
472 | * Loop while data remains. | ||
473 | */ | ||
474 | while (nbuf > 0 && nd->nd_dpa_buf != NULL) { | ||
475 | |||
476 | n = (nd->nd_dpa_out - nd->nd_dpa_in - 1) & DPA_MASK; | ||
477 | |||
478 | /* | ||
479 | * Enforce flow control on the DPA device. | ||
480 | */ | ||
481 | if (n < (DPA_MAX - DPA_HIGH_WATER)) | ||
482 | nd->nd_dpa_flag |= DPA_WAIT_SPACE; | ||
483 | |||
484 | /* | ||
485 | * This should never happen, as the flow control above | ||
486 | * should have stopped things before they got to this point. | ||
487 | */ | ||
488 | if (n == 0) { | ||
489 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * Copy as much data as will fit. | ||
495 | */ | ||
496 | |||
497 | if (n > nbuf) | ||
498 | n = nbuf; | ||
499 | |||
500 | r = DPA_MAX - nd->nd_dpa_in; | ||
501 | |||
502 | if (r <= n) { | ||
503 | memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, r); | ||
504 | |||
505 | n -= r; | ||
506 | |||
507 | nd->nd_dpa_in = 0; | ||
508 | |||
509 | buf += r; | ||
510 | nbuf -= r; | ||
511 | } | ||
512 | |||
513 | memcpy(nd->nd_dpa_buf + nd->nd_dpa_in, buf, n); | ||
514 | |||
515 | nd->nd_dpa_in += n; | ||
516 | |||
517 | buf += n; | ||
518 | nbuf -= n; | ||
519 | |||
520 | if (nd->nd_dpa_in >= DPA_MAX) | ||
521 | pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n", | ||
522 | __func__, nd->nd_dpa_in); | ||
523 | |||
524 | /* | ||
525 | * Wakeup any thread waiting for data | ||
526 | */ | ||
527 | if (nd->nd_dpa_flag & DPA_WAIT_DATA) { | ||
528 | nd->nd_dpa_flag &= ~DPA_WAIT_DATA; | ||
529 | wake_up_interruptible(&nd->nd_dpa_wqueue); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* | ||
534 | * Release the DPA lock. | ||
535 | */ | ||
536 | spin_unlock_irqrestore(&nd->nd_dpa_lock, lock_flags); | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * dgrp_monitor_data() -- builds a DPA data packet | ||
541 | * @nd: pointer to a node structure | ||
542 | * @type: type of message to be logged in the DPA buffer | ||
543 | * @buf: buffer of data to be logged in the DPA buffer | ||
544 | * @size -- number of bytes in the "buf" buffer | ||
545 | */ | ||
546 | void dgrp_dpa_data(struct nd_struct *nd, int type, u8 *buf, int size) | ||
547 | { | ||
548 | u8 header[5]; | ||
549 | |||
550 | header[0] = type; | ||
551 | |||
552 | put_unaligned_be32(size, header + 1); | ||
553 | |||
554 | dgrp_dpa(nd, header, sizeof(header)); | ||
555 | dgrp_dpa(nd, buf, size); | ||
556 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c new file mode 100644 index 000000000000..6e4a0ebc0749 --- /dev/null +++ b/drivers/staging/dgrp/dgrp_driver.c | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 1999-2003 Digi International (www.digi.com) | ||
4 | * Jeff Randall | ||
5 | * James Puzzo <jamesp at digi dot com> | ||
6 | * Scott Kilau <Scott_Kilau at digi dot com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the | ||
15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
16 | * PURPOSE. See the GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * Driver specific includes | ||
22 | */ | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/tty.h> | ||
26 | #include <linux/init.h> | ||
27 | |||
28 | /* | ||
29 | * PortServer includes | ||
30 | */ | ||
31 | #include "dgrp_common.h" | ||
32 | |||
33 | |||
34 | MODULE_LICENSE("GPL"); | ||
35 | MODULE_AUTHOR("Digi International, http://www.digi.com"); | ||
36 | MODULE_DESCRIPTION("RealPort driver for Digi's ethernet-based serial connectivity product line"); | ||
37 | MODULE_VERSION(DIGI_VERSION); | ||
38 | |||
39 | struct list_head nd_struct_list; | ||
40 | struct dgrp_poll_data dgrp_poll_data; | ||
41 | |||
42 | int dgrp_rawreadok = 1; /* Bypass flipbuf on input */ | ||
43 | int dgrp_register_cudevices = 1;/* Turn on/off registering legacy cu devices */ | ||
44 | int dgrp_register_prdevices = 1;/* Turn on/off registering transparent print */ | ||
45 | int dgrp_poll_tick = 20; /* Poll interval - in ms */ | ||
46 | |||
47 | module_param_named(rawreadok, dgrp_rawreadok, int, 0644); | ||
48 | MODULE_PARM_DESC(rawreadok, "Bypass flip buffers on input"); | ||
49 | |||
50 | module_param_named(register_cudevices, dgrp_register_cudevices, int, 0644); | ||
51 | MODULE_PARM_DESC(register_cudevices, "Turn on/off registering legacy cu devices"); | ||
52 | |||
53 | module_param_named(register_prdevices, dgrp_register_prdevices, int, 0644); | ||
54 | MODULE_PARM_DESC(register_prdevices, "Turn on/off registering transparent print devices"); | ||
55 | |||
56 | module_param_named(pollrate, dgrp_poll_tick, int, 0644); | ||
57 | MODULE_PARM_DESC(pollrate, "Poll interval in ms"); | ||
58 | |||
59 | /* Driver load/unload functions */ | ||
60 | static int dgrp_init_module(void); | ||
61 | static void dgrp_cleanup_module(void); | ||
62 | |||
63 | module_init(dgrp_init_module); | ||
64 | module_exit(dgrp_cleanup_module); | ||
65 | |||
66 | /* | ||
67 | * init_module() | ||
68 | * | ||
69 | * Module load. This is where it all starts. | ||
70 | */ | ||
71 | static int dgrp_init_module(void) | ||
72 | { | ||
73 | INIT_LIST_HEAD(&nd_struct_list); | ||
74 | |||
75 | spin_lock_init(&dgrp_poll_data.poll_lock); | ||
76 | init_timer(&dgrp_poll_data.timer); | ||
77 | dgrp_poll_data.poll_tick = dgrp_poll_tick; | ||
78 | dgrp_poll_data.timer.function = dgrp_poll_handler; | ||
79 | dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data; | ||
80 | |||
81 | dgrp_create_class_sysfs_files(); | ||
82 | |||
83 | dgrp_register_proc(); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | |||
89 | /* | ||
90 | * Module unload. This is where it all ends. | ||
91 | */ | ||
92 | static void dgrp_cleanup_module(void) | ||
93 | { | ||
94 | struct nd_struct *nd, *next; | ||
95 | |||
96 | /* | ||
97 | * Attempting to free resources in backwards | ||
98 | * order of allocation, in case that helps | ||
99 | * memory pool fragmentation. | ||
100 | */ | ||
101 | dgrp_unregister_proc(); | ||
102 | |||
103 | dgrp_remove_class_sysfs_files(); | ||
104 | |||
105 | |||
106 | list_for_each_entry_safe(nd, next, &nd_struct_list, list) { | ||
107 | dgrp_tty_uninit(nd); | ||
108 | kfree(nd); | ||
109 | } | ||
110 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_mon_ops.c b/drivers/staging/dgrp/dgrp_mon_ops.c new file mode 100644 index 000000000000..268dcb95204b --- /dev/null +++ b/drivers/staging/dgrp/dgrp_mon_ops.c | |||
@@ -0,0 +1,346 @@ | |||
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_mon_ops.c | ||
23 | * | ||
24 | * Description: | ||
25 | * | ||
26 | * Handle the file operations required for the "monitor" devices. | ||
27 | * Includes those functions required to register the "mon" devices | ||
28 | * in "/proc". | ||
29 | * | ||
30 | * Author: | ||
31 | * | ||
32 | * James A. Puzzo | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/tty.h> | ||
38 | #include <linux/sched.h> | ||
39 | #include <asm/unaligned.h> | ||
40 | #include <linux/proc_fs.h> | ||
41 | |||
42 | #include "dgrp_common.h" | ||
43 | |||
44 | /* File operation declarations */ | ||
45 | static int dgrp_mon_open(struct inode *, struct file *); | ||
46 | static int dgrp_mon_release(struct inode *, struct file *); | ||
47 | static ssize_t dgrp_mon_read(struct file *, char __user *, size_t, loff_t *); | ||
48 | static long dgrp_mon_ioctl(struct file *file, unsigned int cmd, | ||
49 | unsigned long arg); | ||
50 | |||
51 | static const struct file_operations mon_ops = { | ||
52 | .owner = THIS_MODULE, | ||
53 | .read = dgrp_mon_read, | ||
54 | .unlocked_ioctl = dgrp_mon_ioctl, | ||
55 | .open = dgrp_mon_open, | ||
56 | .release = dgrp_mon_release, | ||
57 | }; | ||
58 | |||
59 | static struct inode_operations mon_inode_ops = { | ||
60 | .permission = dgrp_inode_permission | ||
61 | }; | ||
62 | |||
63 | void dgrp_register_mon_hook(struct proc_dir_entry *de) | ||
64 | { | ||
65 | struct nd_struct *node = de->data; | ||
66 | |||
67 | de->proc_iops = &mon_inode_ops; | ||
68 | de->proc_fops = &mon_ops; | ||
69 | node->nd_mon_de = de; | ||
70 | sema_init(&node->nd_mon_semaphore, 1); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * dgrp_mon_open() -- open /proc/dgrp/ports device for a PortServer | ||
75 | * @inode: struct inode * | ||
76 | * @file: struct file * | ||
77 | * | ||
78 | * Open function to open the /proc/dgrp/ports device for a PortServer. | ||
79 | */ | ||
80 | static int dgrp_mon_open(struct inode *inode, struct file *file) | ||
81 | { | ||
82 | struct nd_struct *nd; | ||
83 | struct proc_dir_entry *de; | ||
84 | struct timeval tv; | ||
85 | uint32_t time; | ||
86 | u8 *buf; | ||
87 | int rtn; | ||
88 | |||
89 | rtn = try_module_get(THIS_MODULE); | ||
90 | if (!rtn) | ||
91 | return -ENXIO; | ||
92 | |||
93 | rtn = 0; | ||
94 | |||
95 | if (!capable(CAP_SYS_ADMIN)) { | ||
96 | rtn = -EPERM; | ||
97 | goto done; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Make sure that the "private_data" field hasn't already been used. | ||
102 | */ | ||
103 | if (file->private_data) { | ||
104 | rtn = -EINVAL; | ||
105 | goto done; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Get the node pointer, and fail if it doesn't exist. | ||
110 | */ | ||
111 | de = PDE(inode); | ||
112 | if (!de) { | ||
113 | rtn = -ENXIO; | ||
114 | goto done; | ||
115 | } | ||
116 | |||
117 | nd = (struct nd_struct *)de->data; | ||
118 | if (!nd) { | ||
119 | rtn = -ENXIO; | ||
120 | goto done; | ||
121 | } | ||
122 | |||
123 | file->private_data = (void *) nd; | ||
124 | |||
125 | /* | ||
126 | * Allocate the monitor buffer. | ||
127 | */ | ||
128 | |||
129 | /* | ||
130 | * Grab the MON lock. | ||
131 | */ | ||
132 | down(&nd->nd_mon_semaphore); | ||
133 | |||
134 | if (nd->nd_mon_buf) { | ||
135 | rtn = -EBUSY; | ||
136 | goto done_up; | ||
137 | } | ||
138 | |||
139 | nd->nd_mon_buf = kmalloc(MON_MAX, GFP_KERNEL); | ||
140 | |||
141 | if (!nd->nd_mon_buf) { | ||
142 | rtn = -ENOMEM; | ||
143 | goto done_up; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * Enter an RPDUMP file header into the buffer. | ||
148 | */ | ||
149 | |||
150 | buf = nd->nd_mon_buf; | ||
151 | |||
152 | strcpy(buf, RPDUMP_MAGIC); | ||
153 | buf += strlen(buf) + 1; | ||
154 | |||
155 | do_gettimeofday(&tv); | ||
156 | |||
157 | /* | ||
158 | * tv.tv_sec might be a 64 bit quantity. Pare | ||
159 | * it down to 32 bits before attempting to encode | ||
160 | * it. | ||
161 | */ | ||
162 | time = (uint32_t) (tv.tv_sec & 0xffffffff); | ||
163 | |||
164 | put_unaligned_be32(time, buf); | ||
165 | put_unaligned_be16(0, buf + 4); | ||
166 | buf += 6; | ||
167 | |||
168 | if (nd->nd_tx_module) { | ||
169 | buf[0] = RPDUMP_CLIENT; | ||
170 | put_unaligned_be32(0, buf + 1); | ||
171 | put_unaligned_be16(1, buf + 5); | ||
172 | buf[7] = 0xf0 + nd->nd_tx_module; | ||
173 | buf += 8; | ||
174 | } | ||
175 | |||
176 | if (nd->nd_rx_module) { | ||
177 | buf[0] = RPDUMP_SERVER; | ||
178 | put_unaligned_be32(0, buf + 1); | ||
179 | put_unaligned_be16(1, buf + 5); | ||
180 | buf[7] = 0xf0 + nd->nd_rx_module; | ||
181 | buf += 8; | ||
182 | } | ||
183 | |||
184 | nd->nd_mon_out = 0; | ||
185 | nd->nd_mon_in = buf - nd->nd_mon_buf; | ||
186 | nd->nd_mon_lbolt = jiffies; | ||
187 | |||
188 | done_up: | ||
189 | up(&nd->nd_mon_semaphore); | ||
190 | |||
191 | done: | ||
192 | if (rtn) | ||
193 | module_put(THIS_MODULE); | ||
194 | return rtn; | ||
195 | } | ||
196 | |||
197 | |||
198 | /** | ||
199 | * dgrp_mon_release() - Close the MON device for a particular PortServer | ||
200 | * @inode: struct inode * | ||
201 | * @file: struct file * | ||
202 | */ | ||
203 | static int dgrp_mon_release(struct inode *inode, struct file *file) | ||
204 | { | ||
205 | struct nd_struct *nd; | ||
206 | |||
207 | /* | ||
208 | * Get the node pointer, and quit if it doesn't exist. | ||
209 | */ | ||
210 | nd = (struct nd_struct *)(file->private_data); | ||
211 | if (!nd) | ||
212 | goto done; | ||
213 | |||
214 | /* | ||
215 | * Free the monitor buffer. | ||
216 | */ | ||
217 | |||
218 | down(&nd->nd_mon_semaphore); | ||
219 | |||
220 | kfree(nd->nd_mon_buf); | ||
221 | nd->nd_mon_buf = NULL; | ||
222 | nd->nd_mon_out = nd->nd_mon_in; | ||
223 | |||
224 | /* | ||
225 | * Wakeup any thread waiting for buffer space. | ||
226 | */ | ||
227 | |||
228 | if (nd->nd_mon_flag & MON_WAIT_SPACE) { | ||
229 | nd->nd_mon_flag &= ~MON_WAIT_SPACE; | ||
230 | wake_up_interruptible(&nd->nd_mon_wqueue); | ||
231 | } | ||
232 | |||
233 | up(&nd->nd_mon_semaphore); | ||
234 | |||
235 | /* | ||
236 | * Make sure there is no thread in the middle of writing a packet. | ||
237 | */ | ||
238 | down(&nd->nd_net_semaphore); | ||
239 | up(&nd->nd_net_semaphore); | ||
240 | |||
241 | done: | ||
242 | module_put(THIS_MODULE); | ||
243 | file->private_data = NULL; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * dgrp_mon_read() -- Copy data from the monitoring buffer to the user | ||
249 | */ | ||
250 | static ssize_t dgrp_mon_read(struct file *file, char __user *buf, size_t count, | ||
251 | loff_t *ppos) | ||
252 | { | ||
253 | struct nd_struct *nd; | ||
254 | int r; | ||
255 | int offset = 0; | ||
256 | int res = 0; | ||
257 | ssize_t rtn; | ||
258 | |||
259 | /* | ||
260 | * Get the node pointer, and quit if it doesn't exist. | ||
261 | */ | ||
262 | nd = (struct nd_struct *)(file->private_data); | ||
263 | if (!nd) | ||
264 | return -ENXIO; | ||
265 | |||
266 | /* | ||
267 | * Wait for some data to appear in the buffer. | ||
268 | */ | ||
269 | |||
270 | down(&nd->nd_mon_semaphore); | ||
271 | |||
272 | for (;;) { | ||
273 | res = (nd->nd_mon_in - nd->nd_mon_out) & MON_MASK; | ||
274 | |||
275 | if (res) | ||
276 | break; | ||
277 | |||
278 | nd->nd_mon_flag |= MON_WAIT_DATA; | ||
279 | |||
280 | up(&nd->nd_mon_semaphore); | ||
281 | |||
282 | /* | ||
283 | * Go to sleep waiting until the condition becomes true. | ||
284 | */ | ||
285 | rtn = wait_event_interruptible(nd->nd_mon_wqueue, | ||
286 | ((nd->nd_mon_flag & MON_WAIT_DATA) == 0)); | ||
287 | |||
288 | if (rtn) | ||
289 | return rtn; | ||
290 | |||
291 | down(&nd->nd_mon_semaphore); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Read whatever is there. | ||
296 | */ | ||
297 | |||
298 | if (res > count) | ||
299 | res = count; | ||
300 | |||
301 | r = MON_MAX - nd->nd_mon_out; | ||
302 | |||
303 | if (r <= res) { | ||
304 | rtn = copy_to_user((void __user *)buf, | ||
305 | nd->nd_mon_buf + nd->nd_mon_out, r); | ||
306 | if (rtn) { | ||
307 | up(&nd->nd_mon_semaphore); | ||
308 | return -EFAULT; | ||
309 | } | ||
310 | |||
311 | nd->nd_mon_out = 0; | ||
312 | res -= r; | ||
313 | offset = r; | ||
314 | } | ||
315 | |||
316 | rtn = copy_to_user((void __user *) buf + offset, | ||
317 | nd->nd_mon_buf + nd->nd_mon_out, res); | ||
318 | if (rtn) { | ||
319 | up(&nd->nd_mon_semaphore); | ||
320 | return -EFAULT; | ||
321 | } | ||
322 | |||
323 | nd->nd_mon_out += res; | ||
324 | |||
325 | *ppos += res; | ||
326 | |||
327 | up(&nd->nd_mon_semaphore); | ||
328 | |||
329 | /* | ||
330 | * Wakeup any thread waiting for buffer space. | ||
331 | */ | ||
332 | |||
333 | if (nd->nd_mon_flag & MON_WAIT_SPACE) { | ||
334 | nd->nd_mon_flag &= ~MON_WAIT_SPACE; | ||
335 | wake_up_interruptible(&nd->nd_mon_wqueue); | ||
336 | } | ||
337 | |||
338 | return res; | ||
339 | } | ||
340 | |||
341 | /* ioctl is not valid on monitor device */ | ||
342 | static long dgrp_mon_ioctl(struct file *file, unsigned int cmd, | ||
343 | unsigned long arg) | ||
344 | { | ||
345 | return -EINVAL; | ||
346 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c new file mode 100644 index 000000000000..ab839ea3b44c --- /dev/null +++ b/drivers/staging/dgrp/dgrp_net_ops.c | |||
@@ -0,0 +1,3737 @@ | |||
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_net_ops.c | ||
23 | * | ||
24 | * Description: | ||
25 | * | ||
26 | * Handle the file operations required for the "network" devices. | ||
27 | * Includes those functions required to register the "net" devices | ||
28 | * in "/proc". | ||
29 | * | ||
30 | * Author: | ||
31 | * | ||
32 | * James A. Puzzo | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <linux/module.h> | ||
37 | #include <linux/proc_fs.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/string.h> | ||
40 | #include <linux/tty.h> | ||
41 | #include <linux/tty_flip.h> | ||
42 | #include <linux/spinlock.h> | ||
43 | #include <linux/poll.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/ratelimit.h> | ||
46 | #include <asm/unaligned.h> | ||
47 | |||
48 | #define MYFLIPLEN TBUF_MAX | ||
49 | |||
50 | #include "dgrp_common.h" | ||
51 | |||
52 | #define TTY_FLIPBUF_SIZE 512 | ||
53 | #define DEVICE_NAME_SIZE 50 | ||
54 | |||
55 | /* | ||
56 | * Generic helper function declarations | ||
57 | */ | ||
58 | static void parity_scan(struct ch_struct *ch, unsigned char *cbuf, | ||
59 | unsigned char *fbuf, int *len); | ||
60 | |||
61 | /* | ||
62 | * File operation declarations | ||
63 | */ | ||
64 | static int dgrp_net_open(struct inode *, struct file *); | ||
65 | static int dgrp_net_release(struct inode *, struct file *); | ||
66 | static ssize_t dgrp_net_read(struct file *, char __user *, size_t, loff_t *); | ||
67 | static ssize_t dgrp_net_write(struct file *, const char __user *, size_t, | ||
68 | loff_t *); | ||
69 | static long dgrp_net_ioctl(struct file *file, unsigned int cmd, | ||
70 | unsigned long arg); | ||
71 | static unsigned int dgrp_net_select(struct file *file, | ||
72 | struct poll_table_struct *table); | ||
73 | |||
74 | static const struct file_operations net_ops = { | ||
75 | .owner = THIS_MODULE, | ||
76 | .read = dgrp_net_read, | ||
77 | .write = dgrp_net_write, | ||
78 | .poll = dgrp_net_select, | ||
79 | .unlocked_ioctl = dgrp_net_ioctl, | ||
80 | .open = dgrp_net_open, | ||
81 | .release = dgrp_net_release, | ||
82 | }; | ||
83 | |||
84 | static struct inode_operations net_inode_ops = { | ||
85 | .permission = dgrp_inode_permission | ||
86 | }; | ||
87 | |||
88 | void dgrp_register_net_hook(struct proc_dir_entry *de) | ||
89 | { | ||
90 | struct nd_struct *node = de->data; | ||
91 | |||
92 | de->proc_iops = &net_inode_ops; | ||
93 | de->proc_fops = &net_ops; | ||
94 | node->nd_net_de = de; | ||
95 | sema_init(&node->nd_net_semaphore, 1); | ||
96 | node->nd_state = NS_CLOSED; | ||
97 | dgrp_create_node_class_sysfs_files(node); | ||
98 | } | ||
99 | |||
100 | |||
101 | /** | ||
102 | * dgrp_dump() -- prints memory for debugging purposes. | ||
103 | * @mem: Memory location which should be printed to the console | ||
104 | * @len: Number of bytes to be dumped | ||
105 | */ | ||
106 | static void dgrp_dump(u8 *mem, int len) | ||
107 | { | ||
108 | int i; | ||
109 | |||
110 | pr_debug("dgrp dump length = %d, data = ", len); | ||
111 | for (i = 0; i < len; ++i) | ||
112 | pr_debug("%.2x ", mem[i]); | ||
113 | pr_debug("\n"); | ||
114 | } | ||
115 | |||
116 | /** | ||
117 | * dgrp_read_data_block() -- Read a data block | ||
118 | * @ch: struct ch_struct * | ||
119 | * @flipbuf: u8 * | ||
120 | * @flipbuf_size: size of flipbuf | ||
121 | */ | ||
122 | static void dgrp_read_data_block(struct ch_struct *ch, u8 *flipbuf, | ||
123 | int flipbuf_size) | ||
124 | { | ||
125 | int t; | ||
126 | int n; | ||
127 | |||
128 | if (flipbuf_size <= 0) | ||
129 | return; | ||
130 | |||
131 | t = RBUF_MAX - ch->ch_rout; | ||
132 | n = flipbuf_size; | ||
133 | |||
134 | if (n >= t) { | ||
135 | memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, t); | ||
136 | flipbuf += t; | ||
137 | n -= t; | ||
138 | ch->ch_rout = 0; | ||
139 | } | ||
140 | |||
141 | memcpy(flipbuf, ch->ch_rbuf + ch->ch_rout, n); | ||
142 | flipbuf += n; | ||
143 | ch->ch_rout += n; | ||
144 | } | ||
145 | |||
146 | |||
147 | /** | ||
148 | * dgrp_input() -- send data to the line disipline | ||
149 | * @ch: pointer to channel struct | ||
150 | * | ||
151 | * Copys the rbuf to the flipbuf and sends to line discipline. | ||
152 | * Sends input buffer data to the line discipline. | ||
153 | * | ||
154 | * There are several modes to consider here: | ||
155 | * rawreadok, tty->real_raw, and IF_PARMRK | ||
156 | */ | ||
157 | static void dgrp_input(struct ch_struct *ch) | ||
158 | { | ||
159 | struct nd_struct *nd; | ||
160 | struct tty_struct *tty; | ||
161 | int remain; | ||
162 | int data_len; | ||
163 | int len; | ||
164 | int flip_len; | ||
165 | int tty_count; | ||
166 | ulong lock_flags; | ||
167 | struct tty_ldisc *ld; | ||
168 | u8 *myflipbuf; | ||
169 | u8 *myflipflagbuf; | ||
170 | |||
171 | if (!ch) | ||
172 | return; | ||
173 | |||
174 | nd = ch->ch_nd; | ||
175 | |||
176 | if (!nd) | ||
177 | return; | ||
178 | |||
179 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
180 | |||
181 | myflipbuf = nd->nd_inputbuf; | ||
182 | myflipflagbuf = nd->nd_inputflagbuf; | ||
183 | |||
184 | if (!ch->ch_open_count) { | ||
185 | ch->ch_rout = ch->ch_rin; | ||
186 | goto out; | ||
187 | } | ||
188 | |||
189 | if (ch->ch_tun.un_flag & UN_CLOSING) { | ||
190 | ch->ch_rout = ch->ch_rin; | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | tty = (ch->ch_tun).un_tty; | ||
195 | |||
196 | |||
197 | if (!tty || tty->magic != TTY_MAGIC) { | ||
198 | ch->ch_rout = ch->ch_rin; | ||
199 | goto out; | ||
200 | } | ||
201 | |||
202 | tty_count = tty->count; | ||
203 | if (!tty_count) { | ||
204 | ch->ch_rout = ch->ch_rin; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
208 | if (tty->closing || test_bit(TTY_CLOSING, &tty->flags)) { | ||
209 | ch->ch_rout = ch->ch_rin; | ||
210 | goto out; | ||
211 | } | ||
212 | |||
213 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
214 | |||
215 | /* Decide how much data we can send into the tty layer */ | ||
216 | if (dgrp_rawreadok && tty->real_raw) | ||
217 | flip_len = MYFLIPLEN; | ||
218 | else | ||
219 | flip_len = TTY_FLIPBUF_SIZE; | ||
220 | |||
221 | /* data_len should be the number of chars that we read in */ | ||
222 | data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK; | ||
223 | remain = data_len; | ||
224 | |||
225 | /* len is the amount of data we are going to transfer here */ | ||
226 | len = min(data_len, flip_len); | ||
227 | |||
228 | /* take into consideration length of ldisc */ | ||
229 | len = min(len, (N_TTY_BUF_SIZE - 1) - tty->read_cnt); | ||
230 | |||
231 | ld = tty_ldisc_ref(tty); | ||
232 | |||
233 | /* | ||
234 | * If we were unable to get a reference to the ld, | ||
235 | * don't flush our buffer, and act like the ld doesn't | ||
236 | * have any space to put the data right now. | ||
237 | */ | ||
238 | if (!ld) { | ||
239 | len = 0; | ||
240 | } else if (!ld->ops->receive_buf) { | ||
241 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
242 | ch->ch_rout = ch->ch_rin; | ||
243 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
244 | len = 0; | ||
245 | } | ||
246 | |||
247 | /* Check DPA flow control */ | ||
248 | if ((nd->nd_dpa_debug) && | ||
249 | (nd->nd_dpa_flag & DPA_WAIT_SPACE) && | ||
250 | (nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty)))) | ||
251 | len = 0; | ||
252 | |||
253 | if ((len) && !(ch->ch_flag & CH_RXSTOP)) { | ||
254 | |||
255 | dgrp_read_data_block(ch, myflipbuf, len); | ||
256 | |||
257 | /* | ||
258 | * In high performance mode, we don't have to update | ||
259 | * flag_buf or any of the counts or pointers into flip buf. | ||
260 | */ | ||
261 | if (!dgrp_rawreadok || !tty->real_raw) { | ||
262 | if (I_PARMRK(tty) || I_BRKINT(tty) || I_INPCK(tty)) | ||
263 | parity_scan(ch, myflipbuf, myflipflagbuf, &len); | ||
264 | else | ||
265 | memset(myflipflagbuf, TTY_NORMAL, len); | ||
266 | } | ||
267 | |||
268 | if ((nd->nd_dpa_debug) && | ||
269 | (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty))))) | ||
270 | dgrp_dpa_data(nd, 1, myflipbuf, len); | ||
271 | |||
272 | /* | ||
273 | * If we're doing raw reads, jam it right into the | ||
274 | * line disc bypassing the flip buffers. | ||
275 | */ | ||
276 | if (dgrp_rawreadok && tty->real_raw) | ||
277 | ld->ops->receive_buf(tty, myflipbuf, NULL, len); | ||
278 | else { | ||
279 | len = tty_buffer_request_room(tty, len); | ||
280 | tty_insert_flip_string_flags(tty, myflipbuf, | ||
281 | myflipflagbuf, len); | ||
282 | |||
283 | /* Tell the tty layer its okay to "eat" the data now */ | ||
284 | tty_flip_buffer_push(tty); | ||
285 | } | ||
286 | |||
287 | ch->ch_rxcount += len; | ||
288 | } | ||
289 | |||
290 | if (ld) | ||
291 | tty_ldisc_deref(ld); | ||
292 | |||
293 | /* | ||
294 | * Wake up any sleepers (maybe dgrp close) that might be waiting | ||
295 | * for a channel flag state change. | ||
296 | */ | ||
297 | wake_up_interruptible(&ch->ch_flag_wait); | ||
298 | return; | ||
299 | |||
300 | out: | ||
301 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
302 | } | ||
303 | |||
304 | |||
305 | /* | ||
306 | * parity_scan | ||
307 | * | ||
308 | * Loop to inspect each single character or 0xFF escape. | ||
309 | * | ||
310 | * if PARMRK & ~DOSMODE: | ||
311 | * 0xFF 0xFF Normal 0xFF character, escaped | ||
312 | * to eliminate confusion. | ||
313 | * 0xFF 0x00 0x00 Break | ||
314 | * 0xFF 0x00 CC Error character CC. | ||
315 | * CC Normal character CC. | ||
316 | * | ||
317 | * if PARMRK & DOSMODE: | ||
318 | * 0xFF 0x18 0x00 Break | ||
319 | * 0xFF 0x08 0x00 Framing Error | ||
320 | * 0xFF 0x04 0x00 Parity error | ||
321 | * 0xFF 0x0C 0x00 Both Framing and Parity error | ||
322 | * | ||
323 | * TODO: do we need to do the XMODEM, XOFF, XON, XANY processing?? | ||
324 | * as per protocol | ||
325 | */ | ||
326 | static void parity_scan(struct ch_struct *ch, unsigned char *cbuf, | ||
327 | unsigned char *fbuf, int *len) | ||
328 | { | ||
329 | int l = *len; | ||
330 | int count = 0; | ||
331 | int DOS = ((ch->ch_iflag & IF_DOSMODE) == 0 ? 0 : 1); | ||
332 | unsigned char *cout; /* character buffer */ | ||
333 | unsigned char *fout; /* flag buffer */ | ||
334 | unsigned char *in; | ||
335 | unsigned char c; | ||
336 | |||
337 | in = cbuf; | ||
338 | cout = cbuf; | ||
339 | fout = fbuf; | ||
340 | |||
341 | while (l--) { | ||
342 | c = *in; | ||
343 | in++; | ||
344 | |||
345 | switch (ch->ch_pscan_state) { | ||
346 | default: | ||
347 | /* reset to sanity and fall through */ | ||
348 | ch->ch_pscan_state = 0 ; | ||
349 | |||
350 | case 0: | ||
351 | /* No FF seen yet */ | ||
352 | if (c == 0xff) /* delete this character from stream */ | ||
353 | ch->ch_pscan_state = 1; | ||
354 | else { | ||
355 | *cout++ = c; | ||
356 | *fout++ = TTY_NORMAL; | ||
357 | count += 1; | ||
358 | } | ||
359 | break; | ||
360 | |||
361 | case 1: | ||
362 | /* first FF seen */ | ||
363 | if (c == 0xff) { | ||
364 | /* doubled ff, transform to single ff */ | ||
365 | *cout++ = c; | ||
366 | *fout++ = TTY_NORMAL; | ||
367 | count += 1; | ||
368 | ch->ch_pscan_state = 0; | ||
369 | } else { | ||
370 | /* save value examination in next state */ | ||
371 | ch->ch_pscan_savechar = c; | ||
372 | ch->ch_pscan_state = 2; | ||
373 | } | ||
374 | break; | ||
375 | |||
376 | case 2: | ||
377 | /* third character of ff sequence */ | ||
378 | *cout++ = c; | ||
379 | if (DOS) { | ||
380 | if (ch->ch_pscan_savechar & 0x10) | ||
381 | *fout++ = TTY_BREAK; | ||
382 | else if (ch->ch_pscan_savechar & 0x08) | ||
383 | *fout++ = TTY_FRAME; | ||
384 | else | ||
385 | /* | ||
386 | * either marked as a parity error, | ||
387 | * indeterminate, or not in DOSMODE | ||
388 | * call it a parity error | ||
389 | */ | ||
390 | *fout++ = TTY_PARITY; | ||
391 | } else { | ||
392 | /* case FF XX ?? where XX is not 00 */ | ||
393 | if (ch->ch_pscan_savechar & 0xff) { | ||
394 | /* this should not happen */ | ||
395 | pr_info("%s: parity_scan: error unexpected byte\n", | ||
396 | __func__); | ||
397 | *fout++ = TTY_PARITY; | ||
398 | } | ||
399 | /* case FF 00 XX where XX is not 00 */ | ||
400 | else if (c == 0xff) | ||
401 | *fout++ = TTY_PARITY; | ||
402 | /* case FF 00 00 */ | ||
403 | else | ||
404 | *fout++ = TTY_BREAK; | ||
405 | |||
406 | } | ||
407 | count += 1; | ||
408 | ch->ch_pscan_state = 0; | ||
409 | } | ||
410 | } | ||
411 | *len = count; | ||
412 | } | ||
413 | |||
414 | |||
415 | /** | ||
416 | * dgrp_net_idle() -- Idle the network connection | ||
417 | * @nd: pointer to node structure to idle | ||
418 | */ | ||
419 | static void dgrp_net_idle(struct nd_struct *nd) | ||
420 | { | ||
421 | struct ch_struct *ch; | ||
422 | int i; | ||
423 | |||
424 | nd->nd_tx_work = 1; | ||
425 | |||
426 | nd->nd_state = NS_IDLE; | ||
427 | nd->nd_flag = 0; | ||
428 | |||
429 | for (i = nd->nd_seq_out; ; i = (i + 1) & SEQ_MASK) { | ||
430 | if (!nd->nd_seq_wait[i]) { | ||
431 | nd->nd_seq_wait[i] = 0; | ||
432 | wake_up_interruptible(&nd->nd_seq_wque[i]); | ||
433 | } | ||
434 | |||
435 | if (i == nd->nd_seq_in) | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | nd->nd_seq_out = nd->nd_seq_in; | ||
440 | |||
441 | nd->nd_unack = 0; | ||
442 | nd->nd_remain = 0; | ||
443 | |||
444 | nd->nd_tx_module = 0x10; | ||
445 | nd->nd_rx_module = 0x00; | ||
446 | |||
447 | for (i = 0, ch = nd->nd_chan; i < CHAN_MAX; i++, ch++) { | ||
448 | ch->ch_state = CS_IDLE; | ||
449 | |||
450 | ch->ch_otype = 0; | ||
451 | ch->ch_otype_waiting = 0; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | * Increase the number of channels, waking up any | ||
457 | * threads that might be waiting for the channels | ||
458 | * to appear. | ||
459 | */ | ||
460 | static void increase_channel_count(struct nd_struct *nd, int n) | ||
461 | { | ||
462 | struct ch_struct *ch; | ||
463 | struct device *classp; | ||
464 | char name[DEVICE_NAME_SIZE]; | ||
465 | int ret; | ||
466 | u8 *buf; | ||
467 | int i; | ||
468 | |||
469 | for (i = nd->nd_chan_count; i < n; ++i) { | ||
470 | ch = nd->nd_chan + i; | ||
471 | |||
472 | /* FIXME: return a useful error instead! */ | ||
473 | buf = kmalloc(TBUF_MAX, GFP_KERNEL); | ||
474 | if (!buf) | ||
475 | return; | ||
476 | |||
477 | if (ch->ch_tbuf) | ||
478 | pr_info_ratelimited("%s - ch_tbuf was not NULL\n", | ||
479 | __func__); | ||
480 | |||
481 | ch->ch_tbuf = buf; | ||
482 | |||
483 | buf = kmalloc(RBUF_MAX, GFP_KERNEL); | ||
484 | if (!buf) | ||
485 | return; | ||
486 | |||
487 | if (ch->ch_rbuf) | ||
488 | pr_info("%s - ch_rbuf was not NULL\n", | ||
489 | __func__); | ||
490 | ch->ch_rbuf = buf; | ||
491 | |||
492 | classp = tty_port_register_device(&ch->port, | ||
493 | nd->nd_serial_ttdriver, i, | ||
494 | NULL); | ||
495 | |||
496 | ch->ch_tun.un_sysfs = classp; | ||
497 | snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i); | ||
498 | |||
499 | dgrp_create_tty_sysfs(&ch->ch_tun, classp); | ||
500 | ret = sysfs_create_link(&nd->nd_class_dev->kobj, | ||
501 | &classp->kobj, name); | ||
502 | |||
503 | /* NOTE: We don't support "cu" devices anymore, | ||
504 | * so you will notice we don't register them | ||
505 | * here anymore. */ | ||
506 | if (dgrp_register_prdevices) { | ||
507 | classp = tty_register_device(nd->nd_xprint_ttdriver, | ||
508 | i, NULL); | ||
509 | ch->ch_pun.un_sysfs = classp; | ||
510 | snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i); | ||
511 | |||
512 | dgrp_create_tty_sysfs(&ch->ch_pun, classp); | ||
513 | ret = sysfs_create_link(&nd->nd_class_dev->kobj, | ||
514 | &classp->kobj, name); | ||
515 | } | ||
516 | |||
517 | nd->nd_chan_count = i + 1; | ||
518 | wake_up_interruptible(&ch->ch_flag_wait); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Decrease the number of channels, and wake up any threads that might | ||
524 | * be waiting on the channels that vanished. | ||
525 | */ | ||
526 | static void decrease_channel_count(struct nd_struct *nd, int n) | ||
527 | { | ||
528 | struct ch_struct *ch; | ||
529 | char name[DEVICE_NAME_SIZE]; | ||
530 | int i; | ||
531 | |||
532 | for (i = nd->nd_chan_count - 1; i >= n; --i) { | ||
533 | ch = nd->nd_chan + i; | ||
534 | |||
535 | /* | ||
536 | * Make any open ports inoperative. | ||
537 | */ | ||
538 | ch->ch_state = CS_IDLE; | ||
539 | |||
540 | ch->ch_otype = 0; | ||
541 | ch->ch_otype_waiting = 0; | ||
542 | |||
543 | /* | ||
544 | * Only "HANGUP" if we care about carrier | ||
545 | * transitions and we are already open. | ||
546 | */ | ||
547 | if (ch->ch_open_count != 0) { | ||
548 | ch->ch_flag |= CH_HANGUP; | ||
549 | dgrp_carrier(ch); | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Unlike the CH_HANGUP flag above, use another | ||
554 | * flag to indicate to the RealPort state machine | ||
555 | * that this port has disappeared. | ||
556 | */ | ||
557 | if (ch->ch_open_count != 0) | ||
558 | ch->ch_flag |= CH_PORT_GONE; | ||
559 | |||
560 | wake_up_interruptible(&ch->ch_flag_wait); | ||
561 | |||
562 | nd->nd_chan_count = i; | ||
563 | |||
564 | kfree(ch->ch_tbuf); | ||
565 | ch->ch_tbuf = NULL; | ||
566 | |||
567 | kfree(ch->ch_rbuf); | ||
568 | ch->ch_rbuf = NULL; | ||
569 | |||
570 | nd->nd_chan_count = i; | ||
571 | |||
572 | dgrp_remove_tty_sysfs(ch->ch_tun.un_sysfs); | ||
573 | snprintf(name, DEVICE_NAME_SIZE, "tty_%d", i); | ||
574 | sysfs_remove_link(&nd->nd_class_dev->kobj, name); | ||
575 | tty_unregister_device(nd->nd_serial_ttdriver, i); | ||
576 | |||
577 | /* | ||
578 | * NOTE: We don't support "cu" devices anymore, so don't | ||
579 | * unregister them here anymore. | ||
580 | */ | ||
581 | |||
582 | if (dgrp_register_prdevices) { | ||
583 | dgrp_remove_tty_sysfs(ch->ch_pun.un_sysfs); | ||
584 | snprintf(name, DEVICE_NAME_SIZE, "pr_%d", i); | ||
585 | sysfs_remove_link(&nd->nd_class_dev->kobj, name); | ||
586 | tty_unregister_device(nd->nd_xprint_ttdriver, i); | ||
587 | } | ||
588 | } | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * dgrp_chan_count() -- Adjust the node channel count. | ||
593 | * @nd: pointer to a node structure | ||
594 | * @n: new value for channel count | ||
595 | * | ||
596 | * Adjusts the node channel count. If new ports have appeared, it tries | ||
597 | * to signal those processes that might have been waiting for ports to | ||
598 | * appear. If ports have disappeared it tries to signal those processes | ||
599 | * that might be hung waiting for a response for the now non-existant port. | ||
600 | */ | ||
601 | static void dgrp_chan_count(struct nd_struct *nd, int n) | ||
602 | { | ||
603 | if (n == nd->nd_chan_count) | ||
604 | return; | ||
605 | |||
606 | if (n > nd->nd_chan_count) | ||
607 | increase_channel_count(nd, n); | ||
608 | |||
609 | if (n < nd->nd_chan_count) | ||
610 | decrease_channel_count(nd, n); | ||
611 | } | ||
612 | |||
613 | /** | ||
614 | * dgrp_monitor() -- send data to the device monitor queue | ||
615 | * @nd: pointer to a node structure | ||
616 | * @buf: data to copy to the monitoring buffer | ||
617 | * @len: number of bytes to transfer to the buffer | ||
618 | * | ||
619 | * Called by the net device routines to send data to the device | ||
620 | * monitor queue. If the device monitor buffer is too full to | ||
621 | * accept the data, it waits until the buffer is ready. | ||
622 | */ | ||
623 | static void dgrp_monitor(struct nd_struct *nd, u8 *buf, int len) | ||
624 | { | ||
625 | int n; | ||
626 | int r; | ||
627 | int rtn; | ||
628 | |||
629 | /* | ||
630 | * Grab monitor lock. | ||
631 | */ | ||
632 | down(&nd->nd_mon_semaphore); | ||
633 | |||
634 | /* | ||
635 | * Loop while data remains. | ||
636 | */ | ||
637 | while ((len > 0) && (nd->nd_mon_buf)) { | ||
638 | /* | ||
639 | * Determine the amount of available space left in the | ||
640 | * buffer. If there's none, wait until some appears. | ||
641 | */ | ||
642 | |||
643 | n = (nd->nd_mon_out - nd->nd_mon_in - 1) & MON_MASK; | ||
644 | |||
645 | if (!n) { | ||
646 | nd->nd_mon_flag |= MON_WAIT_SPACE; | ||
647 | |||
648 | up(&nd->nd_mon_semaphore); | ||
649 | |||
650 | /* | ||
651 | * Go to sleep waiting until the condition becomes true. | ||
652 | */ | ||
653 | rtn = wait_event_interruptible(nd->nd_mon_wqueue, | ||
654 | ((nd->nd_mon_flag & MON_WAIT_SPACE) == 0)); | ||
655 | |||
656 | /* FIXME: really ignore rtn? */ | ||
657 | |||
658 | /* | ||
659 | * We can't exit here if we receive a signal, since | ||
660 | * to do so would trash the debug stream. | ||
661 | */ | ||
662 | |||
663 | down(&nd->nd_mon_semaphore); | ||
664 | |||
665 | continue; | ||
666 | } | ||
667 | |||
668 | /* | ||
669 | * Copy as much data as will fit. | ||
670 | */ | ||
671 | |||
672 | if (n > len) | ||
673 | n = len; | ||
674 | |||
675 | r = MON_MAX - nd->nd_mon_in; | ||
676 | |||
677 | if (r <= n) { | ||
678 | memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, r); | ||
679 | |||
680 | n -= r; | ||
681 | |||
682 | nd->nd_mon_in = 0; | ||
683 | |||
684 | buf += r; | ||
685 | len -= r; | ||
686 | } | ||
687 | |||
688 | memcpy(nd->nd_mon_buf + nd->nd_mon_in, buf, n); | ||
689 | |||
690 | nd->nd_mon_in += n; | ||
691 | |||
692 | buf += n; | ||
693 | len -= n; | ||
694 | |||
695 | if (nd->nd_mon_in >= MON_MAX) | ||
696 | pr_info_ratelimited("%s - nd_mon_in (%i) >= MON_MAX\n", | ||
697 | __func__, nd->nd_mon_in); | ||
698 | |||
699 | /* | ||
700 | * Wakeup any thread waiting for data | ||
701 | */ | ||
702 | |||
703 | if (nd->nd_mon_flag & MON_WAIT_DATA) { | ||
704 | nd->nd_mon_flag &= ~MON_WAIT_DATA; | ||
705 | wake_up_interruptible(&nd->nd_mon_wqueue); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Release the monitor lock. | ||
711 | */ | ||
712 | up(&nd->nd_mon_semaphore); | ||
713 | } | ||
714 | |||
715 | /** | ||
716 | * dgrp_encode_time() -- Encodes rpdump time into a 4-byte quantity. | ||
717 | * @nd: pointer to a node structure | ||
718 | * @buf: destination buffer | ||
719 | * | ||
720 | * Encodes "rpdump" time into a 4-byte quantity. Time is measured since | ||
721 | * open. | ||
722 | */ | ||
723 | static void dgrp_encode_time(struct nd_struct *nd, u8 *buf) | ||
724 | { | ||
725 | ulong t; | ||
726 | |||
727 | /* | ||
728 | * Convert time in HZ since open to time in milliseconds | ||
729 | * since open. | ||
730 | */ | ||
731 | t = jiffies - nd->nd_mon_lbolt; | ||
732 | t = 1000 * (t / HZ) + 1000 * (t % HZ) / HZ; | ||
733 | |||
734 | put_unaligned_be32((uint)(t & 0xffffffff), buf); | ||
735 | } | ||
736 | |||
737 | |||
738 | |||
739 | /** | ||
740 | * dgrp_monitor_message() -- Builds a rpdump style message. | ||
741 | * @nd: pointer to a node structure | ||
742 | * @message: destination buffer | ||
743 | */ | ||
744 | static void dgrp_monitor_message(struct nd_struct *nd, char *message) | ||
745 | { | ||
746 | u8 header[7]; | ||
747 | int n; | ||
748 | |||
749 | header[0] = RPDUMP_MESSAGE; | ||
750 | |||
751 | dgrp_encode_time(nd, header + 1); | ||
752 | |||
753 | n = strlen(message); | ||
754 | |||
755 | put_unaligned_be16(n, header + 5); | ||
756 | |||
757 | dgrp_monitor(nd, header, sizeof(header)); | ||
758 | dgrp_monitor(nd, (u8 *) message, n); | ||
759 | } | ||
760 | |||
761 | |||
762 | |||
763 | /** | ||
764 | * dgrp_monitor_reset() -- Note a reset in the monitoring buffer. | ||
765 | * @nd: pointer to a node structure | ||
766 | */ | ||
767 | static void dgrp_monitor_reset(struct nd_struct *nd) | ||
768 | { | ||
769 | u8 header[5]; | ||
770 | |||
771 | header[0] = RPDUMP_RESET; | ||
772 | |||
773 | dgrp_encode_time(nd, header + 1); | ||
774 | |||
775 | dgrp_monitor(nd, header, sizeof(header)); | ||
776 | } | ||
777 | |||
778 | /** | ||
779 | * dgrp_monitor_data() -- builds a monitor data packet | ||
780 | * @nd: pointer to a node structure | ||
781 | * @type: type of message to be logged | ||
782 | * @buf: data to be logged | ||
783 | * @size: number of bytes in the buffer | ||
784 | */ | ||
785 | static void dgrp_monitor_data(struct nd_struct *nd, u8 type, u8 *buf, int size) | ||
786 | { | ||
787 | u8 header[7]; | ||
788 | |||
789 | header[0] = type; | ||
790 | |||
791 | dgrp_encode_time(nd, header + 1); | ||
792 | |||
793 | put_unaligned_be16(size, header + 5); | ||
794 | |||
795 | dgrp_monitor(nd, header, sizeof(header)); | ||
796 | dgrp_monitor(nd, buf, size); | ||
797 | } | ||
798 | |||
799 | static int alloc_nd_buffers(struct nd_struct *nd) | ||
800 | { | ||
801 | |||
802 | nd->nd_iobuf = NULL; | ||
803 | nd->nd_writebuf = NULL; | ||
804 | nd->nd_inputbuf = NULL; | ||
805 | nd->nd_inputflagbuf = NULL; | ||
806 | |||
807 | /* | ||
808 | * Allocate the network read/write buffer. | ||
809 | */ | ||
810 | nd->nd_iobuf = kzalloc(UIO_MAX + 10, GFP_KERNEL); | ||
811 | if (!nd->nd_iobuf) | ||
812 | goto out_err; | ||
813 | |||
814 | /* | ||
815 | * Allocate a buffer for doing the copy from user space to | ||
816 | * kernel space in the write routines. | ||
817 | */ | ||
818 | nd->nd_writebuf = kzalloc(WRITEBUFLEN, GFP_KERNEL); | ||
819 | if (!nd->nd_writebuf) | ||
820 | goto out_err; | ||
821 | |||
822 | /* | ||
823 | * Allocate a buffer for doing the copy from kernel space to | ||
824 | * tty buffer space in the read routines. | ||
825 | */ | ||
826 | nd->nd_inputbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); | ||
827 | if (!nd->nd_inputbuf) | ||
828 | goto out_err; | ||
829 | |||
830 | /* | ||
831 | * Allocate a buffer for doing the copy from kernel space to | ||
832 | * tty buffer space in the read routines. | ||
833 | */ | ||
834 | nd->nd_inputflagbuf = kzalloc(MYFLIPLEN, GFP_KERNEL); | ||
835 | if (!nd->nd_inputflagbuf) | ||
836 | goto out_err; | ||
837 | |||
838 | return 0; | ||
839 | |||
840 | out_err: | ||
841 | kfree(nd->nd_iobuf); | ||
842 | kfree(nd->nd_writebuf); | ||
843 | kfree(nd->nd_inputbuf); | ||
844 | kfree(nd->nd_inputflagbuf); | ||
845 | return -ENOMEM; | ||
846 | } | ||
847 | |||
848 | /* | ||
849 | * dgrp_net_open() -- Open the NET device for a particular PortServer | ||
850 | */ | ||
851 | static int dgrp_net_open(struct inode *inode, struct file *file) | ||
852 | { | ||
853 | struct nd_struct *nd; | ||
854 | struct proc_dir_entry *de; | ||
855 | ulong lock_flags; | ||
856 | int rtn; | ||
857 | |||
858 | rtn = try_module_get(THIS_MODULE); | ||
859 | if (!rtn) | ||
860 | return -EAGAIN; | ||
861 | |||
862 | if (!capable(CAP_SYS_ADMIN)) { | ||
863 | rtn = -EPERM; | ||
864 | goto done; | ||
865 | } | ||
866 | |||
867 | /* | ||
868 | * Make sure that the "private_data" field hasn't already been used. | ||
869 | */ | ||
870 | if (file->private_data) { | ||
871 | rtn = -EINVAL; | ||
872 | goto done; | ||
873 | } | ||
874 | |||
875 | /* | ||
876 | * Get the node pointer, and fail if it doesn't exist. | ||
877 | */ | ||
878 | de = PDE(inode); | ||
879 | if (!de) { | ||
880 | rtn = -ENXIO; | ||
881 | goto done; | ||
882 | } | ||
883 | |||
884 | nd = (struct nd_struct *) de->data; | ||
885 | if (!nd) { | ||
886 | rtn = -ENXIO; | ||
887 | goto done; | ||
888 | } | ||
889 | |||
890 | file->private_data = (void *) nd; | ||
891 | |||
892 | /* | ||
893 | * Grab the NET lock. | ||
894 | */ | ||
895 | down(&nd->nd_net_semaphore); | ||
896 | |||
897 | if (nd->nd_state != NS_CLOSED) { | ||
898 | rtn = -EBUSY; | ||
899 | goto unlock; | ||
900 | } | ||
901 | |||
902 | /* | ||
903 | * Initialize the link speed parameters. | ||
904 | */ | ||
905 | |||
906 | nd->nd_link.lk_fast_rate = UIO_MAX; | ||
907 | nd->nd_link.lk_slow_rate = UIO_MAX; | ||
908 | |||
909 | nd->nd_link.lk_fast_delay = 1000; | ||
910 | nd->nd_link.lk_slow_delay = 1000; | ||
911 | |||
912 | nd->nd_link.lk_header_size = 46; | ||
913 | |||
914 | |||
915 | rtn = alloc_nd_buffers(nd); | ||
916 | if (rtn) | ||
917 | goto unlock; | ||
918 | |||
919 | /* | ||
920 | * The port is now open, so move it to the IDLE state | ||
921 | */ | ||
922 | dgrp_net_idle(nd); | ||
923 | |||
924 | nd->nd_tx_time = jiffies; | ||
925 | |||
926 | /* | ||
927 | * If the polling routing is not running, start it running here | ||
928 | */ | ||
929 | spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); | ||
930 | |||
931 | if (!dgrp_poll_data.node_active_count) { | ||
932 | dgrp_poll_data.node_active_count = 2; | ||
933 | dgrp_poll_data.timer.expires = jiffies + | ||
934 | dgrp_poll_tick * HZ / 1000; | ||
935 | add_timer(&dgrp_poll_data.timer); | ||
936 | } | ||
937 | |||
938 | spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); | ||
939 | |||
940 | dgrp_monitor_message(nd, "Net Open"); | ||
941 | |||
942 | unlock: | ||
943 | /* | ||
944 | * Release the NET lock. | ||
945 | */ | ||
946 | up(&nd->nd_net_semaphore); | ||
947 | |||
948 | done: | ||
949 | if (rtn) | ||
950 | module_put(THIS_MODULE); | ||
951 | |||
952 | return rtn; | ||
953 | } | ||
954 | |||
955 | /* dgrp_net_release() -- close the NET device for a particular PortServer */ | ||
956 | static int dgrp_net_release(struct inode *inode, struct file *file) | ||
957 | { | ||
958 | struct nd_struct *nd; | ||
959 | ulong lock_flags; | ||
960 | |||
961 | nd = (struct nd_struct *)(file->private_data); | ||
962 | if (!nd) | ||
963 | goto done; | ||
964 | |||
965 | /* TODO : historical locking placeholder */ | ||
966 | /* | ||
967 | * In the HPUX version of the RealPort driver (which served as a basis | ||
968 | * for this driver) this locking code was used. Saved if ever we need | ||
969 | * to review the locking under Linux. | ||
970 | */ | ||
971 | /* spinlock(&nd->nd_lock); */ | ||
972 | |||
973 | |||
974 | /* | ||
975 | * Grab the NET lock. | ||
976 | */ | ||
977 | down(&nd->nd_net_semaphore); | ||
978 | |||
979 | /* | ||
980 | * Before "closing" the internal connection, make sure all | ||
981 | * ports are "idle". | ||
982 | */ | ||
983 | dgrp_net_idle(nd); | ||
984 | |||
985 | nd->nd_state = NS_CLOSED; | ||
986 | nd->nd_flag = 0; | ||
987 | |||
988 | /* | ||
989 | * TODO ... must the wait queue be reset on close? | ||
990 | * should any pending waiters be reset? | ||
991 | * Let's decide to assert that the waitq is empty... and see | ||
992 | * how soon we break. | ||
993 | */ | ||
994 | if (waitqueue_active(&nd->nd_tx_waitq)) | ||
995 | pr_info("%s - expected waitqueue_active to be false\n", | ||
996 | __func__); | ||
997 | |||
998 | nd->nd_send = 0; | ||
999 | |||
1000 | kfree(nd->nd_iobuf); | ||
1001 | nd->nd_iobuf = NULL; | ||
1002 | |||
1003 | /* TODO : historical locking placeholder */ | ||
1004 | /* | ||
1005 | * In the HPUX version of the RealPort driver (which served as a basis | ||
1006 | * for this driver) this locking code was used. Saved if ever we need | ||
1007 | * to review the locking under Linux. | ||
1008 | */ | ||
1009 | /* spinunlock( &nd->nd_lock ); */ | ||
1010 | |||
1011 | |||
1012 | kfree(nd->nd_writebuf); | ||
1013 | nd->nd_writebuf = NULL; | ||
1014 | |||
1015 | kfree(nd->nd_inputbuf); | ||
1016 | nd->nd_inputbuf = NULL; | ||
1017 | |||
1018 | kfree(nd->nd_inputflagbuf); | ||
1019 | nd->nd_inputflagbuf = NULL; | ||
1020 | |||
1021 | /* TODO : historical locking placeholder */ | ||
1022 | /* | ||
1023 | * In the HPUX version of the RealPort driver (which served as a basis | ||
1024 | * for this driver) this locking code was used. Saved if ever we need | ||
1025 | * to review the locking under Linux. | ||
1026 | */ | ||
1027 | /* spinlock(&nd->nd_lock); */ | ||
1028 | |||
1029 | /* | ||
1030 | * Set the active port count to zero. | ||
1031 | */ | ||
1032 | dgrp_chan_count(nd, 0); | ||
1033 | |||
1034 | /* TODO : historical locking placeholder */ | ||
1035 | /* | ||
1036 | * In the HPUX version of the RealPort driver (which served as a basis | ||
1037 | * for this driver) this locking code was used. Saved if ever we need | ||
1038 | * to review the locking under Linux. | ||
1039 | */ | ||
1040 | /* spinunlock(&nd->nd_lock); */ | ||
1041 | |||
1042 | /* | ||
1043 | * Release the NET lock. | ||
1044 | */ | ||
1045 | up(&nd->nd_net_semaphore); | ||
1046 | |||
1047 | /* | ||
1048 | * Cause the poller to stop scheduling itself if this is | ||
1049 | * the last active node. | ||
1050 | */ | ||
1051 | spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); | ||
1052 | |||
1053 | if (dgrp_poll_data.node_active_count == 2) { | ||
1054 | del_timer(&dgrp_poll_data.timer); | ||
1055 | dgrp_poll_data.node_active_count = 0; | ||
1056 | } | ||
1057 | |||
1058 | spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); | ||
1059 | |||
1060 | done: | ||
1061 | down(&nd->nd_net_semaphore); | ||
1062 | |||
1063 | dgrp_monitor_message(nd, "Net Close"); | ||
1064 | |||
1065 | up(&nd->nd_net_semaphore); | ||
1066 | |||
1067 | module_put(THIS_MODULE); | ||
1068 | file->private_data = NULL; | ||
1069 | return 0; | ||
1070 | } | ||
1071 | |||
1072 | /* used in dgrp_send to setup command header */ | ||
1073 | static inline u8 *set_cmd_header(u8 *b, u8 port, u8 cmd) | ||
1074 | { | ||
1075 | *b++ = 0xb0 + (port & 0x0f); | ||
1076 | *b++ = cmd; | ||
1077 | return b; | ||
1078 | } | ||
1079 | |||
1080 | /** | ||
1081 | * dgrp_send() -- build a packet for transmission to the server | ||
1082 | * @nd: pointer to a node structure | ||
1083 | * @tmax: maximum bytes to transmit | ||
1084 | * | ||
1085 | * returns number of bytes sent | ||
1086 | */ | ||
1087 | static int dgrp_send(struct nd_struct *nd, long tmax) | ||
1088 | { | ||
1089 | struct ch_struct *ch = nd->nd_chan; | ||
1090 | u8 *b; | ||
1091 | u8 *buf; | ||
1092 | u8 *mbuf; | ||
1093 | u8 port; | ||
1094 | int mod; | ||
1095 | long send; | ||
1096 | int maxport; | ||
1097 | long lastport = -1; | ||
1098 | ushort rwin; | ||
1099 | long in; | ||
1100 | ushort n; | ||
1101 | long t; | ||
1102 | long ttotal; | ||
1103 | long tchan; | ||
1104 | long tsend; | ||
1105 | ushort tsafe; | ||
1106 | long work; | ||
1107 | long send_sync; | ||
1108 | long wanted_sync_port = -1; | ||
1109 | ushort tdata[CHAN_MAX]; | ||
1110 | long used_buffer; | ||
1111 | |||
1112 | mbuf = nd->nd_iobuf + UIO_BASE; | ||
1113 | buf = b = mbuf; | ||
1114 | |||
1115 | send_sync = nd->nd_link.lk_slow_rate < UIO_MAX; | ||
1116 | |||
1117 | ttotal = 0; | ||
1118 | tchan = 0; | ||
1119 | |||
1120 | memset(tdata, 0, sizeof(tdata)); | ||
1121 | |||
1122 | |||
1123 | /* | ||
1124 | * If there are any outstanding requests to be serviced, | ||
1125 | * service them here. | ||
1126 | */ | ||
1127 | if (nd->nd_send & NR_PASSWORD) { | ||
1128 | |||
1129 | /* | ||
1130 | * Send Password response. | ||
1131 | */ | ||
1132 | |||
1133 | b[0] = 0xfc; | ||
1134 | b[1] = 0x20; | ||
1135 | put_unaligned_be16(strlen(nd->password), b + 2); | ||
1136 | b += 4; | ||
1137 | b += strlen(nd->password); | ||
1138 | nd->nd_send &= ~(NR_PASSWORD); | ||
1139 | } | ||
1140 | |||
1141 | |||
1142 | /* | ||
1143 | * Loop over all modules to generate commands, and determine | ||
1144 | * the amount of data queued for transmit. | ||
1145 | */ | ||
1146 | |||
1147 | for (mod = 0, port = 0; port < nd->nd_chan_count; mod++) { | ||
1148 | /* | ||
1149 | * If this is not the current module, enter a module select | ||
1150 | * code in the buffer. | ||
1151 | */ | ||
1152 | |||
1153 | if (mod != nd->nd_tx_module) | ||
1154 | mbuf = ++b; | ||
1155 | |||
1156 | /* | ||
1157 | * Loop to process one module. | ||
1158 | */ | ||
1159 | |||
1160 | maxport = port + 16; | ||
1161 | |||
1162 | if (maxport > nd->nd_chan_count) | ||
1163 | maxport = nd->nd_chan_count; | ||
1164 | |||
1165 | for (; port < maxport; port++, ch++) { | ||
1166 | /* | ||
1167 | * Switch based on channel state. | ||
1168 | */ | ||
1169 | |||
1170 | switch (ch->ch_state) { | ||
1171 | /* | ||
1172 | * Send requests when the port is closed, and there | ||
1173 | * are no Open, Close or Cancel requests expected. | ||
1174 | */ | ||
1175 | |||
1176 | case CS_IDLE: | ||
1177 | /* | ||
1178 | * Wait until any open error code | ||
1179 | * has been delivered to all | ||
1180 | * associated ports. | ||
1181 | */ | ||
1182 | |||
1183 | if (ch->ch_open_error) { | ||
1184 | if (ch->ch_wait_count[ch->ch_otype]) { | ||
1185 | work = 1; | ||
1186 | break; | ||
1187 | } | ||
1188 | |||
1189 | ch->ch_open_error = 0; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * Wait until the channel HANGUP flag is reset | ||
1194 | * before sending the first open. We can only | ||
1195 | * get to this state after a server disconnect. | ||
1196 | */ | ||
1197 | |||
1198 | if ((ch->ch_flag & CH_HANGUP) != 0) | ||
1199 | break; | ||
1200 | |||
1201 | /* | ||
1202 | * If recovering from a TCP disconnect, or if | ||
1203 | * there is an immediate open pending, send an | ||
1204 | * Immediate Open request. | ||
1205 | */ | ||
1206 | if ((ch->ch_flag & CH_PORT_GONE) || | ||
1207 | ch->ch_wait_count[OTYPE_IMMEDIATE] != 0) { | ||
1208 | b = set_cmd_header(b, port, 10); | ||
1209 | *b++ = 0; | ||
1210 | |||
1211 | ch->ch_state = CS_WAIT_OPEN; | ||
1212 | ch->ch_otype = OTYPE_IMMEDIATE; | ||
1213 | break; | ||
1214 | } | ||
1215 | |||
1216 | /* | ||
1217 | * If there is no Persistent or Incoming Open on the wait | ||
1218 | * list in the server, and a thread is waiting for a | ||
1219 | * Persistent or Incoming Open, send a Persistent or Incoming | ||
1220 | * Open Request. | ||
1221 | */ | ||
1222 | if (ch->ch_otype_waiting == 0) { | ||
1223 | if (ch->ch_wait_count[OTYPE_PERSISTENT] != 0) { | ||
1224 | b = set_cmd_header(b, port, 10); | ||
1225 | *b++ = 1; | ||
1226 | |||
1227 | ch->ch_state = CS_WAIT_OPEN; | ||
1228 | ch->ch_otype = OTYPE_PERSISTENT; | ||
1229 | } else if (ch->ch_wait_count[OTYPE_INCOMING] != 0) { | ||
1230 | b = set_cmd_header(b, port, 10); | ||
1231 | *b++ = 2; | ||
1232 | |||
1233 | ch->ch_state = CS_WAIT_OPEN; | ||
1234 | ch->ch_otype = OTYPE_INCOMING; | ||
1235 | } | ||
1236 | break; | ||
1237 | } | ||
1238 | |||
1239 | /* | ||
1240 | * If a Persistent or Incoming Open is pending in | ||
1241 | * the server, but there is no longer an open | ||
1242 | * thread waiting for it, cancel the request. | ||
1243 | */ | ||
1244 | |||
1245 | if (ch->ch_wait_count[ch->ch_otype_waiting] == 0) { | ||
1246 | b = set_cmd_header(b, port, 10); | ||
1247 | *b++ = 4; | ||
1248 | |||
1249 | ch->ch_state = CS_WAIT_CANCEL; | ||
1250 | ch->ch_otype = ch->ch_otype_waiting; | ||
1251 | } | ||
1252 | break; | ||
1253 | |||
1254 | /* | ||
1255 | * Send port parameter queries. | ||
1256 | */ | ||
1257 | case CS_SEND_QUERY: | ||
1258 | /* | ||
1259 | * Clear out all FEP state that might remain | ||
1260 | * from the last connection. | ||
1261 | */ | ||
1262 | |||
1263 | ch->ch_flag |= CH_PARAM; | ||
1264 | |||
1265 | ch->ch_flag &= ~CH_RX_FLUSH; | ||
1266 | |||
1267 | ch->ch_expect = 0; | ||
1268 | |||
1269 | ch->ch_s_tin = 0; | ||
1270 | ch->ch_s_tpos = 0; | ||
1271 | ch->ch_s_tsize = 0; | ||
1272 | ch->ch_s_treq = 0; | ||
1273 | ch->ch_s_elast = 0; | ||
1274 | |||
1275 | ch->ch_s_rin = 0; | ||
1276 | ch->ch_s_rwin = 0; | ||
1277 | ch->ch_s_rsize = 0; | ||
1278 | |||
1279 | ch->ch_s_tmax = 0; | ||
1280 | ch->ch_s_ttime = 0; | ||
1281 | ch->ch_s_rmax = 0; | ||
1282 | ch->ch_s_rtime = 0; | ||
1283 | ch->ch_s_rlow = 0; | ||
1284 | ch->ch_s_rhigh = 0; | ||
1285 | |||
1286 | ch->ch_s_brate = 0; | ||
1287 | ch->ch_s_iflag = 0; | ||
1288 | ch->ch_s_cflag = 0; | ||
1289 | ch->ch_s_oflag = 0; | ||
1290 | ch->ch_s_xflag = 0; | ||
1291 | |||
1292 | ch->ch_s_mout = 0; | ||
1293 | ch->ch_s_mflow = 0; | ||
1294 | ch->ch_s_mctrl = 0; | ||
1295 | ch->ch_s_xon = 0; | ||
1296 | ch->ch_s_xoff = 0; | ||
1297 | ch->ch_s_lnext = 0; | ||
1298 | ch->ch_s_xxon = 0; | ||
1299 | ch->ch_s_xxoff = 0; | ||
1300 | |||
1301 | /* Send Sequence Request */ | ||
1302 | b = set_cmd_header(b, port, 14); | ||
1303 | |||
1304 | /* Configure Event Conditions Packet */ | ||
1305 | b = set_cmd_header(b, port, 42); | ||
1306 | put_unaligned_be16(0x02c0, b); | ||
1307 | b += 2; | ||
1308 | *b++ = (DM_DTR | DM_RTS | DM_CTS | | ||
1309 | DM_DSR | DM_RI | DM_CD); | ||
1310 | |||
1311 | /* Send Status Request */ | ||
1312 | b = set_cmd_header(b, port, 16); | ||
1313 | |||
1314 | /* Send Buffer Request */ | ||
1315 | b = set_cmd_header(b, port, 20); | ||
1316 | |||
1317 | /* Send Port Capability Request */ | ||
1318 | b = set_cmd_header(b, port, 22); | ||
1319 | |||
1320 | ch->ch_expect = (RR_SEQUENCE | | ||
1321 | RR_STATUS | | ||
1322 | RR_BUFFER | | ||
1323 | RR_CAPABILITY); | ||
1324 | |||
1325 | ch->ch_state = CS_WAIT_QUERY; | ||
1326 | |||
1327 | /* Raise modem signals */ | ||
1328 | b = set_cmd_header(b, port, 44); | ||
1329 | |||
1330 | if (ch->ch_flag & CH_PORT_GONE) | ||
1331 | ch->ch_s_mout = ch->ch_mout; | ||
1332 | else | ||
1333 | ch->ch_s_mout = ch->ch_mout = DM_DTR | DM_RTS; | ||
1334 | |||
1335 | *b++ = ch->ch_mout; | ||
1336 | *b++ = ch->ch_s_mflow = 0; | ||
1337 | *b++ = ch->ch_s_mctrl = ch->ch_mctrl = 0; | ||
1338 | |||
1339 | if (ch->ch_flag & CH_PORT_GONE) | ||
1340 | ch->ch_flag &= ~CH_PORT_GONE; | ||
1341 | |||
1342 | break; | ||
1343 | |||
1344 | /* | ||
1345 | * Handle normal open and ready mode. | ||
1346 | */ | ||
1347 | |||
1348 | case CS_READY: | ||
1349 | |||
1350 | /* | ||
1351 | * If the port is not open, and there are no | ||
1352 | * no longer any ports requesting an open, | ||
1353 | * then close the port. | ||
1354 | */ | ||
1355 | |||
1356 | if (ch->ch_open_count == 0 && | ||
1357 | ch->ch_wait_count[ch->ch_otype] == 0) { | ||
1358 | goto send_close; | ||
1359 | } | ||
1360 | |||
1361 | /* | ||
1362 | * Process waiting input. | ||
1363 | * | ||
1364 | * If there is no one to read it, discard the data. | ||
1365 | * | ||
1366 | * Otherwise if we are not in fastcook mode, or if there is a | ||
1367 | * fastcook thread waiting for data, send the data to the | ||
1368 | * line discipline. | ||
1369 | */ | ||
1370 | if (ch->ch_rin != ch->ch_rout) { | ||
1371 | if (ch->ch_tun.un_open_count == 0 || | ||
1372 | (ch->ch_tun.un_flag & UN_CLOSING) || | ||
1373 | (ch->ch_cflag & CF_CREAD) == 0) { | ||
1374 | ch->ch_rout = ch->ch_rin; | ||
1375 | } else if ((ch->ch_flag & CH_FAST_READ) == 0 || | ||
1376 | ch->ch_inwait != 0) { | ||
1377 | dgrp_input(ch); | ||
1378 | |||
1379 | if (ch->ch_rin != ch->ch_rout) | ||
1380 | work = 1; | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | /* | ||
1385 | * Handle receive flush, and changes to | ||
1386 | * server port parameters. | ||
1387 | */ | ||
1388 | |||
1389 | if (ch->ch_flag & (CH_RX_FLUSH | CH_PARAM)) { | ||
1390 | /* | ||
1391 | * If we are in receive flush mode, | ||
1392 | * and enough data has gone by, reset | ||
1393 | * receive flush mode. | ||
1394 | */ | ||
1395 | if (ch->ch_flag & CH_RX_FLUSH) { | ||
1396 | if (((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) > | ||
1397 | ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) | ||
1398 | ch->ch_flag &= ~CH_RX_FLUSH; | ||
1399 | else | ||
1400 | work = 1; | ||
1401 | } | ||
1402 | |||
1403 | /* | ||
1404 | * Send TMAX, TTIME. | ||
1405 | */ | ||
1406 | |||
1407 | if (ch->ch_s_tmax != ch->ch_tmax || | ||
1408 | ch->ch_s_ttime != ch->ch_ttime) { | ||
1409 | b = set_cmd_header(b, port, 48); | ||
1410 | |||
1411 | ch->ch_s_tmax = ch->ch_tmax; | ||
1412 | ch->ch_s_ttime = ch->ch_ttime; | ||
1413 | |||
1414 | put_unaligned_be16(ch->ch_s_tmax, | ||
1415 | b); | ||
1416 | b += 2; | ||
1417 | |||
1418 | put_unaligned_be16(ch->ch_s_ttime, | ||
1419 | b); | ||
1420 | b += 2; | ||
1421 | } | ||
1422 | |||
1423 | /* | ||
1424 | * Send RLOW, RHIGH. | ||
1425 | */ | ||
1426 | |||
1427 | if (ch->ch_s_rlow != ch->ch_rlow || | ||
1428 | ch->ch_s_rhigh != ch->ch_rhigh) { | ||
1429 | b = set_cmd_header(b, port, 45); | ||
1430 | |||
1431 | ch->ch_s_rlow = ch->ch_rlow; | ||
1432 | ch->ch_s_rhigh = ch->ch_rhigh; | ||
1433 | |||
1434 | put_unaligned_be16(ch->ch_s_rlow, | ||
1435 | b); | ||
1436 | b += 2; | ||
1437 | |||
1438 | put_unaligned_be16(ch->ch_s_rhigh, | ||
1439 | b); | ||
1440 | b += 2; | ||
1441 | } | ||
1442 | |||
1443 | /* | ||
1444 | * Send BRATE, CFLAG, IFLAG, | ||
1445 | * OFLAG, XFLAG. | ||
1446 | */ | ||
1447 | |||
1448 | if (ch->ch_s_brate != ch->ch_brate || | ||
1449 | ch->ch_s_cflag != ch->ch_cflag || | ||
1450 | ch->ch_s_iflag != ch->ch_iflag || | ||
1451 | ch->ch_s_oflag != ch->ch_oflag || | ||
1452 | ch->ch_s_xflag != ch->ch_xflag) { | ||
1453 | b = set_cmd_header(b, port, 40); | ||
1454 | |||
1455 | ch->ch_s_brate = ch->ch_brate; | ||
1456 | ch->ch_s_cflag = ch->ch_cflag; | ||
1457 | ch->ch_s_iflag = ch->ch_iflag; | ||
1458 | ch->ch_s_oflag = ch->ch_oflag; | ||
1459 | ch->ch_s_xflag = ch->ch_xflag; | ||
1460 | |||
1461 | put_unaligned_be16(ch->ch_s_brate, | ||
1462 | b); | ||
1463 | b += 2; | ||
1464 | |||
1465 | put_unaligned_be16(ch->ch_s_cflag, | ||
1466 | b); | ||
1467 | b += 2; | ||
1468 | |||
1469 | put_unaligned_be16(ch->ch_s_iflag, | ||
1470 | b); | ||
1471 | b += 2; | ||
1472 | |||
1473 | put_unaligned_be16(ch->ch_s_oflag, | ||
1474 | b); | ||
1475 | b += 2; | ||
1476 | |||
1477 | put_unaligned_be16(ch->ch_s_xflag, | ||
1478 | b); | ||
1479 | b += 2; | ||
1480 | } | ||
1481 | |||
1482 | /* | ||
1483 | * Send MOUT, MFLOW, MCTRL. | ||
1484 | */ | ||
1485 | |||
1486 | if (ch->ch_s_mout != ch->ch_mout || | ||
1487 | ch->ch_s_mflow != ch->ch_mflow || | ||
1488 | ch->ch_s_mctrl != ch->ch_mctrl) { | ||
1489 | b = set_cmd_header(b, port, 44); | ||
1490 | |||
1491 | *b++ = ch->ch_s_mout = ch->ch_mout; | ||
1492 | *b++ = ch->ch_s_mflow = ch->ch_mflow; | ||
1493 | *b++ = ch->ch_s_mctrl = ch->ch_mctrl; | ||
1494 | } | ||
1495 | |||
1496 | /* | ||
1497 | * Send Flow control characters. | ||
1498 | */ | ||
1499 | |||
1500 | if (ch->ch_s_xon != ch->ch_xon || | ||
1501 | ch->ch_s_xoff != ch->ch_xoff || | ||
1502 | ch->ch_s_lnext != ch->ch_lnext || | ||
1503 | ch->ch_s_xxon != ch->ch_xxon || | ||
1504 | ch->ch_s_xxoff != ch->ch_xxoff) { | ||
1505 | b = set_cmd_header(b, port, 46); | ||
1506 | |||
1507 | *b++ = ch->ch_s_xon = ch->ch_xon; | ||
1508 | *b++ = ch->ch_s_xoff = ch->ch_xoff; | ||
1509 | *b++ = ch->ch_s_lnext = ch->ch_lnext; | ||
1510 | *b++ = ch->ch_s_xxon = ch->ch_xxon; | ||
1511 | *b++ = ch->ch_s_xxoff = ch->ch_xxoff; | ||
1512 | } | ||
1513 | |||
1514 | /* | ||
1515 | * Send RMAX, RTIME. | ||
1516 | */ | ||
1517 | |||
1518 | if (ch->ch_s_rmax != ch->ch_rmax || | ||
1519 | ch->ch_s_rtime != ch->ch_rtime) { | ||
1520 | b = set_cmd_header(b, port, 47); | ||
1521 | |||
1522 | ch->ch_s_rmax = ch->ch_rmax; | ||
1523 | ch->ch_s_rtime = ch->ch_rtime; | ||
1524 | |||
1525 | put_unaligned_be16(ch->ch_s_rmax, | ||
1526 | b); | ||
1527 | b += 2; | ||
1528 | |||
1529 | put_unaligned_be16(ch->ch_s_rtime, | ||
1530 | b); | ||
1531 | b += 2; | ||
1532 | } | ||
1533 | |||
1534 | ch->ch_flag &= ~CH_PARAM; | ||
1535 | wake_up_interruptible(&ch->ch_flag_wait); | ||
1536 | } | ||
1537 | |||
1538 | |||
1539 | /* | ||
1540 | * Handle action commands. | ||
1541 | */ | ||
1542 | |||
1543 | if (ch->ch_send != 0) { | ||
1544 | /* int send = ch->ch_send & ~ch->ch_expect; */ | ||
1545 | send = ch->ch_send & ~ch->ch_expect; | ||
1546 | |||
1547 | /* Send character immediate */ | ||
1548 | if ((send & RR_TX_ICHAR) != 0) { | ||
1549 | b = set_cmd_header(b, port, 60); | ||
1550 | |||
1551 | *b++ = ch->ch_xon; | ||
1552 | ch->ch_expect |= RR_TX_ICHAR; | ||
1553 | } | ||
1554 | |||
1555 | /* BREAK request */ | ||
1556 | if ((send & RR_TX_BREAK) != 0) { | ||
1557 | if (ch->ch_break_time != 0) { | ||
1558 | b = set_cmd_header(b, port, 61); | ||
1559 | put_unaligned_be16(ch->ch_break_time, | ||
1560 | b); | ||
1561 | b += 2; | ||
1562 | |||
1563 | ch->ch_expect |= RR_TX_BREAK; | ||
1564 | ch->ch_break_time = 0; | ||
1565 | } else { | ||
1566 | ch->ch_send &= ~RR_TX_BREAK; | ||
1567 | ch->ch_flag &= ~CH_TX_BREAK; | ||
1568 | wake_up_interruptible(&ch->ch_flag_wait); | ||
1569 | } | ||
1570 | } | ||
1571 | |||
1572 | /* | ||
1573 | * Flush input/output buffers. | ||
1574 | */ | ||
1575 | |||
1576 | if ((send & (RR_RX_FLUSH | RR_TX_FLUSH)) != 0) { | ||
1577 | b = set_cmd_header(b, port, 62); | ||
1578 | |||
1579 | *b++ = ((send & RR_TX_FLUSH) == 0 ? 1 : | ||
1580 | (send & RR_RX_FLUSH) == 0 ? 2 : 3); | ||
1581 | |||
1582 | if (send & RR_RX_FLUSH) { | ||
1583 | ch->ch_flush_seq = nd->nd_seq_in; | ||
1584 | ch->ch_flag |= CH_RX_FLUSH; | ||
1585 | work = 1; | ||
1586 | send_sync = 1; | ||
1587 | wanted_sync_port = port; | ||
1588 | } | ||
1589 | |||
1590 | ch->ch_send &= ~(RR_RX_FLUSH | RR_TX_FLUSH); | ||
1591 | } | ||
1592 | |||
1593 | /* Pause input/output */ | ||
1594 | if ((send & (RR_RX_STOP | RR_TX_STOP)) != 0) { | ||
1595 | b = set_cmd_header(b, port, 63); | ||
1596 | *b = 0; | ||
1597 | |||
1598 | if ((send & RR_TX_STOP) != 0) | ||
1599 | *b |= EV_OPU; | ||
1600 | |||
1601 | if ((send & RR_RX_STOP) != 0) | ||
1602 | *b |= EV_IPU; | ||
1603 | |||
1604 | b++; | ||
1605 | |||
1606 | ch->ch_send &= ~(RR_RX_STOP | RR_TX_STOP); | ||
1607 | } | ||
1608 | |||
1609 | /* Start input/output */ | ||
1610 | if ((send & (RR_RX_START | RR_TX_START)) != 0) { | ||
1611 | b = set_cmd_header(b, port, 64); | ||
1612 | *b = 0; | ||
1613 | |||
1614 | if ((send & RR_TX_START) != 0) | ||
1615 | *b |= EV_OPU | EV_OPS | EV_OPX; | ||
1616 | |||
1617 | if ((send & RR_RX_START) != 0) | ||
1618 | *b |= EV_IPU | EV_IPS; | ||
1619 | |||
1620 | b++; | ||
1621 | |||
1622 | ch->ch_send &= ~(RR_RX_START | RR_TX_START); | ||
1623 | } | ||
1624 | } | ||
1625 | |||
1626 | |||
1627 | /* | ||
1628 | * Send a window sequence to acknowledge received data. | ||
1629 | */ | ||
1630 | |||
1631 | rwin = (ch->ch_s_rin + | ||
1632 | ((ch->ch_rout - ch->ch_rin - 1) & RBUF_MASK)); | ||
1633 | |||
1634 | n = (rwin - ch->ch_s_rwin) & 0xffff; | ||
1635 | |||
1636 | if (n >= RBUF_MAX / 4) { | ||
1637 | b[0] = 0xa0 + (port & 0xf); | ||
1638 | ch->ch_s_rwin = rwin; | ||
1639 | put_unaligned_be16(rwin, b + 1); | ||
1640 | b += 3; | ||
1641 | } | ||
1642 | |||
1643 | /* | ||
1644 | * If the terminal is waiting on LOW | ||
1645 | * water or EMPTY, and the condition | ||
1646 | * is now satisfied, call the line | ||
1647 | * discipline to put more data in the | ||
1648 | * buffer. | ||
1649 | */ | ||
1650 | |||
1651 | n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1652 | |||
1653 | if ((ch->ch_tun.un_flag & (UN_EMPTY|UN_LOW)) != 0) { | ||
1654 | if ((ch->ch_tun.un_flag & UN_LOW) != 0 ? | ||
1655 | (n <= TBUF_LOW) : | ||
1656 | (n == 0 && ch->ch_s_tpos == ch->ch_s_tin)) { | ||
1657 | ch->ch_tun.un_flag &= ~(UN_EMPTY|UN_LOW); | ||
1658 | |||
1659 | if (waitqueue_active(&((ch->ch_tun.un_tty)->write_wait))) | ||
1660 | wake_up_interruptible(&((ch->ch_tun.un_tty)->write_wait)); | ||
1661 | tty_wakeup(ch->ch_tun.un_tty); | ||
1662 | n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1663 | } | ||
1664 | } | ||
1665 | |||
1666 | /* | ||
1667 | * If the printer is waiting on LOW | ||
1668 | * water, TIME, EMPTY or PWAIT, and is | ||
1669 | * now ready to put more data in the | ||
1670 | * buffer, call the line discipline to | ||
1671 | * do the job. | ||
1672 | */ | ||
1673 | |||
1674 | if (ch->ch_pun.un_open_count && | ||
1675 | (ch->ch_pun.un_flag & | ||
1676 | (UN_EMPTY|UN_TIME|UN_LOW|UN_PWAIT)) != 0) { | ||
1677 | |||
1678 | if ((ch->ch_pun.un_flag & UN_LOW) != 0 ? | ||
1679 | (n <= TBUF_LOW) : | ||
1680 | (ch->ch_pun.un_flag & UN_TIME) != 0 ? | ||
1681 | ((jiffies - ch->ch_waketime) >= 0) : | ||
1682 | (n == 0 && ch->ch_s_tpos == ch->ch_s_tin) && | ||
1683 | ((ch->ch_pun.un_flag & UN_EMPTY) != 0 || | ||
1684 | ((ch->ch_tun.un_open_count && | ||
1685 | ch->ch_tun.un_tty->ops->chars_in_buffer) ? | ||
1686 | (ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) == 0 | ||
1687 | : 1 | ||
1688 | ) | ||
1689 | )) { | ||
1690 | ch->ch_pun.un_flag &= ~(UN_EMPTY | UN_TIME | UN_LOW | UN_PWAIT); | ||
1691 | |||
1692 | if (waitqueue_active(&((ch->ch_pun.un_tty)->write_wait))) | ||
1693 | wake_up_interruptible(&((ch->ch_pun.un_tty)->write_wait)); | ||
1694 | tty_wakeup(ch->ch_pun.un_tty); | ||
1695 | n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1696 | |||
1697 | } else if ((ch->ch_pun.un_flag & UN_TIME) != 0) { | ||
1698 | work = 1; | ||
1699 | } | ||
1700 | } | ||
1701 | |||
1702 | |||
1703 | /* | ||
1704 | * Determine the max number of bytes | ||
1705 | * this port can send, including | ||
1706 | * packet header overhead. | ||
1707 | */ | ||
1708 | |||
1709 | t = ((ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff); | ||
1710 | |||
1711 | if (n > t) | ||
1712 | n = t; | ||
1713 | |||
1714 | if (n != 0) { | ||
1715 | n += (n <= 8 ? 1 : n <= 255 ? 2 : 3); | ||
1716 | |||
1717 | tdata[tchan++] = n; | ||
1718 | ttotal += n; | ||
1719 | } | ||
1720 | break; | ||
1721 | |||
1722 | /* | ||
1723 | * Close the port. | ||
1724 | */ | ||
1725 | |||
1726 | send_close: | ||
1727 | case CS_SEND_CLOSE: | ||
1728 | b = set_cmd_header(b, port, 10); | ||
1729 | if (ch->ch_otype == OTYPE_IMMEDIATE) | ||
1730 | *b++ = 3; | ||
1731 | else | ||
1732 | *b++ = 4; | ||
1733 | |||
1734 | ch->ch_state = CS_WAIT_CLOSE; | ||
1735 | break; | ||
1736 | |||
1737 | /* | ||
1738 | * Wait for a previous server request. | ||
1739 | */ | ||
1740 | |||
1741 | case CS_WAIT_OPEN: | ||
1742 | case CS_WAIT_CANCEL: | ||
1743 | case CS_WAIT_FAIL: | ||
1744 | case CS_WAIT_QUERY: | ||
1745 | case CS_WAIT_CLOSE: | ||
1746 | break; | ||
1747 | |||
1748 | default: | ||
1749 | pr_info("%s - unexpected channel state (%i)\n", | ||
1750 | __func__, ch->ch_state); | ||
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | /* | ||
1755 | * If a module select code is needed, drop one in. If space | ||
1756 | * was reserved for one, but none is needed, recover the space. | ||
1757 | */ | ||
1758 | |||
1759 | if (mod != nd->nd_tx_module) { | ||
1760 | if (b != mbuf) { | ||
1761 | mbuf[-1] = 0xf0 | mod; | ||
1762 | nd->nd_tx_module = mod; | ||
1763 | } else { | ||
1764 | b--; | ||
1765 | } | ||
1766 | } | ||
1767 | } | ||
1768 | |||
1769 | /* | ||
1770 | * Adjust "tmax" so that under worst case conditions we do | ||
1771 | * not overflow either the daemon buffer or the internal | ||
1772 | * buffer in the loop that follows. Leave a safe area | ||
1773 | * of 64 bytes so we start getting asserts before we start | ||
1774 | * losing data or clobbering memory. | ||
1775 | */ | ||
1776 | |||
1777 | n = UIO_MAX - UIO_BASE; | ||
1778 | |||
1779 | if (tmax > n) | ||
1780 | tmax = n; | ||
1781 | |||
1782 | tmax -= 64; | ||
1783 | |||
1784 | tsafe = tmax; | ||
1785 | |||
1786 | /* | ||
1787 | * Allocate space for 5 Module Selects, 1 Sequence Request, | ||
1788 | * and 1 Set TREQ for each active channel. | ||
1789 | */ | ||
1790 | |||
1791 | tmax -= 5 + 3 + 4 * nd->nd_chan_count; | ||
1792 | |||
1793 | /* | ||
1794 | * Further reduce "tmax" to the available transmit credit. | ||
1795 | * Note that this is a soft constraint; The transmit credit | ||
1796 | * can go negative for a time and then recover. | ||
1797 | */ | ||
1798 | |||
1799 | n = nd->nd_tx_deposit - nd->nd_tx_charge - nd->nd_link.lk_header_size; | ||
1800 | |||
1801 | if (tmax > n) | ||
1802 | tmax = n; | ||
1803 | |||
1804 | /* | ||
1805 | * Finally reduce tmax by the number of bytes already in | ||
1806 | * the buffer. | ||
1807 | */ | ||
1808 | |||
1809 | tmax -= b - buf; | ||
1810 | |||
1811 | /* | ||
1812 | * Suspend data transmit unless every ready channel can send | ||
1813 | * at least 1 character. | ||
1814 | */ | ||
1815 | if (tmax < 2 * nd->nd_chan_count) { | ||
1816 | tsend = 1; | ||
1817 | |||
1818 | } else if (tchan > 1 && ttotal > tmax) { | ||
1819 | |||
1820 | /* | ||
1821 | * If transmit is limited by the credit budget, find the | ||
1822 | * largest number of characters we can send without driving | ||
1823 | * the credit negative. | ||
1824 | */ | ||
1825 | |||
1826 | long tm = tmax; | ||
1827 | int tc = tchan; | ||
1828 | int try; | ||
1829 | |||
1830 | tsend = tm / tc; | ||
1831 | |||
1832 | for (try = 0; try < 3; try++) { | ||
1833 | int i; | ||
1834 | int c = 0; | ||
1835 | |||
1836 | for (i = 0; i < tc; i++) { | ||
1837 | if (tsend < tdata[i]) | ||
1838 | tdata[c++] = tdata[i]; | ||
1839 | else | ||
1840 | tm -= tdata[i]; | ||
1841 | } | ||
1842 | |||
1843 | if (c == tc) | ||
1844 | break; | ||
1845 | |||
1846 | tsend = tm / c; | ||
1847 | |||
1848 | if (c == 1) | ||
1849 | break; | ||
1850 | |||
1851 | tc = c; | ||
1852 | } | ||
1853 | |||
1854 | tsend = tm / nd->nd_chan_count; | ||
1855 | |||
1856 | if (tsend < 2) | ||
1857 | tsend = 1; | ||
1858 | |||
1859 | } else { | ||
1860 | /* | ||
1861 | * If no budgetary constraints, or only one channel ready | ||
1862 | * to send, set the character limit to the remaining | ||
1863 | * buffer size. | ||
1864 | */ | ||
1865 | |||
1866 | tsend = tmax; | ||
1867 | } | ||
1868 | |||
1869 | tsend -= (tsend <= 9) ? 1 : (tsend <= 257) ? 2 : 3; | ||
1870 | |||
1871 | /* | ||
1872 | * Loop over all channels, sending queued data. | ||
1873 | */ | ||
1874 | |||
1875 | port = 0; | ||
1876 | ch = nd->nd_chan; | ||
1877 | used_buffer = tmax; | ||
1878 | |||
1879 | for (mod = 0; port < nd->nd_chan_count; mod++) { | ||
1880 | /* | ||
1881 | * If this is not the current module, enter a module select | ||
1882 | * code in the buffer. | ||
1883 | */ | ||
1884 | |||
1885 | if (mod != nd->nd_tx_module) | ||
1886 | mbuf = ++b; | ||
1887 | |||
1888 | /* | ||
1889 | * Loop to process one module. | ||
1890 | */ | ||
1891 | |||
1892 | maxport = port + 16; | ||
1893 | |||
1894 | if (maxport > nd->nd_chan_count) | ||
1895 | maxport = nd->nd_chan_count; | ||
1896 | |||
1897 | for (; port < maxport; port++, ch++) { | ||
1898 | if (ch->ch_state != CS_READY) | ||
1899 | continue; | ||
1900 | |||
1901 | lastport = port; | ||
1902 | |||
1903 | n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1904 | |||
1905 | /* | ||
1906 | * If there is data that can be sent, send it. | ||
1907 | */ | ||
1908 | |||
1909 | if (n != 0 && used_buffer > 0) { | ||
1910 | t = (ch->ch_s_tsize + ch->ch_s_tpos - ch->ch_s_tin) & 0xffff; | ||
1911 | |||
1912 | if (n > t) | ||
1913 | n = t; | ||
1914 | |||
1915 | if (n > tsend) { | ||
1916 | work = 1; | ||
1917 | n = tsend; | ||
1918 | } | ||
1919 | |||
1920 | if (n > used_buffer) { | ||
1921 | work = 1; | ||
1922 | n = used_buffer; | ||
1923 | } | ||
1924 | |||
1925 | if (n <= 0) | ||
1926 | continue; | ||
1927 | |||
1928 | /* | ||
1929 | * Create the correct size transmit header, | ||
1930 | * depending on the amount of data to transmit. | ||
1931 | */ | ||
1932 | |||
1933 | if (n <= 8) { | ||
1934 | |||
1935 | b[0] = ((n - 1) << 4) + (port & 0xf); | ||
1936 | b += 1; | ||
1937 | |||
1938 | } else if (n <= 255) { | ||
1939 | |||
1940 | b[0] = 0x80 + (port & 0xf); | ||
1941 | b[1] = n; | ||
1942 | b += 2; | ||
1943 | |||
1944 | } else { | ||
1945 | |||
1946 | b[0] = 0x90 + (port & 0xf); | ||
1947 | put_unaligned_be16(n, b + 1); | ||
1948 | b += 3; | ||
1949 | } | ||
1950 | |||
1951 | ch->ch_s_tin = (ch->ch_s_tin + n) & 0xffff; | ||
1952 | |||
1953 | /* | ||
1954 | * Copy transmit data to the packet. | ||
1955 | */ | ||
1956 | |||
1957 | t = TBUF_MAX - ch->ch_tout; | ||
1958 | |||
1959 | if (n >= t) { | ||
1960 | memcpy(b, ch->ch_tbuf + ch->ch_tout, t); | ||
1961 | b += t; | ||
1962 | n -= t; | ||
1963 | used_buffer -= t; | ||
1964 | ch->ch_tout = 0; | ||
1965 | } | ||
1966 | |||
1967 | memcpy(b, ch->ch_tbuf + ch->ch_tout, n); | ||
1968 | b += n; | ||
1969 | used_buffer -= n; | ||
1970 | ch->ch_tout += n; | ||
1971 | n = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1972 | } | ||
1973 | |||
1974 | /* | ||
1975 | * Wake any terminal unit process waiting in the | ||
1976 | * dgrp_write routine for low water. | ||
1977 | */ | ||
1978 | |||
1979 | if (n > TBUF_LOW) | ||
1980 | continue; | ||
1981 | |||
1982 | if ((ch->ch_flag & CH_LOW) != 0) { | ||
1983 | ch->ch_flag &= ~CH_LOW; | ||
1984 | wake_up_interruptible(&ch->ch_flag_wait); | ||
1985 | } | ||
1986 | |||
1987 | /* selwakeup tty_sel */ | ||
1988 | if (ch->ch_tun.un_open_count) { | ||
1989 | struct tty_struct *tty = (ch->ch_tun.un_tty); | ||
1990 | |||
1991 | if (waitqueue_active(&tty->write_wait)) | ||
1992 | wake_up_interruptible(&tty->write_wait); | ||
1993 | |||
1994 | tty_wakeup(tty); | ||
1995 | } | ||
1996 | |||
1997 | if (ch->ch_pun.un_open_count) { | ||
1998 | struct tty_struct *tty = (ch->ch_pun.un_tty); | ||
1999 | |||
2000 | if (waitqueue_active(&tty->write_wait)) | ||
2001 | wake_up_interruptible(&tty->write_wait); | ||
2002 | |||
2003 | tty_wakeup(tty); | ||
2004 | } | ||
2005 | |||
2006 | /* | ||
2007 | * Do EMPTY processing. | ||
2008 | */ | ||
2009 | |||
2010 | if (n != 0) | ||
2011 | continue; | ||
2012 | |||
2013 | if ((ch->ch_flag & (CH_EMPTY | CH_DRAIN)) != 0 || | ||
2014 | (ch->ch_pun.un_flag & UN_EMPTY) != 0) { | ||
2015 | /* | ||
2016 | * If there is still data in the server, ask the server | ||
2017 | * to notify us when its all gone. | ||
2018 | */ | ||
2019 | |||
2020 | if (ch->ch_s_treq != ch->ch_s_tin) { | ||
2021 | b = set_cmd_header(b, port, 43); | ||
2022 | |||
2023 | ch->ch_s_treq = ch->ch_s_tin; | ||
2024 | put_unaligned_be16(ch->ch_s_treq, | ||
2025 | b); | ||
2026 | b += 2; | ||
2027 | } | ||
2028 | |||
2029 | /* | ||
2030 | * If there is a thread waiting for buffer empty, | ||
2031 | * and we are truly empty, wake the thread. | ||
2032 | */ | ||
2033 | |||
2034 | else if ((ch->ch_flag & CH_EMPTY) != 0 && | ||
2035 | (ch->ch_send & RR_TX_BREAK) == 0) { | ||
2036 | ch->ch_flag &= ~CH_EMPTY; | ||
2037 | |||
2038 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2039 | } | ||
2040 | } | ||
2041 | } | ||
2042 | |||
2043 | /* | ||
2044 | * If a module select code is needed, drop one in. If space | ||
2045 | * was reserved for one, but none is needed, recover the space. | ||
2046 | */ | ||
2047 | |||
2048 | if (mod != nd->nd_tx_module) { | ||
2049 | if (b != mbuf) { | ||
2050 | mbuf[-1] = 0xf0 | mod; | ||
2051 | nd->nd_tx_module = mod; | ||
2052 | } else { | ||
2053 | b--; | ||
2054 | } | ||
2055 | } | ||
2056 | } | ||
2057 | |||
2058 | /* | ||
2059 | * Send a synchronization sequence associated with the last open | ||
2060 | * channel that sent data, and remember the time when the data was | ||
2061 | * sent. | ||
2062 | */ | ||
2063 | |||
2064 | in = nd->nd_seq_in; | ||
2065 | |||
2066 | if ((send_sync || nd->nd_seq_wait[in] != 0) && lastport >= 0) { | ||
2067 | u8 *bb = b; | ||
2068 | |||
2069 | /* | ||
2070 | * Attempt the use the port that really wanted the sync. | ||
2071 | * This gets around a race condition where the "lastport" is in | ||
2072 | * the middle of the close() routine, and by the time we | ||
2073 | * send this command, it will have already acked the close, and | ||
2074 | * thus not send the sync response. | ||
2075 | */ | ||
2076 | if (wanted_sync_port >= 0) | ||
2077 | lastport = wanted_sync_port; | ||
2078 | /* | ||
2079 | * Set a flag just in case the port is in the middle of a close, | ||
2080 | * it will not be permitted to actually close until we get an | ||
2081 | * sync response, and clear the flag there. | ||
2082 | */ | ||
2083 | ch = nd->nd_chan + lastport; | ||
2084 | ch->ch_flag |= CH_WAITING_SYNC; | ||
2085 | |||
2086 | mod = lastport >> 4; | ||
2087 | |||
2088 | if (mod != nd->nd_tx_module) { | ||
2089 | bb[0] = 0xf0 + mod; | ||
2090 | bb += 1; | ||
2091 | |||
2092 | nd->nd_tx_module = mod; | ||
2093 | } | ||
2094 | |||
2095 | bb = set_cmd_header(bb, lastport, 12); | ||
2096 | *bb++ = in; | ||
2097 | |||
2098 | nd->nd_seq_size[in] = bb - buf; | ||
2099 | nd->nd_seq_time[in] = jiffies; | ||
2100 | |||
2101 | if (++in >= SEQ_MAX) | ||
2102 | in = 0; | ||
2103 | |||
2104 | if (in != nd->nd_seq_out) { | ||
2105 | b = bb; | ||
2106 | nd->nd_seq_in = in; | ||
2107 | nd->nd_unack += b - buf; | ||
2108 | } | ||
2109 | } | ||
2110 | |||
2111 | /* | ||
2112 | * If there are no open ports, a sync cannot be sent. | ||
2113 | * There is nothing left to wait for anyway, so wake any | ||
2114 | * thread waiting for an acknowledgement. | ||
2115 | */ | ||
2116 | |||
2117 | else if (nd->nd_seq_wait[in] != 0) { | ||
2118 | nd->nd_seq_wait[in] = 0; | ||
2119 | |||
2120 | wake_up_interruptible(&nd->nd_seq_wque[in]); | ||
2121 | } | ||
2122 | |||
2123 | /* | ||
2124 | * If there is no traffic for an interval of IDLE_MAX, then | ||
2125 | * send a single byte packet. | ||
2126 | */ | ||
2127 | |||
2128 | if (b != buf) { | ||
2129 | nd->nd_tx_time = jiffies; | ||
2130 | } else if ((ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX) { | ||
2131 | *b++ = 0xf0 | nd->nd_tx_module; | ||
2132 | nd->nd_tx_time = jiffies; | ||
2133 | } | ||
2134 | |||
2135 | n = b - buf; | ||
2136 | |||
2137 | if (n >= tsafe) | ||
2138 | pr_info("%s - n(%i) >= tsafe(%i)\n", | ||
2139 | __func__, n, tsafe); | ||
2140 | |||
2141 | if (tsend < 0) | ||
2142 | dgrp_dump(buf, n); | ||
2143 | |||
2144 | nd->nd_tx_work = work; | ||
2145 | |||
2146 | return n; | ||
2147 | } | ||
2148 | |||
2149 | /* | ||
2150 | * dgrp_net_read() | ||
2151 | * Data to be sent TO the PortServer from the "async." half of the driver. | ||
2152 | */ | ||
2153 | static ssize_t dgrp_net_read(struct file *file, char __user *buf, size_t count, | ||
2154 | loff_t *ppos) | ||
2155 | { | ||
2156 | struct nd_struct *nd; | ||
2157 | long n; | ||
2158 | u8 *local_buf; | ||
2159 | u8 *b; | ||
2160 | ssize_t rtn; | ||
2161 | |||
2162 | /* | ||
2163 | * Get the node pointer, and quit if it doesn't exist. | ||
2164 | */ | ||
2165 | nd = (struct nd_struct *)(file->private_data); | ||
2166 | if (!nd) | ||
2167 | return -ENXIO; | ||
2168 | |||
2169 | if (count < UIO_MIN) | ||
2170 | return -EINVAL; | ||
2171 | |||
2172 | /* | ||
2173 | * Only one read/write operation may be in progress at | ||
2174 | * any given time. | ||
2175 | */ | ||
2176 | |||
2177 | /* | ||
2178 | * Grab the NET lock. | ||
2179 | */ | ||
2180 | down(&nd->nd_net_semaphore); | ||
2181 | |||
2182 | nd->nd_read_count++; | ||
2183 | |||
2184 | nd->nd_tx_ready = 0; | ||
2185 | |||
2186 | /* | ||
2187 | * Determine the effective size of the buffer. | ||
2188 | */ | ||
2189 | |||
2190 | if (nd->nd_remain > UIO_BASE) | ||
2191 | pr_info_ratelimited("%s - nd_remain(%i) > UIO_BASE\n", | ||
2192 | __func__, nd->nd_remain); | ||
2193 | |||
2194 | b = local_buf = nd->nd_iobuf + UIO_BASE; | ||
2195 | |||
2196 | /* | ||
2197 | * Generate data according to the node state. | ||
2198 | */ | ||
2199 | |||
2200 | switch (nd->nd_state) { | ||
2201 | /* | ||
2202 | * Initialize the connection. | ||
2203 | */ | ||
2204 | |||
2205 | case NS_IDLE: | ||
2206 | if (nd->nd_mon_buf) | ||
2207 | dgrp_monitor_reset(nd); | ||
2208 | |||
2209 | /* | ||
2210 | * Request a Product ID Packet. | ||
2211 | */ | ||
2212 | |||
2213 | b[0] = 0xfb; | ||
2214 | b[1] = 0x01; | ||
2215 | b += 2; | ||
2216 | |||
2217 | nd->nd_expect |= NR_IDENT; | ||
2218 | |||
2219 | /* | ||
2220 | * Request a Server Capability ID Response. | ||
2221 | */ | ||
2222 | |||
2223 | b[0] = 0xfb; | ||
2224 | b[1] = 0x02; | ||
2225 | b += 2; | ||
2226 | |||
2227 | nd->nd_expect |= NR_CAPABILITY; | ||
2228 | |||
2229 | /* | ||
2230 | * Request a Server VPD Response. | ||
2231 | */ | ||
2232 | |||
2233 | b[0] = 0xfb; | ||
2234 | b[1] = 0x18; | ||
2235 | b += 2; | ||
2236 | |||
2237 | nd->nd_expect |= NR_VPD; | ||
2238 | |||
2239 | nd->nd_state = NS_WAIT_QUERY; | ||
2240 | break; | ||
2241 | |||
2242 | /* | ||
2243 | * We do serious communication with the server only in | ||
2244 | * the READY state. | ||
2245 | */ | ||
2246 | |||
2247 | case NS_READY: | ||
2248 | b = dgrp_send(nd, count) + local_buf; | ||
2249 | break; | ||
2250 | |||
2251 | /* | ||
2252 | * Send off an error after receiving a bogus message | ||
2253 | * from the server. | ||
2254 | */ | ||
2255 | |||
2256 | case NS_SEND_ERROR: | ||
2257 | n = strlen(nd->nd_error); | ||
2258 | |||
2259 | b[0] = 0xff; | ||
2260 | b[1] = n; | ||
2261 | memcpy(b + 2, nd->nd_error, n); | ||
2262 | b += 2 + n; | ||
2263 | |||
2264 | dgrp_net_idle(nd); | ||
2265 | /* | ||
2266 | * Set the active port count to zero. | ||
2267 | */ | ||
2268 | dgrp_chan_count(nd, 0); | ||
2269 | break; | ||
2270 | |||
2271 | default: | ||
2272 | break; | ||
2273 | } | ||
2274 | |||
2275 | n = b - local_buf; | ||
2276 | |||
2277 | if (n != 0) { | ||
2278 | nd->nd_send_count++; | ||
2279 | |||
2280 | nd->nd_tx_byte += n + nd->nd_link.lk_header_size; | ||
2281 | nd->nd_tx_charge += n + nd->nd_link.lk_header_size; | ||
2282 | } | ||
2283 | |||
2284 | rtn = copy_to_user((void __user *)buf, local_buf, n); | ||
2285 | if (rtn) { | ||
2286 | rtn = -EFAULT; | ||
2287 | goto done; | ||
2288 | } | ||
2289 | |||
2290 | *ppos += n; | ||
2291 | |||
2292 | rtn = n; | ||
2293 | |||
2294 | if (nd->nd_mon_buf) | ||
2295 | dgrp_monitor_data(nd, RPDUMP_CLIENT, local_buf, n); | ||
2296 | |||
2297 | /* | ||
2298 | * Release the NET lock. | ||
2299 | */ | ||
2300 | done: | ||
2301 | up(&nd->nd_net_semaphore); | ||
2302 | |||
2303 | return rtn; | ||
2304 | } | ||
2305 | |||
2306 | /** | ||
2307 | * dgrp_receive() -- decode data packets received from the remote PortServer. | ||
2308 | * @nd: pointer to a node structure | ||
2309 | */ | ||
2310 | static void dgrp_receive(struct nd_struct *nd) | ||
2311 | { | ||
2312 | struct ch_struct *ch; | ||
2313 | u8 *buf; | ||
2314 | u8 *b; | ||
2315 | u8 *dbuf; | ||
2316 | char *error; | ||
2317 | long port; | ||
2318 | long dlen; | ||
2319 | long plen; | ||
2320 | long remain; | ||
2321 | long n; | ||
2322 | long mlast; | ||
2323 | long elast; | ||
2324 | long mstat; | ||
2325 | long estat; | ||
2326 | |||
2327 | char ID[3]; | ||
2328 | |||
2329 | nd->nd_tx_time = jiffies; | ||
2330 | |||
2331 | ID_TO_CHAR(nd->nd_ID, ID); | ||
2332 | |||
2333 | b = buf = nd->nd_iobuf; | ||
2334 | remain = nd->nd_remain; | ||
2335 | |||
2336 | /* | ||
2337 | * Loop to process Realport protocol packets. | ||
2338 | */ | ||
2339 | |||
2340 | while (remain > 0) { | ||
2341 | int n0 = b[0] >> 4; | ||
2342 | int n1 = b[0] & 0x0f; | ||
2343 | |||
2344 | if (n0 <= 12) { | ||
2345 | port = (nd->nd_rx_module << 4) + n1; | ||
2346 | |||
2347 | if (port >= nd->nd_chan_count) { | ||
2348 | error = "Improper Port Number"; | ||
2349 | goto prot_error; | ||
2350 | } | ||
2351 | |||
2352 | ch = nd->nd_chan + port; | ||
2353 | } else { | ||
2354 | port = -1; | ||
2355 | ch = NULL; | ||
2356 | } | ||
2357 | |||
2358 | /* | ||
2359 | * Process by major packet type. | ||
2360 | */ | ||
2361 | |||
2362 | switch (n0) { | ||
2363 | |||
2364 | /* | ||
2365 | * Process 1-byte header data packet. | ||
2366 | */ | ||
2367 | |||
2368 | case 0: | ||
2369 | case 1: | ||
2370 | case 2: | ||
2371 | case 3: | ||
2372 | case 4: | ||
2373 | case 5: | ||
2374 | case 6: | ||
2375 | case 7: | ||
2376 | dlen = n0 + 1; | ||
2377 | plen = dlen + 1; | ||
2378 | |||
2379 | dbuf = b + 1; | ||
2380 | goto data; | ||
2381 | |||
2382 | /* | ||
2383 | * Process 2-byte header data packet. | ||
2384 | */ | ||
2385 | |||
2386 | case 8: | ||
2387 | if (remain < 3) | ||
2388 | goto done; | ||
2389 | |||
2390 | dlen = b[1]; | ||
2391 | plen = dlen + 2; | ||
2392 | |||
2393 | dbuf = b + 2; | ||
2394 | goto data; | ||
2395 | |||
2396 | /* | ||
2397 | * Process 3-byte header data packet. | ||
2398 | */ | ||
2399 | |||
2400 | case 9: | ||
2401 | if (remain < 4) | ||
2402 | goto done; | ||
2403 | |||
2404 | dlen = get_unaligned_be16(b + 1); | ||
2405 | plen = dlen + 3; | ||
2406 | |||
2407 | dbuf = b + 3; | ||
2408 | |||
2409 | /* | ||
2410 | * Common packet handling code. | ||
2411 | */ | ||
2412 | |||
2413 | data: | ||
2414 | nd->nd_tx_work = 1; | ||
2415 | |||
2416 | /* | ||
2417 | * Otherwise data should appear only when we are | ||
2418 | * in the CS_READY state. | ||
2419 | */ | ||
2420 | |||
2421 | if (ch->ch_state < CS_READY) { | ||
2422 | error = "Data received before RWIN established"; | ||
2423 | goto prot_error; | ||
2424 | } | ||
2425 | |||
2426 | /* | ||
2427 | * Assure that the data received is within the | ||
2428 | * allowable window. | ||
2429 | */ | ||
2430 | |||
2431 | n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff; | ||
2432 | |||
2433 | if (dlen > n) { | ||
2434 | error = "Receive data overrun"; | ||
2435 | goto prot_error; | ||
2436 | } | ||
2437 | |||
2438 | /* | ||
2439 | * If we received 3 or less characters, | ||
2440 | * assume it is a human typing, and set RTIME | ||
2441 | * to 10 milliseconds. | ||
2442 | * | ||
2443 | * If we receive 10 or more characters, | ||
2444 | * assume its not a human typing, and set RTIME | ||
2445 | * to 100 milliseconds. | ||
2446 | */ | ||
2447 | |||
2448 | if (ch->ch_edelay != DGRP_RTIME) { | ||
2449 | if (ch->ch_rtime != ch->ch_edelay) { | ||
2450 | ch->ch_rtime = ch->ch_edelay; | ||
2451 | ch->ch_flag |= CH_PARAM; | ||
2452 | } | ||
2453 | } else if (dlen <= 3) { | ||
2454 | if (ch->ch_rtime != 10) { | ||
2455 | ch->ch_rtime = 10; | ||
2456 | ch->ch_flag |= CH_PARAM; | ||
2457 | } | ||
2458 | } else { | ||
2459 | if (ch->ch_rtime != DGRP_RTIME) { | ||
2460 | ch->ch_rtime = DGRP_RTIME; | ||
2461 | ch->ch_flag |= CH_PARAM; | ||
2462 | } | ||
2463 | } | ||
2464 | |||
2465 | /* | ||
2466 | * If a portion of the packet is outside the | ||
2467 | * buffer, shorten the effective length of the | ||
2468 | * data packet to be the amount of data received. | ||
2469 | */ | ||
2470 | |||
2471 | if (remain < plen) | ||
2472 | dlen -= plen - remain; | ||
2473 | |||
2474 | /* | ||
2475 | * Detect if receive flush is now complete. | ||
2476 | */ | ||
2477 | |||
2478 | if ((ch->ch_flag & CH_RX_FLUSH) != 0 && | ||
2479 | ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >= | ||
2480 | ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { | ||
2481 | ch->ch_flag &= ~CH_RX_FLUSH; | ||
2482 | } | ||
2483 | |||
2484 | /* | ||
2485 | * If we are ready to receive, move the data into | ||
2486 | * the receive buffer. | ||
2487 | */ | ||
2488 | |||
2489 | ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff; | ||
2490 | |||
2491 | if (ch->ch_state == CS_READY && | ||
2492 | (ch->ch_tun.un_open_count != 0) && | ||
2493 | (ch->ch_tun.un_flag & UN_CLOSING) == 0 && | ||
2494 | (ch->ch_cflag & CF_CREAD) != 0 && | ||
2495 | (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 && | ||
2496 | (ch->ch_send & RR_RX_FLUSH) == 0) { | ||
2497 | |||
2498 | if (ch->ch_rin + dlen >= RBUF_MAX) { | ||
2499 | n = RBUF_MAX - ch->ch_rin; | ||
2500 | |||
2501 | memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n); | ||
2502 | |||
2503 | ch->ch_rin = 0; | ||
2504 | dbuf += n; | ||
2505 | dlen -= n; | ||
2506 | } | ||
2507 | |||
2508 | memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen); | ||
2509 | |||
2510 | ch->ch_rin += dlen; | ||
2511 | |||
2512 | |||
2513 | /* | ||
2514 | * If we are not in fastcook mode, or | ||
2515 | * if there is a fastcook thread | ||
2516 | * waiting for data, send the data to | ||
2517 | * the line discipline. | ||
2518 | */ | ||
2519 | |||
2520 | if ((ch->ch_flag & CH_FAST_READ) == 0 || | ||
2521 | ch->ch_inwait != 0) { | ||
2522 | dgrp_input(ch); | ||
2523 | } | ||
2524 | |||
2525 | /* | ||
2526 | * If there is a read thread waiting | ||
2527 | * in select, and we are in fastcook | ||
2528 | * mode, wake him up. | ||
2529 | */ | ||
2530 | |||
2531 | if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) && | ||
2532 | (ch->ch_flag & CH_FAST_READ) != 0) | ||
2533 | wake_up_interruptible(&ch->ch_tun.un_tty->read_wait); | ||
2534 | |||
2535 | /* | ||
2536 | * Wake any thread waiting in the | ||
2537 | * fastcook loop. | ||
2538 | */ | ||
2539 | |||
2540 | if ((ch->ch_flag & CH_INPUT) != 0) { | ||
2541 | ch->ch_flag &= ~CH_INPUT; | ||
2542 | |||
2543 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2544 | } | ||
2545 | } | ||
2546 | |||
2547 | /* | ||
2548 | * Fabricate and insert a data packet header to | ||
2549 | * preceed the remaining data when it comes in. | ||
2550 | */ | ||
2551 | |||
2552 | if (remain < plen) { | ||
2553 | dlen = plen - remain; | ||
2554 | b = buf; | ||
2555 | |||
2556 | b[0] = 0x90 + n1; | ||
2557 | put_unaligned_be16(dlen, b + 1); | ||
2558 | |||
2559 | remain = 3; | ||
2560 | goto done; | ||
2561 | } | ||
2562 | break; | ||
2563 | |||
2564 | /* | ||
2565 | * Handle Window Sequence packets. | ||
2566 | */ | ||
2567 | |||
2568 | case 10: | ||
2569 | plen = 3; | ||
2570 | if (remain < plen) | ||
2571 | goto done; | ||
2572 | |||
2573 | nd->nd_tx_work = 1; | ||
2574 | |||
2575 | { | ||
2576 | ushort tpos = get_unaligned_be16(b + 1); | ||
2577 | |||
2578 | ushort ack = (tpos - ch->ch_s_tpos) & 0xffff; | ||
2579 | ushort unack = (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff; | ||
2580 | ushort notify = (ch->ch_s_treq - ch->ch_s_tpos) & 0xffff; | ||
2581 | |||
2582 | if (ch->ch_state < CS_READY || ack > unack) { | ||
2583 | error = "Improper Window Sequence"; | ||
2584 | goto prot_error; | ||
2585 | } | ||
2586 | |||
2587 | ch->ch_s_tpos = tpos; | ||
2588 | |||
2589 | if (notify <= ack) | ||
2590 | ch->ch_s_treq = tpos; | ||
2591 | } | ||
2592 | break; | ||
2593 | |||
2594 | /* | ||
2595 | * Handle Command response packets. | ||
2596 | */ | ||
2597 | |||
2598 | case 11: | ||
2599 | |||
2600 | /* | ||
2601 | * RealPort engine fix - 03/11/2004 | ||
2602 | * | ||
2603 | * This check did not used to be here. | ||
2604 | * | ||
2605 | * We were using b[1] without verifying that the data | ||
2606 | * is actually there and valid. On a split packet, it | ||
2607 | * might not be yet. | ||
2608 | * | ||
2609 | * NOTE: I have never actually seen the failure happen | ||
2610 | * under Linux, but since I have seen it occur | ||
2611 | * under both Solaris and HP-UX, the assumption | ||
2612 | * is that it *could* happen here as well... | ||
2613 | */ | ||
2614 | if (remain < 2) | ||
2615 | goto done; | ||
2616 | |||
2617 | |||
2618 | switch (b[1]) { | ||
2619 | |||
2620 | /* | ||
2621 | * Handle Open Response. | ||
2622 | */ | ||
2623 | |||
2624 | case 11: | ||
2625 | plen = 6; | ||
2626 | if (remain < plen) | ||
2627 | goto done; | ||
2628 | |||
2629 | nd->nd_tx_work = 1; | ||
2630 | |||
2631 | { | ||
2632 | int req = b[2]; | ||
2633 | int resp = b[3]; | ||
2634 | port = get_unaligned_be16(b + 4); | ||
2635 | |||
2636 | if (port >= nd->nd_chan_count) { | ||
2637 | error = "Open channel number out of range"; | ||
2638 | goto prot_error; | ||
2639 | } | ||
2640 | |||
2641 | ch = nd->nd_chan + port; | ||
2642 | |||
2643 | /* | ||
2644 | * How we handle an open response depends primarily | ||
2645 | * on our current channel state. | ||
2646 | */ | ||
2647 | |||
2648 | switch (ch->ch_state) { | ||
2649 | case CS_IDLE: | ||
2650 | |||
2651 | /* | ||
2652 | * Handle a delayed open. | ||
2653 | */ | ||
2654 | |||
2655 | if (ch->ch_otype_waiting != 0 && | ||
2656 | req == ch->ch_otype_waiting && | ||
2657 | resp == 0) { | ||
2658 | ch->ch_otype = req; | ||
2659 | ch->ch_otype_waiting = 0; | ||
2660 | ch->ch_state = CS_SEND_QUERY; | ||
2661 | break; | ||
2662 | } | ||
2663 | goto open_error; | ||
2664 | |||
2665 | case CS_WAIT_OPEN: | ||
2666 | |||
2667 | /* | ||
2668 | * Handle the open response. | ||
2669 | */ | ||
2670 | |||
2671 | if (req == ch->ch_otype) { | ||
2672 | switch (resp) { | ||
2673 | |||
2674 | /* | ||
2675 | * On successful response, open the | ||
2676 | * port and proceed normally. | ||
2677 | */ | ||
2678 | |||
2679 | case 0: | ||
2680 | ch->ch_state = CS_SEND_QUERY; | ||
2681 | break; | ||
2682 | |||
2683 | /* | ||
2684 | * On a busy response to a persistent open, | ||
2685 | * remember that the open is pending. | ||
2686 | */ | ||
2687 | |||
2688 | case 1: | ||
2689 | case 2: | ||
2690 | if (req != OTYPE_IMMEDIATE) { | ||
2691 | ch->ch_otype_waiting = req; | ||
2692 | ch->ch_state = CS_IDLE; | ||
2693 | break; | ||
2694 | } | ||
2695 | |||
2696 | /* | ||
2697 | * Otherwise the server open failed. If | ||
2698 | * the Unix port is open, hang it up. | ||
2699 | */ | ||
2700 | |||
2701 | default: | ||
2702 | if (ch->ch_open_count != 0) { | ||
2703 | ch->ch_flag |= CH_HANGUP; | ||
2704 | dgrp_carrier(ch); | ||
2705 | ch->ch_state = CS_IDLE; | ||
2706 | break; | ||
2707 | } | ||
2708 | |||
2709 | ch->ch_open_error = resp; | ||
2710 | ch->ch_state = CS_IDLE; | ||
2711 | |||
2712 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2713 | } | ||
2714 | break; | ||
2715 | } | ||
2716 | |||
2717 | /* | ||
2718 | * Handle delayed response arrival preceeding | ||
2719 | * the open response we are waiting for. | ||
2720 | */ | ||
2721 | |||
2722 | if (ch->ch_otype_waiting != 0 && | ||
2723 | req == ch->ch_otype_waiting && | ||
2724 | resp == 0) { | ||
2725 | ch->ch_otype = ch->ch_otype_waiting; | ||
2726 | ch->ch_otype_waiting = 0; | ||
2727 | ch->ch_state = CS_WAIT_FAIL; | ||
2728 | break; | ||
2729 | } | ||
2730 | goto open_error; | ||
2731 | |||
2732 | |||
2733 | case CS_WAIT_FAIL: | ||
2734 | |||
2735 | /* | ||
2736 | * Handle response to immediate open arriving | ||
2737 | * after a delayed open success. | ||
2738 | */ | ||
2739 | |||
2740 | if (req == OTYPE_IMMEDIATE) { | ||
2741 | ch->ch_state = CS_SEND_QUERY; | ||
2742 | break; | ||
2743 | } | ||
2744 | goto open_error; | ||
2745 | |||
2746 | |||
2747 | case CS_WAIT_CANCEL: | ||
2748 | /* | ||
2749 | * Handle delayed open response arriving before | ||
2750 | * the cancel response. | ||
2751 | */ | ||
2752 | |||
2753 | if (req == ch->ch_otype_waiting && | ||
2754 | resp == 0) { | ||
2755 | ch->ch_otype_waiting = 0; | ||
2756 | break; | ||
2757 | } | ||
2758 | |||
2759 | /* | ||
2760 | * Handle cancel response. | ||
2761 | */ | ||
2762 | |||
2763 | if (req == 4 && resp == 0) { | ||
2764 | ch->ch_otype_waiting = 0; | ||
2765 | ch->ch_state = CS_IDLE; | ||
2766 | break; | ||
2767 | } | ||
2768 | goto open_error; | ||
2769 | |||
2770 | |||
2771 | case CS_WAIT_CLOSE: | ||
2772 | /* | ||
2773 | * Handle a successful response to a port | ||
2774 | * close. | ||
2775 | */ | ||
2776 | |||
2777 | if (req >= 3) { | ||
2778 | ch->ch_state = CS_IDLE; | ||
2779 | break; | ||
2780 | } | ||
2781 | goto open_error; | ||
2782 | |||
2783 | open_error: | ||
2784 | default: | ||
2785 | { | ||
2786 | error = "Improper Open Response"; | ||
2787 | goto prot_error; | ||
2788 | } | ||
2789 | } | ||
2790 | } | ||
2791 | break; | ||
2792 | |||
2793 | /* | ||
2794 | * Handle Synchronize Response. | ||
2795 | */ | ||
2796 | |||
2797 | case 13: | ||
2798 | plen = 3; | ||
2799 | if (remain < plen) | ||
2800 | goto done; | ||
2801 | { | ||
2802 | int seq = b[2]; | ||
2803 | int s; | ||
2804 | |||
2805 | /* | ||
2806 | * If channel was waiting for this sync response, | ||
2807 | * unset the flag, and wake up anyone waiting | ||
2808 | * on the event. | ||
2809 | */ | ||
2810 | if (ch->ch_flag & CH_WAITING_SYNC) { | ||
2811 | ch->ch_flag &= ~(CH_WAITING_SYNC); | ||
2812 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2813 | } | ||
2814 | |||
2815 | if (((seq - nd->nd_seq_out) & SEQ_MASK) >= | ||
2816 | ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { | ||
2817 | break; | ||
2818 | } | ||
2819 | |||
2820 | for (s = nd->nd_seq_out;; s = (s + 1) & SEQ_MASK) { | ||
2821 | if (nd->nd_seq_wait[s] != 0) { | ||
2822 | nd->nd_seq_wait[s] = 0; | ||
2823 | |||
2824 | wake_up_interruptible(&nd->nd_seq_wque[s]); | ||
2825 | } | ||
2826 | |||
2827 | nd->nd_unack -= nd->nd_seq_size[s]; | ||
2828 | |||
2829 | if (s == seq) | ||
2830 | break; | ||
2831 | } | ||
2832 | |||
2833 | nd->nd_seq_out = (seq + 1) & SEQ_MASK; | ||
2834 | } | ||
2835 | break; | ||
2836 | |||
2837 | /* | ||
2838 | * Handle Sequence Response. | ||
2839 | */ | ||
2840 | |||
2841 | case 15: | ||
2842 | plen = 6; | ||
2843 | if (remain < plen) | ||
2844 | goto done; | ||
2845 | |||
2846 | { | ||
2847 | /* Record that we have received the Sequence | ||
2848 | * Response, but we aren't interested in the | ||
2849 | * sequence numbers. We were using RIN like it | ||
2850 | * was ROUT and that was causing problems, | ||
2851 | * fixed 7-13-2001 David Fries. See comment in | ||
2852 | * drp.h for ch_s_rin variable. | ||
2853 | int rin = get_unaligned_be16(b + 2); | ||
2854 | int tpos = get_unaligned_be16(b + 4); | ||
2855 | */ | ||
2856 | |||
2857 | ch->ch_send &= ~RR_SEQUENCE; | ||
2858 | ch->ch_expect &= ~RR_SEQUENCE; | ||
2859 | } | ||
2860 | goto check_query; | ||
2861 | |||
2862 | /* | ||
2863 | * Handle Status Response. | ||
2864 | */ | ||
2865 | |||
2866 | case 17: | ||
2867 | plen = 5; | ||
2868 | if (remain < plen) | ||
2869 | goto done; | ||
2870 | |||
2871 | { | ||
2872 | ch->ch_s_elast = get_unaligned_be16(b + 2); | ||
2873 | ch->ch_s_mlast = b[4]; | ||
2874 | |||
2875 | ch->ch_expect &= ~RR_STATUS; | ||
2876 | ch->ch_send &= ~RR_STATUS; | ||
2877 | |||
2878 | /* | ||
2879 | * CH_PHYS_CD is cleared because something _could_ be | ||
2880 | * waiting for the initial sense of carrier... and if | ||
2881 | * carrier is high immediately, we want to be sure to | ||
2882 | * wake them as soon as possible. | ||
2883 | */ | ||
2884 | ch->ch_flag &= ~CH_PHYS_CD; | ||
2885 | |||
2886 | dgrp_carrier(ch); | ||
2887 | } | ||
2888 | goto check_query; | ||
2889 | |||
2890 | /* | ||
2891 | * Handle Line Error Response. | ||
2892 | */ | ||
2893 | |||
2894 | case 19: | ||
2895 | plen = 14; | ||
2896 | if (remain < plen) | ||
2897 | goto done; | ||
2898 | |||
2899 | break; | ||
2900 | |||
2901 | /* | ||
2902 | * Handle Buffer Response. | ||
2903 | */ | ||
2904 | |||
2905 | case 21: | ||
2906 | plen = 6; | ||
2907 | if (remain < plen) | ||
2908 | goto done; | ||
2909 | |||
2910 | { | ||
2911 | ch->ch_s_rsize = get_unaligned_be16(b + 2); | ||
2912 | ch->ch_s_tsize = get_unaligned_be16(b + 4); | ||
2913 | |||
2914 | ch->ch_send &= ~RR_BUFFER; | ||
2915 | ch->ch_expect &= ~RR_BUFFER; | ||
2916 | } | ||
2917 | goto check_query; | ||
2918 | |||
2919 | /* | ||
2920 | * Handle Port Capability Response. | ||
2921 | */ | ||
2922 | |||
2923 | case 23: | ||
2924 | plen = 32; | ||
2925 | if (remain < plen) | ||
2926 | goto done; | ||
2927 | |||
2928 | { | ||
2929 | ch->ch_send &= ~RR_CAPABILITY; | ||
2930 | ch->ch_expect &= ~RR_CAPABILITY; | ||
2931 | } | ||
2932 | |||
2933 | /* | ||
2934 | * When all queries are complete, set those parameters | ||
2935 | * derived from the query results, then transition | ||
2936 | * to the READY state. | ||
2937 | */ | ||
2938 | |||
2939 | check_query: | ||
2940 | if (ch->ch_state == CS_WAIT_QUERY && | ||
2941 | (ch->ch_expect & (RR_SEQUENCE | | ||
2942 | RR_STATUS | | ||
2943 | RR_BUFFER | | ||
2944 | RR_CAPABILITY)) == 0) { | ||
2945 | ch->ch_tmax = ch->ch_s_tsize / 4; | ||
2946 | |||
2947 | if (ch->ch_edelay == DGRP_TTIME) | ||
2948 | ch->ch_ttime = DGRP_TTIME; | ||
2949 | else | ||
2950 | ch->ch_ttime = ch->ch_edelay; | ||
2951 | |||
2952 | ch->ch_rmax = ch->ch_s_rsize / 4; | ||
2953 | |||
2954 | if (ch->ch_edelay == DGRP_RTIME) | ||
2955 | ch->ch_rtime = DGRP_RTIME; | ||
2956 | else | ||
2957 | ch->ch_rtime = ch->ch_edelay; | ||
2958 | |||
2959 | ch->ch_rlow = 2 * ch->ch_s_rsize / 8; | ||
2960 | ch->ch_rhigh = 6 * ch->ch_s_rsize / 8; | ||
2961 | |||
2962 | ch->ch_state = CS_READY; | ||
2963 | |||
2964 | nd->nd_tx_work = 1; | ||
2965 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2966 | |||
2967 | } | ||
2968 | break; | ||
2969 | |||
2970 | default: | ||
2971 | goto decode_error; | ||
2972 | } | ||
2973 | break; | ||
2974 | |||
2975 | /* | ||
2976 | * Handle Events. | ||
2977 | */ | ||
2978 | |||
2979 | case 12: | ||
2980 | plen = 4; | ||
2981 | if (remain < plen) | ||
2982 | goto done; | ||
2983 | |||
2984 | mlast = ch->ch_s_mlast; | ||
2985 | elast = ch->ch_s_elast; | ||
2986 | |||
2987 | mstat = ch->ch_s_mlast = b[1]; | ||
2988 | estat = ch->ch_s_elast = get_unaligned_be16(b + 2); | ||
2989 | |||
2990 | /* | ||
2991 | * Handle modem changes. | ||
2992 | */ | ||
2993 | |||
2994 | if (((mstat ^ mlast) & DM_CD) != 0) | ||
2995 | dgrp_carrier(ch); | ||
2996 | |||
2997 | |||
2998 | /* | ||
2999 | * Handle received break. | ||
3000 | */ | ||
3001 | |||
3002 | if ((estat & ~elast & EV_RXB) != 0 && | ||
3003 | (ch->ch_tun.un_open_count != 0) && | ||
3004 | I_BRKINT(ch->ch_tun.un_tty) && | ||
3005 | !(I_IGNBRK(ch->ch_tun.un_tty))) { | ||
3006 | |||
3007 | tty_buffer_request_room(ch->ch_tun.un_tty, 1); | ||
3008 | tty_insert_flip_char(ch->ch_tun.un_tty, 0, TTY_BREAK); | ||
3009 | tty_flip_buffer_push(ch->ch_tun.un_tty); | ||
3010 | |||
3011 | } | ||
3012 | |||
3013 | /* | ||
3014 | * On transmit break complete, if more break traffic | ||
3015 | * is waiting then send it. Otherwise wake any threads | ||
3016 | * waiting for transmitter empty. | ||
3017 | */ | ||
3018 | |||
3019 | if ((~estat & elast & EV_TXB) != 0 && | ||
3020 | (ch->ch_expect & RR_TX_BREAK) != 0) { | ||
3021 | |||
3022 | nd->nd_tx_work = 1; | ||
3023 | |||
3024 | ch->ch_expect &= ~RR_TX_BREAK; | ||
3025 | |||
3026 | if (ch->ch_break_time != 0) { | ||
3027 | ch->ch_send |= RR_TX_BREAK; | ||
3028 | } else { | ||
3029 | ch->ch_send &= ~RR_TX_BREAK; | ||
3030 | ch->ch_flag &= ~CH_TX_BREAK; | ||
3031 | wake_up_interruptible(&ch->ch_flag_wait); | ||
3032 | } | ||
3033 | } | ||
3034 | break; | ||
3035 | |||
3036 | case 13: | ||
3037 | case 14: | ||
3038 | error = "Unrecognized command"; | ||
3039 | goto prot_error; | ||
3040 | |||
3041 | /* | ||
3042 | * Decode Special Codes. | ||
3043 | */ | ||
3044 | |||
3045 | case 15: | ||
3046 | switch (n1) { | ||
3047 | /* | ||
3048 | * One byte module select. | ||
3049 | */ | ||
3050 | |||
3051 | case 0: | ||
3052 | case 1: | ||
3053 | case 2: | ||
3054 | case 3: | ||
3055 | case 4: | ||
3056 | case 5: | ||
3057 | case 6: | ||
3058 | case 7: | ||
3059 | plen = 1; | ||
3060 | nd->nd_rx_module = n1; | ||
3061 | break; | ||
3062 | |||
3063 | /* | ||
3064 | * Two byte module select. | ||
3065 | */ | ||
3066 | |||
3067 | case 8: | ||
3068 | plen = 2; | ||
3069 | if (remain < plen) | ||
3070 | goto done; | ||
3071 | |||
3072 | nd->nd_rx_module = b[1]; | ||
3073 | break; | ||
3074 | |||
3075 | /* | ||
3076 | * ID Request packet. | ||
3077 | */ | ||
3078 | |||
3079 | case 11: | ||
3080 | if (remain < 4) | ||
3081 | goto done; | ||
3082 | |||
3083 | plen = get_unaligned_be16(b + 2); | ||
3084 | |||
3085 | if (plen < 12 || plen > 1000) { | ||
3086 | error = "Response Packet length error"; | ||
3087 | goto prot_error; | ||
3088 | } | ||
3089 | |||
3090 | nd->nd_tx_work = 1; | ||
3091 | |||
3092 | switch (b[1]) { | ||
3093 | /* | ||
3094 | * Echo packet. | ||
3095 | */ | ||
3096 | |||
3097 | case 0: | ||
3098 | nd->nd_send |= NR_ECHO; | ||
3099 | break; | ||
3100 | |||
3101 | /* | ||
3102 | * ID Response packet. | ||
3103 | */ | ||
3104 | |||
3105 | case 1: | ||
3106 | nd->nd_send |= NR_IDENT; | ||
3107 | break; | ||
3108 | |||
3109 | /* | ||
3110 | * ID Response packet. | ||
3111 | */ | ||
3112 | |||
3113 | case 32: | ||
3114 | nd->nd_send |= NR_PASSWORD; | ||
3115 | break; | ||
3116 | |||
3117 | } | ||
3118 | break; | ||
3119 | |||
3120 | /* | ||
3121 | * Various node-level response packets. | ||
3122 | */ | ||
3123 | |||
3124 | case 12: | ||
3125 | if (remain < 4) | ||
3126 | goto done; | ||
3127 | |||
3128 | plen = get_unaligned_be16(b + 2); | ||
3129 | |||
3130 | if (plen < 4 || plen > 1000) { | ||
3131 | error = "Response Packet length error"; | ||
3132 | goto prot_error; | ||
3133 | } | ||
3134 | |||
3135 | nd->nd_tx_work = 1; | ||
3136 | |||
3137 | switch (b[1]) { | ||
3138 | /* | ||
3139 | * Echo packet. | ||
3140 | */ | ||
3141 | |||
3142 | case 0: | ||
3143 | nd->nd_expect &= ~NR_ECHO; | ||
3144 | break; | ||
3145 | |||
3146 | /* | ||
3147 | * Product Response Packet. | ||
3148 | */ | ||
3149 | |||
3150 | case 1: | ||
3151 | { | ||
3152 | int desclen; | ||
3153 | |||
3154 | nd->nd_hw_ver = (b[8] << 8) | b[9]; | ||
3155 | nd->nd_sw_ver = (b[10] << 8) | b[11]; | ||
3156 | nd->nd_hw_id = b[6]; | ||
3157 | desclen = ((plen - 12) > MAX_DESC_LEN) ? MAX_DESC_LEN : | ||
3158 | plen - 12; | ||
3159 | |||
3160 | if (desclen <= 0) { | ||
3161 | error = "Response Packet desclen error"; | ||
3162 | goto prot_error; | ||
3163 | } | ||
3164 | |||
3165 | strncpy(nd->nd_ps_desc, b + 12, desclen); | ||
3166 | nd->nd_ps_desc[desclen] = 0; | ||
3167 | } | ||
3168 | |||
3169 | nd->nd_expect &= ~NR_IDENT; | ||
3170 | break; | ||
3171 | |||
3172 | /* | ||
3173 | * Capability Response Packet. | ||
3174 | */ | ||
3175 | |||
3176 | case 2: | ||
3177 | { | ||
3178 | int nn = get_unaligned_be16(b + 4); | ||
3179 | |||
3180 | if (nn > CHAN_MAX) | ||
3181 | nn = CHAN_MAX; | ||
3182 | |||
3183 | dgrp_chan_count(nd, nn); | ||
3184 | } | ||
3185 | |||
3186 | nd->nd_expect &= ~NR_CAPABILITY; | ||
3187 | break; | ||
3188 | |||
3189 | /* | ||
3190 | * VPD Response Packet. | ||
3191 | */ | ||
3192 | |||
3193 | case 15: | ||
3194 | /* | ||
3195 | * NOTE: case 15 is here ONLY because the EtherLite | ||
3196 | * is broken, and sends a response to 24 back as 15. | ||
3197 | * To resolve this, the EtherLite firmware is now | ||
3198 | * fixed to send back 24 correctly, but, for backwards | ||
3199 | * compatibility, we now have reserved 15 for the | ||
3200 | * bad EtherLite response to 24 as well. | ||
3201 | */ | ||
3202 | |||
3203 | /* Fallthru! */ | ||
3204 | |||
3205 | case 24: | ||
3206 | |||
3207 | /* | ||
3208 | * If the product doesn't support VPD, | ||
3209 | * it will send back a null IDRESP, | ||
3210 | * which is a length of 4 bytes. | ||
3211 | */ | ||
3212 | if (plen > 4) { | ||
3213 | memcpy(nd->nd_vpd, b + 4, min(plen - 4, (long) VPDSIZE)); | ||
3214 | nd->nd_vpd_len = min(plen - 4, (long) VPDSIZE); | ||
3215 | } | ||
3216 | |||
3217 | nd->nd_expect &= ~NR_VPD; | ||
3218 | break; | ||
3219 | |||
3220 | default: | ||
3221 | goto decode_error; | ||
3222 | } | ||
3223 | |||
3224 | if (nd->nd_expect == 0 && | ||
3225 | nd->nd_state == NS_WAIT_QUERY) { | ||
3226 | nd->nd_state = NS_READY; | ||
3227 | } | ||
3228 | break; | ||
3229 | |||
3230 | /* | ||
3231 | * Debug packet. | ||
3232 | */ | ||
3233 | |||
3234 | case 14: | ||
3235 | if (remain < 4) | ||
3236 | goto done; | ||
3237 | |||
3238 | plen = get_unaligned_be16(b + 2) + 4; | ||
3239 | |||
3240 | if (plen > 1000) { | ||
3241 | error = "Debug Packet too large"; | ||
3242 | goto prot_error; | ||
3243 | } | ||
3244 | |||
3245 | if (remain < plen) | ||
3246 | goto done; | ||
3247 | break; | ||
3248 | |||
3249 | /* | ||
3250 | * Handle reset packet. | ||
3251 | */ | ||
3252 | |||
3253 | case 15: | ||
3254 | if (remain < 2) | ||
3255 | goto done; | ||
3256 | |||
3257 | plen = 2 + b[1]; | ||
3258 | |||
3259 | if (remain < plen) | ||
3260 | goto done; | ||
3261 | |||
3262 | nd->nd_tx_work = 1; | ||
3263 | |||
3264 | n = b[plen]; | ||
3265 | b[plen] = 0; | ||
3266 | |||
3267 | b[plen] = n; | ||
3268 | |||
3269 | error = "Client Reset Acknowledge"; | ||
3270 | goto prot_error; | ||
3271 | |||
3272 | default: | ||
3273 | goto decode_error; | ||
3274 | } | ||
3275 | break; | ||
3276 | |||
3277 | default: | ||
3278 | goto decode_error; | ||
3279 | } | ||
3280 | |||
3281 | b += plen; | ||
3282 | remain -= plen; | ||
3283 | } | ||
3284 | |||
3285 | /* | ||
3286 | * When the buffer is exhausted, copy any data left at the | ||
3287 | * top of the buffer back down to the bottom for the next | ||
3288 | * read request. | ||
3289 | */ | ||
3290 | |||
3291 | done: | ||
3292 | if (remain > 0 && b != buf) | ||
3293 | memcpy(buf, b, remain); | ||
3294 | |||
3295 | nd->nd_remain = remain; | ||
3296 | return; | ||
3297 | |||
3298 | /* | ||
3299 | * Handle a decode error. | ||
3300 | */ | ||
3301 | |||
3302 | decode_error: | ||
3303 | error = "Protocol decode error"; | ||
3304 | |||
3305 | /* | ||
3306 | * Handle a general protocol error. | ||
3307 | */ | ||
3308 | |||
3309 | prot_error: | ||
3310 | nd->nd_remain = 0; | ||
3311 | nd->nd_state = NS_SEND_ERROR; | ||
3312 | nd->nd_error = error; | ||
3313 | } | ||
3314 | |||
3315 | /* | ||
3316 | * dgrp_net_write() -- write data to the network device. | ||
3317 | * | ||
3318 | * A zero byte write indicates that the connection to the RealPort | ||
3319 | * device has been broken. | ||
3320 | * | ||
3321 | * A non-zero write indicates data from the RealPort device. | ||
3322 | */ | ||
3323 | static ssize_t dgrp_net_write(struct file *file, const char __user *buf, | ||
3324 | size_t count, loff_t *ppos) | ||
3325 | { | ||
3326 | struct nd_struct *nd; | ||
3327 | ssize_t rtn = 0; | ||
3328 | long n; | ||
3329 | long total = 0; | ||
3330 | |||
3331 | /* | ||
3332 | * Get the node pointer, and quit if it doesn't exist. | ||
3333 | */ | ||
3334 | nd = (struct nd_struct *)(file->private_data); | ||
3335 | if (!nd) | ||
3336 | return -ENXIO; | ||
3337 | |||
3338 | /* | ||
3339 | * Grab the NET lock. | ||
3340 | */ | ||
3341 | down(&nd->nd_net_semaphore); | ||
3342 | |||
3343 | nd->nd_write_count++; | ||
3344 | |||
3345 | /* | ||
3346 | * Handle disconnect. | ||
3347 | */ | ||
3348 | |||
3349 | if (count == 0) { | ||
3350 | dgrp_net_idle(nd); | ||
3351 | /* | ||
3352 | * Set the active port count to zero. | ||
3353 | */ | ||
3354 | dgrp_chan_count(nd, 0); | ||
3355 | goto unlock; | ||
3356 | } | ||
3357 | |||
3358 | /* | ||
3359 | * Loop to process entire receive packet. | ||
3360 | */ | ||
3361 | |||
3362 | while (count > 0) { | ||
3363 | n = UIO_MAX - nd->nd_remain; | ||
3364 | |||
3365 | if (n > count) | ||
3366 | n = count; | ||
3367 | |||
3368 | nd->nd_rx_byte += n + nd->nd_link.lk_header_size; | ||
3369 | |||
3370 | rtn = copy_from_user(nd->nd_iobuf + nd->nd_remain, | ||
3371 | (void __user *) buf + total, n); | ||
3372 | if (rtn) { | ||
3373 | rtn = -EFAULT; | ||
3374 | goto unlock; | ||
3375 | } | ||
3376 | |||
3377 | *ppos += n; | ||
3378 | |||
3379 | total += n; | ||
3380 | |||
3381 | count -= n; | ||
3382 | |||
3383 | if (nd->nd_mon_buf) | ||
3384 | dgrp_monitor_data(nd, RPDUMP_SERVER, | ||
3385 | nd->nd_iobuf + nd->nd_remain, n); | ||
3386 | |||
3387 | nd->nd_remain += n; | ||
3388 | |||
3389 | dgrp_receive(nd); | ||
3390 | } | ||
3391 | |||
3392 | rtn = total; | ||
3393 | |||
3394 | unlock: | ||
3395 | /* | ||
3396 | * Release the NET lock. | ||
3397 | */ | ||
3398 | up(&nd->nd_net_semaphore); | ||
3399 | |||
3400 | return rtn; | ||
3401 | } | ||
3402 | |||
3403 | |||
3404 | /* | ||
3405 | * dgrp_net_select() | ||
3406 | * Determine whether a device is ready to be read or written to, and | ||
3407 | * sleep if not. | ||
3408 | */ | ||
3409 | static unsigned int dgrp_net_select(struct file *file, | ||
3410 | struct poll_table_struct *table) | ||
3411 | { | ||
3412 | unsigned int retval = 0; | ||
3413 | struct nd_struct *nd = file->private_data; | ||
3414 | |||
3415 | poll_wait(file, &nd->nd_tx_waitq, table); | ||
3416 | |||
3417 | if (nd->nd_tx_ready) | ||
3418 | retval |= POLLIN | POLLRDNORM; /* Conditionally readable */ | ||
3419 | |||
3420 | retval |= POLLOUT | POLLWRNORM; /* Always writeable */ | ||
3421 | |||
3422 | return retval; | ||
3423 | } | ||
3424 | |||
3425 | /* | ||
3426 | * dgrp_net_ioctl | ||
3427 | * | ||
3428 | * Implement those functions which allow the network daemon to control | ||
3429 | * the network parameters in the driver. The ioctls include ones to | ||
3430 | * get and set the link speed parameters for the PortServer. | ||
3431 | */ | ||
3432 | static long dgrp_net_ioctl(struct file *file, unsigned int cmd, | ||
3433 | unsigned long arg) | ||
3434 | { | ||
3435 | struct nd_struct *nd; | ||
3436 | int rtn = 0; | ||
3437 | long size = _IOC_SIZE(cmd); | ||
3438 | struct link_struct link; | ||
3439 | |||
3440 | nd = file->private_data; | ||
3441 | |||
3442 | if (_IOC_DIR(cmd) & _IOC_READ) | ||
3443 | rtn = access_ok(VERIFY_WRITE, (void __user *) arg, size); | ||
3444 | else if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
3445 | rtn = access_ok(VERIFY_READ, (void __user *) arg, size); | ||
3446 | |||
3447 | if (!rtn) | ||
3448 | return rtn; | ||
3449 | |||
3450 | switch (cmd) { | ||
3451 | case DIGI_SETLINK: | ||
3452 | if (size != sizeof(struct link_struct)) | ||
3453 | return -EINVAL; | ||
3454 | |||
3455 | if (copy_from_user((void *)(&link), (void __user *) arg, size)) | ||
3456 | return -EFAULT; | ||
3457 | |||
3458 | if (link.lk_fast_rate < 9600) | ||
3459 | link.lk_fast_rate = 9600; | ||
3460 | |||
3461 | if (link.lk_slow_rate < 2400) | ||
3462 | link.lk_slow_rate = 2400; | ||
3463 | |||
3464 | if (link.lk_fast_rate > 10000000) | ||
3465 | link.lk_fast_rate = 10000000; | ||
3466 | |||
3467 | if (link.lk_slow_rate > link.lk_fast_rate) | ||
3468 | link.lk_slow_rate = link.lk_fast_rate; | ||
3469 | |||
3470 | if (link.lk_fast_delay > 2000) | ||
3471 | link.lk_fast_delay = 2000; | ||
3472 | |||
3473 | if (link.lk_slow_delay > 10000) | ||
3474 | link.lk_slow_delay = 10000; | ||
3475 | |||
3476 | if (link.lk_fast_delay < 60) | ||
3477 | link.lk_fast_delay = 60; | ||
3478 | |||
3479 | if (link.lk_slow_delay < link.lk_fast_delay) | ||
3480 | link.lk_slow_delay = link.lk_fast_delay; | ||
3481 | |||
3482 | if (link.lk_header_size < 2) | ||
3483 | link.lk_header_size = 2; | ||
3484 | |||
3485 | if (link.lk_header_size > 128) | ||
3486 | link.lk_header_size = 128; | ||
3487 | |||
3488 | link.lk_fast_rate /= 8 * 1000 / dgrp_poll_tick; | ||
3489 | link.lk_slow_rate /= 8 * 1000 / dgrp_poll_tick; | ||
3490 | |||
3491 | link.lk_fast_delay /= dgrp_poll_tick; | ||
3492 | link.lk_slow_delay /= dgrp_poll_tick; | ||
3493 | |||
3494 | nd->nd_link = link; | ||
3495 | |||
3496 | break; | ||
3497 | |||
3498 | case DIGI_GETLINK: | ||
3499 | if (size != sizeof(struct link_struct)) | ||
3500 | return -EINVAL; | ||
3501 | |||
3502 | if (copy_to_user((void __user *)arg, (void *)(&nd->nd_link), | ||
3503 | size)) | ||
3504 | return -EFAULT; | ||
3505 | |||
3506 | break; | ||
3507 | |||
3508 | default: | ||
3509 | return -EINVAL; | ||
3510 | |||
3511 | } | ||
3512 | |||
3513 | return 0; | ||
3514 | } | ||
3515 | |||
3516 | /** | ||
3517 | * dgrp_poll_handler() -- handler for poll timer | ||
3518 | * | ||
3519 | * As each timer expires, it determines (a) whether the "transmit" | ||
3520 | * waiter needs to be woken up, and (b) whether the poller needs to | ||
3521 | * be rescheduled. | ||
3522 | */ | ||
3523 | void dgrp_poll_handler(unsigned long arg) | ||
3524 | { | ||
3525 | struct dgrp_poll_data *poll_data; | ||
3526 | struct nd_struct *nd; | ||
3527 | struct link_struct *lk; | ||
3528 | ulong time; | ||
3529 | ulong poll_time; | ||
3530 | ulong freq; | ||
3531 | ulong lock_flags; | ||
3532 | |||
3533 | poll_data = (struct dgrp_poll_data *) arg; | ||
3534 | freq = 1000 / poll_data->poll_tick; | ||
3535 | poll_data->poll_round += 17; | ||
3536 | |||
3537 | if (poll_data->poll_round >= freq) | ||
3538 | poll_data->poll_round -= freq; | ||
3539 | |||
3540 | /* | ||
3541 | * Loop to process all open nodes. | ||
3542 | * | ||
3543 | * For each node, determine the rate at which it should | ||
3544 | * be transmitting data. Then if the node should wake up | ||
3545 | * and transmit data now, enable the net receive select | ||
3546 | * to get the transmit going. | ||
3547 | */ | ||
3548 | |||
3549 | list_for_each_entry(nd, &nd_struct_list, list) { | ||
3550 | |||
3551 | lk = &nd->nd_link; | ||
3552 | |||
3553 | /* | ||
3554 | * Decrement statistics. These are only for use with | ||
3555 | * KME, so don't worry that the operations are done | ||
3556 | * unlocked, and so the results are occassionally wrong. | ||
3557 | */ | ||
3558 | |||
3559 | nd->nd_read_count -= (nd->nd_read_count + | ||
3560 | poll_data->poll_round) / freq; | ||
3561 | nd->nd_write_count -= (nd->nd_write_count + | ||
3562 | poll_data->poll_round) / freq; | ||
3563 | nd->nd_send_count -= (nd->nd_send_count + | ||
3564 | poll_data->poll_round) / freq; | ||
3565 | nd->nd_tx_byte -= (nd->nd_tx_byte + | ||
3566 | poll_data->poll_round) / freq; | ||
3567 | nd->nd_rx_byte -= (nd->nd_rx_byte + | ||
3568 | poll_data->poll_round) / freq; | ||
3569 | |||
3570 | /* | ||
3571 | * Wake the daemon to transmit data only when there is | ||
3572 | * enough byte credit to send data. | ||
3573 | * | ||
3574 | * The results are approximate because the operations | ||
3575 | * are performed unlocked, and we are inspecting | ||
3576 | * data asynchronously updated elsewhere. The whole | ||
3577 | * thing is just approximation anyway, so that should | ||
3578 | * be okay. | ||
3579 | */ | ||
3580 | |||
3581 | if (lk->lk_slow_rate >= UIO_MAX) { | ||
3582 | |||
3583 | nd->nd_delay = 0; | ||
3584 | nd->nd_rate = UIO_MAX; | ||
3585 | |||
3586 | nd->nd_tx_deposit = nd->nd_tx_charge + 3 * UIO_MAX; | ||
3587 | nd->nd_tx_credit = 3 * UIO_MAX; | ||
3588 | |||
3589 | } else { | ||
3590 | |||
3591 | long rate; | ||
3592 | long delay; | ||
3593 | long deposit; | ||
3594 | long charge; | ||
3595 | long size; | ||
3596 | long excess; | ||
3597 | |||
3598 | long seq_in = nd->nd_seq_in; | ||
3599 | long seq_out = nd->nd_seq_out; | ||
3600 | |||
3601 | /* | ||
3602 | * If there are no outstanding packets, run at the | ||
3603 | * fastest rate. | ||
3604 | */ | ||
3605 | |||
3606 | if (seq_in == seq_out) { | ||
3607 | delay = 0; | ||
3608 | rate = lk->lk_fast_rate; | ||
3609 | } | ||
3610 | |||
3611 | /* | ||
3612 | * Otherwise compute the transmit rate based on the | ||
3613 | * delay since the oldest packet. | ||
3614 | */ | ||
3615 | |||
3616 | else { | ||
3617 | /* | ||
3618 | * The actual delay is computed as the | ||
3619 | * time since the oldest unacknowledged | ||
3620 | * packet was sent, minus the time it | ||
3621 | * took to send that packet to the server. | ||
3622 | */ | ||
3623 | |||
3624 | delay = ((jiffies - nd->nd_seq_time[seq_out]) | ||
3625 | - (nd->nd_seq_size[seq_out] / | ||
3626 | lk->lk_fast_rate)); | ||
3627 | |||
3628 | /* | ||
3629 | * If the delay is less than the "fast" | ||
3630 | * delay, transmit full speed. If greater | ||
3631 | * than the "slow" delay, transmit at the | ||
3632 | * "slow" speed. In between, interpolate | ||
3633 | * between the fast and slow speeds. | ||
3634 | */ | ||
3635 | |||
3636 | rate = | ||
3637 | (delay <= lk->lk_fast_delay ? | ||
3638 | lk->lk_fast_rate : | ||
3639 | delay >= lk->lk_slow_delay ? | ||
3640 | lk->lk_slow_rate : | ||
3641 | (lk->lk_slow_rate + | ||
3642 | (lk->lk_slow_delay - delay) * | ||
3643 | (lk->lk_fast_rate - lk->lk_slow_rate) / | ||
3644 | (lk->lk_slow_delay - lk->lk_fast_delay) | ||
3645 | ) | ||
3646 | ); | ||
3647 | } | ||
3648 | |||
3649 | nd->nd_delay = delay; | ||
3650 | nd->nd_rate = rate; | ||
3651 | |||
3652 | /* | ||
3653 | * Increase the transmit credit by depositing the | ||
3654 | * current transmit rate. | ||
3655 | */ | ||
3656 | |||
3657 | deposit = nd->nd_tx_deposit; | ||
3658 | charge = nd->nd_tx_charge; | ||
3659 | |||
3660 | deposit += rate; | ||
3661 | |||
3662 | /* | ||
3663 | * If the available transmit credit becomes too large, | ||
3664 | * reduce the deposit to correct the value. | ||
3665 | * | ||
3666 | * Too large is the max of: | ||
3667 | * 6 times the header size | ||
3668 | * 3 times the current transmit rate. | ||
3669 | */ | ||
3670 | |||
3671 | size = 2 * nd->nd_link.lk_header_size; | ||
3672 | |||
3673 | if (size < rate) | ||
3674 | size = rate; | ||
3675 | |||
3676 | size *= 3; | ||
3677 | |||
3678 | excess = deposit - charge - size; | ||
3679 | |||
3680 | if (excess > 0) | ||
3681 | deposit -= excess; | ||
3682 | |||
3683 | nd->nd_tx_deposit = deposit; | ||
3684 | nd->nd_tx_credit = deposit - charge; | ||
3685 | |||
3686 | /* | ||
3687 | * Wake the transmit task only if the transmit credit | ||
3688 | * is at least 3 times the transmit header size. | ||
3689 | */ | ||
3690 | |||
3691 | size = 3 * lk->lk_header_size; | ||
3692 | |||
3693 | if (nd->nd_tx_credit < size) | ||
3694 | continue; | ||
3695 | } | ||
3696 | |||
3697 | |||
3698 | /* | ||
3699 | * Enable the READ select to wake the daemon if there | ||
3700 | * is useful work for the drp_read routine to perform. | ||
3701 | */ | ||
3702 | |||
3703 | if (waitqueue_active(&nd->nd_tx_waitq) && | ||
3704 | (nd->nd_tx_work != 0 || | ||
3705 | (ulong)(jiffies - nd->nd_tx_time) >= IDLE_MAX)) { | ||
3706 | nd->nd_tx_ready = 1; | ||
3707 | |||
3708 | wake_up_interruptible(&nd->nd_tx_waitq); | ||
3709 | |||
3710 | /* not needed */ | ||
3711 | /* nd->nd_flag &= ~ND_SELECT; */ | ||
3712 | } | ||
3713 | } | ||
3714 | |||
3715 | |||
3716 | /* | ||
3717 | * Schedule ourself back at the nominal wakeup interval. | ||
3718 | */ | ||
3719 | spin_lock_irqsave(&poll_data->poll_lock, lock_flags); | ||
3720 | |||
3721 | poll_data->node_active_count--; | ||
3722 | if (poll_data->node_active_count > 0) { | ||
3723 | poll_data->node_active_count++; | ||
3724 | poll_time = poll_data->timer.expires + | ||
3725 | poll_data->poll_tick * HZ / 1000; | ||
3726 | |||
3727 | time = poll_time - jiffies; | ||
3728 | |||
3729 | if (time >= 2 * poll_data->poll_tick) | ||
3730 | poll_time = jiffies + dgrp_poll_tick * HZ / 1000; | ||
3731 | |||
3732 | poll_data->timer.expires = poll_time; | ||
3733 | add_timer(&poll_data->timer); | ||
3734 | } | ||
3735 | |||
3736 | spin_unlock_irqrestore(&poll_data->poll_lock, lock_flags); | ||
3737 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_ports_ops.c b/drivers/staging/dgrp/dgrp_ports_ops.c new file mode 100644 index 000000000000..cd1fc2088624 --- /dev/null +++ b/drivers/staging/dgrp/dgrp_ports_ops.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 1999-2000 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 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * | ||
24 | * Filename: | ||
25 | * | ||
26 | * dgrp_ports_ops.c | ||
27 | * | ||
28 | * Description: | ||
29 | * | ||
30 | * Handle the file operations required for the /proc/dgrp/ports/... | ||
31 | * devices. Basically gathers tty status for the node and returns it. | ||
32 | * | ||
33 | * Author: | ||
34 | * | ||
35 | * James A. Puzzo | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/module.h> | ||
40 | #include <linux/proc_fs.h> | ||
41 | #include <linux/tty.h> | ||
42 | #include <linux/sched.h> | ||
43 | #include <linux/seq_file.h> | ||
44 | |||
45 | #include "dgrp_common.h" | ||
46 | |||
47 | /* File operation declarations */ | ||
48 | static int dgrp_ports_open(struct inode *, struct file *); | ||
49 | |||
50 | static const struct file_operations ports_ops = { | ||
51 | .owner = THIS_MODULE, | ||
52 | .open = dgrp_ports_open, | ||
53 | .read = seq_read, | ||
54 | .llseek = seq_lseek, | ||
55 | .release = seq_release | ||
56 | }; | ||
57 | |||
58 | static struct inode_operations ports_inode_ops = { | ||
59 | .permission = dgrp_inode_permission | ||
60 | }; | ||
61 | |||
62 | |||
63 | void dgrp_register_ports_hook(struct proc_dir_entry *de) | ||
64 | { | ||
65 | struct nd_struct *node = de->data; | ||
66 | |||
67 | de->proc_iops = &ports_inode_ops; | ||
68 | de->proc_fops = &ports_ops; | ||
69 | node->nd_ports_de = de; | ||
70 | } | ||
71 | |||
72 | static void *dgrp_ports_seq_start(struct seq_file *seq, loff_t *pos) | ||
73 | { | ||
74 | if (*pos == 0) | ||
75 | seq_puts(seq, "#num tty_open pr_open tot_wait MSTAT IFLAG OFLAG CFLAG BPS DIGIFLAGS\n"); | ||
76 | |||
77 | return pos; | ||
78 | } | ||
79 | |||
80 | static void *dgrp_ports_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
81 | { | ||
82 | struct nd_struct *nd = seq->private; | ||
83 | |||
84 | if (*pos >= nd->nd_chan_count) | ||
85 | return NULL; | ||
86 | |||
87 | *pos += 1; | ||
88 | |||
89 | return pos; | ||
90 | } | ||
91 | |||
92 | static void dgrp_ports_seq_stop(struct seq_file *seq, void *v) | ||
93 | { | ||
94 | } | ||
95 | |||
96 | static int dgrp_ports_seq_show(struct seq_file *seq, void *v) | ||
97 | { | ||
98 | loff_t *pos = v; | ||
99 | struct nd_struct *nd; | ||
100 | struct ch_struct *ch; | ||
101 | struct un_struct *tun, *pun; | ||
102 | unsigned int totcnt; | ||
103 | |||
104 | nd = seq->private; | ||
105 | if (!nd) | ||
106 | return 0; | ||
107 | |||
108 | if (*pos >= nd->nd_chan_count) | ||
109 | return 0; | ||
110 | |||
111 | ch = &nd->nd_chan[*pos]; | ||
112 | tun = &ch->ch_tun; | ||
113 | pun = &ch->ch_pun; | ||
114 | |||
115 | /* | ||
116 | * If port is not open and no one is waiting to | ||
117 | * open it, the modem signal values can't be | ||
118 | * trusted, and will be zeroed. | ||
119 | */ | ||
120 | totcnt = tun->un_open_count + | ||
121 | pun->un_open_count + | ||
122 | ch->ch_wait_count[0] + | ||
123 | ch->ch_wait_count[1] + | ||
124 | ch->ch_wait_count[2]; | ||
125 | |||
126 | seq_printf(seq, "%02d %02d %02d %02d 0x%04X 0x%04X 0x%04X 0x%04X %-6d 0x%04X\n", | ||
127 | (int) *pos, | ||
128 | tun->un_open_count, | ||
129 | pun->un_open_count, | ||
130 | ch->ch_wait_count[0] + | ||
131 | ch->ch_wait_count[1] + | ||
132 | ch->ch_wait_count[2], | ||
133 | (totcnt ? ch->ch_s_mlast : 0), | ||
134 | ch->ch_s_iflag, | ||
135 | ch->ch_s_oflag, | ||
136 | ch->ch_s_cflag, | ||
137 | (ch->ch_s_brate ? (1843200 / ch->ch_s_brate) : 0), | ||
138 | ch->ch_digi.digi_flags); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static const struct seq_operations ports_seq_ops = { | ||
144 | .start = dgrp_ports_seq_start, | ||
145 | .next = dgrp_ports_seq_next, | ||
146 | .stop = dgrp_ports_seq_stop, | ||
147 | .show = dgrp_ports_seq_show, | ||
148 | }; | ||
149 | |||
150 | /** | ||
151 | * dgrp_ports_open -- open the /proc/dgrp/ports/... device | ||
152 | * @inode: struct inode * | ||
153 | * @file: struct file * | ||
154 | * | ||
155 | * Open function to open the /proc/dgrp/ports device for a PortServer. | ||
156 | * This is the open function for struct file_operations | ||
157 | */ | ||
158 | static int dgrp_ports_open(struct inode *inode, struct file *file) | ||
159 | { | ||
160 | struct seq_file *seq; | ||
161 | int rtn; | ||
162 | |||
163 | rtn = seq_open(file, &ports_seq_ops); | ||
164 | if (!rtn) { | ||
165 | seq = file->private_data; | ||
166 | seq->private = PDE(inode)->data; | ||
167 | } | ||
168 | |||
169 | return rtn; | ||
170 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_specproc.c b/drivers/staging/dgrp/dgrp_specproc.c new file mode 100644 index 000000000000..28f5c9ab6b43 --- /dev/null +++ b/drivers/staging/dgrp/dgrp_specproc.c | |||
@@ -0,0 +1,822 @@ | |||
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/vmalloc.h> | ||
43 | |||
44 | #include "dgrp_common.h" | ||
45 | |||
46 | static struct dgrp_proc_entry dgrp_table[]; | ||
47 | static struct proc_dir_entry *dgrp_proc_dir_entry; | ||
48 | |||
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)); | ||
55 | |||
56 | /* File operation declarations */ | ||
57 | static int dgrp_gen_proc_open(struct inode *, struct file *); | ||
58 | static int dgrp_gen_proc_close(struct inode *, struct file *); | ||
59 | static int parse_write_config(char *); | ||
60 | |||
61 | |||
62 | static const struct file_operations dgrp_proc_file_ops = { | ||
63 | .owner = THIS_MODULE, | ||
64 | .open = dgrp_gen_proc_open, | ||
65 | .release = dgrp_gen_proc_close, | ||
66 | }; | ||
67 | |||
68 | static struct inode_operations proc_inode_ops = { | ||
69 | .permission = dgrp_inode_permission | ||
70 | }; | ||
71 | |||
72 | |||
73 | static void register_proc_table(struct dgrp_proc_entry *, | ||
74 | struct proc_dir_entry *); | ||
75 | static void unregister_proc_table(struct dgrp_proc_entry *, | ||
76 | struct proc_dir_entry *); | ||
77 | |||
78 | static struct dgrp_proc_entry dgrp_net_table[]; | ||
79 | static struct dgrp_proc_entry dgrp_mon_table[]; | ||
80 | static struct dgrp_proc_entry dgrp_ports_table[]; | ||
81 | static struct dgrp_proc_entry dgrp_dpa_table[]; | ||
82 | |||
83 | static ssize_t config_proc_write(struct file *file, const char __user *buffer, | ||
84 | size_t count, loff_t *pos); | ||
85 | |||
86 | static int nodeinfo_proc_open(struct inode *inode, struct file *file); | ||
87 | static int info_proc_open(struct inode *inode, struct file *file); | ||
88 | static int config_proc_open(struct inode *inode, struct file *file); | ||
89 | |||
90 | static struct file_operations config_proc_file_ops = { | ||
91 | .owner = THIS_MODULE, | ||
92 | .open = config_proc_open, | ||
93 | .read = seq_read, | ||
94 | .llseek = seq_lseek, | ||
95 | .release = seq_release, | ||
96 | .write = config_proc_write | ||
97 | }; | ||
98 | |||
99 | static struct file_operations info_proc_file_ops = { | ||
100 | .owner = THIS_MODULE, | ||
101 | .open = info_proc_open, | ||
102 | .read = seq_read, | ||
103 | .llseek = seq_lseek, | ||
104 | .release = seq_release, | ||
105 | }; | ||
106 | |||
107 | static struct file_operations nodeinfo_proc_file_ops = { | ||
108 | .owner = THIS_MODULE, | ||
109 | .open = nodeinfo_proc_open, | ||
110 | .read = seq_read, | ||
111 | .llseek = seq_lseek, | ||
112 | .release = seq_release, | ||
113 | }; | ||
114 | |||
115 | static struct dgrp_proc_entry dgrp_table[] = { | ||
116 | { | ||
117 | .id = DGRP_CONFIG, | ||
118 | .name = "config", | ||
119 | .mode = 0644, | ||
120 | .proc_file_ops = &config_proc_file_ops, | ||
121 | }, | ||
122 | { | ||
123 | .id = DGRP_INFO, | ||
124 | .name = "info", | ||
125 | .mode = 0644, | ||
126 | .proc_file_ops = &info_proc_file_ops, | ||
127 | }, | ||
128 | { | ||
129 | .id = DGRP_NODEINFO, | ||
130 | .name = "nodeinfo", | ||
131 | .mode = 0644, | ||
132 | .proc_file_ops = &nodeinfo_proc_file_ops, | ||
133 | }, | ||
134 | { | ||
135 | .id = DGRP_NETDIR, | ||
136 | .name = "net", | ||
137 | .mode = 0500, | ||
138 | .child = dgrp_net_table | ||
139 | }, | ||
140 | { | ||
141 | .id = DGRP_MONDIR, | ||
142 | .name = "mon", | ||
143 | .mode = 0500, | ||
144 | .child = dgrp_mon_table | ||
145 | }, | ||
146 | { | ||
147 | .id = DGRP_PORTSDIR, | ||
148 | .name = "ports", | ||
149 | .mode = 0500, | ||
150 | .child = dgrp_ports_table | ||
151 | }, | ||
152 | { | ||
153 | .id = DGRP_DPADIR, | ||
154 | .name = "dpa", | ||
155 | .mode = 0500, | ||
156 | .child = dgrp_dpa_table | ||
157 | } | ||
158 | }; | ||
159 | |||
160 | static struct proc_dir_entry *net_entry_pointer; | ||
161 | static struct proc_dir_entry *mon_entry_pointer; | ||
162 | static struct proc_dir_entry *dpa_entry_pointer; | ||
163 | static struct proc_dir_entry *ports_entry_pointer; | ||
164 | |||
165 | static struct dgrp_proc_entry dgrp_net_table[] = { | ||
166 | {0} | ||
167 | }; | ||
168 | |||
169 | static struct dgrp_proc_entry dgrp_mon_table[] = { | ||
170 | {0} | ||
171 | }; | ||
172 | |||
173 | static struct dgrp_proc_entry dgrp_ports_table[] = { | ||
174 | {0} | ||
175 | }; | ||
176 | |||
177 | static struct dgrp_proc_entry dgrp_dpa_table[] = { | ||
178 | {0} | ||
179 | }; | ||
180 | |||
181 | void dgrp_unregister_proc(void) | ||
182 | { | ||
183 | unregister_proc_table(dgrp_table, dgrp_proc_dir_entry); | ||
184 | net_entry_pointer = NULL; | ||
185 | mon_entry_pointer = NULL; | ||
186 | dpa_entry_pointer = NULL; | ||
187 | ports_entry_pointer = NULL; | ||
188 | |||
189 | if (dgrp_proc_dir_entry) { | ||
190 | remove_proc_entry(dgrp_proc_dir_entry->name, | ||
191 | dgrp_proc_dir_entry->parent); | ||
192 | dgrp_proc_dir_entry = NULL; | ||
193 | } | ||
194 | |||
195 | } | ||
196 | |||
197 | void dgrp_register_proc(void) | ||
198 | { | ||
199 | /* | ||
200 | * Register /proc/dgrp | ||
201 | */ | ||
202 | dgrp_proc_dir_entry = proc_create("dgrp", S_IFDIR, NULL, | ||
203 | &dgrp_proc_file_ops); | ||
204 | register_proc_table(dgrp_table, dgrp_proc_dir_entry); | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * /proc/sys support | ||
209 | */ | ||
210 | static int dgrp_proc_match(int len, const char *name, struct proc_dir_entry *de) | ||
211 | { | ||
212 | if (!de || !de->low_ino) | ||
213 | return 0; | ||
214 | if (de->namelen != len) | ||
215 | return 0; | ||
216 | return !memcmp(name, de->name, len); | ||
217 | } | ||
218 | |||
219 | |||
220 | /* | ||
221 | * Scan the entries in table and add them all to /proc at the position | ||
222 | * referred to by "root" | ||
223 | */ | ||
224 | static void register_proc_table(struct dgrp_proc_entry *table, | ||
225 | struct proc_dir_entry *root) | ||
226 | { | ||
227 | struct proc_dir_entry *de; | ||
228 | int len; | ||
229 | mode_t mode; | ||
230 | |||
231 | for (; table->id; table++) { | ||
232 | /* Can't do anything without a proc name. */ | ||
233 | if (!table->name) | ||
234 | continue; | ||
235 | |||
236 | /* Maybe we can't do anything with it... */ | ||
237 | if (!table->proc_file_ops && | ||
238 | !table->child) { | ||
239 | pr_warn("dgrp: Can't register %s\n", | ||
240 | table->name); | ||
241 | continue; | ||
242 | } | ||
243 | |||
244 | len = strlen(table->name); | ||
245 | mode = table->mode; | ||
246 | |||
247 | de = NULL; | ||
248 | if (!table->child) | ||
249 | mode |= S_IFREG; | ||
250 | else { | ||
251 | mode |= S_IFDIR; | ||
252 | for (de = root->subdir; de; de = de->next) { | ||
253 | if (dgrp_proc_match(len, table->name, de)) | ||
254 | break; | ||
255 | } | ||
256 | /* If the subdir exists already, de is non-NULL */ | ||
257 | } | ||
258 | |||
259 | if (!de) { | ||
260 | de = create_proc_entry(table->name, mode, root); | ||
261 | if (!de) | ||
262 | continue; | ||
263 | de->data = (void *) table; | ||
264 | if (!table->child) { | ||
265 | de->proc_iops = &proc_inode_ops; | ||
266 | if (table->proc_file_ops) | ||
267 | de->proc_fops = table->proc_file_ops; | ||
268 | else | ||
269 | de->proc_fops = &dgrp_proc_file_ops; | ||
270 | } | ||
271 | } | ||
272 | table->de = de; | ||
273 | if (de->mode & S_IFDIR) | ||
274 | register_proc_table(table->child, de); | ||
275 | |||
276 | if (table->id == DGRP_NETDIR) | ||
277 | net_entry_pointer = de; | ||
278 | |||
279 | if (table->id == DGRP_MONDIR) | ||
280 | mon_entry_pointer = de; | ||
281 | |||
282 | if (table->id == DGRP_DPADIR) | ||
283 | dpa_entry_pointer = de; | ||
284 | |||
285 | if (table->id == DGRP_PORTSDIR) | ||
286 | ports_entry_pointer = de; | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Unregister a /proc sysctl table and any subdirectories. | ||
292 | */ | ||
293 | static void unregister_proc_table(struct dgrp_proc_entry *table, | ||
294 | struct proc_dir_entry *root) | ||
295 | { | ||
296 | struct proc_dir_entry *de; | ||
297 | struct nd_struct *tmp; | ||
298 | |||
299 | list_for_each_entry(tmp, &nd_struct_list, list) { | ||
300 | if ((table == dgrp_net_table) && (tmp->nd_net_de)) { | ||
301 | unregister_dgrp_device(tmp->nd_net_de); | ||
302 | dgrp_remove_node_class_sysfs_files(tmp); | ||
303 | } | ||
304 | |||
305 | if ((table == dgrp_mon_table) && (tmp->nd_mon_de)) | ||
306 | unregister_dgrp_device(tmp->nd_mon_de); | ||
307 | |||
308 | if ((table == dgrp_dpa_table) && (tmp->nd_dpa_de)) | ||
309 | unregister_dgrp_device(tmp->nd_dpa_de); | ||
310 | |||
311 | if ((table == dgrp_ports_table) && (tmp->nd_ports_de)) | ||
312 | unregister_dgrp_device(tmp->nd_ports_de); | ||
313 | } | ||
314 | |||
315 | for (; table->id; table++) { | ||
316 | de = table->de; | ||
317 | |||
318 | if (!de) | ||
319 | continue; | ||
320 | if (de->mode & S_IFDIR) { | ||
321 | if (!table->child) { | ||
322 | pr_alert("dgrp: malformed sysctl tree on free\n"); | ||
323 | continue; | ||
324 | } | ||
325 | unregister_proc_table(table->child, de); | ||
326 | |||
327 | /* Don't unregister directories which still have entries */ | ||
328 | if (de->subdir) | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | /* Don't unregister proc entries that are still being used.. */ | ||
333 | if ((atomic_read(&de->count)) != 1) { | ||
334 | pr_alert("proc entry %s in use, not removing\n", | ||
335 | de->name); | ||
336 | continue; | ||
337 | } | ||
338 | |||
339 | remove_proc_entry(de->name, de->parent); | ||
340 | table->de = NULL; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | static int dgrp_gen_proc_open(struct inode *inode, struct file *file) | ||
345 | { | ||
346 | struct proc_dir_entry *de; | ||
347 | struct dgrp_proc_entry *entry; | ||
348 | int ret = 0; | ||
349 | |||
350 | de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode); | ||
351 | if (!de || !de->data) { | ||
352 | ret = -ENXIO; | ||
353 | goto done; | ||
354 | } | ||
355 | |||
356 | entry = (struct dgrp_proc_entry *) de->data; | ||
357 | if (!entry) { | ||
358 | ret = -ENXIO; | ||
359 | goto done; | ||
360 | } | ||
361 | |||
362 | down(&entry->excl_sem); | ||
363 | |||
364 | if (entry->excl_cnt) | ||
365 | ret = -EBUSY; | ||
366 | else | ||
367 | entry->excl_cnt++; | ||
368 | |||
369 | up(&entry->excl_sem); | ||
370 | |||
371 | done: | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int dgrp_gen_proc_close(struct inode *inode, struct file *file) | ||
376 | { | ||
377 | struct proc_dir_entry *de; | ||
378 | struct dgrp_proc_entry *entry; | ||
379 | |||
380 | de = (struct proc_dir_entry *) PDE(file->f_dentry->d_inode); | ||
381 | if (!de || !de->data) | ||
382 | goto done; | ||
383 | |||
384 | entry = (struct dgrp_proc_entry *) de->data; | ||
385 | if (!entry) | ||
386 | goto done; | ||
387 | |||
388 | down(&entry->excl_sem); | ||
389 | |||
390 | if (entry->excl_cnt) | ||
391 | entry->excl_cnt = 0; | ||
392 | |||
393 | up(&entry->excl_sem); | ||
394 | |||
395 | done: | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static void *config_proc_start(struct seq_file *m, loff_t *pos) | ||
400 | { | ||
401 | return seq_list_start_head(&nd_struct_list, *pos); | ||
402 | } | ||
403 | |||
404 | static void *config_proc_next(struct seq_file *p, void *v, loff_t *pos) | ||
405 | { | ||
406 | return seq_list_next(v, &nd_struct_list, pos); | ||
407 | } | ||
408 | |||
409 | static void config_proc_stop(struct seq_file *m, void *v) | ||
410 | { | ||
411 | } | ||
412 | |||
413 | static int config_proc_show(struct seq_file *m, void *v) | ||
414 | { | ||
415 | struct nd_struct *nd; | ||
416 | char tmp_id[4]; | ||
417 | |||
418 | if (v == &nd_struct_list) { | ||
419 | seq_puts(m, "#-----------------------------------------------------------------------------\n"); | ||
420 | seq_puts(m, "# Avail\n"); | ||
421 | seq_puts(m, "# ID Major State Ports\n"); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | nd = list_entry(v, struct nd_struct, list); | ||
426 | |||
427 | ID_TO_CHAR(nd->nd_ID, tmp_id); | ||
428 | |||
429 | seq_printf(m, " %-2.2s %-5ld %-10.10s %-5d\n", | ||
430 | tmp_id, | ||
431 | nd->nd_major, | ||
432 | ND_STATE_STR(nd->nd_state), | ||
433 | nd->nd_chan_count); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static const struct seq_operations proc_config_ops = { | ||
439 | .start = config_proc_start, | ||
440 | .next = config_proc_next, | ||
441 | .stop = config_proc_stop, | ||
442 | .show = config_proc_show | ||
443 | }; | ||
444 | |||
445 | static int config_proc_open(struct inode *inode, struct file *file) | ||
446 | { | ||
447 | return seq_open(file, &proc_config_ops); | ||
448 | } | ||
449 | |||
450 | |||
451 | /* | ||
452 | * When writing configuration information, each "record" (i.e. each | ||
453 | * write) is treated as an independent request. See the "parse" | ||
454 | * description for more details. | ||
455 | */ | ||
456 | static ssize_t config_proc_write(struct file *file, const char __user *buffer, | ||
457 | size_t count, loff_t *pos) | ||
458 | { | ||
459 | ssize_t retval; | ||
460 | char *inbuf, *sp; | ||
461 | char *line, *ldelim; | ||
462 | |||
463 | if (count > 32768) | ||
464 | return -EINVAL; | ||
465 | |||
466 | inbuf = sp = vzalloc(count + 1); | ||
467 | if (!inbuf) | ||
468 | return -ENOMEM; | ||
469 | |||
470 | if (copy_from_user(inbuf, buffer, count)) { | ||
471 | retval = -EFAULT; | ||
472 | goto done; | ||
473 | } | ||
474 | |||
475 | inbuf[count] = 0; | ||
476 | |||
477 | ldelim = "\n"; | ||
478 | |||
479 | line = strpbrk(sp, ldelim); | ||
480 | while (line) { | ||
481 | *line = 0; | ||
482 | retval = parse_write_config(sp); | ||
483 | if (retval) | ||
484 | goto done; | ||
485 | |||
486 | sp = line + 1; | ||
487 | line = strpbrk(sp, ldelim); | ||
488 | } | ||
489 | |||
490 | retval = count; | ||
491 | done: | ||
492 | vfree(inbuf); | ||
493 | return retval; | ||
494 | } | ||
495 | |||
496 | /* | ||
497 | * ------------------------------------------------------------------------ | ||
498 | * | ||
499 | * The following are the functions to parse input | ||
500 | * | ||
501 | * ------------------------------------------------------------------------ | ||
502 | */ | ||
503 | static inline char *skip_past_ws(const char *str) | ||
504 | { | ||
505 | while ((*str) && !isspace(*str)) | ||
506 | ++str; | ||
507 | |||
508 | return skip_spaces(str); | ||
509 | } | ||
510 | |||
511 | static int parse_id(char **c, char *cID) | ||
512 | { | ||
513 | int tmp = **c; | ||
514 | |||
515 | if (isalnum(tmp) || (tmp == '_')) | ||
516 | cID[0] = tmp; | ||
517 | else | ||
518 | return -EINVAL; | ||
519 | |||
520 | (*c)++; tmp = **c; | ||
521 | |||
522 | if (isalnum(tmp) || (tmp == '_')) { | ||
523 | cID[1] = tmp; | ||
524 | (*c)++; | ||
525 | } else | ||
526 | cID[1] = 0; | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static int parse_add_config(char *buf) | ||
532 | { | ||
533 | char *c = buf; | ||
534 | int retval; | ||
535 | char cID[2]; | ||
536 | long ID; | ||
537 | |||
538 | c = skip_past_ws(c); | ||
539 | |||
540 | retval = parse_id(&c, cID); | ||
541 | if (retval < 0) | ||
542 | return retval; | ||
543 | |||
544 | ID = CHAR_TO_ID(cID); | ||
545 | |||
546 | c = skip_past_ws(c); | ||
547 | |||
548 | return dgrp_add_id(ID); | ||
549 | } | ||
550 | |||
551 | static int parse_del_config(char *buf) | ||
552 | { | ||
553 | char *c = buf; | ||
554 | int retval; | ||
555 | struct nd_struct *nd; | ||
556 | char cID[2]; | ||
557 | long ID; | ||
558 | long major; | ||
559 | |||
560 | c = skip_past_ws(c); | ||
561 | |||
562 | retval = parse_id(&c, cID); | ||
563 | if (retval < 0) | ||
564 | return retval; | ||
565 | |||
566 | ID = CHAR_TO_ID(cID); | ||
567 | |||
568 | c = skip_past_ws(c); | ||
569 | |||
570 | retval = kstrtol(c, 10, &major); | ||
571 | if (retval) | ||
572 | return retval; | ||
573 | |||
574 | nd = nd_struct_get(major); | ||
575 | if (!nd) | ||
576 | return -EINVAL; | ||
577 | |||
578 | if ((nd->nd_major != major) || (nd->nd_ID != ID)) | ||
579 | return -EINVAL; | ||
580 | |||
581 | return dgrp_remove_nd(nd); | ||
582 | } | ||
583 | |||
584 | static int parse_chg_config(char *buf) | ||
585 | { | ||
586 | return -EINVAL; | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * The passed character buffer represents a single configuration request. | ||
591 | * If the first character is a "+", it is parsed as a request to add a | ||
592 | * PortServer | ||
593 | * If the first character is a "-", it is parsed as a request to delete a | ||
594 | * PortServer | ||
595 | * If the first character is a "*", it is parsed as a request to change a | ||
596 | * PortServer | ||
597 | * Any other character (including whitespace) causes the record to be | ||
598 | * ignored. | ||
599 | */ | ||
600 | static int parse_write_config(char *buf) | ||
601 | { | ||
602 | int retval; | ||
603 | |||
604 | switch (buf[0]) { | ||
605 | case '+': | ||
606 | retval = parse_add_config(buf); | ||
607 | break; | ||
608 | case '-': | ||
609 | retval = parse_del_config(buf); | ||
610 | break; | ||
611 | case '*': | ||
612 | retval = parse_chg_config(buf); | ||
613 | break; | ||
614 | default: | ||
615 | retval = -EINVAL; | ||
616 | } | ||
617 | |||
618 | return retval; | ||
619 | } | ||
620 | |||
621 | static int info_proc_show(struct seq_file *m, void *v) | ||
622 | { | ||
623 | seq_printf(m, "version: %s\n", DIGI_VERSION); | ||
624 | seq_puts(m, "register_with_sysfs: 1\n"); | ||
625 | seq_printf(m, "rawreadok: 0x%08x\t(%d)\n", | ||
626 | dgrp_rawreadok, dgrp_rawreadok); | ||
627 | seq_printf(m, "pollrate: 0x%08x\t(%d)\n", | ||
628 | dgrp_poll_tick, dgrp_poll_tick); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int info_proc_open(struct inode *inode, struct file *file) | ||
634 | { | ||
635 | return single_open(file, info_proc_show, NULL); | ||
636 | } | ||
637 | |||
638 | |||
639 | static void *nodeinfo_start(struct seq_file *m, loff_t *pos) | ||
640 | { | ||
641 | return seq_list_start_head(&nd_struct_list, *pos); | ||
642 | } | ||
643 | |||
644 | static void *nodeinfo_next(struct seq_file *p, void *v, loff_t *pos) | ||
645 | { | ||
646 | return seq_list_next(v, &nd_struct_list, pos); | ||
647 | } | ||
648 | |||
649 | static void nodeinfo_stop(struct seq_file *m, void *v) | ||
650 | { | ||
651 | } | ||
652 | |||
653 | static int nodeinfo_show(struct seq_file *m, void *v) | ||
654 | { | ||
655 | struct nd_struct *nd; | ||
656 | char hwver[8]; | ||
657 | char swver[8]; | ||
658 | char tmp_id[4]; | ||
659 | |||
660 | if (v == &nd_struct_list) { | ||
661 | seq_puts(m, "#-----------------------------------------------------------------------------\n"); | ||
662 | seq_puts(m, "# HW HW SW\n"); | ||
663 | seq_puts(m, "# ID State Version ID Version Description\n"); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | nd = list_entry(v, struct nd_struct, list); | ||
668 | |||
669 | ID_TO_CHAR(nd->nd_ID, tmp_id); | ||
670 | |||
671 | if (nd->nd_state == NS_READY) { | ||
672 | sprintf(hwver, "%d.%d", (nd->nd_hw_ver >> 8) & 0xff, | ||
673 | nd->nd_hw_ver & 0xff); | ||
674 | sprintf(swver, "%d.%d", (nd->nd_sw_ver >> 8) & 0xff, | ||
675 | nd->nd_sw_ver & 0xff); | ||
676 | seq_printf(m, " %-2.2s %-10.10s %-7.7s %-3d %-7.7s %-35.35s\n", | ||
677 | tmp_id, | ||
678 | ND_STATE_STR(nd->nd_state), | ||
679 | hwver, | ||
680 | nd->nd_hw_id, | ||
681 | swver, | ||
682 | nd->nd_ps_desc); | ||
683 | |||
684 | } else { | ||
685 | seq_printf(m, " %-2.2s %-10.10s\n", | ||
686 | tmp_id, | ||
687 | ND_STATE_STR(nd->nd_state)); | ||
688 | } | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | |||
694 | static const struct seq_operations nodeinfo_ops = { | ||
695 | .start = nodeinfo_start, | ||
696 | .next = nodeinfo_next, | ||
697 | .stop = nodeinfo_stop, | ||
698 | .show = nodeinfo_show | ||
699 | }; | ||
700 | |||
701 | static int nodeinfo_proc_open(struct inode *inode, struct file *file) | ||
702 | { | ||
703 | return seq_open(file, &nodeinfo_ops); | ||
704 | } | ||
705 | |||
706 | /** | ||
707 | * dgrp_add_id() -- creates new nd struct and adds it to list | ||
708 | * @id: id of device to add | ||
709 | */ | ||
710 | static int dgrp_add_id(long id) | ||
711 | { | ||
712 | struct nd_struct *nd; | ||
713 | int ret; | ||
714 | int i; | ||
715 | |||
716 | nd = kzalloc(sizeof(struct nd_struct), GFP_KERNEL); | ||
717 | if (!nd) | ||
718 | return -ENOMEM; | ||
719 | |||
720 | nd->nd_major = 0; | ||
721 | nd->nd_ID = id; | ||
722 | |||
723 | spin_lock_init(&nd->nd_lock); | ||
724 | |||
725 | init_waitqueue_head(&nd->nd_tx_waitq); | ||
726 | init_waitqueue_head(&nd->nd_mon_wqueue); | ||
727 | init_waitqueue_head(&nd->nd_dpa_wqueue); | ||
728 | for (i = 0; i < SEQ_MAX; i++) | ||
729 | init_waitqueue_head(&nd->nd_seq_wque[i]); | ||
730 | |||
731 | /* setup the structures to get the major number */ | ||
732 | ret = dgrp_tty_init(nd); | ||
733 | if (ret) | ||
734 | goto error_out; | ||
735 | |||
736 | nd->nd_major = nd->nd_serial_ttdriver->major; | ||
737 | |||
738 | ret = nd_struct_add(nd); | ||
739 | if (ret) | ||
740 | goto error_out; | ||
741 | |||
742 | register_dgrp_device(nd, net_entry_pointer, dgrp_register_net_hook); | ||
743 | register_dgrp_device(nd, mon_entry_pointer, dgrp_register_mon_hook); | ||
744 | register_dgrp_device(nd, dpa_entry_pointer, dgrp_register_dpa_hook); | ||
745 | register_dgrp_device(nd, ports_entry_pointer, | ||
746 | dgrp_register_ports_hook); | ||
747 | |||
748 | return 0; | ||
749 | |||
750 | error_out: | ||
751 | kfree(nd); | ||
752 | return ret; | ||
753 | |||
754 | } | ||
755 | |||
756 | static int dgrp_remove_nd(struct nd_struct *nd) | ||
757 | { | ||
758 | int ret; | ||
759 | |||
760 | /* Check to see if the selected structure is in use */ | ||
761 | if (nd->nd_tty_ref_cnt) | ||
762 | return -EBUSY; | ||
763 | |||
764 | if (nd->nd_net_de) { | ||
765 | unregister_dgrp_device(nd->nd_net_de); | ||
766 | dgrp_remove_node_class_sysfs_files(nd); | ||
767 | } | ||
768 | |||
769 | if (nd->nd_mon_de) | ||
770 | unregister_dgrp_device(nd->nd_mon_de); | ||
771 | |||
772 | if (nd->nd_ports_de) | ||
773 | unregister_dgrp_device(nd->nd_ports_de); | ||
774 | |||
775 | if (nd->nd_dpa_de) | ||
776 | unregister_dgrp_device(nd->nd_dpa_de); | ||
777 | |||
778 | dgrp_tty_uninit(nd); | ||
779 | |||
780 | ret = nd_struct_del(nd); | ||
781 | if (ret) | ||
782 | return ret; | ||
783 | |||
784 | kfree(nd); | ||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static void register_dgrp_device(struct nd_struct *node, | ||
789 | struct proc_dir_entry *root, | ||
790 | void (*register_hook)(struct proc_dir_entry *de)) | ||
791 | { | ||
792 | char buf[3]; | ||
793 | struct proc_dir_entry *de; | ||
794 | |||
795 | ID_TO_CHAR(node->nd_ID, buf); | ||
796 | |||
797 | de = create_proc_entry(buf, 0600 | S_IFREG, root); | ||
798 | if (!de) | ||
799 | return; | ||
800 | |||
801 | de->data = (void *) node; | ||
802 | |||
803 | if (register_hook) | ||
804 | register_hook(de); | ||
805 | |||
806 | } | ||
807 | |||
808 | static void unregister_dgrp_device(struct proc_dir_entry *de) | ||
809 | { | ||
810 | if (!de) | ||
811 | return; | ||
812 | |||
813 | /* Don't unregister proc entries that are still being used.. */ | ||
814 | if ((atomic_read(&de->count)) != 1) { | ||
815 | pr_alert("%s - proc entry %s in use. Not removing.\n", | ||
816 | __func__, de->name); | ||
817 | return; | ||
818 | } | ||
819 | |||
820 | remove_proc_entry(de->name, de->parent); | ||
821 | de = NULL; | ||
822 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c new file mode 100644 index 000000000000..e5a3c88d016e --- /dev/null +++ b/drivers/staging/dgrp/dgrp_sysfs.c | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * Copyright 2004 Digi International (www.digi.com) | ||
3 | * Scott H Kilau <Scott_Kilau at digi dot com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2, or (at your option) | ||
8 | * any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the | ||
12 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
13 | * PURPOSE. See the GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include "dgrp_common.h" | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/version.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/ctype.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/serial_reg.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/kdev_t.h> | ||
27 | |||
28 | |||
29 | #define PORTSERVER_DIVIDEND 1843200 | ||
30 | #define SERIAL_TYPE_NORMAL 1 | ||
31 | #define SERIAL_TYPE_CALLOUT 2 | ||
32 | #define SERIAL_TYPE_XPRINT 3 | ||
33 | |||
34 | |||
35 | static struct class *dgrp_class; | ||
36 | static struct device *dgrp_class_nodes_dev; | ||
37 | static struct device *dgrp_class_global_settings_dev; | ||
38 | |||
39 | |||
40 | static ssize_t dgrp_class_version_show(struct class *class, | ||
41 | struct class_attribute *attr, char *buf) | ||
42 | { | ||
43 | return snprintf(buf, PAGE_SIZE, "%s\n", DIGI_VERSION); | ||
44 | } | ||
45 | static CLASS_ATTR(driver_version, 0400, dgrp_class_version_show, NULL); | ||
46 | |||
47 | |||
48 | static ssize_t dgrp_class_register_with_sysfs_show(struct device *c, | ||
49 | struct device_attribute *attr, | ||
50 | char *buf) | ||
51 | { | ||
52 | return snprintf(buf, PAGE_SIZE, "1\n"); | ||
53 | } | ||
54 | static DEVICE_ATTR(register_with_sysfs, 0400, | ||
55 | dgrp_class_register_with_sysfs_show, NULL); | ||
56 | |||
57 | |||
58 | static ssize_t dgrp_class_rawreadok_show(struct device *c, | ||
59 | struct device_attribute *attr, | ||
60 | char *buf) | ||
61 | { | ||
62 | return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_rawreadok); | ||
63 | } | ||
64 | static ssize_t dgrp_class_rawreadok_store(struct device *c, | ||
65 | struct device_attribute *attr, | ||
66 | const char *buf, size_t count) | ||
67 | { | ||
68 | sscanf(buf, "0x%x\n", &dgrp_rawreadok); | ||
69 | return count; | ||
70 | } | ||
71 | static DEVICE_ATTR(rawreadok, 0600, dgrp_class_rawreadok_show, | ||
72 | dgrp_class_rawreadok_store); | ||
73 | |||
74 | |||
75 | static ssize_t dgrp_class_pollrate_show(struct device *c, | ||
76 | struct device_attribute *attr, | ||
77 | char *buf) | ||
78 | { | ||
79 | return snprintf(buf, PAGE_SIZE, "%d\n", dgrp_poll_tick); | ||
80 | } | ||
81 | |||
82 | static ssize_t dgrp_class_pollrate_store(struct device *c, | ||
83 | struct device_attribute *attr, | ||
84 | const char *buf, size_t count) | ||
85 | { | ||
86 | sscanf(buf, "0x%x\n", &dgrp_poll_tick); | ||
87 | return count; | ||
88 | } | ||
89 | static DEVICE_ATTR(pollrate, 0600, dgrp_class_pollrate_show, | ||
90 | dgrp_class_pollrate_store); | ||
91 | |||
92 | static struct attribute *dgrp_sysfs_global_settings_entries[] = { | ||
93 | &dev_attr_pollrate.attr, | ||
94 | &dev_attr_rawreadok.attr, | ||
95 | &dev_attr_register_with_sysfs.attr, | ||
96 | NULL | ||
97 | }; | ||
98 | |||
99 | |||
100 | static struct attribute_group dgrp_global_settings_attribute_group = { | ||
101 | .name = NULL, | ||
102 | .attrs = dgrp_sysfs_global_settings_entries, | ||
103 | }; | ||
104 | |||
105 | |||
106 | |||
107 | void dgrp_create_class_sysfs_files(void) | ||
108 | { | ||
109 | int ret = 0; | ||
110 | int max_majors = 1U << (32 - MINORBITS); | ||
111 | |||
112 | dgrp_class = class_create(THIS_MODULE, "digi_realport"); | ||
113 | ret = class_create_file(dgrp_class, &class_attr_driver_version); | ||
114 | |||
115 | dgrp_class_global_settings_dev = device_create(dgrp_class, NULL, | ||
116 | MKDEV(0, max_majors + 1), NULL, "driver_settings"); | ||
117 | |||
118 | ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj, | ||
119 | &dgrp_global_settings_attribute_group); | ||
120 | if (ret) { | ||
121 | pr_alert("%s: failed to create sysfs global settings device attributes.\n", | ||
122 | __func__); | ||
123 | sysfs_remove_group(&dgrp_class_global_settings_dev->kobj, | ||
124 | &dgrp_global_settings_attribute_group); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | dgrp_class_nodes_dev = device_create(dgrp_class, NULL, | ||
129 | MKDEV(0, max_majors + 2), NULL, "nodes"); | ||
130 | |||
131 | } | ||
132 | |||
133 | |||
134 | void dgrp_remove_class_sysfs_files(void) | ||
135 | { | ||
136 | struct nd_struct *nd; | ||
137 | int max_majors = 1U << (32 - MINORBITS); | ||
138 | |||
139 | list_for_each_entry(nd, &nd_struct_list, list) | ||
140 | dgrp_remove_node_class_sysfs_files(nd); | ||
141 | |||
142 | sysfs_remove_group(&dgrp_class_global_settings_dev->kobj, | ||
143 | &dgrp_global_settings_attribute_group); | ||
144 | |||
145 | class_remove_file(dgrp_class, &class_attr_driver_version); | ||
146 | |||
147 | device_destroy(dgrp_class, MKDEV(0, max_majors + 1)); | ||
148 | device_destroy(dgrp_class, MKDEV(0, max_majors + 2)); | ||
149 | class_destroy(dgrp_class); | ||
150 | } | ||
151 | |||
152 | static ssize_t dgrp_node_state_show(struct device *c, | ||
153 | struct device_attribute *attr, char *buf) | ||
154 | { | ||
155 | struct nd_struct *nd; | ||
156 | |||
157 | if (!c) | ||
158 | return 0; | ||
159 | nd = (struct nd_struct *) dev_get_drvdata(c); | ||
160 | if (!nd) | ||
161 | return 0; | ||
162 | |||
163 | return snprintf(buf, PAGE_SIZE, "%s\n", ND_STATE_STR(nd->nd_state)); | ||
164 | } | ||
165 | |||
166 | static DEVICE_ATTR(state, 0600, dgrp_node_state_show, NULL); | ||
167 | |||
168 | static ssize_t dgrp_node_description_show(struct device *c, | ||
169 | struct device_attribute *attr, | ||
170 | char *buf) | ||
171 | { | ||
172 | struct nd_struct *nd; | ||
173 | |||
174 | if (!c) | ||
175 | return 0; | ||
176 | nd = (struct nd_struct *) dev_get_drvdata(c); | ||
177 | if (!nd) | ||
178 | return 0; | ||
179 | |||
180 | if (nd->nd_state == NS_READY && nd->nd_ps_desc) | ||
181 | return snprintf(buf, PAGE_SIZE, "%s\n", nd->nd_ps_desc); | ||
182 | return 0; | ||
183 | } | ||
184 | static DEVICE_ATTR(description_info, 0600, dgrp_node_description_show, NULL); | ||
185 | |||
186 | static ssize_t dgrp_node_hw_version_show(struct device *c, | ||
187 | struct device_attribute *attr, | ||
188 | char *buf) | ||
189 | { | ||
190 | struct nd_struct *nd; | ||
191 | |||
192 | if (!c) | ||
193 | return 0; | ||
194 | nd = (struct nd_struct *) dev_get_drvdata(c); | ||
195 | if (!nd) | ||
196 | return 0; | ||
197 | |||
198 | if (nd->nd_state == NS_READY) | ||
199 | return snprintf(buf, PAGE_SIZE, "%d.%d\n", | ||
200 | (nd->nd_hw_ver >> 8) & 0xff, | ||
201 | nd->nd_hw_ver & 0xff); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | static DEVICE_ATTR(hw_version_info, 0600, dgrp_node_hw_version_show, NULL); | ||
206 | |||
207 | static ssize_t dgrp_node_hw_id_show(struct device *c, | ||
208 | struct device_attribute *attr, char *buf) | ||
209 | { | ||
210 | struct nd_struct *nd; | ||
211 | |||
212 | if (!c) | ||
213 | return 0; | ||
214 | nd = (struct nd_struct *) dev_get_drvdata(c); | ||
215 | if (!nd) | ||
216 | return 0; | ||
217 | |||
218 | |||
219 | if (nd->nd_state == NS_READY) | ||
220 | return snprintf(buf, PAGE_SIZE, "%d\n", nd->nd_hw_id); | ||
221 | return 0; | ||
222 | } | ||
223 | static DEVICE_ATTR(hw_id_info, 0600, dgrp_node_hw_id_show, NULL); | ||
224 | |||
225 | static ssize_t dgrp_node_sw_version_show(struct device *c, | ||
226 | struct device_attribute *attr, | ||
227 | char *buf) | ||
228 | { | ||
229 | struct nd_struct *nd; | ||
230 | |||
231 | if (!c) | ||
232 | return 0; | ||
233 | |||
234 | nd = (struct nd_struct *) dev_get_drvdata(c); | ||
235 | if (!nd) | ||
236 | return 0; | ||
237 | |||
238 | if (nd->nd_state == NS_READY) | ||
239 | return snprintf(buf, PAGE_SIZE, "%d.%d\n", | ||
240 | (nd->nd_sw_ver >> 8) & 0xff, | ||
241 | nd->nd_sw_ver & 0xff); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | static DEVICE_ATTR(sw_version_info, 0600, dgrp_node_sw_version_show, NULL); | ||
246 | |||
247 | |||
248 | static struct attribute *dgrp_sysfs_node_entries[] = { | ||
249 | &dev_attr_state.attr, | ||
250 | &dev_attr_description_info.attr, | ||
251 | &dev_attr_hw_version_info.attr, | ||
252 | &dev_attr_hw_id_info.attr, | ||
253 | &dev_attr_sw_version_info.attr, | ||
254 | NULL | ||
255 | }; | ||
256 | |||
257 | |||
258 | static struct attribute_group dgrp_node_attribute_group = { | ||
259 | .name = NULL, | ||
260 | .attrs = dgrp_sysfs_node_entries, | ||
261 | }; | ||
262 | |||
263 | |||
264 | void dgrp_create_node_class_sysfs_files(struct nd_struct *nd) | ||
265 | { | ||
266 | int ret; | ||
267 | char name[10]; | ||
268 | |||
269 | if (nd->nd_ID) | ||
270 | ID_TO_CHAR(nd->nd_ID, name); | ||
271 | else | ||
272 | sprintf(name, "node%ld", nd->nd_major); | ||
273 | |||
274 | nd->nd_class_dev = device_create(dgrp_class, dgrp_class_nodes_dev, | ||
275 | MKDEV(0, nd->nd_major), NULL, name); | ||
276 | |||
277 | ret = sysfs_create_group(&nd->nd_class_dev->kobj, | ||
278 | &dgrp_node_attribute_group); | ||
279 | |||
280 | if (ret) { | ||
281 | pr_alert("%s: failed to create sysfs node device attributes.\n", | ||
282 | __func__); | ||
283 | sysfs_remove_group(&nd->nd_class_dev->kobj, | ||
284 | &dgrp_node_attribute_group); | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | dev_set_drvdata(nd->nd_class_dev, nd); | ||
289 | |||
290 | } | ||
291 | |||
292 | |||
293 | void dgrp_remove_node_class_sysfs_files(struct nd_struct *nd) | ||
294 | { | ||
295 | if (nd->nd_class_dev) { | ||
296 | sysfs_remove_group(&nd->nd_class_dev->kobj, | ||
297 | &dgrp_node_attribute_group); | ||
298 | |||
299 | device_destroy(dgrp_class, MKDEV(0, nd->nd_major)); | ||
300 | nd->nd_class_dev = NULL; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | |||
305 | |||
306 | static ssize_t dgrp_tty_state_show(struct device *d, | ||
307 | struct device_attribute *attr, char *buf) | ||
308 | { | ||
309 | struct un_struct *un; | ||
310 | |||
311 | if (!d) | ||
312 | return 0; | ||
313 | un = (struct un_struct *) dev_get_drvdata(d); | ||
314 | if (!un) | ||
315 | return 0; | ||
316 | |||
317 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
318 | un->un_open_count ? "Open" : "Closed"); | ||
319 | } | ||
320 | static DEVICE_ATTR(state_info, 0600, dgrp_tty_state_show, NULL); | ||
321 | |||
322 | static ssize_t dgrp_tty_baud_show(struct device *d, | ||
323 | struct device_attribute *attr, char *buf) | ||
324 | { | ||
325 | struct ch_struct *ch; | ||
326 | struct un_struct *un; | ||
327 | |||
328 | if (!d) | ||
329 | return 0; | ||
330 | un = (struct un_struct *) dev_get_drvdata(d); | ||
331 | if (!un) | ||
332 | return 0; | ||
333 | ch = un->un_ch; | ||
334 | if (!ch) | ||
335 | return 0; | ||
336 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
337 | un->un_open_count ? (PORTSERVER_DIVIDEND / ch->ch_s_brate) : 0); | ||
338 | } | ||
339 | static DEVICE_ATTR(baud_info, 0400, dgrp_tty_baud_show, NULL); | ||
340 | |||
341 | |||
342 | static ssize_t dgrp_tty_msignals_show(struct device *d, | ||
343 | struct device_attribute *attr, char *buf) | ||
344 | { | ||
345 | struct ch_struct *ch; | ||
346 | struct un_struct *un; | ||
347 | |||
348 | if (!d) | ||
349 | return 0; | ||
350 | un = (struct un_struct *) dev_get_drvdata(d); | ||
351 | if (!un) | ||
352 | return 0; | ||
353 | ch = un->un_ch; | ||
354 | if (!ch) | ||
355 | return 0; | ||
356 | |||
357 | if (ch->ch_open_count) { | ||
358 | return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", | ||
359 | (ch->ch_s_mlast & DM_RTS) ? "RTS" : "", | ||
360 | (ch->ch_s_mlast & DM_CTS) ? "CTS" : "", | ||
361 | (ch->ch_s_mlast & DM_DTR) ? "DTR" : "", | ||
362 | (ch->ch_s_mlast & DM_DSR) ? "DSR" : "", | ||
363 | (ch->ch_s_mlast & DM_CD) ? "DCD" : "", | ||
364 | (ch->ch_s_mlast & DM_RI) ? "RI" : ""); | ||
365 | } | ||
366 | return 0; | ||
367 | } | ||
368 | static DEVICE_ATTR(msignals_info, 0400, dgrp_tty_msignals_show, NULL); | ||
369 | |||
370 | |||
371 | static ssize_t dgrp_tty_iflag_show(struct device *d, | ||
372 | struct device_attribute *attr, char *buf) | ||
373 | { | ||
374 | struct ch_struct *ch; | ||
375 | struct un_struct *un; | ||
376 | |||
377 | if (!d) | ||
378 | return 0; | ||
379 | un = (struct un_struct *) dev_get_drvdata(d); | ||
380 | if (!un) | ||
381 | return 0; | ||
382 | ch = un->un_ch; | ||
383 | if (!ch) | ||
384 | return 0; | ||
385 | return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_iflag); | ||
386 | } | ||
387 | static DEVICE_ATTR(iflag_info, 0600, dgrp_tty_iflag_show, NULL); | ||
388 | |||
389 | |||
390 | static ssize_t dgrp_tty_cflag_show(struct device *d, | ||
391 | struct device_attribute *attr, char *buf) | ||
392 | { | ||
393 | struct ch_struct *ch; | ||
394 | struct un_struct *un; | ||
395 | |||
396 | if (!d) | ||
397 | return 0; | ||
398 | un = (struct un_struct *) dev_get_drvdata(d); | ||
399 | if (!un) | ||
400 | return 0; | ||
401 | ch = un->un_ch; | ||
402 | if (!ch) | ||
403 | return 0; | ||
404 | return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_cflag); | ||
405 | } | ||
406 | static DEVICE_ATTR(cflag_info, 0600, dgrp_tty_cflag_show, NULL); | ||
407 | |||
408 | |||
409 | static ssize_t dgrp_tty_oflag_show(struct device *d, | ||
410 | struct device_attribute *attr, char *buf) | ||
411 | { | ||
412 | struct ch_struct *ch; | ||
413 | struct un_struct *un; | ||
414 | |||
415 | if (!d) | ||
416 | return 0; | ||
417 | un = (struct un_struct *) dev_get_drvdata(d); | ||
418 | if (!un) | ||
419 | return 0; | ||
420 | ch = un->un_ch; | ||
421 | if (!ch) | ||
422 | return 0; | ||
423 | return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_s_oflag); | ||
424 | } | ||
425 | static DEVICE_ATTR(oflag_info, 0600, dgrp_tty_oflag_show, NULL); | ||
426 | |||
427 | |||
428 | static ssize_t dgrp_tty_digi_flag_show(struct device *d, | ||
429 | struct device_attribute *attr, char *buf) | ||
430 | { | ||
431 | struct ch_struct *ch; | ||
432 | struct un_struct *un; | ||
433 | |||
434 | if (!d) | ||
435 | return 0; | ||
436 | un = (struct un_struct *) dev_get_drvdata(d); | ||
437 | if (!un) | ||
438 | return 0; | ||
439 | ch = un->un_ch; | ||
440 | if (!ch) | ||
441 | return 0; | ||
442 | return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); | ||
443 | } | ||
444 | static DEVICE_ATTR(digi_flag_info, 0600, dgrp_tty_digi_flag_show, NULL); | ||
445 | |||
446 | |||
447 | static ssize_t dgrp_tty_rxcount_show(struct device *d, | ||
448 | struct device_attribute *attr, char *buf) | ||
449 | { | ||
450 | struct ch_struct *ch; | ||
451 | struct un_struct *un; | ||
452 | |||
453 | if (!d) | ||
454 | return 0; | ||
455 | un = (struct un_struct *) dev_get_drvdata(d); | ||
456 | if (!un) | ||
457 | return 0; | ||
458 | ch = un->un_ch; | ||
459 | if (!ch) | ||
460 | return 0; | ||
461 | return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_rxcount); | ||
462 | } | ||
463 | static DEVICE_ATTR(rxcount_info, 0600, dgrp_tty_rxcount_show, NULL); | ||
464 | |||
465 | |||
466 | static ssize_t dgrp_tty_txcount_show(struct device *d, | ||
467 | struct device_attribute *attr, char *buf) | ||
468 | { | ||
469 | struct ch_struct *ch; | ||
470 | struct un_struct *un; | ||
471 | |||
472 | if (!d) | ||
473 | return 0; | ||
474 | un = (struct un_struct *) dev_get_drvdata(d); | ||
475 | if (!un) | ||
476 | return 0; | ||
477 | ch = un->un_ch; | ||
478 | if (!ch) | ||
479 | return 0; | ||
480 | return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_txcount); | ||
481 | } | ||
482 | static DEVICE_ATTR(txcount_info, 0600, dgrp_tty_txcount_show, NULL); | ||
483 | |||
484 | |||
485 | static ssize_t dgrp_tty_name_show(struct device *d, | ||
486 | struct device_attribute *attr, char *buf) | ||
487 | { | ||
488 | struct nd_struct *nd; | ||
489 | struct ch_struct *ch; | ||
490 | struct un_struct *un; | ||
491 | char name[10]; | ||
492 | |||
493 | if (!d) | ||
494 | return 0; | ||
495 | un = (struct un_struct *) dev_get_drvdata(d); | ||
496 | if (!un) | ||
497 | return 0; | ||
498 | ch = un->un_ch; | ||
499 | if (!ch) | ||
500 | return 0; | ||
501 | nd = ch->ch_nd; | ||
502 | if (!nd) | ||
503 | return 0; | ||
504 | |||
505 | ID_TO_CHAR(nd->nd_ID, name); | ||
506 | |||
507 | return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", | ||
508 | un->un_type == SERIAL_TYPE_XPRINT ? "pr" : "tty", | ||
509 | name, ch->ch_portnum); | ||
510 | } | ||
511 | static DEVICE_ATTR(custom_name, 0600, dgrp_tty_name_show, NULL); | ||
512 | |||
513 | |||
514 | static struct attribute *dgrp_sysfs_tty_entries[] = { | ||
515 | &dev_attr_state_info.attr, | ||
516 | &dev_attr_baud_info.attr, | ||
517 | &dev_attr_msignals_info.attr, | ||
518 | &dev_attr_iflag_info.attr, | ||
519 | &dev_attr_cflag_info.attr, | ||
520 | &dev_attr_oflag_info.attr, | ||
521 | &dev_attr_digi_flag_info.attr, | ||
522 | &dev_attr_rxcount_info.attr, | ||
523 | &dev_attr_txcount_info.attr, | ||
524 | &dev_attr_custom_name.attr, | ||
525 | NULL | ||
526 | }; | ||
527 | |||
528 | |||
529 | static struct attribute_group dgrp_tty_attribute_group = { | ||
530 | .name = NULL, | ||
531 | .attrs = dgrp_sysfs_tty_entries, | ||
532 | }; | ||
533 | |||
534 | |||
535 | void dgrp_create_tty_sysfs(struct un_struct *un, struct device *c) | ||
536 | { | ||
537 | int ret; | ||
538 | |||
539 | ret = sysfs_create_group(&c->kobj, &dgrp_tty_attribute_group); | ||
540 | if (ret) { | ||
541 | pr_alert("%s: failed to create sysfs tty device attributes.\n", | ||
542 | __func__); | ||
543 | sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group); | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | dev_set_drvdata(c, un); | ||
548 | |||
549 | } | ||
550 | |||
551 | |||
552 | void dgrp_remove_tty_sysfs(struct device *c) | ||
553 | { | ||
554 | sysfs_remove_group(&c->kobj, &dgrp_tty_attribute_group); | ||
555 | } | ||
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c new file mode 100644 index 000000000000..7d7de873870c --- /dev/null +++ b/drivers/staging/dgrp/dgrp_tty.c | |||
@@ -0,0 +1,3331 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 1999 Digi International (www.digi.com) | ||
4 | * Gene Olson <Gene_Olson at digi dot com> | ||
5 | * James Puzzo <jamesp at digi dot com> | ||
6 | * Jeff Randall | ||
7 | * Scott Kilau <scottk at digi dot com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the | ||
16 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
17 | * PURPOSE. See the GNU General Public License for more details. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | * | ||
23 | * Filename: | ||
24 | * | ||
25 | * dgrp_tty.c | ||
26 | * | ||
27 | * Description: | ||
28 | * | ||
29 | * This file implements the tty driver functionality for the | ||
30 | * RealPort driver software. | ||
31 | * | ||
32 | * Author: | ||
33 | * | ||
34 | * James A. Puzzo | ||
35 | * Ann-Marie Westgate | ||
36 | * | ||
37 | */ | ||
38 | |||
39 | #include <linux/slab.h> | ||
40 | #include <linux/tty.h> | ||
41 | #include <linux/tty_flip.h> | ||
42 | #include <linux/sched.h> | ||
43 | |||
44 | #include "dgrp_common.h" | ||
45 | |||
46 | #ifndef _POSIX_VDISABLE | ||
47 | #define _POSIX_VDISABLE ('\0') | ||
48 | #endif | ||
49 | |||
50 | /* | ||
51 | * forward declarations | ||
52 | */ | ||
53 | |||
54 | static void drp_param(struct ch_struct *); | ||
55 | static void dgrp_tty_close(struct tty_struct *, struct file *); | ||
56 | |||
57 | /* ioctl helper functions */ | ||
58 | static int set_modem_info(struct ch_struct *, unsigned int, unsigned int *); | ||
59 | static int get_modem_info(struct ch_struct *, unsigned int *); | ||
60 | static void dgrp_set_custom_speed(struct ch_struct *, int); | ||
61 | static int dgrp_tty_digigetedelay(struct tty_struct *, int *); | ||
62 | static int dgrp_tty_digisetedelay(struct tty_struct *, int *); | ||
63 | static int dgrp_send_break(struct ch_struct *, int); | ||
64 | |||
65 | static ushort tty_to_ch_flags(struct tty_struct *, char); | ||
66 | static tcflag_t ch_to_tty_flags(unsigned short, char); | ||
67 | |||
68 | static void dgrp_tty_input_start(struct tty_struct *); | ||
69 | static void dgrp_tty_input_stop(struct tty_struct *); | ||
70 | |||
71 | static void drp_wmove(struct ch_struct *, int, void*, int); | ||
72 | |||
73 | static int dgrp_tty_open(struct tty_struct *, struct file *); | ||
74 | static void dgrp_tty_close(struct tty_struct *, struct file *); | ||
75 | static int dgrp_tty_write(struct tty_struct *, const unsigned char *, int); | ||
76 | static int dgrp_tty_write_room(struct tty_struct *); | ||
77 | static void dgrp_tty_flush_buffer(struct tty_struct *); | ||
78 | static int dgrp_tty_chars_in_buffer(struct tty_struct *); | ||
79 | static int dgrp_tty_ioctl(struct tty_struct *, unsigned int, unsigned long); | ||
80 | static void dgrp_tty_set_termios(struct tty_struct *, struct ktermios *); | ||
81 | static void dgrp_tty_stop(struct tty_struct *); | ||
82 | static void dgrp_tty_start(struct tty_struct *); | ||
83 | static void dgrp_tty_throttle(struct tty_struct *); | ||
84 | static void dgrp_tty_unthrottle(struct tty_struct *); | ||
85 | static void dgrp_tty_hangup(struct tty_struct *); | ||
86 | static int dgrp_tty_put_char(struct tty_struct *, unsigned char); | ||
87 | static int dgrp_tty_tiocmget(struct tty_struct *); | ||
88 | static int dgrp_tty_tiocmset(struct tty_struct *, unsigned int, unsigned int); | ||
89 | static int dgrp_tty_send_break(struct tty_struct *, int); | ||
90 | static void dgrp_tty_send_xchar(struct tty_struct *, char); | ||
91 | |||
92 | /* | ||
93 | * tty defines | ||
94 | */ | ||
95 | #define SERIAL_TYPE_NORMAL 1 | ||
96 | #define SERIAL_TYPE_CALLOUT 2 | ||
97 | #define SERIAL_TYPE_XPRINT 3 | ||
98 | |||
99 | |||
100 | /* | ||
101 | * tty globals/statics | ||
102 | */ | ||
103 | |||
104 | |||
105 | #define PORTSERVER_DIVIDEND 1843200 | ||
106 | |||
107 | /* | ||
108 | * Default transparent print information. | ||
109 | */ | ||
110 | static struct digi_struct digi_init = { | ||
111 | .digi_flags = DIGI_COOK, /* Flags */ | ||
112 | .digi_maxcps = 100, /* Max CPS */ | ||
113 | .digi_maxchar = 50, /* Max chars in print queue */ | ||
114 | .digi_bufsize = 100, /* Printer buffer size */ | ||
115 | .digi_onlen = 4, /* size of printer on string */ | ||
116 | .digi_offlen = 4, /* size of printer off string */ | ||
117 | .digi_onstr = "\033[5i", /* ANSI printer on string */ | ||
118 | .digi_offstr = "\033[4i", /* ANSI printer off string */ | ||
119 | .digi_term = "ansi" /* default terminal type */ | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * Define a local default termios struct. All ports will be created | ||
124 | * with this termios initially. | ||
125 | * | ||
126 | * This defines a raw port at 9600 baud, 8 data bits, no parity, | ||
127 | * 1 stop bit. | ||
128 | */ | ||
129 | static struct ktermios DefaultTermios = { | ||
130 | .c_iflag = (ICRNL | IXON), | ||
131 | .c_oflag = (OPOST | ONLCR), | ||
132 | .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL), | ||
133 | .c_lflag = (ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ||
134 | | ECHOKE | IEXTEN), | ||
135 | .c_cc = INIT_C_CC, | ||
136 | .c_line = 0, | ||
137 | }; | ||
138 | |||
139 | /* Define our tty operations struct */ | ||
140 | static const struct tty_operations dgrp_tty_ops = { | ||
141 | .open = dgrp_tty_open, | ||
142 | .close = dgrp_tty_close, | ||
143 | .write = dgrp_tty_write, | ||
144 | .write_room = dgrp_tty_write_room, | ||
145 | .flush_buffer = dgrp_tty_flush_buffer, | ||
146 | .chars_in_buffer = dgrp_tty_chars_in_buffer, | ||
147 | .flush_chars = NULL, | ||
148 | .ioctl = dgrp_tty_ioctl, | ||
149 | .set_termios = dgrp_tty_set_termios, | ||
150 | .stop = dgrp_tty_stop, | ||
151 | .start = dgrp_tty_start, | ||
152 | .throttle = dgrp_tty_throttle, | ||
153 | .unthrottle = dgrp_tty_unthrottle, | ||
154 | .hangup = dgrp_tty_hangup, | ||
155 | .put_char = dgrp_tty_put_char, | ||
156 | .tiocmget = dgrp_tty_tiocmget, | ||
157 | .tiocmset = dgrp_tty_tiocmset, | ||
158 | .break_ctl = dgrp_tty_send_break, | ||
159 | .send_xchar = dgrp_tty_send_xchar | ||
160 | }; | ||
161 | |||
162 | |||
163 | static int calc_baud_rate(struct un_struct *un) | ||
164 | { | ||
165 | int i; | ||
166 | int brate; | ||
167 | |||
168 | struct baud_rates { | ||
169 | unsigned int rate; | ||
170 | unsigned int cflag; | ||
171 | }; | ||
172 | |||
173 | static struct baud_rates baud_rates[] = { | ||
174 | { 921600, B921600 }, | ||
175 | { 460800, B460800 }, | ||
176 | { 230400, B230400 }, | ||
177 | { 115200, B115200 }, | ||
178 | { 57600, B57600 }, | ||
179 | { 38400, B38400 }, | ||
180 | { 19200, B19200 }, | ||
181 | { 9600, B9600 }, | ||
182 | { 4800, B4800 }, | ||
183 | { 2400, B2400 }, | ||
184 | { 1200, B1200 }, | ||
185 | { 600, B600 }, | ||
186 | { 300, B300 }, | ||
187 | { 200, B200 }, | ||
188 | { 150, B150 }, | ||
189 | { 134, B134 }, | ||
190 | { 110, B110 }, | ||
191 | { 75, B75 }, | ||
192 | { 50, B50 }, | ||
193 | { 0, B9600 } | ||
194 | }; | ||
195 | |||
196 | brate = C_BAUD(un->un_tty); | ||
197 | |||
198 | for (i = 0; baud_rates[i].rate; i++) { | ||
199 | if (baud_rates[i].cflag == brate) | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | return baud_rates[i].rate; | ||
204 | } | ||
205 | |||
206 | static int calc_fastbaud_rate(struct un_struct *un, struct ktermios *uts) | ||
207 | { | ||
208 | int i; | ||
209 | int brate; | ||
210 | |||
211 | ulong bauds[2][16] = { | ||
212 | { /* fastbaud*/ | ||
213 | 0, 57600, 76800, 115200, | ||
214 | 131657, 153600, 230400, 460800, | ||
215 | 921600, 1200, 1800, 2400, | ||
216 | 4800, 9600, 19200, 38400 }, | ||
217 | { /* fastbaud & CBAUDEX */ | ||
218 | 0, 57600, 115200, 230400, | ||
219 | 460800, 150, 200, 921600, | ||
220 | 600, 1200, 1800, 2400, | ||
221 | 4800, 9600, 19200, 38400 } | ||
222 | }; | ||
223 | |||
224 | brate = C_BAUD(un->un_tty) & 0xff; | ||
225 | |||
226 | i = (uts->c_cflag & CBAUDEX) ? 1 : 0; | ||
227 | |||
228 | |||
229 | if ((i >= 0) && (i < 2) && (brate >= 0) && (brate < 16)) | ||
230 | brate = bauds[i][brate]; | ||
231 | else | ||
232 | brate = 0; | ||
233 | |||
234 | return brate; | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * drp_param() -- send parameter values to be sent to the node | ||
239 | * @ch: channel structure of port to modify | ||
240 | * | ||
241 | * Interprets the tty and modem changes made by an application | ||
242 | * program (by examining the termios structures) and sets up | ||
243 | * parameter values to be sent to the node. | ||
244 | */ | ||
245 | static void drp_param(struct ch_struct *ch) | ||
246 | { | ||
247 | struct nd_struct *nd; | ||
248 | struct un_struct *un; | ||
249 | int brate; | ||
250 | int mflow; | ||
251 | int xflag; | ||
252 | int iflag; | ||
253 | struct ktermios *tts, *pts, *uts; | ||
254 | |||
255 | nd = ch->ch_nd; | ||
256 | |||
257 | /* | ||
258 | * If the terminal device is open, use it to set up all tty | ||
259 | * modes and functions. Otherwise use the printer device. | ||
260 | */ | ||
261 | |||
262 | if (ch->ch_tun.un_open_count) { | ||
263 | |||
264 | un = &ch->ch_tun; | ||
265 | tts = &ch->ch_tun.un_tty->termios; | ||
266 | |||
267 | /* | ||
268 | * If both devices are open, copy critical line | ||
269 | * parameters from the tty device to the printer, | ||
270 | * so that if the tty is closed, the printer will | ||
271 | * continue without disruption. | ||
272 | */ | ||
273 | |||
274 | if (ch->ch_pun.un_open_count) { | ||
275 | |||
276 | pts = &ch->ch_pun.un_tty->termios; | ||
277 | |||
278 | pts->c_cflag ^= | ||
279 | (pts->c_cflag ^ tts->c_cflag) & | ||
280 | (CBAUD | CSIZE | CSTOPB | CREAD | PARENB | | ||
281 | PARODD | HUPCL | CLOCAL); | ||
282 | |||
283 | pts->c_iflag ^= | ||
284 | (pts->c_iflag ^ tts->c_iflag) & | ||
285 | (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | | ||
286 | ISTRIP | IXON | IXANY | IXOFF); | ||
287 | |||
288 | pts->c_cc[VSTART] = tts->c_cc[VSTART]; | ||
289 | pts->c_cc[VSTOP] = tts->c_cc[VSTOP]; | ||
290 | } | ||
291 | } else if (ch->ch_pun.un_open_count == 0) { | ||
292 | pr_warn("%s - ch_pun.un_open_count shouldn't be 0\n", | ||
293 | __func__); | ||
294 | return; | ||
295 | } else { | ||
296 | un = &ch->ch_pun; | ||
297 | } | ||
298 | |||
299 | uts = &un->un_tty->termios; | ||
300 | |||
301 | /* | ||
302 | * Determine if FAST writes can be performed. | ||
303 | */ | ||
304 | |||
305 | if ((ch->ch_digi.digi_flags & DIGI_COOK) != 0 && | ||
306 | (ch->ch_tun.un_open_count != 0) && | ||
307 | !((un->un_tty)->ldisc->ops->flags & LDISC_FLAG_DEFINED) && | ||
308 | !(L_XCASE(un->un_tty))) { | ||
309 | ch->ch_flag |= CH_FAST_WRITE; | ||
310 | } else { | ||
311 | ch->ch_flag &= ~CH_FAST_WRITE; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * If FAST writes can be performed, and OPOST is on in the | ||
316 | * terminal device, do OPOST handling in the server. | ||
317 | */ | ||
318 | |||
319 | if ((ch->ch_flag & CH_FAST_WRITE) && | ||
320 | O_OPOST(un->un_tty) != 0) { | ||
321 | int oflag = tty_to_ch_flags(un->un_tty, 'o'); | ||
322 | |||
323 | /* add to ch_ocook any processing flags set in the termio */ | ||
324 | ch->ch_ocook |= oflag & (OF_OLCUC | | ||
325 | OF_ONLCR | | ||
326 | OF_OCRNL | | ||
327 | OF_ONLRET | | ||
328 | OF_TABDLY); | ||
329 | |||
330 | /* | ||
331 | * the hpux driver clears any flags set in ch_ocook | ||
332 | * from the termios oflag. It is STILL reported though | ||
333 | * by a TCGETA | ||
334 | */ | ||
335 | |||
336 | oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); | ||
337 | uts->c_oflag &= ~oflag; | ||
338 | |||
339 | } else { | ||
340 | /* clear the ch->ch_ocook flag */ | ||
341 | int oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); | ||
342 | uts->c_oflag |= oflag; | ||
343 | ch->ch_ocook = 0; | ||
344 | } | ||
345 | |||
346 | ch->ch_oflag = ch->ch_ocook; | ||
347 | |||
348 | |||
349 | ch->ch_flag &= ~CH_FAST_READ; | ||
350 | |||
351 | /* | ||
352 | * Generate channel flags | ||
353 | */ | ||
354 | |||
355 | if (C_BAUD(un->un_tty) == B0) { | ||
356 | if (!(ch->ch_flag & CH_BAUD0)) { | ||
357 | /* TODO : the HPUX driver flushes line */ | ||
358 | /* TODO : discipline, I assume I don't have to */ | ||
359 | |||
360 | ch->ch_tout = ch->ch_tin; | ||
361 | ch->ch_rout = ch->ch_rin; | ||
362 | |||
363 | ch->ch_break_time = 0; | ||
364 | |||
365 | ch->ch_send |= RR_TX_FLUSH | RR_RX_FLUSH; | ||
366 | |||
367 | ch->ch_mout &= ~(DM_DTR | DM_RTS); | ||
368 | |||
369 | ch->ch_flag |= CH_BAUD0; | ||
370 | } | ||
371 | } else if (ch->ch_custom_speed) { | ||
372 | ch->ch_brate = PORTSERVER_DIVIDEND / ch->ch_custom_speed ; | ||
373 | |||
374 | if (ch->ch_flag & CH_BAUD0) { | ||
375 | ch->ch_mout |= DM_DTR | DM_RTS; | ||
376 | |||
377 | ch->ch_flag &= ~CH_BAUD0; | ||
378 | } | ||
379 | } else { | ||
380 | /* | ||
381 | * Baud rate mapping. | ||
382 | * | ||
383 | * If FASTBAUD isn't on, we can scan the new baud rate list | ||
384 | * as required. | ||
385 | * | ||
386 | * However, if FASTBAUD is on, we must go to the old | ||
387 | * baud rate mapping that existed many many moons ago, | ||
388 | * for compatibility reasons. | ||
389 | */ | ||
390 | |||
391 | if (!(ch->ch_digi.digi_flags & DIGI_FAST)) | ||
392 | brate = calc_baud_rate(un); | ||
393 | else | ||
394 | brate = calc_fastbaud_rate(un, uts); | ||
395 | |||
396 | if (brate == 0) | ||
397 | brate = 9600; | ||
398 | |||
399 | ch->ch_brate = PORTSERVER_DIVIDEND / brate; | ||
400 | |||
401 | if (ch->ch_flag & CH_BAUD0) { | ||
402 | ch->ch_mout |= DM_DTR | DM_RTS; | ||
403 | |||
404 | ch->ch_flag &= ~CH_BAUD0; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | /* | ||
409 | * Generate channel cflags from the termio. | ||
410 | */ | ||
411 | |||
412 | ch->ch_cflag = tty_to_ch_flags(un->un_tty, 'c'); | ||
413 | |||
414 | /* | ||
415 | * Generate channel iflags from the termio. | ||
416 | */ | ||
417 | |||
418 | iflag = (int) tty_to_ch_flags(un->un_tty, 'i'); | ||
419 | |||
420 | if (START_CHAR(un->un_tty) == _POSIX_VDISABLE || | ||
421 | STOP_CHAR(un->un_tty) == _POSIX_VDISABLE) { | ||
422 | iflag &= ~(IF_IXON | IF_IXANY | IF_IXOFF); | ||
423 | } | ||
424 | |||
425 | ch->ch_iflag = iflag; | ||
426 | |||
427 | /* | ||
428 | * Generate flow control characters | ||
429 | */ | ||
430 | |||
431 | /* | ||
432 | * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE} | ||
433 | * is defined for the terminal device file, and the value | ||
434 | * of one of the changable special control characters (see | ||
435 | * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be | ||
436 | * disabled, that is, no input data shall be recognized as | ||
437 | * the disabled special character." | ||
438 | * | ||
439 | * OK, so we don't ever assign S/DXB XON or XOFF to _POSIX_VDISABLE. | ||
440 | */ | ||
441 | |||
442 | if (uts->c_cc[VSTART] != _POSIX_VDISABLE) | ||
443 | ch->ch_xon = uts->c_cc[VSTART]; | ||
444 | if (uts->c_cc[VSTOP] != _POSIX_VDISABLE) | ||
445 | ch->ch_xoff = uts->c_cc[VSTOP]; | ||
446 | |||
447 | ch->ch_lnext = (uts->c_cc[VLNEXT] == _POSIX_VDISABLE ? 0 : | ||
448 | uts->c_cc[VLNEXT]); | ||
449 | |||
450 | /* | ||
451 | * Also, if either c_cc[START] or c_cc[STOP] is set to | ||
452 | * _POSIX_VDISABLE, we can't really do software flow | ||
453 | * control--in either direction--so we turn it off as | ||
454 | * far as S/DXB is concerned. In essence, if you disable | ||
455 | * one, you disable the other too. | ||
456 | */ | ||
457 | if ((uts->c_cc[VSTART] == _POSIX_VDISABLE) || | ||
458 | (uts->c_cc[VSTOP] == _POSIX_VDISABLE)) | ||
459 | ch->ch_iflag &= ~(IF_IXOFF | IF_IXON); | ||
460 | |||
461 | /* | ||
462 | * Update xflags. | ||
463 | */ | ||
464 | |||
465 | xflag = 0; | ||
466 | |||
467 | if (ch->ch_digi.digi_flags & DIGI_AIXON) | ||
468 | xflag = XF_XIXON; | ||
469 | |||
470 | if ((ch->ch_xxon == _POSIX_VDISABLE) || | ||
471 | (ch->ch_xxoff == _POSIX_VDISABLE)) | ||
472 | xflag &= ~XF_XIXON; | ||
473 | |||
474 | ch->ch_xflag = xflag; | ||
475 | |||
476 | |||
477 | /* | ||
478 | * Figure effective DCD value. | ||
479 | */ | ||
480 | |||
481 | if (C_CLOCAL(un->un_tty)) | ||
482 | ch->ch_flag |= CH_CLOCAL; | ||
483 | else | ||
484 | ch->ch_flag &= ~CH_CLOCAL; | ||
485 | |||
486 | /* | ||
487 | * Check modem signals | ||
488 | */ | ||
489 | |||
490 | dgrp_carrier(ch); | ||
491 | |||
492 | /* | ||
493 | * Get hardware handshake value. | ||
494 | */ | ||
495 | |||
496 | mflow = 0; | ||
497 | |||
498 | if (C_CRTSCTS(un->un_tty)) | ||
499 | mflow |= (DM_RTS | DM_CTS); | ||
500 | |||
501 | if (ch->ch_digi.digi_flags & RTSPACE) | ||
502 | mflow |= DM_RTS; | ||
503 | |||
504 | if (ch->ch_digi.digi_flags & DTRPACE) | ||
505 | mflow |= DM_DTR; | ||
506 | |||
507 | if (ch->ch_digi.digi_flags & CTSPACE) | ||
508 | mflow |= DM_CTS; | ||
509 | |||
510 | if (ch->ch_digi.digi_flags & DSRPACE) | ||
511 | mflow |= DM_DSR; | ||
512 | |||
513 | if (ch->ch_digi.digi_flags & DCDPACE) | ||
514 | mflow |= DM_CD; | ||
515 | |||
516 | if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) | ||
517 | mflow |= DM_RTS_TOGGLE; | ||
518 | |||
519 | ch->ch_mflow = mflow; | ||
520 | |||
521 | /* | ||
522 | * Send the changes to the server. | ||
523 | */ | ||
524 | |||
525 | ch->ch_flag |= CH_PARAM; | ||
526 | (ch->ch_nd)->nd_tx_work = 1; | ||
527 | |||
528 | if (waitqueue_active(&ch->ch_flag_wait)) | ||
529 | wake_up_interruptible(&ch->ch_flag_wait); | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * This function is just used as a callback for timeouts | ||
534 | * waiting on the ch_sleep flag. | ||
535 | */ | ||
536 | static void wake_up_drp_sleep_timer(unsigned long ptr) | ||
537 | { | ||
538 | struct ch_struct *ch = (struct ch_struct *) ptr; | ||
539 | if (ch) | ||
540 | wake_up(&ch->ch_sleep); | ||
541 | } | ||
542 | |||
543 | |||
544 | /* | ||
545 | * Set up our own sleep that can't be cancelled | ||
546 | * until our timeout occurs. | ||
547 | */ | ||
548 | static void drp_my_sleep(struct ch_struct *ch) | ||
549 | { | ||
550 | struct timer_list drp_wakeup_timer; | ||
551 | DECLARE_WAITQUEUE(wait, current); | ||
552 | |||
553 | /* | ||
554 | * First make sure we're ready to receive the wakeup. | ||
555 | */ | ||
556 | |||
557 | add_wait_queue(&ch->ch_sleep, &wait); | ||
558 | current->state = TASK_UNINTERRUPTIBLE; | ||
559 | |||
560 | /* | ||
561 | * Since we are uninterruptible, set a timer to | ||
562 | * unset the uninterruptable state in 1 second. | ||
563 | */ | ||
564 | |||
565 | init_timer(&drp_wakeup_timer); | ||
566 | drp_wakeup_timer.function = wake_up_drp_sleep_timer; | ||
567 | drp_wakeup_timer.data = (unsigned long) ch; | ||
568 | drp_wakeup_timer.expires = jiffies + (1 * HZ); | ||
569 | add_timer(&drp_wakeup_timer); | ||
570 | |||
571 | schedule(); | ||
572 | |||
573 | del_timer(&drp_wakeup_timer); | ||
574 | |||
575 | remove_wait_queue(&ch->ch_sleep, &wait); | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * dgrp_tty_open() | ||
580 | * | ||
581 | * returns: | ||
582 | * -EBUSY - this is a callout device and the normal device is active | ||
583 | * - there is an error in opening the tty | ||
584 | * -ENODEV - the channel does not exist | ||
585 | * -EAGAIN - we are in the middle of hanging up or closing | ||
586 | * - IMMEDIATE_OPEN fails | ||
587 | * -ENXIO or -EAGAIN | ||
588 | * - if the port is outside physical range | ||
589 | * -EINTR - the open is interrupted | ||
590 | * | ||
591 | */ | ||
592 | static int dgrp_tty_open(struct tty_struct *tty, struct file *file) | ||
593 | { | ||
594 | int retval = 0; | ||
595 | struct nd_struct *nd; | ||
596 | struct ch_struct *ch; | ||
597 | struct un_struct *un; | ||
598 | int port; | ||
599 | int delay_error; | ||
600 | int otype; | ||
601 | int unf; | ||
602 | int wait_carrier; | ||
603 | int category; | ||
604 | int counts_were_incremented = 0; | ||
605 | ulong lock_flags; | ||
606 | DECLARE_WAITQUEUE(wait, current); | ||
607 | |||
608 | /* | ||
609 | * Do some initial checks to see if the node and port exist | ||
610 | */ | ||
611 | |||
612 | nd = nd_struct_get(MAJOR(tty_devnum(tty))); | ||
613 | port = PORT_NUM(MINOR(tty_devnum(tty))); | ||
614 | category = OPEN_CATEGORY(MINOR(tty_devnum(tty))); | ||
615 | |||
616 | if (!nd) | ||
617 | return -ENODEV; | ||
618 | |||
619 | if (port >= CHAN_MAX) | ||
620 | return -ENODEV; | ||
621 | |||
622 | /* | ||
623 | * The channel exists. | ||
624 | */ | ||
625 | |||
626 | ch = nd->nd_chan + port; | ||
627 | |||
628 | un = IS_PRINT(MINOR(tty_devnum(tty))) ? &ch->ch_pun : &ch->ch_tun; | ||
629 | un->un_tty = tty; | ||
630 | tty->driver_data = un; | ||
631 | |||
632 | /* | ||
633 | * If we are in the middle of hanging up, | ||
634 | * then return an error | ||
635 | */ | ||
636 | if (tty_hung_up_p(file)) { | ||
637 | retval = ((un->un_flag & UN_HUP_NOTIFY) ? | ||
638 | -EAGAIN : -ERESTARTSYS); | ||
639 | goto done; | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * If the port is in the middle of closing, then block | ||
644 | * until it is done, then try again. | ||
645 | */ | ||
646 | retval = wait_event_interruptible(un->un_close_wait, | ||
647 | ((un->un_flag & UN_CLOSING) == 0)); | ||
648 | |||
649 | if (retval) | ||
650 | goto done; | ||
651 | |||
652 | /* | ||
653 | * If the port is in the middle of a reopen after a network disconnect, | ||
654 | * wait until it is done, then try again. | ||
655 | */ | ||
656 | retval = wait_event_interruptible(ch->ch_flag_wait, | ||
657 | ((ch->ch_flag & CH_PORT_GONE) == 0)); | ||
658 | |||
659 | if (retval) | ||
660 | goto done; | ||
661 | |||
662 | /* | ||
663 | * If this is a callout device, then just make sure the normal | ||
664 | * device isn't being used. | ||
665 | */ | ||
666 | |||
667 | if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { | ||
668 | if (un->un_flag & UN_NORMAL_ACTIVE) { | ||
669 | retval = -EBUSY; | ||
670 | goto done; | ||
671 | } else { | ||
672 | un->un_flag |= UN_CALLOUT_ACTIVE; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * Loop waiting until the open can be successfully completed. | ||
678 | */ | ||
679 | |||
680 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
681 | |||
682 | nd->nd_tx_work = 1; | ||
683 | |||
684 | for (;;) { | ||
685 | wait_carrier = 0; | ||
686 | |||
687 | /* | ||
688 | * Determine the open type from the flags provided. | ||
689 | */ | ||
690 | |||
691 | /* | ||
692 | * If the port is not enabled, then exit | ||
693 | */ | ||
694 | if (test_bit(TTY_IO_ERROR, &tty->flags)) { | ||
695 | /* there was an error in opening the tty */ | ||
696 | if (un->un_flag & UN_CALLOUT_ACTIVE) | ||
697 | retval = -EBUSY; | ||
698 | else | ||
699 | un->un_flag |= UN_NORMAL_ACTIVE; | ||
700 | goto unlock; | ||
701 | } | ||
702 | |||
703 | if (file->f_flags & O_NONBLOCK) { | ||
704 | |||
705 | /* | ||
706 | * if the O_NONBLOCK is set, errors on read and write | ||
707 | * must return -EAGAIN immediately and NOT sleep | ||
708 | * on the waitqs. | ||
709 | */ | ||
710 | otype = OTYPE_IMMEDIATE; | ||
711 | delay_error = -EAGAIN; | ||
712 | |||
713 | } else if (!OPEN_WAIT_AVAIL(category) || | ||
714 | (file->f_flags & O_NDELAY) != 0) { | ||
715 | otype = OTYPE_IMMEDIATE; | ||
716 | delay_error = -EBUSY; | ||
717 | |||
718 | } else if (!OPEN_WAIT_CARRIER(category) || | ||
719 | ((ch->ch_digi.digi_flags & DIGI_FORCEDCD) != 0) || | ||
720 | C_CLOCAL(tty)) { | ||
721 | otype = OTYPE_PERSISTENT; | ||
722 | delay_error = 0; | ||
723 | |||
724 | } else { | ||
725 | otype = OTYPE_INCOMING; | ||
726 | delay_error = 0; | ||
727 | } | ||
728 | |||
729 | /* | ||
730 | * Handle port currently outside physical port range. | ||
731 | */ | ||
732 | |||
733 | if (port >= nd->nd_chan_count) { | ||
734 | if (otype == OTYPE_IMMEDIATE) { | ||
735 | retval = (nd->nd_state == NS_READY) ? | ||
736 | -ENXIO : -EAGAIN; | ||
737 | goto unlock; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * Handle port not currently open. | ||
743 | */ | ||
744 | |||
745 | else if (ch->ch_open_count == 0) { | ||
746 | /* | ||
747 | * Return an error when an Incoming Open | ||
748 | * response indicates the port is busy. | ||
749 | */ | ||
750 | |||
751 | if (ch->ch_open_error != 0 && otype == ch->ch_otype) { | ||
752 | retval = (ch->ch_open_error <= 2) ? | ||
753 | delay_error : -ENXIO ; | ||
754 | goto unlock; | ||
755 | } | ||
756 | |||
757 | /* | ||
758 | * Fail any new Immediate open if we do not have | ||
759 | * a normal connection to the server. | ||
760 | */ | ||
761 | |||
762 | if (nd->nd_state != NS_READY && | ||
763 | otype == OTYPE_IMMEDIATE) { | ||
764 | retval = -EAGAIN; | ||
765 | goto unlock; | ||
766 | } | ||
767 | |||
768 | /* | ||
769 | * If a Realport open of the correct type has | ||
770 | * succeeded, complete the open. | ||
771 | */ | ||
772 | |||
773 | if (ch->ch_state == CS_READY && ch->ch_otype == otype) | ||
774 | break; | ||
775 | } | ||
776 | |||
777 | /* | ||
778 | * Handle port already open and active as a device | ||
779 | * of same category. | ||
780 | */ | ||
781 | |||
782 | else if ((ch->ch_category == category) || | ||
783 | IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
784 | /* | ||
785 | * Fail if opening the device now would | ||
786 | * violate exclusive use. | ||
787 | */ | ||
788 | unf = ch->ch_tun.un_flag | ch->ch_pun.un_flag; | ||
789 | |||
790 | if ((file->f_flags & O_EXCL) || (unf & UN_EXCL)) { | ||
791 | retval = -EBUSY; | ||
792 | goto unlock; | ||
793 | } | ||
794 | |||
795 | /* | ||
796 | * If the open device is in the hangup state, all | ||
797 | * system calls fail except close(). | ||
798 | */ | ||
799 | |||
800 | /* TODO : check on hangup_p calls */ | ||
801 | |||
802 | if (ch->ch_flag & CH_HANGUP) { | ||
803 | retval = -ENXIO; | ||
804 | goto unlock; | ||
805 | } | ||
806 | |||
807 | /* | ||
808 | * If the port is ready, and carrier is ignored | ||
809 | * or present, then complete the open. | ||
810 | */ | ||
811 | |||
812 | if (ch->ch_state == CS_READY && | ||
813 | (otype != OTYPE_INCOMING || | ||
814 | ch->ch_flag & CH_VIRT_CD)) | ||
815 | break; | ||
816 | |||
817 | wait_carrier = 1; | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * Handle port active with a different category device. | ||
822 | */ | ||
823 | |||
824 | else { | ||
825 | if (otype == OTYPE_IMMEDIATE) { | ||
826 | retval = delay_error; | ||
827 | goto unlock; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * Wait until conditions change, then take another | ||
833 | * try at the open. | ||
834 | */ | ||
835 | |||
836 | ch->ch_wait_count[otype]++; | ||
837 | |||
838 | if (wait_carrier) | ||
839 | ch->ch_wait_carrier++; | ||
840 | |||
841 | /* | ||
842 | * Prepare the task to accept the wakeup, then | ||
843 | * release our locks and release control. | ||
844 | */ | ||
845 | |||
846 | add_wait_queue(&ch->ch_flag_wait, &wait); | ||
847 | current->state = TASK_INTERRUPTIBLE; | ||
848 | |||
849 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
850 | |||
851 | /* | ||
852 | * Give up control, we'll come back if we're | ||
853 | * interrupted or are woken up. | ||
854 | */ | ||
855 | schedule(); | ||
856 | remove_wait_queue(&ch->ch_flag_wait, &wait); | ||
857 | |||
858 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
859 | |||
860 | current->state = TASK_RUNNING; | ||
861 | |||
862 | ch->ch_wait_count[otype]--; | ||
863 | |||
864 | if (wait_carrier) | ||
865 | ch->ch_wait_carrier--; | ||
866 | |||
867 | nd->nd_tx_work = 1; | ||
868 | |||
869 | if (signal_pending(current)) { | ||
870 | retval = -EINTR; | ||
871 | goto unlock; | ||
872 | } | ||
873 | } /* end for(;;) */ | ||
874 | |||
875 | /* | ||
876 | * The open has succeeded. No turning back. | ||
877 | */ | ||
878 | counts_were_incremented = 1; | ||
879 | un->un_open_count++; | ||
880 | ch->ch_open_count++; | ||
881 | |||
882 | /* | ||
883 | * Initialize the channel, if it's not already open. | ||
884 | */ | ||
885 | |||
886 | if (ch->ch_open_count == 1) { | ||
887 | ch->ch_flag = 0; | ||
888 | ch->ch_inwait = 0; | ||
889 | ch->ch_category = category; | ||
890 | ch->ch_pscan_state = 0; | ||
891 | |||
892 | /* TODO : find out what PS-1 bug Gene was referring to */ | ||
893 | /* TODO : in the following comment. */ | ||
894 | |||
895 | ch->ch_send = RR_TX_START | RR_RX_START; /* PS-1 bug */ | ||
896 | |||
897 | if (C_CLOCAL(tty) || | ||
898 | ch->ch_s_mlast & DM_CD || | ||
899 | ch->ch_digi.digi_flags & DIGI_FORCEDCD) | ||
900 | ch->ch_flag |= CH_VIRT_CD; | ||
901 | else if (OPEN_FORCES_CARRIER(category)) | ||
902 | ch->ch_flag |= CH_VIRT_CD; | ||
903 | |||
904 | } | ||
905 | |||
906 | /* | ||
907 | * Initialize the unit, if it is not already open. | ||
908 | */ | ||
909 | |||
910 | if (un->un_open_count == 1) { | ||
911 | /* | ||
912 | * Since all terminal options are always sticky in Linux, | ||
913 | * we don't need the UN_STICKY flag to be handled specially. | ||
914 | */ | ||
915 | /* clears all the digi flags, leaves serial flags */ | ||
916 | un->un_flag &= ~UN_DIGI_MASK; | ||
917 | |||
918 | if (file->f_flags & O_EXCL) | ||
919 | un->un_flag |= UN_EXCL; | ||
920 | |||
921 | /* TODO : include "session" and "pgrp" */ | ||
922 | |||
923 | /* | ||
924 | * In Linux, all terminal parameters are intended to be sticky. | ||
925 | * as a result, we "remove" the code which once reset the ports | ||
926 | * to sane values. | ||
927 | */ | ||
928 | |||
929 | drp_param(ch); | ||
930 | |||
931 | } | ||
932 | |||
933 | un->un_flag |= UN_INITIALIZED; | ||
934 | |||
935 | retval = 0; | ||
936 | |||
937 | unlock: | ||
938 | |||
939 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
940 | |||
941 | done: | ||
942 | /* | ||
943 | * Linux does a close for every open, even failed ones! | ||
944 | */ | ||
945 | if (!counts_were_incremented) { | ||
946 | un->un_open_count++; | ||
947 | ch->ch_open_count++; | ||
948 | } | ||
949 | |||
950 | if (retval) | ||
951 | dev_err(tty->dev, "tty open bad return (%i)\n", retval); | ||
952 | |||
953 | return retval; | ||
954 | } | ||
955 | |||
956 | |||
957 | |||
958 | |||
959 | /* | ||
960 | * dgrp_tty_close() -- close function for tty_operations | ||
961 | */ | ||
962 | static void dgrp_tty_close(struct tty_struct *tty, struct file *file) | ||
963 | { | ||
964 | struct ch_struct *ch; | ||
965 | struct un_struct *un; | ||
966 | struct nd_struct *nd; | ||
967 | int tpos; | ||
968 | int port; | ||
969 | int err = 0; | ||
970 | int s = 0; | ||
971 | ulong waketime; | ||
972 | ulong lock_flags; | ||
973 | int sent_printer_offstr = 0; | ||
974 | |||
975 | port = PORT_NUM(MINOR(tty_devnum(tty))); | ||
976 | |||
977 | un = tty->driver_data; | ||
978 | |||
979 | if (!un) | ||
980 | return; | ||
981 | |||
982 | ch = un->un_ch; | ||
983 | |||
984 | if (!ch) | ||
985 | return; | ||
986 | |||
987 | nd = ch->ch_nd; | ||
988 | |||
989 | if (!nd) | ||
990 | return; | ||
991 | |||
992 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
993 | |||
994 | |||
995 | /* Used to be on channel basis, now we check on a unit basis. */ | ||
996 | if (un->un_open_count != 1) | ||
997 | goto unlock; | ||
998 | |||
999 | /* | ||
1000 | * OK, its the last close on the unit | ||
1001 | */ | ||
1002 | un->un_flag |= UN_CLOSING; | ||
1003 | |||
1004 | /* | ||
1005 | * Notify the discipline to only process XON/XOFF characters. | ||
1006 | */ | ||
1007 | tty->closing = 1; | ||
1008 | |||
1009 | /* | ||
1010 | * Wait for output to drain only if this is | ||
1011 | * the last close against the channel | ||
1012 | */ | ||
1013 | |||
1014 | if (ch->ch_open_count == 1) { | ||
1015 | /* | ||
1016 | * If its the print device, we need to ensure at all costs that | ||
1017 | * the offstr will fit. If it won't, flush our tbuf. | ||
1018 | */ | ||
1019 | if (IS_PRINT(MINOR(tty_devnum(tty))) && | ||
1020 | (((ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK) < | ||
1021 | ch->ch_digi.digi_offlen)) | ||
1022 | ch->ch_tin = ch->ch_tout; | ||
1023 | |||
1024 | /* | ||
1025 | * Turn off the printer. Don't bother checking to see if its | ||
1026 | * IS_PRINT... Since this is the last close the flag is going | ||
1027 | * to be cleared, so we MUST make sure the offstr gets inserted | ||
1028 | * into tbuf. | ||
1029 | */ | ||
1030 | |||
1031 | if ((ch->ch_flag & CH_PRON) != 0) { | ||
1032 | drp_wmove(ch, 0, ch->ch_digi.digi_offstr, | ||
1033 | ch->ch_digi.digi_offlen); | ||
1034 | ch->ch_flag &= ~CH_PRON; | ||
1035 | sent_printer_offstr = 1; | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | /* | ||
1040 | * Wait until either the output queue has drained, or we see | ||
1041 | * absolutely no progress for 15 seconds. | ||
1042 | */ | ||
1043 | |||
1044 | tpos = ch->ch_s_tpos; | ||
1045 | |||
1046 | waketime = jiffies + 15 * HZ; | ||
1047 | |||
1048 | for (;;) { | ||
1049 | |||
1050 | /* | ||
1051 | * Make sure the port still exists. | ||
1052 | */ | ||
1053 | |||
1054 | if (port >= nd->nd_chan_count) { | ||
1055 | err = 1; | ||
1056 | break; | ||
1057 | } | ||
1058 | |||
1059 | if (signal_pending(current)) { | ||
1060 | err = 1; | ||
1061 | break; | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * If the port is idle (not opened on the server), we have | ||
1066 | * no way of draining/flushing/closing the port on that server. | ||
1067 | * So break out of loop. | ||
1068 | */ | ||
1069 | if (ch->ch_state == CS_IDLE) | ||
1070 | break; | ||
1071 | |||
1072 | nd->nd_tx_work = 1; | ||
1073 | |||
1074 | /* | ||
1075 | * Exit if the queues for this unit are empty, | ||
1076 | * and either the other unit is still open or all | ||
1077 | * data has drained. | ||
1078 | */ | ||
1079 | |||
1080 | if ((un->un_tty)->ops->chars_in_buffer ? | ||
1081 | ((un->un_tty)->ops->chars_in_buffer)(un->un_tty) == 0 : 1) { | ||
1082 | |||
1083 | /* | ||
1084 | * We don't need to wait for a buffer to drain | ||
1085 | * if the other unit is open. | ||
1086 | */ | ||
1087 | |||
1088 | if (ch->ch_open_count != un->un_open_count) | ||
1089 | break; | ||
1090 | |||
1091 | /* | ||
1092 | * The wait is complete when all queues are | ||
1093 | * drained, and any break in progress is complete. | ||
1094 | */ | ||
1095 | |||
1096 | if (ch->ch_tin == ch->ch_tout && | ||
1097 | ch->ch_s_tin == ch->ch_s_tpos && | ||
1098 | (ch->ch_send & RR_TX_BREAK) == 0) { | ||
1099 | break; | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | /* | ||
1104 | * Flush TX data and exit the wait if NDELAY is set, | ||
1105 | * or this is not a DIGI printer, and the close timeout | ||
1106 | * expires. | ||
1107 | */ | ||
1108 | |||
1109 | if ((file->f_flags & (O_NDELAY | O_NONBLOCK)) || | ||
1110 | ((long)(jiffies - waketime) >= 0 && | ||
1111 | (ch->ch_digi.digi_flags & DIGI_PRINTER) == 0)) { | ||
1112 | |||
1113 | /* | ||
1114 | * If we sent the printer off string, we cannot | ||
1115 | * flush our internal buffers, or we might lose | ||
1116 | * the offstr. | ||
1117 | */ | ||
1118 | if (!sent_printer_offstr) | ||
1119 | dgrp_tty_flush_buffer(tty); | ||
1120 | |||
1121 | tty_ldisc_flush(tty); | ||
1122 | break; | ||
1123 | } | ||
1124 | |||
1125 | /* | ||
1126 | * Otherwise take a short nap. | ||
1127 | */ | ||
1128 | |||
1129 | ch->ch_flag |= CH_DRAIN; | ||
1130 | |||
1131 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
1132 | |||
1133 | schedule_timeout_interruptible(1); | ||
1134 | s = signal_pending(current); | ||
1135 | |||
1136 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
1137 | |||
1138 | if (s) { | ||
1139 | /* | ||
1140 | * If we had sent the printer off string, we now have | ||
1141 | * some problems. | ||
1142 | * | ||
1143 | * The system won't let us sleep since we got an error | ||
1144 | * back from sleep, presumably because the user did | ||
1145 | * a ctrl-c... | ||
1146 | * But we need to ensure that the offstr gets sent! | ||
1147 | * Thus, we have to do something else besides sleeping. | ||
1148 | * The plan: | ||
1149 | * 1) Make this task uninterruptable. | ||
1150 | * 2) Set up a timer to go off in 1 sec. | ||
1151 | * 3) Act as tho we just got out of the sleep above. | ||
1152 | * | ||
1153 | * Thankfully, in the real world, this just | ||
1154 | * never happens. | ||
1155 | */ | ||
1156 | |||
1157 | if (sent_printer_offstr) { | ||
1158 | spin_unlock_irqrestore(&nd->nd_lock, | ||
1159 | lock_flags); | ||
1160 | drp_my_sleep(ch); | ||
1161 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
1162 | } else { | ||
1163 | err = 1; | ||
1164 | break; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * Restart the wait if any progress is seen. | ||
1170 | */ | ||
1171 | |||
1172 | if (ch->ch_s_tpos != tpos) { | ||
1173 | tpos = ch->ch_s_tpos; | ||
1174 | |||
1175 | /* TODO: this gives us timeout problems with nist ?? */ | ||
1176 | waketime = jiffies + 15 * HZ; | ||
1177 | } | ||
1178 | } | ||
1179 | |||
1180 | /* | ||
1181 | * Close the line discipline | ||
1182 | */ | ||
1183 | |||
1184 | /* this is done in tty_io.c */ | ||
1185 | /* if ((un->un_tty)->ldisc.close) | ||
1186 | * ((un->un_tty)->ldisc.close)(un->un_tty); | ||
1187 | */ | ||
1188 | |||
1189 | /* don't do this here */ | ||
1190 | /* un->un_flag = 0; */ | ||
1191 | |||
1192 | /* | ||
1193 | * Flush the receive buffer on terminal unit close only. | ||
1194 | */ | ||
1195 | |||
1196 | if (!IS_PRINT(MINOR(tty_devnum(tty)))) | ||
1197 | ch->ch_rout = ch->ch_rin; | ||
1198 | |||
1199 | |||
1200 | /* | ||
1201 | * Don't permit the close to happen until we get any pending | ||
1202 | * sync request responses. | ||
1203 | * There could be other ports depending upon the response as well. | ||
1204 | * | ||
1205 | * Also, don't permit the close to happen until any parameter | ||
1206 | * changes have been sent out from the state machine as well. | ||
1207 | * This is required because of a ditty -a race with -HUPCL | ||
1208 | * We MUST make sure all channel parameters have been sent to the | ||
1209 | * Portserver before sending a close. | ||
1210 | */ | ||
1211 | |||
1212 | if ((err != 1) && (ch->ch_state != CS_IDLE)) { | ||
1213 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
1214 | s = wait_event_interruptible(ch->ch_flag_wait, | ||
1215 | ((ch->ch_flag & (CH_WAITING_SYNC | CH_PARAM)) == 0)); | ||
1216 | spin_lock_irqsave(&nd->nd_lock, lock_flags); | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1220 | * Cleanup the channel if last unit open. | ||
1221 | */ | ||
1222 | |||
1223 | if (ch->ch_open_count == 1) { | ||
1224 | ch->ch_flag = 0; | ||
1225 | ch->ch_category = 0; | ||
1226 | ch->ch_send = 0; | ||
1227 | ch->ch_expect = 0; | ||
1228 | ch->ch_tout = ch->ch_tin; | ||
1229 | /* (un->un_tty)->device = 0; */ | ||
1230 | |||
1231 | if (ch->ch_state == CS_READY) | ||
1232 | ch->ch_state = CS_SEND_CLOSE; | ||
1233 | } | ||
1234 | |||
1235 | /* | ||
1236 | * Send the changes to the server | ||
1237 | */ | ||
1238 | if (ch->ch_state != CS_IDLE) { | ||
1239 | ch->ch_flag |= CH_PARAM; | ||
1240 | wake_up_interruptible(&ch->ch_flag_wait); | ||
1241 | } | ||
1242 | |||
1243 | nd->nd_tx_work = 1; | ||
1244 | nd->nd_tx_ready = 1; | ||
1245 | |||
1246 | unlock: | ||
1247 | tty->closing = 0; | ||
1248 | |||
1249 | if (ch->ch_open_count <= 0) | ||
1250 | dev_info(tty->dev, | ||
1251 | "%s - unexpected value for ch->ch_open_count: %i\n", | ||
1252 | __func__, ch->ch_open_count); | ||
1253 | else | ||
1254 | ch->ch_open_count--; | ||
1255 | |||
1256 | if (un->un_open_count <= 0) | ||
1257 | dev_info(tty->dev, | ||
1258 | "%s - unexpected value for un->un_open_count: %i\n", | ||
1259 | __func__, un->un_open_count); | ||
1260 | else | ||
1261 | un->un_open_count--; | ||
1262 | |||
1263 | un->un_flag &= ~(UN_NORMAL_ACTIVE | UN_CALLOUT_ACTIVE | UN_CLOSING); | ||
1264 | if (waitqueue_active(&un->un_close_wait)) | ||
1265 | wake_up_interruptible(&un->un_close_wait); | ||
1266 | |||
1267 | spin_unlock_irqrestore(&nd->nd_lock, lock_flags); | ||
1268 | |||
1269 | return; | ||
1270 | |||
1271 | } | ||
1272 | |||
1273 | static void drp_wmove(struct ch_struct *ch, int from_user, void *buf, int count) | ||
1274 | { | ||
1275 | int n; | ||
1276 | int ret = 0; | ||
1277 | |||
1278 | ch->ch_nd->nd_tx_work = 1; | ||
1279 | |||
1280 | n = TBUF_MAX - ch->ch_tin; | ||
1281 | |||
1282 | if (count >= n) { | ||
1283 | if (from_user) | ||
1284 | ret = copy_from_user(ch->ch_tbuf + ch->ch_tin, | ||
1285 | (void __user *) buf, n); | ||
1286 | else | ||
1287 | memcpy(ch->ch_tbuf + ch->ch_tin, buf, n); | ||
1288 | |||
1289 | buf = (char *) buf + n; | ||
1290 | count -= n; | ||
1291 | ch->ch_tin = 0; | ||
1292 | } | ||
1293 | |||
1294 | if (from_user) | ||
1295 | ret = copy_from_user(ch->ch_tbuf + ch->ch_tin, | ||
1296 | (void __user *) buf, count); | ||
1297 | else | ||
1298 | memcpy(ch->ch_tbuf + ch->ch_tin, buf, count); | ||
1299 | |||
1300 | ch->ch_tin += count; | ||
1301 | } | ||
1302 | |||
1303 | |||
1304 | static int dgrp_calculate_txprint_bounds(struct ch_struct *ch, int space, | ||
1305 | int *un_flag) | ||
1306 | { | ||
1307 | clock_t tt; | ||
1308 | clock_t mt; | ||
1309 | unsigned short tmax = 0; | ||
1310 | |||
1311 | /* | ||
1312 | * If the terminal device is busy, reschedule when | ||
1313 | * the terminal device becomes idle. | ||
1314 | */ | ||
1315 | |||
1316 | if (ch->ch_tun.un_open_count != 0 && | ||
1317 | ch->ch_tun.un_tty->ops->chars_in_buffer && | ||
1318 | ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) { | ||
1319 | *un_flag = UN_PWAIT; | ||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | /* | ||
1324 | * Assure that whenever there is printer data in the output | ||
1325 | * buffer, there always remains enough space after it to | ||
1326 | * turn the printer off. | ||
1327 | */ | ||
1328 | space -= ch->ch_digi.digi_offlen; | ||
1329 | |||
1330 | if (space <= 0) { | ||
1331 | *un_flag = UN_EMPTY; | ||
1332 | return 0; | ||
1333 | } | ||
1334 | |||
1335 | /* | ||
1336 | * We measure printer CPS speed by incrementing | ||
1337 | * ch_cpstime by (HZ / digi_maxcps) for every | ||
1338 | * character we output, restricting output so | ||
1339 | * that ch_cpstime never exceeds lbolt. | ||
1340 | * | ||
1341 | * However if output has not been done for some | ||
1342 | * time, lbolt will grow to very much larger than | ||
1343 | * ch_cpstime, which would allow essentially | ||
1344 | * unlimited amounts of output until ch_cpstime | ||
1345 | * finally caught up. To avoid this, we adjust | ||
1346 | * cps_time when necessary so the difference | ||
1347 | * between lbolt and ch_cpstime never results | ||
1348 | * in sending more than digi_bufsize characters. | ||
1349 | * | ||
1350 | * This nicely models a printer with an internal | ||
1351 | * buffer of digi_bufsize characters. | ||
1352 | * | ||
1353 | * Get the time between lbolt and ch->ch_cpstime; | ||
1354 | */ | ||
1355 | |||
1356 | tt = jiffies - ch->ch_cpstime; | ||
1357 | |||
1358 | /* | ||
1359 | * Compute the time required to send digi_bufsize | ||
1360 | * characters. | ||
1361 | */ | ||
1362 | |||
1363 | mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps; | ||
1364 | |||
1365 | /* | ||
1366 | * Compute the number of characters that can be sent | ||
1367 | * without violating the time constraint. If the | ||
1368 | * direct calculation of this number is bigger than | ||
1369 | * digi_bufsize, limit the number to digi_bufsize, | ||
1370 | * and adjust cpstime to match. | ||
1371 | */ | ||
1372 | |||
1373 | if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) { | ||
1374 | tmax = ch->ch_digi.digi_bufsize; | ||
1375 | ch->ch_cpstime = jiffies - mt; | ||
1376 | } else { | ||
1377 | tmax = ch->ch_digi.digi_maxcps * tt / HZ; | ||
1378 | } | ||
1379 | |||
1380 | /* | ||
1381 | * If the time constraint now binds, limit the transmit | ||
1382 | * count accordingly, and tentatively arrange to be | ||
1383 | * rescheduled based on time. | ||
1384 | */ | ||
1385 | |||
1386 | if (tmax < space) { | ||
1387 | *un_flag = UN_TIME; | ||
1388 | space = tmax; | ||
1389 | } | ||
1390 | |||
1391 | /* | ||
1392 | * Compute the total number of characters we can | ||
1393 | * output before the total number of characters known | ||
1394 | * to be in the output queue exceeds digi_maxchar. | ||
1395 | */ | ||
1396 | |||
1397 | tmax = (ch->ch_digi.digi_maxchar - | ||
1398 | ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) - | ||
1399 | ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff)); | ||
1400 | |||
1401 | |||
1402 | /* | ||
1403 | * If the digi_maxchar constraint now holds, limit | ||
1404 | * the transmit count accordingly, and arrange to | ||
1405 | * be rescheduled when the queue becomes empty. | ||
1406 | */ | ||
1407 | |||
1408 | if (space > tmax) { | ||
1409 | *un_flag = UN_EMPTY; | ||
1410 | space = tmax; | ||
1411 | } | ||
1412 | |||
1413 | if (space <= 0) | ||
1414 | *un_flag |= UN_EMPTY; | ||
1415 | |||
1416 | return space; | ||
1417 | } | ||
1418 | |||
1419 | |||
1420 | static int dgrp_tty_write(struct tty_struct *tty, | ||
1421 | const unsigned char *buf, | ||
1422 | int count) | ||
1423 | { | ||
1424 | struct nd_struct *nd; | ||
1425 | struct un_struct *un; | ||
1426 | struct ch_struct *ch; | ||
1427 | int space; | ||
1428 | int n; | ||
1429 | int t; | ||
1430 | int sendcount; | ||
1431 | int un_flag; | ||
1432 | ulong lock_flags; | ||
1433 | |||
1434 | if (tty == NULL) | ||
1435 | return 0; | ||
1436 | |||
1437 | un = tty->driver_data; | ||
1438 | if (!un) | ||
1439 | return 0; | ||
1440 | |||
1441 | ch = un->un_ch; | ||
1442 | if (!ch) | ||
1443 | return 0; | ||
1444 | |||
1445 | nd = ch->ch_nd; | ||
1446 | if (!nd) | ||
1447 | return 0; | ||
1448 | |||
1449 | /* | ||
1450 | * Ignore the request if the channel is not ready. | ||
1451 | */ | ||
1452 | if (ch->ch_state != CS_READY) | ||
1453 | return 0; | ||
1454 | |||
1455 | spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); | ||
1456 | |||
1457 | /* | ||
1458 | * Ignore the request if output is blocked. | ||
1459 | */ | ||
1460 | if ((un->un_flag & (UN_EMPTY | UN_LOW | UN_TIME | UN_PWAIT)) != 0) { | ||
1461 | count = 0; | ||
1462 | goto out; | ||
1463 | } | ||
1464 | |||
1465 | /* | ||
1466 | * Also ignore the request if DPA has this port open, | ||
1467 | * and is flow controlled on reading more data. | ||
1468 | */ | ||
1469 | if (nd->nd_dpa_debug && nd->nd_dpa_flag & DPA_WAIT_SPACE && | ||
1470 | nd->nd_dpa_port == MINOR(tty_devnum(ch->ch_tun.un_tty))) { | ||
1471 | count = 0; | ||
1472 | goto out; | ||
1473 | } | ||
1474 | |||
1475 | /* | ||
1476 | * Limit amount we will write to the amount of space | ||
1477 | * available in the channel buffer. | ||
1478 | */ | ||
1479 | sendcount = 0; | ||
1480 | |||
1481 | space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; | ||
1482 | |||
1483 | /* | ||
1484 | * Handle the printer device. | ||
1485 | */ | ||
1486 | |||
1487 | un_flag = UN_LOW; | ||
1488 | |||
1489 | if (IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
1490 | clock_t tt; | ||
1491 | clock_t mt; | ||
1492 | unsigned short tmax = 0; | ||
1493 | |||
1494 | /* | ||
1495 | * If the terminal device is busy, reschedule when | ||
1496 | * the terminal device becomes idle. | ||
1497 | */ | ||
1498 | |||
1499 | if (ch->ch_tun.un_open_count != 0 && | ||
1500 | ((ch->ch_tun.un_tty->ops->chars_in_buffer)(ch->ch_tun.un_tty) != 0)) { | ||
1501 | un->un_flag |= UN_PWAIT; | ||
1502 | count = 0; | ||
1503 | goto out; | ||
1504 | } | ||
1505 | |||
1506 | /* | ||
1507 | * Assure that whenever there is printer data in the output | ||
1508 | * buffer, there always remains enough space after it to | ||
1509 | * turn the printer off. | ||
1510 | */ | ||
1511 | space -= ch->ch_digi.digi_offlen; | ||
1512 | |||
1513 | /* | ||
1514 | * Output the printer on string. | ||
1515 | */ | ||
1516 | |||
1517 | if ((ch->ch_flag & CH_PRON) == 0) { | ||
1518 | space -= ch->ch_digi.digi_onlen; | ||
1519 | |||
1520 | if (space < 0) { | ||
1521 | un->un_flag |= UN_EMPTY; | ||
1522 | (ch->ch_nd)->nd_tx_work = 1; | ||
1523 | count = 0; | ||
1524 | goto out; | ||
1525 | } | ||
1526 | |||
1527 | drp_wmove(ch, 0, ch->ch_digi.digi_onstr, | ||
1528 | ch->ch_digi.digi_onlen); | ||
1529 | |||
1530 | ch->ch_flag |= CH_PRON; | ||
1531 | } | ||
1532 | |||
1533 | /* | ||
1534 | * We measure printer CPS speed by incrementing | ||
1535 | * ch_cpstime by (HZ / digi_maxcps) for every | ||
1536 | * character we output, restricting output so | ||
1537 | * that ch_cpstime never exceeds lbolt. | ||
1538 | * | ||
1539 | * However if output has not been done for some | ||
1540 | * time, lbolt will grow to very much larger than | ||
1541 | * ch_cpstime, which would allow essentially | ||
1542 | * unlimited amounts of output until ch_cpstime | ||
1543 | * finally caught up. To avoid this, we adjust | ||
1544 | * cps_time when necessary so the difference | ||
1545 | * between lbolt and ch_cpstime never results | ||
1546 | * in sending more than digi_bufsize characters. | ||
1547 | * | ||
1548 | * This nicely models a printer with an internal | ||
1549 | * buffer of digi_bufsize characters. | ||
1550 | * | ||
1551 | * Get the time between lbolt and ch->ch_cpstime; | ||
1552 | */ | ||
1553 | |||
1554 | tt = jiffies - ch->ch_cpstime; | ||
1555 | |||
1556 | /* | ||
1557 | * Compute the time required to send digi_bufsize | ||
1558 | * characters. | ||
1559 | */ | ||
1560 | |||
1561 | mt = HZ * ch->ch_digi.digi_bufsize / ch->ch_digi.digi_maxcps; | ||
1562 | |||
1563 | /* | ||
1564 | * Compute the number of characters that can be sent | ||
1565 | * without violating the time constraint. If the | ||
1566 | * direct calculation of this number is bigger than | ||
1567 | * digi_bufsize, limit the number to digi_bufsize, | ||
1568 | * and adjust cpstime to match. | ||
1569 | */ | ||
1570 | |||
1571 | if ((clock_t)(tt + HZ) > (clock_t)(mt + HZ)) { | ||
1572 | tmax = ch->ch_digi.digi_bufsize; | ||
1573 | ch->ch_cpstime = jiffies - mt; | ||
1574 | } else { | ||
1575 | tmax = ch->ch_digi.digi_maxcps * tt / HZ; | ||
1576 | } | ||
1577 | |||
1578 | /* | ||
1579 | * If the time constraint now binds, limit the transmit | ||
1580 | * count accordingly, and tentatively arrange to be | ||
1581 | * rescheduled based on time. | ||
1582 | */ | ||
1583 | |||
1584 | if (tmax < space) { | ||
1585 | space = tmax; | ||
1586 | un_flag = UN_TIME; | ||
1587 | } | ||
1588 | |||
1589 | /* | ||
1590 | * Compute the total number of characters we can | ||
1591 | * output before the total number of characters known | ||
1592 | * to be in the output queue exceeds digi_maxchar. | ||
1593 | */ | ||
1594 | |||
1595 | tmax = (ch->ch_digi.digi_maxchar - | ||
1596 | ((ch->ch_tin - ch->ch_tout) & TBUF_MASK) - | ||
1597 | ((ch->ch_s_tin - ch->ch_s_tpos) & 0xffff)); | ||
1598 | |||
1599 | |||
1600 | /* | ||
1601 | * If the digi_maxchar constraint now holds, limit | ||
1602 | * the transmit count accordingly, and arrange to | ||
1603 | * be rescheduled when the queue becomes empty. | ||
1604 | */ | ||
1605 | |||
1606 | if (space > tmax) { | ||
1607 | space = tmax; | ||
1608 | un_flag = UN_EMPTY; | ||
1609 | } | ||
1610 | |||
1611 | } | ||
1612 | /* | ||
1613 | * Handle the terminal device. | ||
1614 | */ | ||
1615 | else { | ||
1616 | |||
1617 | /* | ||
1618 | * If the printer device is on, turn it off. | ||
1619 | */ | ||
1620 | |||
1621 | if ((ch->ch_flag & CH_PRON) != 0) { | ||
1622 | |||
1623 | space -= ch->ch_digi.digi_offlen; | ||
1624 | |||
1625 | drp_wmove(ch, 0, ch->ch_digi.digi_offstr, | ||
1626 | ch->ch_digi.digi_offlen); | ||
1627 | |||
1628 | ch->ch_flag &= ~CH_PRON; | ||
1629 | } | ||
1630 | } | ||
1631 | |||
1632 | /* | ||
1633 | * If space is 0 and its because the ch->tbuf | ||
1634 | * is full, then Linux will handle a callback when queue | ||
1635 | * space becomes available. | ||
1636 | * tty_write returns count = 0 | ||
1637 | */ | ||
1638 | |||
1639 | if (space <= 0) { | ||
1640 | /* the linux tty_io.c handles this if we return 0 */ | ||
1641 | /* if (fp->flags & O_NONBLOCK) return -EAGAIN; */ | ||
1642 | |||
1643 | un->un_flag |= UN_EMPTY; | ||
1644 | (ch->ch_nd)->nd_tx_work = 1; | ||
1645 | count = 0; | ||
1646 | goto out; | ||
1647 | } | ||
1648 | |||
1649 | count = min(count, space); | ||
1650 | |||
1651 | if (count > 0) { | ||
1652 | |||
1653 | un->un_tbusy++; | ||
1654 | |||
1655 | /* | ||
1656 | * Copy the buffer contents to the ch_tbuf | ||
1657 | * being careful to wrap around the circular queue | ||
1658 | */ | ||
1659 | |||
1660 | t = TBUF_MAX - ch->ch_tin; | ||
1661 | n = count; | ||
1662 | |||
1663 | if (n >= t) { | ||
1664 | memcpy(ch->ch_tbuf + ch->ch_tin, buf, t); | ||
1665 | if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty)))) | ||
1666 | dgrp_dpa_data(nd, 0, (char *) buf, t); | ||
1667 | buf += t; | ||
1668 | n -= t; | ||
1669 | ch->ch_tin = 0; | ||
1670 | sendcount += n; | ||
1671 | } | ||
1672 | |||
1673 | memcpy(ch->ch_tbuf + ch->ch_tin, buf, n); | ||
1674 | if (nd->nd_dpa_debug && nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(un->un_tty)))) | ||
1675 | dgrp_dpa_data(nd, 0, (char *) buf, n); | ||
1676 | buf += n; | ||
1677 | ch->ch_tin += n; | ||
1678 | sendcount += n; | ||
1679 | |||
1680 | un->un_tbusy--; | ||
1681 | (ch->ch_nd)->nd_tx_work = 1; | ||
1682 | if (ch->ch_edelay != DGRP_RTIME) { | ||
1683 | (ch->ch_nd)->nd_tx_ready = 1; | ||
1684 | wake_up_interruptible(&nd->nd_tx_waitq); | ||
1685 | } | ||
1686 | } | ||
1687 | |||
1688 | ch->ch_txcount += count; | ||
1689 | |||
1690 | if (IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
1691 | |||
1692 | /* | ||
1693 | * Adjust ch_cpstime to account | ||
1694 | * for the characters just output. | ||
1695 | */ | ||
1696 | |||
1697 | if (sendcount > 0) { | ||
1698 | int cc = HZ * sendcount + ch->ch_cpsrem; | ||
1699 | |||
1700 | ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps; | ||
1701 | ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps; | ||
1702 | } | ||
1703 | |||
1704 | /* | ||
1705 | * If we are now waiting on time, schedule ourself | ||
1706 | * back when we'll be able to send a block of | ||
1707 | * digi_maxchar characters. | ||
1708 | */ | ||
1709 | |||
1710 | if ((un_flag & UN_TIME) != 0) { | ||
1711 | ch->ch_waketime = (ch->ch_cpstime + | ||
1712 | (ch->ch_digi.digi_maxchar * HZ / | ||
1713 | ch->ch_digi.digi_maxcps)); | ||
1714 | } | ||
1715 | } | ||
1716 | |||
1717 | /* | ||
1718 | * If the printer unit is waiting for completion | ||
1719 | * of terminal output, get him going again. | ||
1720 | */ | ||
1721 | |||
1722 | if ((ch->ch_pun.un_flag & UN_PWAIT) != 0) | ||
1723 | (ch->ch_nd)->nd_tx_work = 1; | ||
1724 | |||
1725 | out: | ||
1726 | spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); | ||
1727 | |||
1728 | return count; | ||
1729 | } | ||
1730 | |||
1731 | |||
1732 | /* | ||
1733 | * Put a character into ch->ch_buf | ||
1734 | * | ||
1735 | * - used by the line discipline for OPOST processing | ||
1736 | */ | ||
1737 | |||
1738 | static int dgrp_tty_put_char(struct tty_struct *tty, unsigned char new_char) | ||
1739 | { | ||
1740 | struct un_struct *un; | ||
1741 | struct ch_struct *ch; | ||
1742 | ulong lock_flags; | ||
1743 | int space; | ||
1744 | int retval = 0; | ||
1745 | |||
1746 | if (tty == NULL) | ||
1747 | return 0; | ||
1748 | |||
1749 | un = tty->driver_data; | ||
1750 | if (!un) | ||
1751 | return 0; | ||
1752 | |||
1753 | ch = un->un_ch; | ||
1754 | if (!ch) | ||
1755 | return 0; | ||
1756 | |||
1757 | if (ch->ch_state != CS_READY) | ||
1758 | return 0; | ||
1759 | |||
1760 | spin_lock_irqsave(&dgrp_poll_data.poll_lock, lock_flags); | ||
1761 | |||
1762 | |||
1763 | /* | ||
1764 | * If space is 0 and its because the ch->tbuf | ||
1765 | * Warn and dump the character, there isn't anything else | ||
1766 | * we can do about it. David_Fries@digi.com | ||
1767 | */ | ||
1768 | |||
1769 | space = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; | ||
1770 | |||
1771 | un->un_tbusy++; | ||
1772 | |||
1773 | /* | ||
1774 | * Output the printer on string if device is TXPrint. | ||
1775 | */ | ||
1776 | if (IS_PRINT(MINOR(tty_devnum(tty))) && (ch->ch_flag & CH_PRON) == 0) { | ||
1777 | if (space < ch->ch_digi.digi_onlen) { | ||
1778 | un->un_tbusy--; | ||
1779 | goto out; | ||
1780 | } | ||
1781 | space -= ch->ch_digi.digi_onlen; | ||
1782 | drp_wmove(ch, 0, ch->ch_digi.digi_onstr, | ||
1783 | ch->ch_digi.digi_onlen); | ||
1784 | ch->ch_flag |= CH_PRON; | ||
1785 | } | ||
1786 | |||
1787 | /* | ||
1788 | * Output the printer off string if device is NOT TXPrint. | ||
1789 | */ | ||
1790 | |||
1791 | if (!IS_PRINT(MINOR(tty_devnum(tty))) && | ||
1792 | ((ch->ch_flag & CH_PRON) != 0)) { | ||
1793 | if (space < ch->ch_digi.digi_offlen) { | ||
1794 | un->un_tbusy--; | ||
1795 | goto out; | ||
1796 | } | ||
1797 | |||
1798 | space -= ch->ch_digi.digi_offlen; | ||
1799 | drp_wmove(ch, 0, ch->ch_digi.digi_offstr, | ||
1800 | ch->ch_digi.digi_offlen); | ||
1801 | ch->ch_flag &= ~CH_PRON; | ||
1802 | } | ||
1803 | |||
1804 | if (!space) { | ||
1805 | un->un_tbusy--; | ||
1806 | goto out; | ||
1807 | } | ||
1808 | |||
1809 | /* | ||
1810 | * Copy the character to the ch_tbuf being | ||
1811 | * careful to wrap around the circular queue | ||
1812 | */ | ||
1813 | ch->ch_tbuf[ch->ch_tin] = new_char; | ||
1814 | ch->ch_tin = (1 + ch->ch_tin) & TBUF_MASK; | ||
1815 | |||
1816 | if (IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
1817 | |||
1818 | /* | ||
1819 | * Adjust ch_cpstime to account | ||
1820 | * for the character just output. | ||
1821 | */ | ||
1822 | |||
1823 | int cc = HZ + ch->ch_cpsrem; | ||
1824 | |||
1825 | ch->ch_cpstime += cc / ch->ch_digi.digi_maxcps; | ||
1826 | ch->ch_cpsrem = cc % ch->ch_digi.digi_maxcps; | ||
1827 | |||
1828 | /* | ||
1829 | * If we are now waiting on time, schedule ourself | ||
1830 | * back when we'll be able to send a block of | ||
1831 | * digi_maxchar characters. | ||
1832 | */ | ||
1833 | |||
1834 | ch->ch_waketime = (ch->ch_cpstime + | ||
1835 | (ch->ch_digi.digi_maxchar * HZ / | ||
1836 | ch->ch_digi.digi_maxcps)); | ||
1837 | } | ||
1838 | |||
1839 | |||
1840 | un->un_tbusy--; | ||
1841 | (ch->ch_nd)->nd_tx_work = 1; | ||
1842 | |||
1843 | retval = 1; | ||
1844 | out: | ||
1845 | spin_unlock_irqrestore(&dgrp_poll_data.poll_lock, lock_flags); | ||
1846 | return retval; | ||
1847 | } | ||
1848 | |||
1849 | |||
1850 | |||
1851 | /* | ||
1852 | * Flush TX buffer (make in == out) | ||
1853 | * | ||
1854 | * check tty_ioctl.c -- this is called after TCOFLUSH | ||
1855 | */ | ||
1856 | static void dgrp_tty_flush_buffer(struct tty_struct *tty) | ||
1857 | { | ||
1858 | struct un_struct *un; | ||
1859 | struct ch_struct *ch; | ||
1860 | |||
1861 | if (!tty) | ||
1862 | return; | ||
1863 | un = tty->driver_data; | ||
1864 | if (!un) | ||
1865 | return; | ||
1866 | |||
1867 | ch = un->un_ch; | ||
1868 | if (!ch) | ||
1869 | return; | ||
1870 | |||
1871 | ch->ch_tout = ch->ch_tin; | ||
1872 | /* do NOT do this here! */ | ||
1873 | /* ch->ch_s_tpos = ch->ch_s_tin = 0; */ | ||
1874 | |||
1875 | /* send the flush output command now */ | ||
1876 | ch->ch_send |= RR_TX_FLUSH; | ||
1877 | (ch->ch_nd)->nd_tx_ready = 1; | ||
1878 | (ch->ch_nd)->nd_tx_work = 1; | ||
1879 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
1880 | |||
1881 | if (waitqueue_active(&tty->write_wait)) | ||
1882 | wake_up_interruptible(&tty->write_wait); | ||
1883 | |||
1884 | tty_wakeup(tty); | ||
1885 | |||
1886 | } | ||
1887 | |||
1888 | /* | ||
1889 | * Return space available in Tx buffer | ||
1890 | * count = ( ch->ch_tout - ch->ch_tin ) mod (TBUF_MAX - 1) | ||
1891 | */ | ||
1892 | static int dgrp_tty_write_room(struct tty_struct *tty) | ||
1893 | { | ||
1894 | struct un_struct *un; | ||
1895 | struct ch_struct *ch; | ||
1896 | int count; | ||
1897 | |||
1898 | if (!tty) | ||
1899 | return 0; | ||
1900 | |||
1901 | un = tty->driver_data; | ||
1902 | if (!un) | ||
1903 | return 0; | ||
1904 | |||
1905 | ch = un->un_ch; | ||
1906 | if (!ch) | ||
1907 | return 0; | ||
1908 | |||
1909 | count = (ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK; | ||
1910 | |||
1911 | /* We *MUST* check this, and return 0 if the Printer Unit cannot | ||
1912 | * take any more data within its time constraints... If we don't | ||
1913 | * return 0 and the printer has hit it time constraint, the ld will | ||
1914 | * call us back doing a put_char, which cannot be rejected!!! | ||
1915 | */ | ||
1916 | if (IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
1917 | int un_flag = 0; | ||
1918 | count = dgrp_calculate_txprint_bounds(ch, count, &un_flag); | ||
1919 | if (count <= 0) | ||
1920 | count = 0; | ||
1921 | |||
1922 | ch->ch_pun.un_flag |= un_flag; | ||
1923 | (ch->ch_nd)->nd_tx_work = 1; | ||
1924 | } | ||
1925 | |||
1926 | return count; | ||
1927 | } | ||
1928 | |||
1929 | /* | ||
1930 | * Return number of characters that have not been transmitted yet. | ||
1931 | * chars_in_buffer = ( ch->ch_tin - ch->ch_tout ) mod (TBUF_MAX - 1) | ||
1932 | * + ( ch->ch_s_tin - ch->ch_s_tout ) mod (0xffff) | ||
1933 | * = number of characters "in transit" | ||
1934 | * | ||
1935 | * Remember that sequence number math is always with a sixteen bit | ||
1936 | * mask, not the TBUF_MASK. | ||
1937 | */ | ||
1938 | |||
1939 | static int dgrp_tty_chars_in_buffer(struct tty_struct *tty) | ||
1940 | { | ||
1941 | struct un_struct *un; | ||
1942 | struct ch_struct *ch; | ||
1943 | int count; | ||
1944 | int count1; | ||
1945 | |||
1946 | if (!tty) | ||
1947 | return 0; | ||
1948 | |||
1949 | un = tty->driver_data; | ||
1950 | if (!un) | ||
1951 | return 0; | ||
1952 | |||
1953 | ch = un->un_ch; | ||
1954 | if (!ch) | ||
1955 | return 0; | ||
1956 | |||
1957 | count1 = count = (ch->ch_tin - ch->ch_tout) & TBUF_MASK; | ||
1958 | count += (ch->ch_s_tin - ch->ch_s_tpos) & 0xffff; | ||
1959 | /* one for tbuf, one for the PS */ | ||
1960 | |||
1961 | /* | ||
1962 | * If we are busy transmitting add 1 | ||
1963 | */ | ||
1964 | count += un->un_tbusy; | ||
1965 | |||
1966 | return count; | ||
1967 | } | ||
1968 | |||
1969 | |||
1970 | /***************************************************************************** | ||
1971 | * | ||
1972 | * Helper applications for dgrp_tty_ioctl() | ||
1973 | * | ||
1974 | ***************************************************************************** | ||
1975 | */ | ||
1976 | |||
1977 | |||
1978 | /** | ||
1979 | * ch_to_tty_flags() -- convert channel flags to termio flags | ||
1980 | * @ch_flag: Digi channel flags | ||
1981 | * @flagtype: type of ch_flag (iflag, oflag or cflag) | ||
1982 | * | ||
1983 | * take the channel flags of the specified type and return the | ||
1984 | * corresponding termio flag | ||
1985 | */ | ||
1986 | static tcflag_t ch_to_tty_flags(ushort ch_flag, char flagtype) | ||
1987 | { | ||
1988 | tcflag_t retval = 0; | ||
1989 | |||
1990 | switch (flagtype) { | ||
1991 | case 'i': | ||
1992 | retval = ((ch_flag & IF_IGNBRK) ? IGNBRK : 0) | ||
1993 | | ((ch_flag & IF_BRKINT) ? BRKINT : 0) | ||
1994 | | ((ch_flag & IF_IGNPAR) ? IGNPAR : 0) | ||
1995 | | ((ch_flag & IF_PARMRK) ? PARMRK : 0) | ||
1996 | | ((ch_flag & IF_INPCK) ? INPCK : 0) | ||
1997 | | ((ch_flag & IF_ISTRIP) ? ISTRIP : 0) | ||
1998 | | ((ch_flag & IF_IXON) ? IXON : 0) | ||
1999 | | ((ch_flag & IF_IXANY) ? IXANY : 0) | ||
2000 | | ((ch_flag & IF_IXOFF) ? IXOFF : 0); | ||
2001 | break; | ||
2002 | |||
2003 | case 'o': | ||
2004 | retval = ((ch_flag & OF_OLCUC) ? OLCUC : 0) | ||
2005 | | ((ch_flag & OF_ONLCR) ? ONLCR : 0) | ||
2006 | | ((ch_flag & OF_OCRNL) ? OCRNL : 0) | ||
2007 | | ((ch_flag & OF_ONOCR) ? ONOCR : 0) | ||
2008 | | ((ch_flag & OF_ONLRET) ? ONLRET : 0) | ||
2009 | /* | ((ch_flag & OF_OTAB3) ? OFILL : 0) */ | ||
2010 | | ((ch_flag & OF_TABDLY) ? TABDLY : 0); | ||
2011 | break; | ||
2012 | |||
2013 | case 'c': | ||
2014 | retval = ((ch_flag & CF_CSTOPB) ? CSTOPB : 0) | ||
2015 | | ((ch_flag & CF_CREAD) ? CREAD : 0) | ||
2016 | | ((ch_flag & CF_PARENB) ? PARENB : 0) | ||
2017 | | ((ch_flag & CF_PARODD) ? PARODD : 0) | ||
2018 | | ((ch_flag & CF_HUPCL) ? HUPCL : 0); | ||
2019 | |||
2020 | switch (ch_flag & CF_CSIZE) { | ||
2021 | case CF_CS5: | ||
2022 | retval |= CS5; | ||
2023 | break; | ||
2024 | case CF_CS6: | ||
2025 | retval |= CS6; | ||
2026 | break; | ||
2027 | case CF_CS7: | ||
2028 | retval |= CS7; | ||
2029 | break; | ||
2030 | case CF_CS8: | ||
2031 | retval |= CS8; | ||
2032 | break; | ||
2033 | default: | ||
2034 | retval |= CS8; | ||
2035 | break; | ||
2036 | } | ||
2037 | break; | ||
2038 | case 'x': | ||
2039 | break; | ||
2040 | case 'l': | ||
2041 | break; | ||
2042 | default: | ||
2043 | return 0; | ||
2044 | } | ||
2045 | |||
2046 | return retval; | ||
2047 | } | ||
2048 | |||
2049 | |||
2050 | /** | ||
2051 | * tty_to_ch_flags() -- convert termio flags to digi channel flags | ||
2052 | * @tty: pointer to a TTY structure holding flag to be converted | ||
2053 | * @flagtype: identifies which flag (iflags, oflags, or cflags) should | ||
2054 | * be converted | ||
2055 | * | ||
2056 | * take the termio flag of the specified type and return the | ||
2057 | * corresponding Digi version of the flags | ||
2058 | */ | ||
2059 | static ushort tty_to_ch_flags(struct tty_struct *tty, char flagtype) | ||
2060 | { | ||
2061 | ushort retval = 0; | ||
2062 | tcflag_t tflag = 0; | ||
2063 | |||
2064 | switch (flagtype) { | ||
2065 | case 'i': | ||
2066 | tflag = tty->termios.c_iflag; | ||
2067 | retval = (I_IGNBRK(tty) ? IF_IGNBRK : 0) | ||
2068 | | (I_BRKINT(tty) ? IF_BRKINT : 0) | ||
2069 | | (I_IGNPAR(tty) ? IF_IGNPAR : 0) | ||
2070 | | (I_PARMRK(tty) ? IF_PARMRK : 0) | ||
2071 | | (I_INPCK(tty) ? IF_INPCK : 0) | ||
2072 | | (I_ISTRIP(tty) ? IF_ISTRIP : 0) | ||
2073 | | (I_IXON(tty) ? IF_IXON : 0) | ||
2074 | | (I_IXANY(tty) ? IF_IXANY : 0) | ||
2075 | | (I_IXOFF(tty) ? IF_IXOFF : 0); | ||
2076 | break; | ||
2077 | case 'o': | ||
2078 | tflag = tty->termios.c_oflag; | ||
2079 | /* | ||
2080 | * If OPOST is set, then do the post processing in the | ||
2081 | * firmware by setting all the processing flags on. | ||
2082 | * If ~OPOST, then make sure we are not doing any | ||
2083 | * output processing!! | ||
2084 | */ | ||
2085 | if (!O_OPOST(tty)) | ||
2086 | retval = 0; | ||
2087 | else | ||
2088 | retval = (O_OLCUC(tty) ? OF_OLCUC : 0) | ||
2089 | | (O_ONLCR(tty) ? OF_ONLCR : 0) | ||
2090 | | (O_OCRNL(tty) ? OF_OCRNL : 0) | ||
2091 | | (O_ONOCR(tty) ? OF_ONOCR : 0) | ||
2092 | | (O_ONLRET(tty) ? OF_ONLRET : 0) | ||
2093 | /* | (O_OFILL(tty) ? OF_TAB3 : 0) */ | ||
2094 | | (O_TABDLY(tty) ? OF_TABDLY : 0); | ||
2095 | break; | ||
2096 | case 'c': | ||
2097 | tflag = tty->termios.c_cflag; | ||
2098 | retval = (C_CSTOPB(tty) ? CF_CSTOPB : 0) | ||
2099 | | (C_CREAD(tty) ? CF_CREAD : 0) | ||
2100 | | (C_PARENB(tty) ? CF_PARENB : 0) | ||
2101 | | (C_PARODD(tty) ? CF_PARODD : 0) | ||
2102 | | (C_HUPCL(tty) ? CF_HUPCL : 0); | ||
2103 | switch (C_CSIZE(tty)) { | ||
2104 | case CS8: | ||
2105 | retval |= CF_CS8; | ||
2106 | break; | ||
2107 | case CS7: | ||
2108 | retval |= CF_CS7; | ||
2109 | break; | ||
2110 | case CS6: | ||
2111 | retval |= CF_CS6; | ||
2112 | break; | ||
2113 | case CS5: | ||
2114 | retval |= CF_CS5; | ||
2115 | break; | ||
2116 | default: | ||
2117 | retval |= CF_CS8; | ||
2118 | break; | ||
2119 | } | ||
2120 | break; | ||
2121 | case 'x': | ||
2122 | break; | ||
2123 | case 'l': | ||
2124 | break; | ||
2125 | default: | ||
2126 | return 0; | ||
2127 | } | ||
2128 | |||
2129 | return retval; | ||
2130 | } | ||
2131 | |||
2132 | |||
2133 | static int dgrp_tty_send_break(struct tty_struct *tty, int msec) | ||
2134 | { | ||
2135 | struct un_struct *un; | ||
2136 | struct ch_struct *ch; | ||
2137 | int ret = -EIO; | ||
2138 | |||
2139 | if (!tty) | ||
2140 | return ret; | ||
2141 | |||
2142 | un = tty->driver_data; | ||
2143 | if (!un) | ||
2144 | return ret; | ||
2145 | |||
2146 | ch = un->un_ch; | ||
2147 | if (!ch) | ||
2148 | return ret; | ||
2149 | |||
2150 | dgrp_send_break(ch, msec); | ||
2151 | return 0; | ||
2152 | } | ||
2153 | |||
2154 | |||
2155 | /* | ||
2156 | * This routine sends a break character out the serial port. | ||
2157 | * | ||
2158 | * duration is in 1/1000's of a second | ||
2159 | */ | ||
2160 | static int dgrp_send_break(struct ch_struct *ch, int msec) | ||
2161 | { | ||
2162 | ulong x; | ||
2163 | |||
2164 | wait_event_interruptible(ch->ch_flag_wait, | ||
2165 | ((ch->ch_flag & CH_TX_BREAK) == 0)); | ||
2166 | ch->ch_break_time += max(msec, 250); | ||
2167 | ch->ch_send |= RR_TX_BREAK; | ||
2168 | ch->ch_flag |= CH_TX_BREAK; | ||
2169 | (ch->ch_nd)->nd_tx_work = 1; | ||
2170 | |||
2171 | x = (msec * HZ) / 1000; | ||
2172 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2173 | |||
2174 | return 0; | ||
2175 | } | ||
2176 | |||
2177 | |||
2178 | /* | ||
2179 | * Return modem signals to ld. | ||
2180 | */ | ||
2181 | static int dgrp_tty_tiocmget(struct tty_struct *tty) | ||
2182 | { | ||
2183 | unsigned int mlast; | ||
2184 | struct un_struct *un = tty->driver_data; | ||
2185 | struct ch_struct *ch; | ||
2186 | |||
2187 | if (!un) | ||
2188 | return -ENODEV; | ||
2189 | |||
2190 | ch = un->un_ch; | ||
2191 | if (!ch) | ||
2192 | return -ENODEV; | ||
2193 | |||
2194 | mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) | | ||
2195 | (ch->ch_mout & (DM_RTS | DM_DTR))); | ||
2196 | |||
2197 | /* defined in /usr/include/asm/termios.h */ | ||
2198 | mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0) | ||
2199 | | ((mlast & DM_DTR) ? TIOCM_DTR : 0) | ||
2200 | | ((mlast & DM_CD) ? TIOCM_CAR : 0) | ||
2201 | | ((mlast & DM_RI) ? TIOCM_RNG : 0) | ||
2202 | | ((mlast & DM_DSR) ? TIOCM_DSR : 0) | ||
2203 | | ((mlast & DM_CTS) ? TIOCM_CTS : 0); | ||
2204 | |||
2205 | return mlast; | ||
2206 | } | ||
2207 | |||
2208 | |||
2209 | /* | ||
2210 | * Set modem lines | ||
2211 | */ | ||
2212 | static int dgrp_tty_tiocmset(struct tty_struct *tty, | ||
2213 | unsigned int set, unsigned int clear) | ||
2214 | { | ||
2215 | ulong lock_flags; | ||
2216 | struct un_struct *un = tty->driver_data; | ||
2217 | struct ch_struct *ch; | ||
2218 | |||
2219 | if (!un) | ||
2220 | return -ENODEV; | ||
2221 | |||
2222 | ch = un->un_ch; | ||
2223 | if (!ch) | ||
2224 | return -ENODEV; | ||
2225 | |||
2226 | if (set & TIOCM_RTS) | ||
2227 | ch->ch_mout |= DM_RTS; | ||
2228 | |||
2229 | if (set & TIOCM_DTR) | ||
2230 | ch->ch_mout |= DM_DTR; | ||
2231 | |||
2232 | if (clear & TIOCM_RTS) | ||
2233 | ch->ch_mout &= ~(DM_RTS); | ||
2234 | |||
2235 | if (clear & TIOCM_DTR) | ||
2236 | ch->ch_mout &= ~(DM_DTR); | ||
2237 | |||
2238 | spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags); | ||
2239 | ch->ch_flag |= CH_PARAM; | ||
2240 | (ch->ch_nd)->nd_tx_work = 1; | ||
2241 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2242 | |||
2243 | spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags); | ||
2244 | |||
2245 | return 0; | ||
2246 | } | ||
2247 | |||
2248 | |||
2249 | |||
2250 | /* | ||
2251 | * Get current modem status | ||
2252 | */ | ||
2253 | static int get_modem_info(struct ch_struct *ch, unsigned int *value) | ||
2254 | { | ||
2255 | unsigned int mlast; | ||
2256 | |||
2257 | mlast = ((ch->ch_s_mlast & ~(DM_RTS | DM_DTR)) | | ||
2258 | (ch->ch_mout & (DM_RTS | DM_DTR))); | ||
2259 | |||
2260 | /* defined in /usr/include/asm/termios.h */ | ||
2261 | mlast = ((mlast & DM_RTS) ? TIOCM_RTS : 0) | ||
2262 | | ((mlast & DM_DTR) ? TIOCM_DTR : 0) | ||
2263 | | ((mlast & DM_CD) ? TIOCM_CAR : 0) | ||
2264 | | ((mlast & DM_RI) ? TIOCM_RNG : 0) | ||
2265 | | ((mlast & DM_DSR) ? TIOCM_DSR : 0) | ||
2266 | | ((mlast & DM_CTS) ? TIOCM_CTS : 0); | ||
2267 | put_user(mlast, (unsigned int __user *) value); | ||
2268 | |||
2269 | return 0; | ||
2270 | } | ||
2271 | |||
2272 | /* | ||
2273 | * Set modem lines | ||
2274 | */ | ||
2275 | static int set_modem_info(struct ch_struct *ch, unsigned int command, | ||
2276 | unsigned int *value) | ||
2277 | { | ||
2278 | int error; | ||
2279 | unsigned int arg; | ||
2280 | int mval = 0; | ||
2281 | ulong lock_flags; | ||
2282 | |||
2283 | error = access_ok(VERIFY_READ, (void __user *) value, sizeof(int)); | ||
2284 | if (error == 0) | ||
2285 | return -EFAULT; | ||
2286 | |||
2287 | get_user(arg, (unsigned int __user *) value); | ||
2288 | mval |= ((arg & TIOCM_RTS) ? DM_RTS : 0) | ||
2289 | | ((arg & TIOCM_DTR) ? DM_DTR : 0); | ||
2290 | |||
2291 | switch (command) { | ||
2292 | case TIOCMBIS: /* set flags */ | ||
2293 | ch->ch_mout |= mval; | ||
2294 | break; | ||
2295 | case TIOCMBIC: /* clear flags */ | ||
2296 | ch->ch_mout &= ~mval; | ||
2297 | break; | ||
2298 | case TIOCMSET: | ||
2299 | ch->ch_mout = mval; | ||
2300 | break; | ||
2301 | default: | ||
2302 | return -EINVAL; | ||
2303 | } | ||
2304 | |||
2305 | spin_lock_irqsave(&(ch->ch_nd)->nd_lock, lock_flags); | ||
2306 | |||
2307 | ch->ch_flag |= CH_PARAM; | ||
2308 | (ch->ch_nd)->nd_tx_work = 1; | ||
2309 | wake_up_interruptible(&ch->ch_flag_wait); | ||
2310 | |||
2311 | spin_unlock_irqrestore(&(ch->ch_nd)->nd_lock, lock_flags); | ||
2312 | |||
2313 | return 0; | ||
2314 | } | ||
2315 | |||
2316 | |||
2317 | /* | ||
2318 | * Assign the custom baud rate to the channel structure | ||
2319 | */ | ||
2320 | static void dgrp_set_custom_speed(struct ch_struct *ch, int newrate) | ||
2321 | { | ||
2322 | int testdiv; | ||
2323 | int testrate_high; | ||
2324 | int testrate_low; | ||
2325 | |||
2326 | int deltahigh, deltalow; | ||
2327 | |||
2328 | if (newrate < 0) | ||
2329 | newrate = 0; | ||
2330 | |||
2331 | /* | ||
2332 | * Since the divisor is stored in a 16-bit integer, we make sure | ||
2333 | * we don't allow any rates smaller than a 16-bit integer would allow. | ||
2334 | * And of course, rates above the dividend won't fly. | ||
2335 | */ | ||
2336 | if (newrate && newrate < ((PORTSERVER_DIVIDEND / 0xFFFF) + 1)) | ||
2337 | newrate = ((PORTSERVER_DIVIDEND / 0xFFFF) + 1); | ||
2338 | if (newrate && newrate > PORTSERVER_DIVIDEND) | ||
2339 | newrate = PORTSERVER_DIVIDEND; | ||
2340 | |||
2341 | while (newrate > 0) { | ||
2342 | testdiv = PORTSERVER_DIVIDEND / newrate; | ||
2343 | |||
2344 | /* | ||
2345 | * If we try to figure out what rate the PortServer would use | ||
2346 | * with the test divisor, it will be either equal or higher | ||
2347 | * than the requested baud rate. If we then determine the | ||
2348 | * rate with a divisor one higher, we will get the next lower | ||
2349 | * supported rate below the requested. | ||
2350 | */ | ||
2351 | testrate_high = PORTSERVER_DIVIDEND / testdiv; | ||
2352 | testrate_low = PORTSERVER_DIVIDEND / (testdiv + 1); | ||
2353 | |||
2354 | /* | ||
2355 | * If the rate for the requested divisor is correct, just | ||
2356 | * use it and be done. | ||
2357 | */ | ||
2358 | if (testrate_high == newrate) | ||
2359 | break; | ||
2360 | |||
2361 | /* | ||
2362 | * Otherwise, pick the rate that is closer (i.e. whichever rate | ||
2363 | * has a smaller delta). | ||
2364 | */ | ||
2365 | deltahigh = testrate_high - newrate; | ||
2366 | deltalow = newrate - testrate_low; | ||
2367 | |||
2368 | if (deltahigh < deltalow) | ||
2369 | newrate = testrate_high; | ||
2370 | else | ||
2371 | newrate = testrate_low; | ||
2372 | |||
2373 | break; | ||
2374 | } | ||
2375 | |||
2376 | ch->ch_custom_speed = newrate; | ||
2377 | |||
2378 | drp_param(ch); | ||
2379 | |||
2380 | return; | ||
2381 | } | ||
2382 | |||
2383 | |||
2384 | /* | ||
2385 | # dgrp_tty_digiseta() | ||
2386 | * | ||
2387 | * Ioctl to set the information from ditty. | ||
2388 | * | ||
2389 | * NOTE: DIGI_IXON, DSRPACE, DCDPACE, and DTRPACE are unsupported. JAR 990922 | ||
2390 | */ | ||
2391 | static int dgrp_tty_digiseta(struct tty_struct *tty, | ||
2392 | struct digi_struct *new_info) | ||
2393 | { | ||
2394 | struct un_struct *un = tty->driver_data; | ||
2395 | struct ch_struct *ch; | ||
2396 | |||
2397 | if (!un) | ||
2398 | return -ENODEV; | ||
2399 | |||
2400 | ch = un->un_ch; | ||
2401 | if (!ch) | ||
2402 | return -ENODEV; | ||
2403 | |||
2404 | if (copy_from_user(&ch->ch_digi, (void __user *) new_info, | ||
2405 | sizeof(struct digi_struct))) | ||
2406 | return -EFAULT; | ||
2407 | |||
2408 | if ((ch->ch_digi.digi_flags & RTSPACE) || | ||
2409 | (ch->ch_digi.digi_flags & CTSPACE)) | ||
2410 | tty->termios.c_cflag |= CRTSCTS; | ||
2411 | else | ||
2412 | tty->termios.c_cflag &= ~CRTSCTS; | ||
2413 | |||
2414 | if (ch->ch_digi.digi_maxcps < 1) | ||
2415 | ch->ch_digi.digi_maxcps = 1; | ||
2416 | |||
2417 | if (ch->ch_digi.digi_maxcps > 10000) | ||
2418 | ch->ch_digi.digi_maxcps = 10000; | ||
2419 | |||
2420 | if (ch->ch_digi.digi_bufsize < 10) | ||
2421 | ch->ch_digi.digi_bufsize = 10; | ||
2422 | |||
2423 | if (ch->ch_digi.digi_maxchar < 1) | ||
2424 | ch->ch_digi.digi_maxchar = 1; | ||
2425 | |||
2426 | if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) | ||
2427 | ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; | ||
2428 | |||
2429 | if (ch->ch_digi.digi_onlen > DIGI_PLEN) | ||
2430 | ch->ch_digi.digi_onlen = DIGI_PLEN; | ||
2431 | |||
2432 | if (ch->ch_digi.digi_offlen > DIGI_PLEN) | ||
2433 | ch->ch_digi.digi_offlen = DIGI_PLEN; | ||
2434 | |||
2435 | /* make the changes now */ | ||
2436 | drp_param(ch); | ||
2437 | |||
2438 | return 0; | ||
2439 | } | ||
2440 | |||
2441 | |||
2442 | |||
2443 | /* | ||
2444 | * dgrp_tty_digigetedelay() | ||
2445 | * | ||
2446 | * Ioctl to get the current edelay setting. | ||
2447 | * | ||
2448 | * | ||
2449 | * | ||
2450 | */ | ||
2451 | static int dgrp_tty_digigetedelay(struct tty_struct *tty, int *retinfo) | ||
2452 | { | ||
2453 | struct un_struct *un; | ||
2454 | struct ch_struct *ch; | ||
2455 | int tmp; | ||
2456 | |||
2457 | if (!retinfo) | ||
2458 | return -EFAULT; | ||
2459 | |||
2460 | if (!tty || tty->magic != TTY_MAGIC) | ||
2461 | return -EFAULT; | ||
2462 | |||
2463 | un = tty->driver_data; | ||
2464 | |||
2465 | if (!un) | ||
2466 | return -ENODEV; | ||
2467 | |||
2468 | ch = un->un_ch; | ||
2469 | if (!ch) | ||
2470 | return -ENODEV; | ||
2471 | |||
2472 | tmp = ch->ch_edelay; | ||
2473 | |||
2474 | if (copy_to_user((void __user *) retinfo, &tmp, sizeof(*retinfo))) | ||
2475 | return -EFAULT; | ||
2476 | |||
2477 | return 0; | ||
2478 | } | ||
2479 | |||
2480 | |||
2481 | /* | ||
2482 | * dgrp_tty_digisetedelay() | ||
2483 | * | ||
2484 | * Ioctl to set the EDELAY setting | ||
2485 | * | ||
2486 | */ | ||
2487 | static int dgrp_tty_digisetedelay(struct tty_struct *tty, int *new_info) | ||
2488 | { | ||
2489 | struct un_struct *un; | ||
2490 | struct ch_struct *ch; | ||
2491 | int new_digi; | ||
2492 | |||
2493 | if (!tty || tty->magic != TTY_MAGIC) | ||
2494 | return -EFAULT; | ||
2495 | |||
2496 | un = tty->driver_data; | ||
2497 | |||
2498 | if (!un) | ||
2499 | return -ENODEV; | ||
2500 | |||
2501 | ch = un->un_ch; | ||
2502 | if (!ch) | ||
2503 | return -ENODEV; | ||
2504 | |||
2505 | if (copy_from_user(&new_digi, (void __user *)new_info, sizeof(int))) | ||
2506 | return -EFAULT; | ||
2507 | |||
2508 | ch->ch_edelay = new_digi; | ||
2509 | |||
2510 | /* make the changes now */ | ||
2511 | drp_param(ch); | ||
2512 | |||
2513 | return 0; | ||
2514 | } | ||
2515 | |||
2516 | |||
2517 | /* | ||
2518 | * The usual assortment of ioctl's | ||
2519 | * | ||
2520 | * note: use tty_check_change to make sure that we are not | ||
2521 | * changing the state of a terminal when we are not a process | ||
2522 | * in the forground. See tty_io.c | ||
2523 | * rc = tty_check_change(tty); | ||
2524 | * if (rc) return rc; | ||
2525 | */ | ||
2526 | static int dgrp_tty_ioctl(struct tty_struct *tty, unsigned int cmd, | ||
2527 | unsigned long arg) | ||
2528 | { | ||
2529 | struct un_struct *un; | ||
2530 | struct ch_struct *ch; | ||
2531 | int rc; | ||
2532 | struct digiflow_struct dflow; | ||
2533 | |||
2534 | if (!tty) | ||
2535 | return -ENODEV; | ||
2536 | |||
2537 | un = tty->driver_data; | ||
2538 | if (!un) | ||
2539 | return -ENODEV; | ||
2540 | |||
2541 | ch = un->un_ch; | ||
2542 | if (!ch) | ||
2543 | return -ENODEV; | ||
2544 | |||
2545 | switch (cmd) { | ||
2546 | |||
2547 | /* | ||
2548 | * Here are all the standard ioctl's that we MUST implement | ||
2549 | */ | ||
2550 | |||
2551 | case TCSBRK: | ||
2552 | /* | ||
2553 | * TCSBRK is SVID version: non-zero arg --> no break | ||
2554 | * this behaviour is exploited by tcdrain(). | ||
2555 | * | ||
2556 | * According to POSIX.1 spec (7.2.2.1.2) breaks should be | ||
2557 | * between 0.25 and 0.5 seconds | ||
2558 | */ | ||
2559 | |||
2560 | rc = tty_check_change(tty); | ||
2561 | if (rc) | ||
2562 | return rc; | ||
2563 | tty_wait_until_sent(tty, 0); | ||
2564 | |||
2565 | if (!arg) | ||
2566 | rc = dgrp_send_break(ch, 250); /* 1/4 second */ | ||
2567 | |||
2568 | if (dgrp_tty_chars_in_buffer(tty) != 0) | ||
2569 | return -EINTR; | ||
2570 | |||
2571 | return 0; | ||
2572 | |||
2573 | case TCSBRKP: | ||
2574 | /* support for POSIX tcsendbreak() | ||
2575 | * | ||
2576 | * According to POSIX.1 spec (7.2.2.1.2) breaks should be | ||
2577 | * between 0.25 and 0.5 seconds so we'll ask for something | ||
2578 | * in the middle: 0.375 seconds. | ||
2579 | */ | ||
2580 | rc = tty_check_change(tty); | ||
2581 | if (rc) | ||
2582 | return rc; | ||
2583 | tty_wait_until_sent(tty, 0); | ||
2584 | |||
2585 | rc = dgrp_send_break(ch, arg ? arg*250 : 250); | ||
2586 | |||
2587 | if (dgrp_tty_chars_in_buffer(tty) != 0) | ||
2588 | return -EINTR; | ||
2589 | return 0; | ||
2590 | |||
2591 | case TIOCSBRK: | ||
2592 | rc = tty_check_change(tty); | ||
2593 | if (rc) | ||
2594 | return rc; | ||
2595 | tty_wait_until_sent(tty, 0); | ||
2596 | |||
2597 | /* | ||
2598 | * RealPort doesn't support turning on a break unconditionally. | ||
2599 | * The RealPort device will stop sending a break automatically | ||
2600 | * after the specified time value that we send in. | ||
2601 | */ | ||
2602 | rc = dgrp_send_break(ch, 250); /* 1/4 second */ | ||
2603 | |||
2604 | if (dgrp_tty_chars_in_buffer(tty) != 0) | ||
2605 | return -EINTR; | ||
2606 | return 0; | ||
2607 | |||
2608 | case TIOCCBRK: | ||
2609 | /* | ||
2610 | * RealPort doesn't support turning off a break unconditionally. | ||
2611 | * The RealPort device will stop sending a break automatically | ||
2612 | * after the specified time value that was sent when turning on | ||
2613 | * the break. | ||
2614 | */ | ||
2615 | return 0; | ||
2616 | |||
2617 | case TIOCGSOFTCAR: | ||
2618 | rc = access_ok(VERIFY_WRITE, (void __user *) arg, | ||
2619 | sizeof(long)); | ||
2620 | if (rc == 0) | ||
2621 | return -EFAULT; | ||
2622 | put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); | ||
2623 | return 0; | ||
2624 | |||
2625 | case TIOCSSOFTCAR: | ||
2626 | get_user(arg, (unsigned long __user *) arg); | ||
2627 | tty->termios.c_cflag = | ||
2628 | ((tty->termios.c_cflag & ~CLOCAL) | | ||
2629 | (arg ? CLOCAL : 0)); | ||
2630 | return 0; | ||
2631 | |||
2632 | case TIOCMGET: | ||
2633 | rc = access_ok(VERIFY_WRITE, (void __user *) arg, | ||
2634 | sizeof(unsigned int)); | ||
2635 | if (rc == 0) | ||
2636 | return -EFAULT; | ||
2637 | return get_modem_info(ch, (unsigned int *) arg); | ||
2638 | |||
2639 | case TIOCMBIS: | ||
2640 | case TIOCMBIC: | ||
2641 | case TIOCMSET: | ||
2642 | return set_modem_info(ch, cmd, (unsigned int *) arg); | ||
2643 | |||
2644 | /* | ||
2645 | * Here are any additional ioctl's that we want to implement | ||
2646 | */ | ||
2647 | |||
2648 | case TCFLSH: | ||
2649 | /* | ||
2650 | * The linux tty driver doesn't have a flush | ||
2651 | * input routine for the driver, assuming all backed | ||
2652 | * up data is in the line disc. buffers. However, | ||
2653 | * we all know that's not the case. Here, we | ||
2654 | * act on the ioctl, but then lie and say we didn't | ||
2655 | * so the line discipline will process the flush | ||
2656 | * also. | ||
2657 | */ | ||
2658 | rc = tty_check_change(tty); | ||
2659 | if (rc) | ||
2660 | return rc; | ||
2661 | |||
2662 | switch (arg) { | ||
2663 | case TCIFLUSH: | ||
2664 | case TCIOFLUSH: | ||
2665 | /* only flush input if this is the only open unit */ | ||
2666 | if (!IS_PRINT(MINOR(tty_devnum(tty)))) { | ||
2667 | ch->ch_rout = ch->ch_rin; | ||
2668 | ch->ch_send |= RR_RX_FLUSH; | ||
2669 | (ch->ch_nd)->nd_tx_work = 1; | ||
2670 | (ch->ch_nd)->nd_tx_ready = 1; | ||
2671 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2672 | } | ||
2673 | if (arg == TCIFLUSH) | ||
2674 | break; | ||
2675 | |||
2676 | case TCOFLUSH: /* flush output, or the receive buffer */ | ||
2677 | /* | ||
2678 | * This is handled in the tty_ioctl.c code | ||
2679 | * calling tty_flush_buffer | ||
2680 | */ | ||
2681 | break; | ||
2682 | |||
2683 | default: | ||
2684 | /* POSIX.1 says return EINVAL if we got a bad arg */ | ||
2685 | return -EINVAL; | ||
2686 | } | ||
2687 | /* pretend we didn't recognize this IOCTL */ | ||
2688 | return -ENOIOCTLCMD; | ||
2689 | |||
2690 | #ifdef TIOCGETP | ||
2691 | case TIOCGETP: | ||
2692 | #endif | ||
2693 | /***************************************** | ||
2694 | Linux HPUX Function | ||
2695 | TCSETA TCSETA - set the termios | ||
2696 | TCSETAF TCSETAF - wait for drain first, then set termios | ||
2697 | TCSETAW TCSETAW - wait for drain, flush the input queue, then set termios | ||
2698 | - looking at the tty_ioctl code, these command all call our | ||
2699 | tty_set_termios at the driver's end, when a TCSETA* is sent, | ||
2700 | it is expecting the tty to have a termio structure, | ||
2701 | NOT a termios stucture. These two structures differ in size | ||
2702 | and the tty_ioctl code does a conversion before processing them both. | ||
2703 | - we should treat the TCSETAW TCSETAF ioctls the same, and let | ||
2704 | the tty_ioctl code do the conversion stuff. | ||
2705 | |||
2706 | TCSETS | ||
2707 | TCSETSF (none) | ||
2708 | TCSETSW | ||
2709 | - the associated tty structure has a termios structure. | ||
2710 | *****************************************/ | ||
2711 | |||
2712 | case TCGETS: | ||
2713 | case TCGETA: | ||
2714 | return -ENOIOCTLCMD; | ||
2715 | |||
2716 | case TCSETAW: | ||
2717 | case TCSETAF: | ||
2718 | case TCSETSF: | ||
2719 | case TCSETSW: | ||
2720 | /* | ||
2721 | * The linux tty driver doesn't have a flush | ||
2722 | * input routine for the driver, assuming all backed | ||
2723 | * up data is in the line disc. buffers. However, | ||
2724 | * we all know that's not the case. Here, we | ||
2725 | * act on the ioctl, but then lie and say we didn't | ||
2726 | * so the line discipline will process the flush | ||
2727 | * also. | ||
2728 | */ | ||
2729 | |||
2730 | /* | ||
2731 | * Also, now that we have TXPrint, we have to check | ||
2732 | * if this is the TXPrint device and the terminal | ||
2733 | * device is open. If so, do NOT run check_change, | ||
2734 | * as the terminal device is ALWAYS the parent. | ||
2735 | */ | ||
2736 | if (!IS_PRINT(MINOR(tty_devnum(tty))) || | ||
2737 | !ch->ch_tun.un_open_count) { | ||
2738 | rc = tty_check_change(tty); | ||
2739 | if (rc) | ||
2740 | return rc; | ||
2741 | } | ||
2742 | |||
2743 | /* wait for all the characters in tbuf to drain */ | ||
2744 | tty_wait_until_sent(tty, 0); | ||
2745 | |||
2746 | if ((cmd == TCSETSF) || (cmd == TCSETAF)) { | ||
2747 | /* flush the contents of the rbuf queue */ | ||
2748 | /* TODO: check if this is print device? */ | ||
2749 | ch->ch_send |= RR_RX_FLUSH; | ||
2750 | (ch->ch_nd)->nd_tx_ready = 1; | ||
2751 | (ch->ch_nd)->nd_tx_work = 1; | ||
2752 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2753 | /* do we need to do this? just to be safe! */ | ||
2754 | ch->ch_rout = ch->ch_rin; | ||
2755 | } | ||
2756 | |||
2757 | /* pretend we didn't recognize this */ | ||
2758 | return -ENOIOCTLCMD; | ||
2759 | |||
2760 | case TCXONC: | ||
2761 | /* | ||
2762 | * The Linux Line Discipline (LD) would do this for us if we | ||
2763 | * let it, but we have the special firmware options to do this | ||
2764 | * the "right way" regardless of hardware or software flow | ||
2765 | * control so we'll do it outselves instead of letting the LD | ||
2766 | * do it. | ||
2767 | */ | ||
2768 | rc = tty_check_change(tty); | ||
2769 | if (rc) | ||
2770 | return rc; | ||
2771 | |||
2772 | switch (arg) { | ||
2773 | case TCOON: | ||
2774 | dgrp_tty_start(tty); | ||
2775 | return 0; | ||
2776 | case TCOOFF: | ||
2777 | dgrp_tty_stop(tty); | ||
2778 | return 0; | ||
2779 | case TCION: | ||
2780 | dgrp_tty_input_start(tty); | ||
2781 | return 0; | ||
2782 | case TCIOFF: | ||
2783 | dgrp_tty_input_stop(tty); | ||
2784 | return 0; | ||
2785 | default: | ||
2786 | return -EINVAL; | ||
2787 | } | ||
2788 | |||
2789 | case DIGI_GETA: | ||
2790 | /* get information for ditty */ | ||
2791 | if (copy_to_user((struct digi_struct __user *) arg, | ||
2792 | &ch->ch_digi, sizeof(struct digi_struct))) | ||
2793 | return -EFAULT; | ||
2794 | break; | ||
2795 | |||
2796 | case DIGI_SETAW: | ||
2797 | case DIGI_SETAF: | ||
2798 | /* wait for all the characters in tbuf to drain */ | ||
2799 | tty_wait_until_sent(tty, 0); | ||
2800 | |||
2801 | if (cmd == DIGI_SETAF) { | ||
2802 | /* flush the contents of the rbuf queue */ | ||
2803 | /* send down a packet with RR_RX_FLUSH set */ | ||
2804 | ch->ch_send |= RR_RX_FLUSH; | ||
2805 | (ch->ch_nd)->nd_tx_ready = 1; | ||
2806 | (ch->ch_nd)->nd_tx_work = 1; | ||
2807 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2808 | /* do we need to do this? just to be safe! */ | ||
2809 | ch->ch_rout = ch->ch_rin; | ||
2810 | } | ||
2811 | |||
2812 | /* pretend we didn't recognize this */ | ||
2813 | |||
2814 | case DIGI_SETA: | ||
2815 | return dgrp_tty_digiseta(tty, (struct digi_struct *) arg); | ||
2816 | |||
2817 | case DIGI_SEDELAY: | ||
2818 | return dgrp_tty_digisetedelay(tty, (int *) arg); | ||
2819 | |||
2820 | case DIGI_GEDELAY: | ||
2821 | return dgrp_tty_digigetedelay(tty, (int *) arg); | ||
2822 | |||
2823 | case DIGI_GETFLOW: | ||
2824 | case DIGI_GETAFLOW: | ||
2825 | if (cmd == (DIGI_GETFLOW)) { | ||
2826 | dflow.startc = tty->termios.c_cc[VSTART]; | ||
2827 | dflow.stopc = tty->termios.c_cc[VSTOP]; | ||
2828 | } else { | ||
2829 | dflow.startc = ch->ch_xxon; | ||
2830 | dflow.stopc = ch->ch_xxoff; | ||
2831 | } | ||
2832 | |||
2833 | if (copy_to_user((char __user *)arg, &dflow, sizeof(dflow))) | ||
2834 | return -EFAULT; | ||
2835 | break; | ||
2836 | |||
2837 | case DIGI_SETFLOW: | ||
2838 | case DIGI_SETAFLOW: | ||
2839 | |||
2840 | if (copy_from_user(&dflow, (char __user *)arg, sizeof(dflow))) | ||
2841 | return -EFAULT; | ||
2842 | |||
2843 | if (cmd == (DIGI_SETFLOW)) { | ||
2844 | tty->termios.c_cc[VSTART] = dflow.startc; | ||
2845 | tty->termios.c_cc[VSTOP] = dflow.stopc; | ||
2846 | } else { | ||
2847 | ch->ch_xxon = dflow.startc; | ||
2848 | ch->ch_xxoff = dflow.stopc; | ||
2849 | } | ||
2850 | break; | ||
2851 | |||
2852 | case DIGI_GETCUSTOMBAUD: | ||
2853 | rc = access_ok(VERIFY_WRITE, (void __user *) arg, sizeof(int)); | ||
2854 | if (rc == 0) | ||
2855 | return -EFAULT; | ||
2856 | put_user(ch->ch_custom_speed, (unsigned int __user *) arg); | ||
2857 | break; | ||
2858 | |||
2859 | case DIGI_SETCUSTOMBAUD: | ||
2860 | { | ||
2861 | int new_rate; | ||
2862 | |||
2863 | get_user(new_rate, (unsigned int __user *) arg); | ||
2864 | dgrp_set_custom_speed(ch, new_rate); | ||
2865 | |||
2866 | break; | ||
2867 | } | ||
2868 | |||
2869 | default: | ||
2870 | return -ENOIOCTLCMD; | ||
2871 | } | ||
2872 | |||
2873 | return 0; | ||
2874 | } | ||
2875 | |||
2876 | /* | ||
2877 | * This routine allows the tty driver to be notified when | ||
2878 | * the device's termios setting have changed. Note that we | ||
2879 | * should be prepared to accept the case where old == NULL | ||
2880 | * and try to do something rational. | ||
2881 | * | ||
2882 | * So we need to make sure that our copies of ch_oflag, | ||
2883 | * ch_clag, and ch_iflag reflect the tty->termios flags. | ||
2884 | */ | ||
2885 | static void dgrp_tty_set_termios(struct tty_struct *tty, struct ktermios *old) | ||
2886 | { | ||
2887 | struct ktermios *ts; | ||
2888 | struct ch_struct *ch; | ||
2889 | struct un_struct *un; | ||
2890 | |||
2891 | /* seems silly, but we have to check all these! */ | ||
2892 | if (!tty) | ||
2893 | return; | ||
2894 | |||
2895 | un = tty->driver_data; | ||
2896 | if (!un) | ||
2897 | return; | ||
2898 | |||
2899 | ts = &tty->termios; | ||
2900 | |||
2901 | ch = un->un_ch; | ||
2902 | if (!ch) | ||
2903 | return; | ||
2904 | |||
2905 | drp_param(ch); | ||
2906 | |||
2907 | /* the CLOCAL flag has just been set */ | ||
2908 | if (!(old->c_cflag & CLOCAL) && C_CLOCAL(tty)) | ||
2909 | wake_up_interruptible(&un->un_open_wait); | ||
2910 | } | ||
2911 | |||
2912 | |||
2913 | /* | ||
2914 | * Throttle receiving data. We just set a bit and stop reading | ||
2915 | * data out of the channel buffer. It will back up and the | ||
2916 | * FEP will do whatever is necessary to stop the far end. | ||
2917 | */ | ||
2918 | static void dgrp_tty_throttle(struct tty_struct *tty) | ||
2919 | { | ||
2920 | struct ch_struct *ch; | ||
2921 | |||
2922 | if (!tty) | ||
2923 | return; | ||
2924 | |||
2925 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
2926 | if (!ch) | ||
2927 | return; | ||
2928 | |||
2929 | ch->ch_flag |= CH_RXSTOP; | ||
2930 | } | ||
2931 | |||
2932 | |||
2933 | static void dgrp_tty_unthrottle(struct tty_struct *tty) | ||
2934 | { | ||
2935 | struct ch_struct *ch; | ||
2936 | |||
2937 | if (!tty) | ||
2938 | return; | ||
2939 | |||
2940 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
2941 | if (!ch) | ||
2942 | return; | ||
2943 | |||
2944 | ch->ch_flag &= ~CH_RXSTOP; | ||
2945 | } | ||
2946 | |||
2947 | /* | ||
2948 | * Stop the transmitter | ||
2949 | */ | ||
2950 | static void dgrp_tty_stop(struct tty_struct *tty) | ||
2951 | { | ||
2952 | struct ch_struct *ch; | ||
2953 | |||
2954 | if (!tty) | ||
2955 | return; | ||
2956 | |||
2957 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
2958 | if (!ch) | ||
2959 | return; | ||
2960 | |||
2961 | ch->ch_send |= RR_TX_STOP; | ||
2962 | ch->ch_send &= ~RR_TX_START; | ||
2963 | |||
2964 | /* make the change NOW! */ | ||
2965 | (ch->ch_nd)->nd_tx_ready = 1; | ||
2966 | if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) | ||
2967 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2968 | } | ||
2969 | |||
2970 | /* | ||
2971 | * Start the transmitter | ||
2972 | */ | ||
2973 | static void dgrp_tty_start(struct tty_struct *tty) | ||
2974 | { | ||
2975 | struct ch_struct *ch; | ||
2976 | |||
2977 | if (!tty) | ||
2978 | return; | ||
2979 | |||
2980 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
2981 | if (!ch) | ||
2982 | return; | ||
2983 | |||
2984 | /* TODO: don't do anything if the transmitter is not stopped */ | ||
2985 | |||
2986 | ch->ch_send |= RR_TX_START; | ||
2987 | ch->ch_send &= ~RR_TX_STOP; | ||
2988 | |||
2989 | /* make the change NOW! */ | ||
2990 | (ch->ch_nd)->nd_tx_ready = 1; | ||
2991 | (ch->ch_nd)->nd_tx_work = 1; | ||
2992 | if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) | ||
2993 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
2994 | |||
2995 | } | ||
2996 | |||
2997 | /* | ||
2998 | * Stop the reciever | ||
2999 | */ | ||
3000 | static void dgrp_tty_input_stop(struct tty_struct *tty) | ||
3001 | { | ||
3002 | struct ch_struct *ch; | ||
3003 | |||
3004 | if (!tty) | ||
3005 | return; | ||
3006 | |||
3007 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
3008 | if (!ch) | ||
3009 | return; | ||
3010 | |||
3011 | ch->ch_send |= RR_RX_STOP; | ||
3012 | ch->ch_send &= ~RR_RX_START; | ||
3013 | (ch->ch_nd)->nd_tx_ready = 1; | ||
3014 | if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) | ||
3015 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
3016 | |||
3017 | } | ||
3018 | |||
3019 | |||
3020 | static void dgrp_tty_send_xchar(struct tty_struct *tty, char c) | ||
3021 | { | ||
3022 | struct un_struct *un; | ||
3023 | struct ch_struct *ch; | ||
3024 | |||
3025 | if (!tty) | ||
3026 | return; | ||
3027 | |||
3028 | un = tty->driver_data; | ||
3029 | if (!un) | ||
3030 | return; | ||
3031 | |||
3032 | ch = un->un_ch; | ||
3033 | if (!ch) | ||
3034 | return; | ||
3035 | if (c == STOP_CHAR(tty)) | ||
3036 | ch->ch_send |= RR_RX_STOP; | ||
3037 | else if (c == START_CHAR(tty)) | ||
3038 | ch->ch_send |= RR_RX_START; | ||
3039 | |||
3040 | ch->ch_nd->nd_tx_ready = 1; | ||
3041 | ch->ch_nd->nd_tx_work = 1; | ||
3042 | |||
3043 | return; | ||
3044 | } | ||
3045 | |||
3046 | |||
3047 | static void dgrp_tty_input_start(struct tty_struct *tty) | ||
3048 | { | ||
3049 | struct ch_struct *ch; | ||
3050 | |||
3051 | if (!tty) | ||
3052 | return; | ||
3053 | |||
3054 | ch = ((struct un_struct *) tty->driver_data)->un_ch; | ||
3055 | if (!ch) | ||
3056 | return; | ||
3057 | |||
3058 | ch->ch_send |= RR_RX_START; | ||
3059 | ch->ch_send &= ~RR_RX_STOP; | ||
3060 | (ch->ch_nd)->nd_tx_ready = 1; | ||
3061 | (ch->ch_nd)->nd_tx_work = 1; | ||
3062 | if (waitqueue_active(&(ch->ch_nd)->nd_tx_waitq)) | ||
3063 | wake_up_interruptible(&(ch->ch_nd)->nd_tx_waitq); | ||
3064 | |||
3065 | } | ||
3066 | |||
3067 | |||
3068 | /* | ||
3069 | * Hangup the port. Like a close, but don't wait for output | ||
3070 | * to drain. | ||
3071 | * | ||
3072 | * How do we close all the channels that are open? | ||
3073 | */ | ||
3074 | static void dgrp_tty_hangup(struct tty_struct *tty) | ||
3075 | { | ||
3076 | struct ch_struct *ch; | ||
3077 | struct nd_struct *nd; | ||
3078 | struct un_struct *un; | ||
3079 | |||
3080 | if (!tty) | ||
3081 | return; | ||
3082 | |||
3083 | un = tty->driver_data; | ||
3084 | if (!un) | ||
3085 | return; | ||
3086 | |||
3087 | ch = un->un_ch; | ||
3088 | if (!ch) | ||
3089 | return; | ||
3090 | |||
3091 | nd = ch->ch_nd; | ||
3092 | |||
3093 | if (C_HUPCL(tty)) { | ||
3094 | /* LOWER DTR */ | ||
3095 | ch->ch_mout &= ~DM_DTR; | ||
3096 | /* Don't do this here */ | ||
3097 | /* ch->ch_flag |= CH_HANGUP; */ | ||
3098 | ch->ch_nd->nd_tx_ready = 1; | ||
3099 | ch->ch_nd->nd_tx_work = 1; | ||
3100 | if (waitqueue_active(&ch->ch_flag_wait)) | ||
3101 | wake_up_interruptible(&ch->ch_flag_wait); | ||
3102 | } | ||
3103 | |||
3104 | } | ||
3105 | |||
3106 | /************************************************************************/ | ||
3107 | /* */ | ||
3108 | /* TTY Initialization/Cleanup Functions */ | ||
3109 | /* */ | ||
3110 | /************************************************************************/ | ||
3111 | |||
3112 | /* | ||
3113 | * Uninitialize the TTY portion of the supplied node. Free all | ||
3114 | * memory and resources associated with this node. Do it in reverse | ||
3115 | * allocation order: this might possibly result in less fragmentation | ||
3116 | * of memory, though I don't know this for sure. | ||
3117 | */ | ||
3118 | void | ||
3119 | dgrp_tty_uninit(struct nd_struct *nd) | ||
3120 | { | ||
3121 | char id[3]; | ||
3122 | |||
3123 | ID_TO_CHAR(nd->nd_ID, id); | ||
3124 | |||
3125 | if (nd->nd_ttdriver_flags & SERIAL_TTDRV_REG) { | ||
3126 | tty_unregister_driver(nd->nd_serial_ttdriver); | ||
3127 | |||
3128 | kfree(nd->nd_serial_ttdriver->ttys); | ||
3129 | nd->nd_serial_ttdriver->ttys = NULL; | ||
3130 | |||
3131 | put_tty_driver(nd->nd_serial_ttdriver); | ||
3132 | nd->nd_ttdriver_flags &= ~SERIAL_TTDRV_REG; | ||
3133 | } | ||
3134 | |||
3135 | if (nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG) { | ||
3136 | tty_unregister_driver(nd->nd_callout_ttdriver); | ||
3137 | |||
3138 | kfree(nd->nd_callout_ttdriver->ttys); | ||
3139 | nd->nd_callout_ttdriver->ttys = NULL; | ||
3140 | |||
3141 | put_tty_driver(nd->nd_callout_ttdriver); | ||
3142 | nd->nd_ttdriver_flags &= ~CALLOUT_TTDRV_REG; | ||
3143 | } | ||
3144 | |||
3145 | if (nd->nd_ttdriver_flags & XPRINT_TTDRV_REG) { | ||
3146 | tty_unregister_driver(nd->nd_xprint_ttdriver); | ||
3147 | |||
3148 | kfree(nd->nd_xprint_ttdriver->ttys); | ||
3149 | nd->nd_xprint_ttdriver->ttys = NULL; | ||
3150 | |||
3151 | put_tty_driver(nd->nd_xprint_ttdriver); | ||
3152 | nd->nd_ttdriver_flags &= ~XPRINT_TTDRV_REG; | ||
3153 | } | ||
3154 | } | ||
3155 | |||
3156 | |||
3157 | |||
3158 | /* | ||
3159 | * Initialize the TTY portion of the supplied node. | ||
3160 | */ | ||
3161 | int | ||
3162 | dgrp_tty_init(struct nd_struct *nd) | ||
3163 | { | ||
3164 | char id[3]; | ||
3165 | int rc; | ||
3166 | int i; | ||
3167 | |||
3168 | ID_TO_CHAR(nd->nd_ID, id); | ||
3169 | |||
3170 | /* | ||
3171 | * Initialize the TTDRIVER structures. | ||
3172 | */ | ||
3173 | |||
3174 | nd->nd_serial_ttdriver = alloc_tty_driver(CHAN_MAX); | ||
3175 | sprintf(nd->nd_serial_name, "tty_dgrp_%s_", id); | ||
3176 | |||
3177 | nd->nd_serial_ttdriver->owner = THIS_MODULE; | ||
3178 | nd->nd_serial_ttdriver->name = nd->nd_serial_name; | ||
3179 | nd->nd_serial_ttdriver->name_base = 0; | ||
3180 | nd->nd_serial_ttdriver->major = 0; | ||
3181 | nd->nd_serial_ttdriver->minor_start = 0; | ||
3182 | nd->nd_serial_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
3183 | nd->nd_serial_ttdriver->subtype = SERIAL_TYPE_NORMAL; | ||
3184 | nd->nd_serial_ttdriver->init_termios = DefaultTermios; | ||
3185 | nd->nd_serial_ttdriver->driver_name = "dgrp"; | ||
3186 | nd->nd_serial_ttdriver->flags = (TTY_DRIVER_REAL_RAW | | ||
3187 | TTY_DRIVER_DYNAMIC_DEV | | ||
3188 | TTY_DRIVER_HARDWARE_BREAK); | ||
3189 | |||
3190 | /* The kernel wants space to store pointers to tty_structs. */ | ||
3191 | nd->nd_serial_ttdriver->ttys = | ||
3192 | kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); | ||
3193 | if (!nd->nd_serial_ttdriver->ttys) | ||
3194 | return -ENOMEM; | ||
3195 | |||
3196 | tty_set_operations(nd->nd_serial_ttdriver, &dgrp_tty_ops); | ||
3197 | |||
3198 | if (!(nd->nd_ttdriver_flags & SERIAL_TTDRV_REG)) { | ||
3199 | /* | ||
3200 | * Register tty devices | ||
3201 | */ | ||
3202 | rc = tty_register_driver(nd->nd_serial_ttdriver); | ||
3203 | if (rc < 0) { | ||
3204 | /* | ||
3205 | * If errno is EBUSY, this means there are no more | ||
3206 | * slots available to have us auto-majored. | ||
3207 | * (Which is currently supported up to 256) | ||
3208 | * | ||
3209 | * We can still request majors above 256, | ||
3210 | * we just have to do it manually. | ||
3211 | */ | ||
3212 | if (rc == -EBUSY) { | ||
3213 | int i; | ||
3214 | int max_majors = 1U << (32 - MINORBITS); | ||
3215 | for (i = 256; i < max_majors; i++) { | ||
3216 | nd->nd_serial_ttdriver->major = i; | ||
3217 | rc = tty_register_driver(nd->nd_serial_ttdriver); | ||
3218 | if (rc >= 0) | ||
3219 | break; | ||
3220 | } | ||
3221 | /* Really fail now, since we ran out | ||
3222 | * of majors to try. */ | ||
3223 | if (i == max_majors) | ||
3224 | return rc; | ||
3225 | |||
3226 | } else { | ||
3227 | return rc; | ||
3228 | } | ||
3229 | } | ||
3230 | nd->nd_ttdriver_flags |= SERIAL_TTDRV_REG; | ||
3231 | } | ||
3232 | |||
3233 | nd->nd_callout_ttdriver = alloc_tty_driver(CHAN_MAX); | ||
3234 | sprintf(nd->nd_callout_name, "cu_dgrp_%s_", id); | ||
3235 | |||
3236 | nd->nd_callout_ttdriver->owner = THIS_MODULE; | ||
3237 | nd->nd_callout_ttdriver->name = nd->nd_callout_name; | ||
3238 | nd->nd_callout_ttdriver->name_base = 0; | ||
3239 | nd->nd_callout_ttdriver->major = nd->nd_serial_ttdriver->major; | ||
3240 | nd->nd_callout_ttdriver->minor_start = 0x40; | ||
3241 | nd->nd_callout_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
3242 | nd->nd_callout_ttdriver->subtype = SERIAL_TYPE_CALLOUT; | ||
3243 | nd->nd_callout_ttdriver->init_termios = DefaultTermios; | ||
3244 | nd->nd_callout_ttdriver->driver_name = "dgrp"; | ||
3245 | nd->nd_callout_ttdriver->flags = (TTY_DRIVER_REAL_RAW | | ||
3246 | TTY_DRIVER_DYNAMIC_DEV | | ||
3247 | TTY_DRIVER_HARDWARE_BREAK); | ||
3248 | |||
3249 | /* The kernel wants space to store pointers to tty_structs. */ | ||
3250 | nd->nd_callout_ttdriver->ttys = | ||
3251 | kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); | ||
3252 | if (!nd->nd_callout_ttdriver->ttys) | ||
3253 | return -ENOMEM; | ||
3254 | |||
3255 | tty_set_operations(nd->nd_callout_ttdriver, &dgrp_tty_ops); | ||
3256 | |||
3257 | if (dgrp_register_cudevices) { | ||
3258 | if (!(nd->nd_ttdriver_flags & CALLOUT_TTDRV_REG)) { | ||
3259 | /* | ||
3260 | * Register cu devices | ||
3261 | */ | ||
3262 | rc = tty_register_driver(nd->nd_callout_ttdriver); | ||
3263 | if (rc < 0) | ||
3264 | return rc; | ||
3265 | nd->nd_ttdriver_flags |= CALLOUT_TTDRV_REG; | ||
3266 | } | ||
3267 | } | ||
3268 | |||
3269 | |||
3270 | nd->nd_xprint_ttdriver = alloc_tty_driver(CHAN_MAX); | ||
3271 | sprintf(nd->nd_xprint_name, "pr_dgrp_%s_", id); | ||
3272 | |||
3273 | nd->nd_xprint_ttdriver->owner = THIS_MODULE; | ||
3274 | nd->nd_xprint_ttdriver->name = nd->nd_xprint_name; | ||
3275 | nd->nd_xprint_ttdriver->name_base = 0; | ||
3276 | nd->nd_xprint_ttdriver->major = nd->nd_serial_ttdriver->major; | ||
3277 | nd->nd_xprint_ttdriver->minor_start = 0x80; | ||
3278 | nd->nd_xprint_ttdriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
3279 | nd->nd_xprint_ttdriver->subtype = SERIAL_TYPE_XPRINT; | ||
3280 | nd->nd_xprint_ttdriver->init_termios = DefaultTermios; | ||
3281 | nd->nd_xprint_ttdriver->driver_name = "dgrp"; | ||
3282 | nd->nd_xprint_ttdriver->flags = (TTY_DRIVER_REAL_RAW | | ||
3283 | TTY_DRIVER_DYNAMIC_DEV | | ||
3284 | TTY_DRIVER_HARDWARE_BREAK); | ||
3285 | |||
3286 | /* The kernel wants space to store pointers to tty_structs. */ | ||
3287 | nd->nd_xprint_ttdriver->ttys = | ||
3288 | kzalloc(CHAN_MAX * sizeof(struct tty_struct *), GFP_KERNEL); | ||
3289 | if (!nd->nd_xprint_ttdriver->ttys) | ||
3290 | return -ENOMEM; | ||
3291 | |||
3292 | tty_set_operations(nd->nd_xprint_ttdriver, &dgrp_tty_ops); | ||
3293 | |||
3294 | if (dgrp_register_prdevices) { | ||
3295 | if (!(nd->nd_ttdriver_flags & XPRINT_TTDRV_REG)) { | ||
3296 | /* | ||
3297 | * Register transparent print devices | ||
3298 | */ | ||
3299 | rc = tty_register_driver(nd->nd_xprint_ttdriver); | ||
3300 | if (rc < 0) | ||
3301 | return rc; | ||
3302 | nd->nd_ttdriver_flags |= XPRINT_TTDRV_REG; | ||
3303 | } | ||
3304 | } | ||
3305 | |||
3306 | for (i = 0; i < CHAN_MAX; i++) { | ||
3307 | struct ch_struct *ch = nd->nd_chan + i; | ||
3308 | |||
3309 | ch->ch_nd = nd; | ||
3310 | ch->ch_digi = digi_init; | ||
3311 | ch->ch_edelay = 100; | ||
3312 | ch->ch_custom_speed = 0; | ||
3313 | ch->ch_portnum = i; | ||
3314 | ch->ch_tun.un_ch = ch; | ||
3315 | ch->ch_pun.un_ch = ch; | ||
3316 | ch->ch_tun.un_type = SERIAL_TYPE_NORMAL; | ||
3317 | ch->ch_pun.un_type = SERIAL_TYPE_XPRINT; | ||
3318 | |||
3319 | init_waitqueue_head(&(ch->ch_flag_wait)); | ||
3320 | init_waitqueue_head(&(ch->ch_sleep)); | ||
3321 | |||
3322 | init_waitqueue_head(&(ch->ch_tun.un_open_wait)); | ||
3323 | init_waitqueue_head(&(ch->ch_tun.un_close_wait)); | ||
3324 | |||
3325 | init_waitqueue_head(&(ch->ch_pun.un_open_wait)); | ||
3326 | init_waitqueue_head(&(ch->ch_pun.un_close_wait)); | ||
3327 | tty_port_init(&ch->port); | ||
3328 | tty_port_init(&ch->port); | ||
3329 | } | ||
3330 | return 0; | ||
3331 | } | ||
diff --git a/drivers/staging/dgrp/digirp.h b/drivers/staging/dgrp/digirp.h new file mode 100644 index 000000000000..33c1394fade7 --- /dev/null +++ b/drivers/staging/dgrp/digirp.h | |||
@@ -0,0 +1,129 @@ | |||
1 | /************************************************************************ | ||
2 | * HP-UX Realport Daemon interface file. | ||
3 | * | ||
4 | * Copyright (C) 1998, by Digi International. All Rights Reserved. | ||
5 | ************************************************************************/ | ||
6 | |||
7 | #ifndef _DIGIDRP_H | ||
8 | #define _DIGIDRP_H | ||
9 | |||
10 | /************************************************************************ | ||
11 | * This file contains defines for the ioctl() interface to | ||
12 | * the realport driver. This ioctl() interface is used by the | ||
13 | * daemon to set speed setup parameters honored by the driver. | ||
14 | ************************************************************************/ | ||
15 | |||
16 | struct link_struct { | ||
17 | int lk_fast_rate; /* Fast line rate to be used | ||
18 | when the delay is less-equal | ||
19 | to lk_fast_delay */ | ||
20 | |||
21 | int lk_fast_delay; /* Fast line rate delay in | ||
22 | milliseconds */ | ||
23 | |||
24 | int lk_slow_rate; /* Slow line rate to be used when | ||
25 | the delay is greater-equal | ||
26 | to lk_slow_delay */ | ||
27 | |||
28 | int lk_slow_delay; /* Slow line rate delay in | ||
29 | milliseconds */ | ||
30 | |||
31 | int lk_header_size; /* Estimated packet header size | ||
32 | when sent across the slowest | ||
33 | link. */ | ||
34 | }; | ||
35 | |||
36 | #define DIGI_GETLINK _IOW('e', 103, struct link_struct) /* Get link parameters */ | ||
37 | #define DIGI_SETLINK _IOW('e', 104, struct link_struct) /* Set link parameters */ | ||
38 | |||
39 | |||
40 | /************************************************************************ | ||
41 | * This module provides application access to special Digi | ||
42 | * serial line enhancements which are not standard UNIX(tm) features. | ||
43 | ************************************************************************/ | ||
44 | |||
45 | struct digiflow_struct { | ||
46 | unsigned char startc; /* flow cntl start char */ | ||
47 | unsigned char stopc; /* flow cntl stop char */ | ||
48 | }; | ||
49 | |||
50 | /************************************************************************ | ||
51 | * Values for digi_flags | ||
52 | ************************************************************************/ | ||
53 | #define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ | ||
54 | #define DIGI_FAST 0x0002 /* Fast baud rates */ | ||
55 | #define RTSPACE 0x0004 /* RTS input flow control */ | ||
56 | #define CTSPACE 0x0008 /* CTS output flow control */ | ||
57 | #define DSRPACE 0x0010 /* DSR output flow control */ | ||
58 | #define DCDPACE 0x0020 /* DCD output flow control */ | ||
59 | #define DTRPACE 0x0040 /* DTR input flow control */ | ||
60 | #define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ | ||
61 | #define DIGI_FORCEDCD 0x0100 /* Force carrier */ | ||
62 | #define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ | ||
63 | #define DIGI_AIXON 0x0400 /* Aux flow control in fep */ | ||
64 | #define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl */ | ||
65 | #define DIGI_PP_INPUT 0x1000 /* Change parallel port to input */ | ||
66 | #define DIGI_422 0x4000 /* Change parallel port to input */ | ||
67 | #define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ | ||
68 | |||
69 | |||
70 | /************************************************************************ | ||
71 | * Values associated with transparent print | ||
72 | ************************************************************************/ | ||
73 | #define DIGI_PLEN 8 /* String length */ | ||
74 | #define DIGI_TSIZ 10 /* Terminal string len */ | ||
75 | |||
76 | |||
77 | /************************************************************************ | ||
78 | * Structure used with ioctl commands for DIGI parameters. | ||
79 | ************************************************************************/ | ||
80 | struct digi_struct { | ||
81 | unsigned short digi_flags; /* Flags (see above) */ | ||
82 | unsigned short digi_maxcps; /* Max printer CPS */ | ||
83 | unsigned short digi_maxchar; /* Max chars in print queue */ | ||
84 | unsigned short digi_bufsize; /* Buffer size */ | ||
85 | unsigned char digi_onlen; /* Length of ON string */ | ||
86 | unsigned char digi_offlen; /* Length of OFF string */ | ||
87 | char digi_onstr[DIGI_PLEN]; /* Printer on string */ | ||
88 | char digi_offstr[DIGI_PLEN]; /* Printer off string */ | ||
89 | char digi_term[DIGI_TSIZ]; /* terminal string */ | ||
90 | }; | ||
91 | |||
92 | /************************************************************************ | ||
93 | * Ioctl command arguments for DIGI parameters. | ||
94 | ************************************************************************/ | ||
95 | /* Read params */ | ||
96 | #define DIGI_GETA _IOR('e', 94, struct digi_struct) | ||
97 | |||
98 | /* Set params */ | ||
99 | #define DIGI_SETA _IOW('e', 95, struct digi_struct) | ||
100 | |||
101 | /* Drain & set params */ | ||
102 | #define DIGI_SETAW _IOW('e', 96, struct digi_struct) | ||
103 | |||
104 | /* Drain, flush & set params */ | ||
105 | #define DIGI_SETAF _IOW('e', 97, struct digi_struct) | ||
106 | |||
107 | /* Get startc/stopc flow control characters */ | ||
108 | #define DIGI_GETFLOW _IOR('e', 99, struct digiflow_struct) | ||
109 | |||
110 | /* Set startc/stopc flow control characters */ | ||
111 | #define DIGI_SETFLOW _IOW('e', 100, struct digiflow_struct) | ||
112 | |||
113 | /* Get Aux. startc/stopc flow control chars */ | ||
114 | #define DIGI_GETAFLOW _IOR('e', 101, struct digiflow_struct) | ||
115 | |||
116 | /* Set Aux. startc/stopc flow control chars */ | ||
117 | #define DIGI_SETAFLOW _IOW('e', 102, struct digiflow_struct) | ||
118 | |||
119 | /* Set integer baud rate */ | ||
120 | #define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) | ||
121 | |||
122 | /* Get integer baud rate */ | ||
123 | #define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) | ||
124 | |||
125 | #define DIGI_GEDELAY _IOR('d', 246, int) /* Get edelay */ | ||
126 | #define DIGI_SEDELAY _IOW('d', 247, int) /* Get edelay */ | ||
127 | |||
128 | |||
129 | #endif /* _DIGIDRP_H */ | ||
diff --git a/drivers/staging/dgrp/drp.h b/drivers/staging/dgrp/drp.h new file mode 100644 index 000000000000..84a1e7be4899 --- /dev/null +++ b/drivers/staging/dgrp/drp.h | |||
@@ -0,0 +1,693 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Copyright 1999 Digi International (www.digi.com) | ||
4 | * Gene Olson <gene at digi dot com> | ||
5 | * James Puzzo <jamesp at digi dot com> | ||
6 | * Scott Kilau <scottk at digi dot com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the | ||
15 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | ||
16 | * PURPOSE. See the GNU General Public License for more details. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | /************************************************************************ | ||
21 | * Master include file for Linux Realport Driver. | ||
22 | ************************************************************************/ | ||
23 | |||
24 | #ifndef __DRP_H | ||
25 | #define __DRP_H | ||
26 | |||
27 | #include <linux/types.h> | ||
28 | #include <linux/wait.h> | ||
29 | #include <linux/semaphore.h> | ||
30 | #include <linux/tty.h> | ||
31 | |||
32 | |||
33 | #include "digirp.h" | ||
34 | |||
35 | /************************************************************************ | ||
36 | * Tuning parameters. | ||
37 | ************************************************************************/ | ||
38 | |||
39 | #define CHAN_MAX 64 /* Max # ports per server */ | ||
40 | |||
41 | #define SEQ_MAX 128 /* Max # transmit sequences (2^n) */ | ||
42 | #define SEQ_MASK (SEQ_MAX-1) /* Sequence buffer modulus mask */ | ||
43 | |||
44 | #define TBUF_MAX 4096 /* Size of transmit buffer (2^n) */ | ||
45 | #define RBUF_MAX 4096 /* Size of receive buffer (2^n) */ | ||
46 | |||
47 | #define TBUF_MASK (TBUF_MAX-1) /* Transmit buffer modulus mask */ | ||
48 | #define RBUF_MASK (RBUF_MAX-1) /* Receive buffer modulus mask */ | ||
49 | |||
50 | #define TBUF_LOW 1000 /* Transmit low water mark */ | ||
51 | |||
52 | #define UIO_BASE 1000 /* Base for write operations */ | ||
53 | #define UIO_MIN 2000 /* Minimum size application buffer */ | ||
54 | #define UIO_MAX 8100 /* Unix I/O buffer size */ | ||
55 | |||
56 | #define MON_MAX 65536 /* Monitor buffer size (2^n) */ | ||
57 | #define MON_MASK (MON_MAX-1) /* Monitor wrap mask */ | ||
58 | |||
59 | #define DPA_MAX 65536 /* DPA buffer size (2^n) */ | ||
60 | #define DPA_MASK (DPA_MAX-1) /* DPA wrap mask */ | ||
61 | #define DPA_HIGH_WATER 58000 /* Enforce flow control when | ||
62 | * over this amount | ||
63 | */ | ||
64 | |||
65 | #define IDLE_MAX (20 * HZ) /* Max TCP link idle time */ | ||
66 | |||
67 | #define MAX_DESC_LEN 100 /* Maximum length of stored PS | ||
68 | * description | ||
69 | */ | ||
70 | |||
71 | #define WRITEBUFLEN ((4096) + 4) /* 4 extra for alignment play space */ | ||
72 | |||
73 | #define VPDSIZE 512 | ||
74 | |||
75 | /************************************************************************ | ||
76 | * Minor device decoding conventions. | ||
77 | ************************************************************************ | ||
78 | * | ||
79 | * For Linux, the net and mon devices are handled via "proc", so we | ||
80 | * only have to mux the "tty" devices. Since every PortServer will | ||
81 | * have an individual major number, the PortServer number does not | ||
82 | * need to be encoded, and in fact, does not need to exist. | ||
83 | * | ||
84 | */ | ||
85 | |||
86 | /* | ||
87 | * Port device decoding conventions: | ||
88 | * | ||
89 | * Device 00 - 3f 64 dial-in modem devices. (tty) | ||
90 | * Device 40 - 7f 64 dial-out tty devices. (cu) | ||
91 | * Device 80 - bf 64 dial-out printer devices. | ||
92 | * | ||
93 | * IS_PRINT(dev) This is a printer device. | ||
94 | * | ||
95 | * OPEN_CATEGORY(dev) Specifies the device category. No two | ||
96 | * devices of different categories may be open | ||
97 | * at the same time. | ||
98 | * | ||
99 | * The following require the category returned by OPEN_CATEGORY(). | ||
100 | * | ||
101 | * OPEN_WAIT_AVAIL(cat) Waits on open until the device becomes | ||
102 | * available. Fails if NDELAY specified. | ||
103 | * | ||
104 | * OPEN_WAIT_CARRIER(cat) Waits on open if carrier is not present. | ||
105 | * Succeeds if NDELAY is given. | ||
106 | * | ||
107 | * OPEN_FORCES_CARRIER(cat) Carrier is forced high on open. | ||
108 | * | ||
109 | */ | ||
110 | |||
111 | #define PORT_NUM(dev) ((dev) & 0x3f) | ||
112 | |||
113 | #define OPEN_CATEGORY(dev) ((((dev) & 0x80) & 0x40)) | ||
114 | #define IS_PRINT(dev) (((dev) & 0xff) >= 0x80) | ||
115 | |||
116 | #define OPEN_WAIT_AVAIL(cat) (((cat) & 0x40) == 0x000) | ||
117 | #define OPEN_WAIT_CARRIER(cat) (((cat) & 0x40) == 0x000) | ||
118 | #define OPEN_FORCES_CARRIER(cat) (((cat) & 0x40) != 0x000) | ||
119 | |||
120 | |||
121 | /************************************************************************ | ||
122 | * Modem signal defines for 16450/16550 compatible FEP. | ||
123 | * set in ch_mout, ch_mflow, ch_mlast etc | ||
124 | ************************************************************************/ | ||
125 | |||
126 | /* TODO : Re-verify that these modem signal definitions are correct */ | ||
127 | |||
128 | #define DM_DTR 0x01 | ||
129 | #define DM_RTS 0x02 | ||
130 | #define DM_RTS_TOGGLE 0x04 | ||
131 | |||
132 | #define DM_OUT1 0x04 | ||
133 | #define DM_OUT2 0x08 | ||
134 | |||
135 | #define DM_CTS 0x10 | ||
136 | #define DM_DSR 0x20 | ||
137 | #define DM_RI 0x40 | ||
138 | #define DM_CD 0x80 /* This is the DCD flag */ | ||
139 | |||
140 | |||
141 | /************************************************************************ | ||
142 | * Realport Event Flags. | ||
143 | ************************************************************************/ | ||
144 | |||
145 | #define EV_OPU 0x0001 /* Ouput paused by client */ | ||
146 | #define EV_OPS 0x0002 /* Output paused by XOFF */ | ||
147 | #define EV_OPX 0x0004 /* Output paused by XXOFF */ | ||
148 | #define EV_OPH 0x0008 /* Output paused by MFLOW */ | ||
149 | #define EV_IPU 0x0010 /* Input paused by client */ | ||
150 | #define EV_IPS 0x0020 /* Input paused by hi/low water */ | ||
151 | #define EV_TXB 0x0040 /* Transmit break pending */ | ||
152 | #define EV_TXI 0x0080 /* Transmit immediate pending */ | ||
153 | #define EV_TXF 0x0100 /* Transmit flow control pending */ | ||
154 | #define EV_RXB 0x0200 /* Break received */ | ||
155 | |||
156 | |||
157 | /************************************************************************ | ||
158 | * Realport CFLAGS. | ||
159 | ************************************************************************/ | ||
160 | |||
161 | #define CF_CS5 0x0000 /* 5 bit characters */ | ||
162 | #define CF_CS6 0x0010 /* 6 bit characters */ | ||
163 | #define CF_CS7 0x0020 /* 7 bit characters */ | ||
164 | #define CF_CS8 0x0030 /* 8 bit characters */ | ||
165 | #define CF_CSIZE 0x0030 /* Character size */ | ||
166 | #define CF_CSTOPB 0x0040 /* Two stop bits */ | ||
167 | #define CF_CREAD 0x0080 /* Enable receiver */ | ||
168 | #define CF_PARENB 0x0100 /* Enable parity */ | ||
169 | #define CF_PARODD 0x0200 /* Odd parity */ | ||
170 | #define CF_HUPCL 0x0400 /* Drop DTR on close */ | ||
171 | |||
172 | |||
173 | /************************************************************************ | ||
174 | * Realport XFLAGS. | ||
175 | ************************************************************************/ | ||
176 | |||
177 | #define XF_XPAR 0x0001 /* Enable Mark/Space Parity */ | ||
178 | #define XF_XMODEM 0x0002 /* Enable in-band modem signalling */ | ||
179 | #define XF_XCASE 0x0004 /* Convert special characters */ | ||
180 | #define XF_XEDATA 0x0008 /* Error data in stream */ | ||
181 | #define XF_XTOSS 0x0010 /* Toss IXANY characters */ | ||
182 | #define XF_XIXON 0x0020 /* xxon/xxoff enable */ | ||
183 | |||
184 | |||
185 | /************************************************************************ | ||
186 | * Realport IFLAGS. | ||
187 | ************************************************************************/ | ||
188 | |||
189 | #define IF_IGNBRK 0x0001 /* Ignore input break */ | ||
190 | #define IF_BRKINT 0x0002 /* Break interrupt */ | ||
191 | #define IF_IGNPAR 0x0004 /* Ignore error characters */ | ||
192 | #define IF_PARMRK 0x0008 /* Error chars marked with 0xff */ | ||
193 | #define IF_INPCK 0x0010 /* Input parity checking enabled */ | ||
194 | #define IF_ISTRIP 0x0020 /* Input chars masked with 0x7F */ | ||
195 | #define IF_IXON 0x0400 /* Output software flow control */ | ||
196 | #define IF_IXANY 0x0800 /* Restart output on any char */ | ||
197 | #define IF_IXOFF 0x1000 /* Input software flow control */ | ||
198 | #define IF_DOSMODE 0x8000 /* 16450-compatible errors */ | ||
199 | |||
200 | |||
201 | /************************************************************************ | ||
202 | * Realport OFLAGS. | ||
203 | ************************************************************************/ | ||
204 | |||
205 | #define OF_OLCUC 0x0002 /* Map lower to upper case */ | ||
206 | #define OF_ONLCR 0x0004 /* Map NL to CR-NL */ | ||
207 | #define OF_OCRNL 0x0008 /* Map CR to NL */ | ||
208 | #define OF_ONOCR 0x0010 /* No CR output at column 0 */ | ||
209 | #define OF_ONLRET 0x0020 /* Assume NL does NL/CR */ | ||
210 | #define OF_TAB3 0x1800 /* Tabs expand to 8 spaces */ | ||
211 | #define OF_TABDLY 0x1800 /* Tab delay */ | ||
212 | |||
213 | /************************************************************************ | ||
214 | * Unit flag definitions for un_flag. | ||
215 | ************************************************************************/ | ||
216 | |||
217 | /* These are the DIGI unit flags */ | ||
218 | #define UN_EXCL 0x00010000 /* Exclusive open */ | ||
219 | #define UN_STICKY 0x00020000 /* TTY Settings are now sticky */ | ||
220 | #define UN_BUSY 0x00040000 /* Some work this channel */ | ||
221 | #define UN_PWAIT 0x00080000 /* Printer waiting for terminal */ | ||
222 | #define UN_TIME 0x00100000 /* Waiting on time */ | ||
223 | #define UN_EMPTY 0x00200000 /* Waiting output queue empty */ | ||
224 | #define UN_LOW 0x00400000 /* Waiting output low water */ | ||
225 | #define UN_DIGI_MASK 0x00FF0000 /* Waiting output low water */ | ||
226 | |||
227 | /* | ||
228 | * Definitions for async_struct (and serial_struct) flags field | ||
229 | * | ||
230 | * these are the ASYNC flags copied from serial.h | ||
231 | * | ||
232 | */ | ||
233 | #define UN_HUP_NOTIFY 0x0001 /* Notify getty on hangups and | ||
234 | * closes on the callout port | ||
235 | */ | ||
236 | #define UN_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ | ||
237 | #define UN_SAK 0x0004 /* Secure Attention Key (Orange book) */ | ||
238 | #define UN_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ | ||
239 | |||
240 | #define UN_SPD_MASK 0x0030 | ||
241 | #define UN_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ | ||
242 | #define UN_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ | ||
243 | #define UN_SPD_CUST 0x0030 /* Use user-specified divisor */ | ||
244 | |||
245 | #define UN_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ | ||
246 | #define UN_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ | ||
247 | |||
248 | #define UN_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ | ||
249 | #define UN_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ | ||
250 | #define UN_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ | ||
251 | |||
252 | #define UN_FLAGS 0x0FFF /* Possible legal async flags */ | ||
253 | #define UN_USR_MASK 0x0430 /* Legal flags that non-privileged | ||
254 | * users can set or reset | ||
255 | */ | ||
256 | |||
257 | #define UN_INITIALIZED 0x80000000 /* Serial port was initialized */ | ||
258 | #define UN_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ | ||
259 | #define UN_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ | ||
260 | #define UN_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ | ||
261 | #define UN_CLOSING 0x08000000 /* Serial port is closing */ | ||
262 | #define UN_CTS_FLOW 0x04000000 /* Do CTS flow control */ | ||
263 | #define UN_CHECK_CD 0x02000000 /* i.e., CLOCAL */ | ||
264 | #define UN_SHARE_IRQ 0x01000000 /* for multifunction cards */ | ||
265 | |||
266 | |||
267 | /************************************************************************ | ||
268 | * Structure for terminal or printer unit. struct un_struct | ||
269 | * | ||
270 | * Note that in some places the code assumes the "tty_t" is placed | ||
271 | * first in the structure. | ||
272 | ************************************************************************/ | ||
273 | |||
274 | struct un_struct { | ||
275 | struct tty_struct *un_tty; /* System TTY struct */ | ||
276 | struct ch_struct *un_ch; /* Associated channel */ | ||
277 | |||
278 | ushort un_open_count; /* Successful open count */ | ||
279 | int un_flag; /* Unit flags */ | ||
280 | ushort un_tbusy; /* Busy transmit count */ | ||
281 | |||
282 | wait_queue_head_t un_open_wait; | ||
283 | wait_queue_head_t un_close_wait; | ||
284 | ushort un_type; | ||
285 | struct device *un_sysfs; | ||
286 | }; | ||
287 | |||
288 | |||
289 | /************************************************************************ | ||
290 | * Channel State Numbers for ch_state. | ||
291 | ************************************************************************/ | ||
292 | |||
293 | /* | ||
294 | * The ordering is important. | ||
295 | * | ||
296 | * state <= CS_WAIT_CANCEL implies the channel is definitely closed. | ||
297 | * | ||
298 | * state >= CS_WAIT_FAIL implies the channel is definitely open. | ||
299 | * | ||
300 | * state >= CS_READY implies data is allowed on the channel. | ||
301 | */ | ||
302 | |||
303 | enum dgrp_ch_state_t { | ||
304 | CS_IDLE = 0, /* Channel is idle */ | ||
305 | CS_WAIT_OPEN = 1, /* Waiting for Immediate Open Resp */ | ||
306 | CS_WAIT_CANCEL = 2, /* Waiting for Per/Incom Cancel Resp */ | ||
307 | CS_WAIT_FAIL = 3, /* Waiting for Immed Open Failure */ | ||
308 | CS_SEND_QUERY = 4, /* Ready to send Port Query */ | ||
309 | CS_WAIT_QUERY = 5, /* Waiting for Port Query Response */ | ||
310 | CS_READY = 6, /* Ready to accept commands and data */ | ||
311 | CS_SEND_CLOSE = 7, /* Ready to send Close Request */ | ||
312 | CS_WAIT_CLOSE = 8 /* Waiting for Close Response */ | ||
313 | }; | ||
314 | |||
315 | /************************************************************************ | ||
316 | * Device flag definitions for ch_flag. | ||
317 | ************************************************************************/ | ||
318 | |||
319 | /* | ||
320 | * Note that the state of the two carrier based flags is key. When | ||
321 | * we check for carrier state transitions, we look at the current | ||
322 | * physical state of the DCD line and compare it with PHYS_CD (which | ||
323 | * was the state the last time we checked), and we also determine | ||
324 | * a new virtual state (composite of the physical state, FORCEDCD, | ||
325 | * CLOCAL, etc.) and compare it with VIRT_CD. | ||
326 | * | ||
327 | * VIRTUAL transitions high will have the side effect of waking blocked | ||
328 | * opens. | ||
329 | * | ||
330 | * PHYSICAL transitions low will cause hangups to occur _IF_ the virtual | ||
331 | * state is also low. We DON'T want to hangup on a PURE virtual drop. | ||
332 | */ | ||
333 | |||
334 | #define CH_HANGUP 0x00002 /* Server port ready to close */ | ||
335 | |||
336 | #define CH_VIRT_CD 0x00004 /* Carrier was virtually present */ | ||
337 | #define CH_PHYS_CD 0x00008 /* Carrier was physically present */ | ||
338 | |||
339 | #define CH_CLOCAL 0x00010 /* CLOCAL set in cflags */ | ||
340 | #define CH_BAUD0 0x00020 /* Baud rate zero hangup */ | ||
341 | |||
342 | #define CH_FAST_READ 0x00040 /* Fast reads are enabled */ | ||
343 | #define CH_FAST_WRITE 0x00080 /* Fast writes are enabled */ | ||
344 | |||
345 | #define CH_PRON 0x00100 /* Printer on string active */ | ||
346 | #define CH_RX_FLUSH 0x00200 /* Flushing receive data */ | ||
347 | #define CH_LOW 0x00400 /* Thread waiting for LOW water */ | ||
348 | #define CH_EMPTY 0x00800 /* Thread waiting for EMPTY */ | ||
349 | #define CH_DRAIN 0x01000 /* Close is waiting to drain */ | ||
350 | #define CH_INPUT 0x02000 /* Thread waiting for INPUT */ | ||
351 | #define CH_RXSTOP 0x04000 /* Stop output to ldisc */ | ||
352 | #define CH_PARAM 0x08000 /* A parameter was updated */ | ||
353 | #define CH_WAITING_SYNC 0x10000 /* A pending sync was assigned | ||
354 | * to this port. | ||
355 | */ | ||
356 | #define CH_PORT_GONE 0x20000 /* Port has disappeared */ | ||
357 | #define CH_TX_BREAK 0x40000 /* TX Break to be sent, | ||
358 | * but has not yet. | ||
359 | */ | ||
360 | |||
361 | /************************************************************************ | ||
362 | * Types of Open Requests for ch_otype. | ||
363 | ************************************************************************/ | ||
364 | |||
365 | #define OTYPE_IMMEDIATE 0 /* Immediate Open */ | ||
366 | #define OTYPE_PERSISTENT 1 /* Persistent Open */ | ||
367 | #define OTYPE_INCOMING 2 /* Incoming Open */ | ||
368 | |||
369 | |||
370 | /************************************************************************ | ||
371 | * Request/Response flags. | ||
372 | ************************************************************************/ | ||
373 | |||
374 | #define RR_SEQUENCE 0x0001 /* Get server RLAST, TIN */ | ||
375 | #define RR_STATUS 0x0002 /* Get server MINT, EINT */ | ||
376 | #define RR_BUFFER 0x0004 /* Get server RSIZE, TSIZE */ | ||
377 | #define RR_CAPABILITY 0x0008 /* Get server port capabilities */ | ||
378 | |||
379 | #define RR_TX_FLUSH 0x0040 /* Flush output buffers */ | ||
380 | #define RR_RX_FLUSH 0x0080 /* Flush input buffers */ | ||
381 | |||
382 | #define RR_TX_STOP 0x0100 /* Pause output */ | ||
383 | #define RR_RX_STOP 0x0200 /* Pause input */ | ||
384 | #define RR_TX_START 0x0400 /* Start output */ | ||
385 | #define RR_RX_START 0x0800 /* Start input */ | ||
386 | |||
387 | #define RR_TX_BREAK 0x1000 /* Send BREAK */ | ||
388 | #define RR_TX_ICHAR 0x2000 /* Send character immediate */ | ||
389 | |||
390 | |||
391 | /************************************************************************ | ||
392 | * Channel information structure. struct ch_struct | ||
393 | ************************************************************************/ | ||
394 | |||
395 | struct ch_struct { | ||
396 | struct digi_struct ch_digi; /* Digi variables */ | ||
397 | int ch_edelay; /* Digi edelay */ | ||
398 | |||
399 | struct tty_port port; | ||
400 | struct un_struct ch_tun; /* Terminal unit info */ | ||
401 | struct un_struct ch_pun; /* Printer unit info */ | ||
402 | |||
403 | struct nd_struct *ch_nd; /* Node pointer */ | ||
404 | u8 *ch_tbuf; /* Local Transmit Buffer */ | ||
405 | u8 *ch_rbuf; /* Local Receive Buffer */ | ||
406 | ulong ch_cpstime; /* Printer CPS time */ | ||
407 | ulong ch_waketime; /* Printer wake time */ | ||
408 | |||
409 | ulong ch_flag; /* CH_* flags */ | ||
410 | |||
411 | enum dgrp_ch_state_t ch_state; /* CS_* Protocol state */ | ||
412 | ushort ch_send; /* Bit vector of RR_* requests */ | ||
413 | ushort ch_expect; /* Bit vector of RR_* responses */ | ||
414 | ushort ch_wait_carrier; /* Thread count waiting for carrier */ | ||
415 | ushort ch_wait_count[3]; /* Thread count waiting by otype */ | ||
416 | |||
417 | ushort ch_portnum; /* Port number */ | ||
418 | ushort ch_open_count; /* Successful open count */ | ||
419 | ushort ch_category; /* Device category */ | ||
420 | ushort ch_open_error; /* Last open error number */ | ||
421 | ushort ch_break_time; /* Pending break request time */ | ||
422 | ushort ch_cpsrem; /* Printer CPS remainder */ | ||
423 | ushort ch_ocook; /* Realport fastcook oflags */ | ||
424 | ushort ch_inwait; /* Thread count in CLIST input */ | ||
425 | |||
426 | ushort ch_tin; /* Local transmit buffer in ptr */ | ||
427 | ushort ch_tout; /* Local transmit buffer out ptr */ | ||
428 | ushort ch_s_tin; /* Realport TIN */ | ||
429 | ushort ch_s_tpos; /* Realport TPOS */ | ||
430 | ushort ch_s_tsize; /* Realport TSIZE */ | ||
431 | ushort ch_s_treq; /* Realport TREQ */ | ||
432 | ushort ch_s_elast; /* Realport ELAST */ | ||
433 | |||
434 | ushort ch_rin; /* Local receive buffer in ptr */ | ||
435 | ushort ch_rout; /* Local receive buffer out ptr */ | ||
436 | ushort ch_s_rin; /* Realport RIN */ | ||
437 | /* David Fries 7-13-2001, ch_s_rin should be renamed ch_s_rout because | ||
438 | * the variable we want to represent is the PortServer's ROUT, which is | ||
439 | * the sequence number for the next byte the PortServer will send us. | ||
440 | * RIN is the sequence number for the next byte the PortServer will | ||
441 | * receive from the uart. The port server will send data as long as | ||
442 | * ROUT is less than RWIN. What would happen is the port is opened, it | ||
443 | * receives data, it gives the value of RIN, we set the RWIN to | ||
444 | * RIN+RBUF_MAX-1, it sends us RWIN-ROUT bytes which overflows. ROUT | ||
445 | * is set to zero when the port is opened, so we start at zero and | ||
446 | * count up as data is received. | ||
447 | */ | ||
448 | ushort ch_s_rwin; /* Realport RWIN */ | ||
449 | ushort ch_s_rsize; /* Realport RSIZE */ | ||
450 | |||
451 | ushort ch_tmax; /* Local TMAX */ | ||
452 | ushort ch_ttime; /* Local TTIME */ | ||
453 | ushort ch_rmax; /* Local RMAX */ | ||
454 | ushort ch_rtime; /* Local RTIME */ | ||
455 | ushort ch_rlow; /* Local RLOW */ | ||
456 | ushort ch_rhigh; /* Local RHIGH */ | ||
457 | |||
458 | ushort ch_s_tmax; /* Realport TMAX */ | ||
459 | ushort ch_s_ttime; /* Realport TTIME */ | ||
460 | ushort ch_s_rmax; /* Realport RMAX */ | ||
461 | ushort ch_s_rtime; /* Realport RTIME */ | ||
462 | ushort ch_s_rlow; /* Realport RLOW */ | ||
463 | ushort ch_s_rhigh; /* Realport RHIGH */ | ||
464 | |||
465 | ushort ch_brate; /* Local baud rate */ | ||
466 | ushort ch_cflag; /* Local tty cflags */ | ||
467 | ushort ch_iflag; /* Local tty iflags */ | ||
468 | ushort ch_oflag; /* Local tty oflags */ | ||
469 | ushort ch_xflag; /* Local tty xflags */ | ||
470 | |||
471 | ushort ch_s_brate; /* Realport BRATE */ | ||
472 | ushort ch_s_cflag; /* Realport CFLAG */ | ||
473 | ushort ch_s_iflag; /* Realport IFLAG */ | ||
474 | ushort ch_s_oflag; /* Realport OFLAG */ | ||
475 | ushort ch_s_xflag; /* Realport XFLAG */ | ||
476 | |||
477 | u8 ch_otype; /* Open request type */ | ||
478 | u8 ch_pscan_savechar; /* Last character read by parity scan */ | ||
479 | u8 ch_pscan_state; /* PScan State based on last 2 chars */ | ||
480 | u8 ch_otype_waiting; /* Type of open pending in server */ | ||
481 | u8 ch_flush_seq; /* Receive flush end sequence */ | ||
482 | u8 ch_s_mlast; /* Realport MLAST */ | ||
483 | |||
484 | u8 ch_mout; /* Local MOUT */ | ||
485 | u8 ch_mflow; /* Local MFLOW */ | ||
486 | u8 ch_mctrl; /* Local MCTRL */ | ||
487 | u8 ch_xon; /* Local XON */ | ||
488 | u8 ch_xoff; /* Local XOFF */ | ||
489 | u8 ch_lnext; /* Local LNEXT */ | ||
490 | u8 ch_xxon; /* Local XXON */ | ||
491 | u8 ch_xxoff; /* Local XXOFF */ | ||
492 | |||
493 | u8 ch_s_mout; /* Realport MOUT */ | ||
494 | u8 ch_s_mflow; /* Realport MFLOW */ | ||
495 | u8 ch_s_mctrl; /* Realport MCTRL */ | ||
496 | u8 ch_s_xon; /* Realport XON */ | ||
497 | u8 ch_s_xoff; /* Realport XOFF */ | ||
498 | u8 ch_s_lnext; /* Realport LNEXT */ | ||
499 | u8 ch_s_xxon; /* Realport XXON */ | ||
500 | u8 ch_s_xxoff; /* Realport XXOFF */ | ||
501 | |||
502 | wait_queue_head_t ch_flag_wait; /* Wait queue for ch_flag changes */ | ||
503 | wait_queue_head_t ch_sleep; /* Wait queue for my_sleep() */ | ||
504 | |||
505 | int ch_custom_speed; /* Realport custom speed */ | ||
506 | int ch_txcount; /* Running TX count */ | ||
507 | int ch_rxcount; /* Running RX count */ | ||
508 | }; | ||
509 | |||
510 | |||
511 | /************************************************************************ | ||
512 | * Node State definitions. | ||
513 | ************************************************************************/ | ||
514 | |||
515 | enum dgrp_nd_state_t { | ||
516 | NS_CLOSED = 0, /* Network device is closed */ | ||
517 | NS_IDLE = 1, /* Network connection inactive */ | ||
518 | NS_SEND_QUERY = 2, /* Send server query */ | ||
519 | NS_WAIT_QUERY = 3, /* Wait for query response */ | ||
520 | NS_READY = 4, /* Network ready */ | ||
521 | NS_SEND_ERROR = 5 /* Must send error hangup */ | ||
522 | }; | ||
523 | |||
524 | #define ND_STATE_STR(x) \ | ||
525 | ((x) == NS_CLOSED ? "CLOSED" : \ | ||
526 | ((x) == NS_IDLE ? "IDLE" : \ | ||
527 | ((x) == NS_SEND_QUERY ? "SEND_QUERY" : \ | ||
528 | ((x) == NS_WAIT_QUERY ? "WAIT_QUERY" : \ | ||
529 | ((x) == NS_READY ? "READY" : \ | ||
530 | ((x) == NS_SEND_ERROR ? "SEND_ERROR" : "UNKNOWN")))))) | ||
531 | |||
532 | /************************************************************************ | ||
533 | * Node Flag definitions. | ||
534 | ************************************************************************/ | ||
535 | |||
536 | #define ND_SELECT 0x0001 /* Multiple net read selects */ | ||
537 | #define ND_DEB_WAIT 0x0002 /* Debug Device waiting */ | ||
538 | |||
539 | |||
540 | /************************************************************************ | ||
541 | * Monitoring flag definitions. | ||
542 | ************************************************************************/ | ||
543 | |||
544 | #define MON_WAIT_DATA 0x0001 /* Waiting for buffer data */ | ||
545 | #define MON_WAIT_SPACE 0x0002 /* Waiting for buffer space */ | ||
546 | |||
547 | /************************************************************************ | ||
548 | * DPA flag definitions. | ||
549 | ************************************************************************/ | ||
550 | |||
551 | #define DPA_WAIT_DATA 0x0001 /* Waiting for buffer data */ | ||
552 | #define DPA_WAIT_SPACE 0x0002 /* Waiting for buffer space */ | ||
553 | |||
554 | |||
555 | /************************************************************************ | ||
556 | * Definitions taken from Realport Dump. | ||
557 | ************************************************************************/ | ||
558 | |||
559 | #define RPDUMP_MAGIC "Digi-RealPort-1.0" | ||
560 | |||
561 | #define RPDUMP_MESSAGE 0xE2 /* Descriptive message */ | ||
562 | #define RPDUMP_RESET 0xE7 /* Connection reset */ | ||
563 | #define RPDUMP_CLIENT 0xE8 /* Client data */ | ||
564 | #define RPDUMP_SERVER 0xE9 /* Server data */ | ||
565 | |||
566 | |||
567 | /************************************************************************ | ||
568 | * Node request/response definitions. | ||
569 | ************************************************************************/ | ||
570 | |||
571 | #define NR_ECHO 0x0001 /* Server echo packet */ | ||
572 | #define NR_IDENT 0x0002 /* Server Product ID */ | ||
573 | #define NR_CAPABILITY 0x0004 /* Server Capabilties */ | ||
574 | #define NR_VPD 0x0008 /* Server VPD, if any */ | ||
575 | #define NR_PASSWORD 0x0010 /* Server Password */ | ||
576 | |||
577 | /************************************************************************ | ||
578 | * Registration status of the node's Linux struct tty_driver structures. | ||
579 | ************************************************************************/ | ||
580 | #define SERIAL_TTDRV_REG 0x0001 /* nd_serial_ttdriver registered */ | ||
581 | #define CALLOUT_TTDRV_REG 0x0002 /* nd_callout_ttdriver registered */ | ||
582 | #define XPRINT_TTDRV_REG 0x0004 /* nd_xprint_ttdriver registered */ | ||
583 | |||
584 | |||
585 | /************************************************************************ | ||
586 | * Node structure. There exists one of these for each associated | ||
587 | * realport server. | ||
588 | ************************************************************************/ | ||
589 | |||
590 | struct nd_struct { | ||
591 | struct list_head list; | ||
592 | long nd_major; /* Node's major number */ | ||
593 | long nd_ID; /* Node's ID code */ | ||
594 | |||
595 | char nd_serial_name[50]; /* "tty_dgrp_<id>_" + null */ | ||
596 | char nd_callout_name[50]; /* "cu_dgrp_<id>_" + null */ | ||
597 | char nd_xprint_name[50]; /* "pr_dgrp_<id>_" + null */ | ||
598 | |||
599 | char password[16]; /* Password for server, if needed */ | ||
600 | int nd_tty_ref_cnt; /* Linux tty reference count */ | ||
601 | |||
602 | struct proc_dir_entry *nd_net_de; /* Dir entry for /proc/dgrp/net */ | ||
603 | struct proc_dir_entry *nd_mon_de; /* Dir entry for /proc/dgrp/mon */ | ||
604 | struct proc_dir_entry *nd_ports_de; /* Dir entry for /proc/dgrp/ports*/ | ||
605 | struct proc_dir_entry *nd_dpa_de; /* Dir entry for /proc/dgrp/dpa */ | ||
606 | |||
607 | spinlock_t nd_lock; /* General node lock */ | ||
608 | |||
609 | struct semaphore nd_net_semaphore; /* Net read/write lock */ | ||
610 | struct semaphore nd_mon_semaphore; /* Monitor buffer lock */ | ||
611 | spinlock_t nd_dpa_lock; /* DPA buffer lock */ | ||
612 | |||
613 | enum dgrp_nd_state_t nd_state; /* NS_* network state */ | ||
614 | int nd_chan_count; /* # active channels */ | ||
615 | int nd_flag; /* Node flags */ | ||
616 | int nd_send; /* Responses to send */ | ||
617 | int nd_expect; /* Responses we expect */ | ||
618 | |||
619 | u8 *nd_iobuf; /* Network R/W Buffer */ | ||
620 | wait_queue_head_t nd_tx_waitq; /* Network select wait queue */ | ||
621 | |||
622 | u8 *nd_inputbuf; /* Input Buffer */ | ||
623 | u8 *nd_inputflagbuf; /* Input Flags Buffer */ | ||
624 | |||
625 | int nd_tx_deposit; /* Accumulated transmit deposits */ | ||
626 | int nd_tx_charge; /* Accumulated transmit charges */ | ||
627 | int nd_tx_credit; /* Current TX credit */ | ||
628 | int nd_tx_ready; /* Ready to transmit */ | ||
629 | int nd_tx_work; /* TX work waiting */ | ||
630 | ulong nd_tx_time; /* Last transmit time */ | ||
631 | ulong nd_poll_time; /* Next scheduled poll time */ | ||
632 | |||
633 | int nd_delay; /* Current TX delay */ | ||
634 | int nd_rate; /* Current TX rate */ | ||
635 | struct link_struct nd_link; /* Link speed params. */ | ||
636 | |||
637 | int nd_seq_in; /* TX seq in ptr */ | ||
638 | int nd_seq_out; /* TX seq out ptr */ | ||
639 | int nd_unack; /* Unacknowledged byte count */ | ||
640 | int nd_remain; /* Remaining receive bytes */ | ||
641 | int nd_tx_module; /* Current TX module # */ | ||
642 | int nd_rx_module; /* Current RX module # */ | ||
643 | char *nd_error; /* Protocol error message */ | ||
644 | |||
645 | int nd_write_count; /* drp_write() call count */ | ||
646 | int nd_read_count; /* drp_read() count */ | ||
647 | int nd_send_count; /* TCP message sent */ | ||
648 | int nd_tx_byte; /* Transmit byte count */ | ||
649 | int nd_rx_byte; /* Receive byte count */ | ||
650 | |||
651 | ulong nd_mon_lbolt; /* Monitor start time */ | ||
652 | int nd_mon_flag; /* Monitor flags */ | ||
653 | int nd_mon_in; /* Monitor in pointer */ | ||
654 | int nd_mon_out; /* Monitor out pointer */ | ||
655 | wait_queue_head_t nd_mon_wqueue; /* Monitor wait queue (on flags) */ | ||
656 | u8 *nd_mon_buf; /* Monitor buffer */ | ||
657 | |||
658 | ulong nd_dpa_lbolt; /* DPA start time */ | ||
659 | int nd_dpa_flag; /* DPA flags */ | ||
660 | int nd_dpa_in; /* DPA in pointer */ | ||
661 | int nd_dpa_out; /* DPA out pointer */ | ||
662 | wait_queue_head_t nd_dpa_wqueue; /* DPA wait queue (on flags) */ | ||
663 | u8 *nd_dpa_buf; /* DPA buffer */ | ||
664 | |||
665 | uint nd_dpa_debug; | ||
666 | uint nd_dpa_port; | ||
667 | |||
668 | wait_queue_head_t nd_seq_wque[SEQ_MAX]; /* TX thread wait queues */ | ||
669 | u8 nd_seq_wait[SEQ_MAX]; /* Transmit thread wait count */ | ||
670 | |||
671 | ushort nd_seq_size[SEQ_MAX]; /* Transmit seq packet size */ | ||
672 | ulong nd_seq_time[SEQ_MAX]; /* Transmit seq packet time */ | ||
673 | |||
674 | ushort nd_hw_ver; /* HW version returned from PS */ | ||
675 | ushort nd_sw_ver; /* SW version returned from PS */ | ||
676 | uint nd_hw_id; /* HW ID returned from PS */ | ||
677 | u8 nd_ps_desc[MAX_DESC_LEN+1]; /* Description from PS */ | ||
678 | uint nd_vpd_len; /* VPD len, if any */ | ||
679 | u8 nd_vpd[VPDSIZE]; /* VPD, if any */ | ||
680 | |||
681 | ulong nd_ttdriver_flags; /* Registration status */ | ||
682 | struct tty_driver *nd_serial_ttdriver; /* Linux TTYDRIVER structure */ | ||
683 | struct tty_driver *nd_callout_ttdriver; /* Linux TTYDRIVER structure */ | ||
684 | struct tty_driver *nd_xprint_ttdriver; /* Linux TTYDRIVER structure */ | ||
685 | |||
686 | u8 *nd_writebuf; /* Used to cache data read | ||
687 | * from user | ||
688 | */ | ||
689 | struct ch_struct nd_chan[CHAN_MAX]; /* Channel array */ | ||
690 | struct device *nd_class_dev; /* Hang our sysfs stuff off of here */ | ||
691 | }; | ||
692 | |||
693 | #endif /* __DRP_H */ | ||
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index 2cdbf280cdab..d751edfda839 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c | |||
@@ -443,7 +443,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, | |||
443 | spin_lock_init(&channel->lock); | 443 | spin_lock_init(&channel->lock); |
444 | channel->pointer_read = 0; | 444 | channel->pointer_read = 0; |
445 | channel->pointer_write = 0; | 445 | channel->pointer_write = 0; |
446 | tty_dev = tty_register_device(tty, i, NULL); | 446 | tty_dev = tty_port_register_device(&channel->tty_port, tty, i, NULL); |
447 | if (IS_ERR(tty_dev)) { | 447 | if (IS_ERR(tty_dev)) { |
448 | dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n"); | 448 | dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n"); |
449 | continue; | 449 | continue; |
@@ -543,7 +543,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, | |||
543 | struct ipoctal_channel *channel = tty->driver_data; | 543 | struct ipoctal_channel *channel = tty->driver_data; |
544 | speed_t baud; | 544 | speed_t baud; |
545 | 545 | ||
546 | cflag = tty->termios->c_cflag; | 546 | cflag = tty->termios.c_cflag; |
547 | 547 | ||
548 | /* Disable and reset everything before change the setup */ | 548 | /* Disable and reset everything before change the setup */ |
549 | iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); | 549 | iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); |
@@ -564,7 +564,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, | |||
564 | default: | 564 | default: |
565 | mr1 |= MR1_CHRL_8_BITS; | 565 | mr1 |= MR1_CHRL_8_BITS; |
566 | /* By default, select CS8 */ | 566 | /* By default, select CS8 */ |
567 | tty->termios->c_cflag = (cflag & ~CSIZE) | CS8; | 567 | tty->termios.c_cflag = (cflag & ~CSIZE) | CS8; |
568 | break; | 568 | break; |
569 | } | 569 | } |
570 | 570 | ||
@@ -578,7 +578,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, | |||
578 | mr1 |= MR1_PARITY_OFF; | 578 | mr1 |= MR1_PARITY_OFF; |
579 | 579 | ||
580 | /* Mark or space parity is not supported */ | 580 | /* Mark or space parity is not supported */ |
581 | tty->termios->c_cflag &= ~CMSPAR; | 581 | tty->termios.c_cflag &= ~CMSPAR; |
582 | 582 | ||
583 | /* Set stop bits */ | 583 | /* Set stop bits */ |
584 | if (cflag & CSTOPB) | 584 | if (cflag & CSTOPB) |
@@ -611,10 +611,10 @@ static void ipoctal_set_termios(struct tty_struct *tty, | |||
611 | } | 611 | } |
612 | 612 | ||
613 | baud = tty_get_baud_rate(tty); | 613 | baud = tty_get_baud_rate(tty); |
614 | tty_termios_encode_baud_rate(tty->termios, baud, baud); | 614 | tty_termios_encode_baud_rate(&tty->termios, baud, baud); |
615 | 615 | ||
616 | /* Set baud rate */ | 616 | /* Set baud rate */ |
617 | switch (tty->termios->c_ospeed) { | 617 | switch (baud) { |
618 | case 75: | 618 | case 75: |
619 | csr |= TX_CLK_75 | RX_CLK_75; | 619 | csr |= TX_CLK_75 | RX_CLK_75; |
620 | break; | 620 | break; |
@@ -655,7 +655,7 @@ static void ipoctal_set_termios(struct tty_struct *tty, | |||
655 | default: | 655 | default: |
656 | csr |= TX_CLK_38400 | RX_CLK_38400; | 656 | csr |= TX_CLK_38400 | RX_CLK_38400; |
657 | /* In case of default, we establish 38400 bps */ | 657 | /* In case of default, we establish 38400 bps */ |
658 | tty_termios_encode_baud_rate(tty->termios, 38400, 38400); | 658 | tty_termios_encode_baud_rate(&tty->termios, 38400, 38400); |
659 | break; | 659 | break; |
660 | } | 660 | } |
661 | 661 | ||
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index c56609c6094b..5c969ade2eb7 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c | |||
@@ -313,10 +313,8 @@ static void qt_read_bulk_callback(struct urb *urb) | |||
313 | } | 313 | } |
314 | 314 | ||
315 | tty = tty_port_tty_get(&port->port); | 315 | tty = tty_port_tty_get(&port->port); |
316 | if (!tty) { | 316 | if (!tty) |
317 | dbg("%s - bad tty pointer - exiting", __func__); | ||
318 | return; | 317 | return; |
319 | } | ||
320 | 318 | ||
321 | data = urb->transfer_buffer; | 319 | data = urb->transfer_buffer; |
322 | 320 | ||
@@ -362,7 +360,7 @@ static void qt_read_bulk_callback(struct urb *urb) | |||
362 | goto exit; | 360 | goto exit; |
363 | } | 361 | } |
364 | 362 | ||
365 | if (tty && RxCount) { | 363 | if (RxCount) { |
366 | flag_data = 0; | 364 | flag_data = 0; |
367 | for (i = 0; i < RxCount; ++i) { | 365 | for (i = 0; i < RxCount; ++i) { |
368 | /* Look ahead code here */ | 366 | /* Look ahead code here */ |
@@ -426,7 +424,7 @@ static void qt_read_bulk_callback(struct urb *urb) | |||
426 | dbg("%s - failed resubmitting read urb, error %d", | 424 | dbg("%s - failed resubmitting read urb, error %d", |
427 | __func__, result); | 425 | __func__, result); |
428 | else { | 426 | else { |
429 | if (tty && RxCount) { | 427 | if (RxCount) { |
430 | tty_flip_buffer_push(tty); | 428 | tty_flip_buffer_push(tty); |
431 | tty_schedule_flip(tty); | 429 | tty_schedule_flip(tty); |
432 | } | 430 | } |
@@ -895,8 +893,6 @@ static int qt_open(struct tty_struct *tty, | |||
895 | * Put this here to make it responsive to stty and defaults set by | 893 | * Put this here to make it responsive to stty and defaults set by |
896 | * the tty layer | 894 | * the tty layer |
897 | */ | 895 | */ |
898 | /* FIXME: is this needed? */ | ||
899 | /* qt_set_termios(tty, port, NULL); */ | ||
900 | 896 | ||
901 | /* Check to see if we've set up our endpoint info yet */ | 897 | /* Check to see if we've set up our endpoint info yet */ |
902 | if (port0->open_ports == 1) { | 898 | if (port0->open_ports == 1) { |
@@ -1193,7 +1189,7 @@ static void qt_set_termios(struct tty_struct *tty, | |||
1193 | struct usb_serial_port *port, | 1189 | struct usb_serial_port *port, |
1194 | struct ktermios *old_termios) | 1190 | struct ktermios *old_termios) |
1195 | { | 1191 | { |
1196 | struct ktermios *termios = tty->termios; | 1192 | struct ktermios *termios = &tty->termios; |
1197 | unsigned char new_LCR = 0; | 1193 | unsigned char new_LCR = 0; |
1198 | unsigned int cflag = termios->c_cflag; | 1194 | unsigned int cflag = termios->c_cflag; |
1199 | unsigned int index; | 1195 | unsigned int index; |
@@ -1202,7 +1198,7 @@ static void qt_set_termios(struct tty_struct *tty, | |||
1202 | 1198 | ||
1203 | index = tty->index - port->serial->minor; | 1199 | index = tty->index - port->serial->minor; |
1204 | 1200 | ||
1205 | switch (cflag) { | 1201 | switch (cflag & CSIZE) { |
1206 | case CS5: | 1202 | case CS5: |
1207 | new_LCR |= SERIAL_5_DATA; | 1203 | new_LCR |= SERIAL_5_DATA; |
1208 | break; | 1204 | break; |
@@ -1213,6 +1209,8 @@ static void qt_set_termios(struct tty_struct *tty, | |||
1213 | new_LCR |= SERIAL_7_DATA; | 1209 | new_LCR |= SERIAL_7_DATA; |
1214 | break; | 1210 | break; |
1215 | default: | 1211 | default: |
1212 | termios->c_cflag &= ~CSIZE; | ||
1213 | termios->c_cflag |= CS8; | ||
1216 | case CS8: | 1214 | case CS8: |
1217 | new_LCR |= SERIAL_8_DATA; | 1215 | new_LCR |= SERIAL_8_DATA; |
1218 | break; | 1216 | break; |
@@ -1299,7 +1297,7 @@ static void qt_set_termios(struct tty_struct *tty, | |||
1299 | dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); | 1297 | dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n"); |
1300 | 1298 | ||
1301 | } | 1299 | } |
1302 | tty->termios->c_cflag &= ~CMSPAR; | 1300 | termios->c_cflag &= ~CMSPAR; |
1303 | /* FIXME: Error cases should be returning the actual bits changed only */ | 1301 | /* FIXME: Error cases should be returning the actual bits changed only */ |
1304 | } | 1302 | } |
1305 | 1303 | ||
diff --git a/drivers/staging/speakup/serialio.h b/drivers/staging/speakup/serialio.h index 614271f9b99f..55d68b5ad165 100644 --- a/drivers/staging/speakup/serialio.h +++ b/drivers/staging/speakup/serialio.h | |||
@@ -1,8 +1,7 @@ | |||
1 | #ifndef _SPEAKUP_SERIAL_H | 1 | #ifndef _SPEAKUP_SERIAL_H |
2 | #define _SPEAKUP_SERIAL_H | 2 | #define _SPEAKUP_SERIAL_H |
3 | 3 | ||
4 | #include <linux/serial.h> /* for rs_table, serial constants & | 4 | #include <linux/serial.h> /* for rs_table, serial constants */ |
5 | serial_uart_config */ | ||
6 | #include <linux/serial_reg.h> /* for more serial constants */ | 5 | #include <linux/serial_reg.h> /* for more serial constants */ |
7 | #ifndef __sparc__ | 6 | #ifndef __sparc__ |
8 | #include <asm/serial.h> | 7 | #include <asm/serial.h> |