diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-03-17 03:44:08 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-03-17 03:44:08 -0400 |
commit | 1d2a1959fe534279cf37aba20b08c24c20840e52 (patch) | |
tree | 67c0b9aa7fe22a44bf0b4af88947799203eb8f67 /drivers/tty | |
parent | 5a79ce76e9bb8f4b2cd8106ee36d15ee05013bcf (diff) | |
parent | 054cfaacf88865bff1dd58d305443d5d6c068a08 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into sh-latest
Diffstat (limited to 'drivers/tty')
80 files changed, 46240 insertions, 1299 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig new file mode 100644 index 000000000000..3fd7199301b6 --- /dev/null +++ b/drivers/tty/Kconfig | |||
@@ -0,0 +1,321 @@ | |||
1 | config VT | ||
2 | bool "Virtual terminal" if EXPERT | ||
3 | depends on !S390 | ||
4 | select INPUT | ||
5 | default y | ||
6 | ---help--- | ||
7 | If you say Y here, you will get support for terminal devices with | ||
8 | display and keyboard devices. These are called "virtual" because you | ||
9 | can run several virtual terminals (also called virtual consoles) on | ||
10 | one physical terminal. This is rather useful, for example one | ||
11 | virtual terminal can collect system messages and warnings, another | ||
12 | one can be used for a text-mode user session, and a third could run | ||
13 | an X session, all in parallel. Switching between virtual terminals | ||
14 | is done with certain key combinations, usually Alt-<function key>. | ||
15 | |||
16 | The setterm command ("man setterm") can be used to change the | ||
17 | properties (such as colors or beeping) of a virtual terminal. The | ||
18 | man page console_codes(4) ("man console_codes") contains the special | ||
19 | character sequences that can be used to change those properties | ||
20 | directly. The fonts used on virtual terminals can be changed with | ||
21 | the setfont ("man setfont") command and the key bindings are defined | ||
22 | with the loadkeys ("man loadkeys") command. | ||
23 | |||
24 | You need at least one virtual terminal device in order to make use | ||
25 | of your keyboard and monitor. Therefore, only people configuring an | ||
26 | embedded system would want to say N here in order to save some | ||
27 | memory; the only way to log into such a system is then via a serial | ||
28 | or network connection. | ||
29 | |||
30 | If unsure, say Y, or else you won't be able to do much with your new | ||
31 | shiny Linux system :-) | ||
32 | |||
33 | config CONSOLE_TRANSLATIONS | ||
34 | depends on VT | ||
35 | default y | ||
36 | bool "Enable character translations in console" if EXPERT | ||
37 | ---help--- | ||
38 | This enables support for font mapping and Unicode translation | ||
39 | on virtual consoles. | ||
40 | |||
41 | config VT_CONSOLE | ||
42 | bool "Support for console on virtual terminal" if EXPERT | ||
43 | depends on VT | ||
44 | default y | ||
45 | ---help--- | ||
46 | The system console is the device which receives all kernel messages | ||
47 | and warnings and which allows logins in single user mode. If you | ||
48 | answer Y here, a virtual terminal (the device used to interact with | ||
49 | a physical terminal) can be used as system console. This is the most | ||
50 | common mode of operations, so you should say Y here unless you want | ||
51 | the kernel messages be output only to a serial port (in which case | ||
52 | you should say Y to "Console on serial port", below). | ||
53 | |||
54 | If you do say Y here, by default the currently visible virtual | ||
55 | terminal (/dev/tty0) will be used as system console. You can change | ||
56 | that with a kernel command line option such as "console=tty3" which | ||
57 | would use the third virtual terminal as system console. (Try "man | ||
58 | bootparam" or see the documentation of your boot loader (lilo or | ||
59 | loadlin) about how to pass options to the kernel at boot time.) | ||
60 | |||
61 | If unsure, say Y. | ||
62 | |||
63 | config HW_CONSOLE | ||
64 | bool | ||
65 | depends on VT && !S390 && !UML | ||
66 | default y | ||
67 | |||
68 | config VT_HW_CONSOLE_BINDING | ||
69 | bool "Support for binding and unbinding console drivers" | ||
70 | depends on HW_CONSOLE | ||
71 | default n | ||
72 | ---help--- | ||
73 | The virtual terminal is the device that interacts with the physical | ||
74 | terminal through console drivers. On these systems, at least one | ||
75 | console driver is loaded. In other configurations, additional console | ||
76 | drivers may be enabled, such as the framebuffer console. If more than | ||
77 | 1 console driver is enabled, setting this to 'y' will allow you to | ||
78 | select the console driver that will serve as the backend for the | ||
79 | virtual terminals. | ||
80 | |||
81 | See <file:Documentation/console/console.txt> for more | ||
82 | information. For framebuffer console users, please refer to | ||
83 | <file:Documentation/fb/fbcon.txt>. | ||
84 | |||
85 | config UNIX98_PTYS | ||
86 | bool "Unix98 PTY support" if EXPERT | ||
87 | default y | ||
88 | ---help--- | ||
89 | A pseudo terminal (PTY) is a software device consisting of two | ||
90 | halves: a master and a slave. The slave device behaves identical to | ||
91 | a physical terminal; the master device is used by a process to | ||
92 | read data from and write data to the slave, thereby emulating a | ||
93 | terminal. Typical programs for the master side are telnet servers | ||
94 | and xterms. | ||
95 | |||
96 | Linux has traditionally used the BSD-like names /dev/ptyxx for | ||
97 | masters and /dev/ttyxx for slaves of pseudo terminals. This scheme | ||
98 | has a number of problems. The GNU C library glibc 2.1 and later, | ||
99 | however, supports the Unix98 naming standard: in order to acquire a | ||
100 | pseudo terminal, a process opens /dev/ptmx; the number of the pseudo | ||
101 | terminal is then made available to the process and the pseudo | ||
102 | terminal slave can be accessed as /dev/pts/<number>. What was | ||
103 | traditionally /dev/ttyp2 will then be /dev/pts/2, for example. | ||
104 | |||
105 | All modern Linux systems use the Unix98 ptys. Say Y unless | ||
106 | you're on an embedded system and want to conserve memory. | ||
107 | |||
108 | config DEVPTS_MULTIPLE_INSTANCES | ||
109 | bool "Support multiple instances of devpts" | ||
110 | depends on UNIX98_PTYS | ||
111 | default n | ||
112 | ---help--- | ||
113 | Enable support for multiple instances of devpts filesystem. | ||
114 | If you want to have isolated PTY namespaces (eg: in containers), | ||
115 | say Y here. Otherwise, say N. If enabled, each mount of devpts | ||
116 | filesystem with the '-o newinstance' option will create an | ||
117 | independent PTY namespace. | ||
118 | |||
119 | config LEGACY_PTYS | ||
120 | bool "Legacy (BSD) PTY support" | ||
121 | default y | ||
122 | ---help--- | ||
123 | A pseudo terminal (PTY) is a software device consisting of two | ||
124 | halves: a master and a slave. The slave device behaves identical to | ||
125 | a physical terminal; the master device is used by a process to | ||
126 | read data from and write data to the slave, thereby emulating a | ||
127 | terminal. Typical programs for the master side are telnet servers | ||
128 | and xterms. | ||
129 | |||
130 | Linux has traditionally used the BSD-like names /dev/ptyxx | ||
131 | for masters and /dev/ttyxx for slaves of pseudo | ||
132 | terminals. This scheme has a number of problems, including | ||
133 | security. This option enables these legacy devices; on most | ||
134 | systems, it is safe to say N. | ||
135 | |||
136 | |||
137 | config LEGACY_PTY_COUNT | ||
138 | int "Maximum number of legacy PTY in use" | ||
139 | depends on LEGACY_PTYS | ||
140 | range 0 256 | ||
141 | default "256" | ||
142 | ---help--- | ||
143 | The maximum number of legacy PTYs that can be used at any one time. | ||
144 | The default is 256, and should be more than enough. Embedded | ||
145 | systems may want to reduce this to save memory. | ||
146 | |||
147 | When not in use, each legacy PTY occupies 12 bytes on 32-bit | ||
148 | architectures and 24 bytes on 64-bit architectures. | ||
149 | |||
150 | config BFIN_JTAG_COMM | ||
151 | tristate "Blackfin JTAG Communication" | ||
152 | depends on BLACKFIN | ||
153 | help | ||
154 | Add support for emulating a TTY device over the Blackfin JTAG. | ||
155 | |||
156 | To compile this driver as a module, choose M here: the | ||
157 | module will be called bfin_jtag_comm. | ||
158 | |||
159 | config BFIN_JTAG_COMM_CONSOLE | ||
160 | bool "Console on Blackfin JTAG" | ||
161 | depends on BFIN_JTAG_COMM=y | ||
162 | |||
163 | config SERIAL_NONSTANDARD | ||
164 | bool "Non-standard serial port support" | ||
165 | depends on HAS_IOMEM | ||
166 | ---help--- | ||
167 | Say Y here if you have any non-standard serial boards -- boards | ||
168 | which aren't supported using the standard "dumb" serial driver. | ||
169 | This includes intelligent serial boards such as Cyclades, | ||
170 | Digiboards, etc. These are usually used for systems that need many | ||
171 | serial ports because they serve many terminals or dial-in | ||
172 | connections. | ||
173 | |||
174 | Note that the answer to this question won't directly affect the | ||
175 | kernel: saying N will just cause the configurator to skip all | ||
176 | the questions about non-standard serial boards. | ||
177 | |||
178 | Most people can say N here. | ||
179 | |||
180 | config ROCKETPORT | ||
181 | tristate "Comtrol RocketPort support" | ||
182 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | ||
183 | help | ||
184 | This driver supports Comtrol RocketPort and RocketModem PCI boards. | ||
185 | These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or | ||
186 | modems. For information about the RocketPort/RocketModem boards | ||
187 | and this driver read <file:Documentation/serial/rocket.txt>. | ||
188 | |||
189 | To compile this driver as a module, choose M here: the | ||
190 | module will be called rocket. | ||
191 | |||
192 | If you want to compile this driver into the kernel, say Y here. If | ||
193 | you don't have a Comtrol RocketPort/RocketModem card installed, say N. | ||
194 | |||
195 | config CYCLADES | ||
196 | tristate "Cyclades async mux support" | ||
197 | depends on SERIAL_NONSTANDARD && (PCI || ISA) | ||
198 | select FW_LOADER | ||
199 | ---help--- | ||
200 | This driver supports Cyclades Z and Y multiserial boards. | ||
201 | You would need something like this to connect more than two modems to | ||
202 | your Linux box, for instance in order to become a dial-in server. | ||
203 | |||
204 | For information about the Cyclades-Z card, read | ||
205 | <file:Documentation/serial/README.cycladesZ>. | ||
206 | |||
207 | To compile this driver as a module, choose M here: the | ||
208 | module will be called cyclades. | ||
209 | |||
210 | If you haven't heard about it, it's safe to say N. | ||
211 | |||
212 | config CYZ_INTR | ||
213 | bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)" | ||
214 | depends on EXPERIMENTAL && CYCLADES | ||
215 | help | ||
216 | The Cyclades-Z family of multiport cards allows 2 (two) driver op | ||
217 | modes: polling and interrupt. In polling mode, the driver will check | ||
218 | the status of the Cyclades-Z ports every certain amount of time | ||
219 | (which is called polling cycle and is configurable). In interrupt | ||
220 | mode, it will use an interrupt line (IRQ) in order to check the | ||
221 | status of the Cyclades-Z ports. The default op mode is polling. If | ||
222 | unsure, say N. | ||
223 | |||
224 | config MOXA_INTELLIO | ||
225 | tristate "Moxa Intellio support" | ||
226 | depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) | ||
227 | select FW_LOADER | ||
228 | help | ||
229 | Say Y here if you have a Moxa Intellio multiport serial card. | ||
230 | |||
231 | To compile this driver as a module, choose M here: the | ||
232 | module will be called moxa. | ||
233 | |||
234 | config MOXA_SMARTIO | ||
235 | tristate "Moxa SmartIO support v. 2.0" | ||
236 | depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) | ||
237 | help | ||
238 | Say Y here if you have a Moxa SmartIO multiport serial card and/or | ||
239 | want to help develop a new version of this driver. | ||
240 | |||
241 | This is upgraded (1.9.1) driver from original Moxa drivers with | ||
242 | changes finally resulting in PCI probing. | ||
243 | |||
244 | This driver can also be built as a module. The module will be called | ||
245 | mxser. If you want to do that, say M here. | ||
246 | |||
247 | config SYNCLINK | ||
248 | tristate "Microgate SyncLink card support" | ||
249 | depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API | ||
250 | help | ||
251 | Provides support for the SyncLink ISA and PCI multiprotocol serial | ||
252 | adapters. These adapters support asynchronous and HDLC bit | ||
253 | synchronous communication up to 10Mbps (PCI adapter). | ||
254 | |||
255 | This driver can only be built as a module ( = code which can be | ||
256 | inserted in and removed from the running kernel whenever you want). | ||
257 | The module will be called synclink. If you want to do that, say M | ||
258 | here. | ||
259 | |||
260 | config SYNCLINKMP | ||
261 | tristate "SyncLink Multiport support" | ||
262 | depends on SERIAL_NONSTANDARD && PCI | ||
263 | help | ||
264 | Enable support for the SyncLink Multiport (2 or 4 ports) | ||
265 | serial adapter, running asynchronous and HDLC communications up | ||
266 | to 2.048Mbps. Each ports is independently selectable for | ||
267 | RS-232, V.35, RS-449, RS-530, and X.21 | ||
268 | |||
269 | This driver may be built as a module ( = code which can be | ||
270 | inserted in and removed from the running kernel whenever you want). | ||
271 | The module will be called synclinkmp. If you want to do that, say M | ||
272 | here. | ||
273 | |||
274 | config SYNCLINK_GT | ||
275 | tristate "SyncLink GT/AC support" | ||
276 | depends on SERIAL_NONSTANDARD && PCI | ||
277 | help | ||
278 | Support for SyncLink GT and SyncLink AC families of | ||
279 | synchronous and asynchronous serial adapters | ||
280 | manufactured by Microgate Systems, Ltd. (www.microgate.com) | ||
281 | |||
282 | config NOZOMI | ||
283 | tristate "HSDPA Broadband Wireless Data Card - Globe Trotter" | ||
284 | depends on PCI && EXPERIMENTAL | ||
285 | help | ||
286 | If you have a HSDPA driver Broadband Wireless Data Card - | ||
287 | Globe Trotter PCMCIA card, say Y here. | ||
288 | |||
289 | To compile this driver as a module, choose M here, the module | ||
290 | will be called nozomi. | ||
291 | |||
292 | config ISI | ||
293 | tristate "Multi-Tech multiport card support (EXPERIMENTAL)" | ||
294 | depends on SERIAL_NONSTANDARD && PCI | ||
295 | select FW_LOADER | ||
296 | help | ||
297 | This is a driver for the Multi-Tech cards which provide several | ||
298 | serial ports. The driver is experimental and can currently only be | ||
299 | built as a module. The module will be called isicom. | ||
300 | If you want to do that, choose M here. | ||
301 | |||
302 | config N_HDLC | ||
303 | tristate "HDLC line discipline support" | ||
304 | depends on SERIAL_NONSTANDARD | ||
305 | help | ||
306 | Allows synchronous HDLC communications with tty device drivers that | ||
307 | support synchronous HDLC such as the Microgate SyncLink adapter. | ||
308 | |||
309 | This driver can be built as a module ( = code which can be | ||
310 | inserted in and removed from the running kernel whenever you want). | ||
311 | The module will be called n_hdlc. If you want to do that, say M | ||
312 | here. | ||
313 | |||
314 | config N_GSM | ||
315 | tristate "GSM MUX line discipline support (EXPERIMENTAL)" | ||
316 | depends on EXPERIMENTAL | ||
317 | depends on NET | ||
318 | help | ||
319 | This line discipline provides support for the GSM MUX protocol and | ||
320 | presents the mux as a set of 61 individual tty devices. | ||
321 | |||
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 396277216e4f..690522fcb338 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile | |||
@@ -11,3 +11,18 @@ obj-$(CONFIG_R3964) += n_r3964.o | |||
11 | obj-y += vt/ | 11 | obj-y += vt/ |
12 | obj-$(CONFIG_HVC_DRIVER) += hvc/ | 12 | obj-$(CONFIG_HVC_DRIVER) += hvc/ |
13 | obj-y += serial/ | 13 | obj-y += serial/ |
14 | |||
15 | # tty drivers | ||
16 | obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o | ||
17 | obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o | ||
18 | obj-$(CONFIG_CYCLADES) += cyclades.o | ||
19 | obj-$(CONFIG_ISI) += isicom.o | ||
20 | obj-$(CONFIG_MOXA_INTELLIO) += moxa.o | ||
21 | obj-$(CONFIG_MOXA_SMARTIO) += mxser.o | ||
22 | obj-$(CONFIG_NOZOMI) += nozomi.o | ||
23 | obj-$(CONFIG_ROCKETPORT) += rocket.o | ||
24 | obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o | ||
25 | obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o | ||
26 | obj-$(CONFIG_SYNCLINK) += synclink.o | ||
27 | |||
28 | obj-y += ipwireless/ | ||
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c new file mode 100644 index 000000000000..f214e5022472 --- /dev/null +++ b/drivers/tty/amiserial.c | |||
@@ -0,0 +1,2178 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/amiserial.c | ||
3 | * | ||
4 | * Serial driver for the amiga builtin port. | ||
5 | * | ||
6 | * This code was created by taking serial.c version 4.30 from kernel | ||
7 | * release 2.3.22, replacing all hardware related stuff with the | ||
8 | * corresponding amiga hardware actions, and removing all irrelevant | ||
9 | * code. As a consequence, it uses many of the constants and names | ||
10 | * associated with the registers and bits of 16550 compatible UARTS - | ||
11 | * but only to keep track of status, etc in the state variables. It | ||
12 | * was done this was to make it easier to keep the code in line with | ||
13 | * (non hardware specific) changes to serial.c. | ||
14 | * | ||
15 | * The port is registered with the tty driver as minor device 64, and | ||
16 | * therefore other ports should should only use 65 upwards. | ||
17 | * | ||
18 | * Richard Lucock 28/12/99 | ||
19 | * | ||
20 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
21 | * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, | ||
22 | * 1998, 1999 Theodore Ts'o | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Serial driver configuration section. Here are the various options: | ||
28 | * | ||
29 | * SERIAL_PARANOIA_CHECK | ||
30 | * Check the magic number for the async_structure where | ||
31 | * ever possible. | ||
32 | */ | ||
33 | |||
34 | #include <linux/delay.h> | ||
35 | |||
36 | #undef SERIAL_PARANOIA_CHECK | ||
37 | #define SERIAL_DO_RESTART | ||
38 | |||
39 | /* Set of debugging defines */ | ||
40 | |||
41 | #undef SERIAL_DEBUG_INTR | ||
42 | #undef SERIAL_DEBUG_OPEN | ||
43 | #undef SERIAL_DEBUG_FLOW | ||
44 | #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
45 | |||
46 | /* Sanity checks */ | ||
47 | |||
48 | #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) | ||
49 | #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ | ||
50 | tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) | ||
51 | #else | ||
52 | #define DBG_CNT(s) | ||
53 | #endif | ||
54 | |||
55 | /* | ||
56 | * End of serial driver configuration section. | ||
57 | */ | ||
58 | |||
59 | #include <linux/module.h> | ||
60 | |||
61 | #include <linux/types.h> | ||
62 | #include <linux/serial.h> | ||
63 | #include <linux/serialP.h> | ||
64 | #include <linux/serial_reg.h> | ||
65 | static char *serial_version = "4.30"; | ||
66 | |||
67 | #include <linux/errno.h> | ||
68 | #include <linux/signal.h> | ||
69 | #include <linux/sched.h> | ||
70 | #include <linux/kernel.h> | ||
71 | #include <linux/timer.h> | ||
72 | #include <linux/interrupt.h> | ||
73 | #include <linux/tty.h> | ||
74 | #include <linux/tty_flip.h> | ||
75 | #include <linux/console.h> | ||
76 | #include <linux/major.h> | ||
77 | #include <linux/string.h> | ||
78 | #include <linux/fcntl.h> | ||
79 | #include <linux/ptrace.h> | ||
80 | #include <linux/ioport.h> | ||
81 | #include <linux/mm.h> | ||
82 | #include <linux/seq_file.h> | ||
83 | #include <linux/slab.h> | ||
84 | #include <linux/init.h> | ||
85 | #include <linux/bitops.h> | ||
86 | #include <linux/platform_device.h> | ||
87 | |||
88 | #include <asm/setup.h> | ||
89 | |||
90 | #include <asm/system.h> | ||
91 | |||
92 | #include <asm/irq.h> | ||
93 | |||
94 | #include <asm/amigahw.h> | ||
95 | #include <asm/amigaints.h> | ||
96 | |||
97 | #define custom amiga_custom | ||
98 | static char *serial_name = "Amiga-builtin serial driver"; | ||
99 | |||
100 | static struct tty_driver *serial_driver; | ||
101 | |||
102 | /* number of characters left in xmit buffer before we ask for more */ | ||
103 | #define WAKEUP_CHARS 256 | ||
104 | |||
105 | static struct async_struct *IRQ_ports; | ||
106 | |||
107 | static unsigned char current_ctl_bits; | ||
108 | |||
109 | static void change_speed(struct async_struct *info, struct ktermios *old); | ||
110 | static void rs_wait_until_sent(struct tty_struct *tty, int timeout); | ||
111 | |||
112 | |||
113 | static struct serial_state rs_table[1]; | ||
114 | |||
115 | #define NR_PORTS ARRAY_SIZE(rs_table) | ||
116 | |||
117 | #include <asm/uaccess.h> | ||
118 | |||
119 | #define serial_isroot() (capable(CAP_SYS_ADMIN)) | ||
120 | |||
121 | |||
122 | static inline int serial_paranoia_check(struct async_struct *info, | ||
123 | char *name, const char *routine) | ||
124 | { | ||
125 | #ifdef SERIAL_PARANOIA_CHECK | ||
126 | static const char *badmagic = | ||
127 | "Warning: bad magic number for serial struct (%s) in %s\n"; | ||
128 | static const char *badinfo = | ||
129 | "Warning: null async_struct for (%s) in %s\n"; | ||
130 | |||
131 | if (!info) { | ||
132 | printk(badinfo, name, routine); | ||
133 | return 1; | ||
134 | } | ||
135 | if (info->magic != SERIAL_MAGIC) { | ||
136 | printk(badmagic, name, routine); | ||
137 | return 1; | ||
138 | } | ||
139 | #endif | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* some serial hardware definitions */ | ||
144 | #define SDR_OVRUN (1<<15) | ||
145 | #define SDR_RBF (1<<14) | ||
146 | #define SDR_TBE (1<<13) | ||
147 | #define SDR_TSRE (1<<12) | ||
148 | |||
149 | #define SERPER_PARENB (1<<15) | ||
150 | |||
151 | #define AC_SETCLR (1<<15) | ||
152 | #define AC_UARTBRK (1<<11) | ||
153 | |||
154 | #define SER_DTR (1<<7) | ||
155 | #define SER_RTS (1<<6) | ||
156 | #define SER_DCD (1<<5) | ||
157 | #define SER_CTS (1<<4) | ||
158 | #define SER_DSR (1<<3) | ||
159 | |||
160 | static __inline__ void rtsdtr_ctrl(int bits) | ||
161 | { | ||
162 | ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR)); | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * ------------------------------------------------------------ | ||
167 | * rs_stop() and rs_start() | ||
168 | * | ||
169 | * This routines are called before setting or resetting tty->stopped. | ||
170 | * They enable or disable transmitter interrupts, as necessary. | ||
171 | * ------------------------------------------------------------ | ||
172 | */ | ||
173 | static void rs_stop(struct tty_struct *tty) | ||
174 | { | ||
175 | struct async_struct *info = tty->driver_data; | ||
176 | unsigned long flags; | ||
177 | |||
178 | if (serial_paranoia_check(info, tty->name, "rs_stop")) | ||
179 | return; | ||
180 | |||
181 | local_irq_save(flags); | ||
182 | if (info->IER & UART_IER_THRI) { | ||
183 | info->IER &= ~UART_IER_THRI; | ||
184 | /* disable Tx interrupt and remove any pending interrupts */ | ||
185 | custom.intena = IF_TBE; | ||
186 | mb(); | ||
187 | custom.intreq = IF_TBE; | ||
188 | mb(); | ||
189 | } | ||
190 | local_irq_restore(flags); | ||
191 | } | ||
192 | |||
193 | static void rs_start(struct tty_struct *tty) | ||
194 | { | ||
195 | struct async_struct *info = tty->driver_data; | ||
196 | unsigned long flags; | ||
197 | |||
198 | if (serial_paranoia_check(info, tty->name, "rs_start")) | ||
199 | return; | ||
200 | |||
201 | local_irq_save(flags); | ||
202 | if (info->xmit.head != info->xmit.tail | ||
203 | && info->xmit.buf | ||
204 | && !(info->IER & UART_IER_THRI)) { | ||
205 | info->IER |= UART_IER_THRI; | ||
206 | custom.intena = IF_SETCLR | IF_TBE; | ||
207 | mb(); | ||
208 | /* set a pending Tx Interrupt, transmitter should restart now */ | ||
209 | custom.intreq = IF_SETCLR | IF_TBE; | ||
210 | mb(); | ||
211 | } | ||
212 | local_irq_restore(flags); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * ---------------------------------------------------------------------- | ||
217 | * | ||
218 | * Here starts the interrupt handling routines. All of the following | ||
219 | * subroutines are declared as inline and are folded into | ||
220 | * rs_interrupt(). They were separated out for readability's sake. | ||
221 | * | ||
222 | * Note: rs_interrupt() is a "fast" interrupt, which means that it | ||
223 | * runs with interrupts turned off. People who may want to modify | ||
224 | * rs_interrupt() should try to keep the interrupt handler as fast as | ||
225 | * possible. After you are done making modifications, it is not a bad | ||
226 | * idea to do: | ||
227 | * | ||
228 | * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c | ||
229 | * | ||
230 | * and look at the resulting assemble code in serial.s. | ||
231 | * | ||
232 | * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 | ||
233 | * ----------------------------------------------------------------------- | ||
234 | */ | ||
235 | |||
236 | /* | ||
237 | * This routine is used by the interrupt handler to schedule | ||
238 | * processing in the software interrupt portion of the driver. | ||
239 | */ | ||
240 | static void rs_sched_event(struct async_struct *info, | ||
241 | int event) | ||
242 | { | ||
243 | info->event |= 1 << event; | ||
244 | tasklet_schedule(&info->tlet); | ||
245 | } | ||
246 | |||
247 | static void receive_chars(struct async_struct *info) | ||
248 | { | ||
249 | int status; | ||
250 | int serdatr; | ||
251 | struct tty_struct *tty = info->tty; | ||
252 | unsigned char ch, flag; | ||
253 | struct async_icount *icount; | ||
254 | int oe = 0; | ||
255 | |||
256 | icount = &info->state->icount; | ||
257 | |||
258 | status = UART_LSR_DR; /* We obviously have a character! */ | ||
259 | serdatr = custom.serdatr; | ||
260 | mb(); | ||
261 | custom.intreq = IF_RBF; | ||
262 | mb(); | ||
263 | |||
264 | if((serdatr & 0x1ff) == 0) | ||
265 | status |= UART_LSR_BI; | ||
266 | if(serdatr & SDR_OVRUN) | ||
267 | status |= UART_LSR_OE; | ||
268 | |||
269 | ch = serdatr & 0xff; | ||
270 | icount->rx++; | ||
271 | |||
272 | #ifdef SERIAL_DEBUG_INTR | ||
273 | printk("DR%02x:%02x...", ch, status); | ||
274 | #endif | ||
275 | flag = TTY_NORMAL; | ||
276 | |||
277 | /* | ||
278 | * We don't handle parity or frame errors - but I have left | ||
279 | * the code in, since I'm not sure that the errors can't be | ||
280 | * detected. | ||
281 | */ | ||
282 | |||
283 | if (status & (UART_LSR_BI | UART_LSR_PE | | ||
284 | UART_LSR_FE | UART_LSR_OE)) { | ||
285 | /* | ||
286 | * For statistics only | ||
287 | */ | ||
288 | if (status & UART_LSR_BI) { | ||
289 | status &= ~(UART_LSR_FE | UART_LSR_PE); | ||
290 | icount->brk++; | ||
291 | } else if (status & UART_LSR_PE) | ||
292 | icount->parity++; | ||
293 | else if (status & UART_LSR_FE) | ||
294 | icount->frame++; | ||
295 | if (status & UART_LSR_OE) | ||
296 | icount->overrun++; | ||
297 | |||
298 | /* | ||
299 | * Now check to see if character should be | ||
300 | * ignored, and mask off conditions which | ||
301 | * should be ignored. | ||
302 | */ | ||
303 | if (status & info->ignore_status_mask) | ||
304 | goto out; | ||
305 | |||
306 | status &= info->read_status_mask; | ||
307 | |||
308 | if (status & (UART_LSR_BI)) { | ||
309 | #ifdef SERIAL_DEBUG_INTR | ||
310 | printk("handling break...."); | ||
311 | #endif | ||
312 | flag = TTY_BREAK; | ||
313 | if (info->flags & ASYNC_SAK) | ||
314 | do_SAK(tty); | ||
315 | } else if (status & UART_LSR_PE) | ||
316 | flag = TTY_PARITY; | ||
317 | else if (status & UART_LSR_FE) | ||
318 | flag = TTY_FRAME; | ||
319 | if (status & UART_LSR_OE) { | ||
320 | /* | ||
321 | * Overrun is special, since it's | ||
322 | * reported immediately, and doesn't | ||
323 | * affect the current character | ||
324 | */ | ||
325 | oe = 1; | ||
326 | } | ||
327 | } | ||
328 | tty_insert_flip_char(tty, ch, flag); | ||
329 | if (oe == 1) | ||
330 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
331 | tty_flip_buffer_push(tty); | ||
332 | out: | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | static void transmit_chars(struct async_struct *info) | ||
337 | { | ||
338 | custom.intreq = IF_TBE; | ||
339 | mb(); | ||
340 | if (info->x_char) { | ||
341 | custom.serdat = info->x_char | 0x100; | ||
342 | mb(); | ||
343 | info->state->icount.tx++; | ||
344 | info->x_char = 0; | ||
345 | return; | ||
346 | } | ||
347 | if (info->xmit.head == info->xmit.tail | ||
348 | || info->tty->stopped | ||
349 | || info->tty->hw_stopped) { | ||
350 | info->IER &= ~UART_IER_THRI; | ||
351 | custom.intena = IF_TBE; | ||
352 | mb(); | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; | ||
357 | mb(); | ||
358 | info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); | ||
359 | info->state->icount.tx++; | ||
360 | |||
361 | if (CIRC_CNT(info->xmit.head, | ||
362 | info->xmit.tail, | ||
363 | SERIAL_XMIT_SIZE) < WAKEUP_CHARS) | ||
364 | rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); | ||
365 | |||
366 | #ifdef SERIAL_DEBUG_INTR | ||
367 | printk("THRE..."); | ||
368 | #endif | ||
369 | if (info->xmit.head == info->xmit.tail) { | ||
370 | custom.intena = IF_TBE; | ||
371 | mb(); | ||
372 | info->IER &= ~UART_IER_THRI; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | static void check_modem_status(struct async_struct *info) | ||
377 | { | ||
378 | unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); | ||
379 | unsigned char dstatus; | ||
380 | struct async_icount *icount; | ||
381 | |||
382 | /* Determine bits that have changed */ | ||
383 | dstatus = status ^ current_ctl_bits; | ||
384 | current_ctl_bits = status; | ||
385 | |||
386 | if (dstatus) { | ||
387 | icount = &info->state->icount; | ||
388 | /* update input line counters */ | ||
389 | if (dstatus & SER_DSR) | ||
390 | icount->dsr++; | ||
391 | if (dstatus & SER_DCD) { | ||
392 | icount->dcd++; | ||
393 | #ifdef CONFIG_HARD_PPS | ||
394 | if ((info->flags & ASYNC_HARDPPS_CD) && | ||
395 | !(status & SER_DCD)) | ||
396 | hardpps(); | ||
397 | #endif | ||
398 | } | ||
399 | if (dstatus & SER_CTS) | ||
400 | icount->cts++; | ||
401 | wake_up_interruptible(&info->delta_msr_wait); | ||
402 | } | ||
403 | |||
404 | if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { | ||
405 | #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) | ||
406 | printk("ttyS%d CD now %s...", info->line, | ||
407 | (!(status & SER_DCD)) ? "on" : "off"); | ||
408 | #endif | ||
409 | if (!(status & SER_DCD)) | ||
410 | wake_up_interruptible(&info->open_wait); | ||
411 | else { | ||
412 | #ifdef SERIAL_DEBUG_OPEN | ||
413 | printk("doing serial hangup..."); | ||
414 | #endif | ||
415 | if (info->tty) | ||
416 | tty_hangup(info->tty); | ||
417 | } | ||
418 | } | ||
419 | if (info->flags & ASYNC_CTS_FLOW) { | ||
420 | if (info->tty->hw_stopped) { | ||
421 | if (!(status & SER_CTS)) { | ||
422 | #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) | ||
423 | printk("CTS tx start..."); | ||
424 | #endif | ||
425 | info->tty->hw_stopped = 0; | ||
426 | info->IER |= UART_IER_THRI; | ||
427 | custom.intena = IF_SETCLR | IF_TBE; | ||
428 | mb(); | ||
429 | /* set a pending Tx Interrupt, transmitter should restart now */ | ||
430 | custom.intreq = IF_SETCLR | IF_TBE; | ||
431 | mb(); | ||
432 | rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); | ||
433 | return; | ||
434 | } | ||
435 | } else { | ||
436 | if ((status & SER_CTS)) { | ||
437 | #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) | ||
438 | printk("CTS tx stop..."); | ||
439 | #endif | ||
440 | info->tty->hw_stopped = 1; | ||
441 | info->IER &= ~UART_IER_THRI; | ||
442 | /* disable Tx interrupt and remove any pending interrupts */ | ||
443 | custom.intena = IF_TBE; | ||
444 | mb(); | ||
445 | custom.intreq = IF_TBE; | ||
446 | mb(); | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static irqreturn_t ser_vbl_int( int irq, void *data) | ||
453 | { | ||
454 | /* vbl is just a periodic interrupt we tie into to update modem status */ | ||
455 | struct async_struct * info = IRQ_ports; | ||
456 | /* | ||
457 | * TBD - is it better to unregister from this interrupt or to | ||
458 | * ignore it if MSI is clear ? | ||
459 | */ | ||
460 | if(info->IER & UART_IER_MSI) | ||
461 | check_modem_status(info); | ||
462 | return IRQ_HANDLED; | ||
463 | } | ||
464 | |||
465 | static irqreturn_t ser_rx_int(int irq, void *dev_id) | ||
466 | { | ||
467 | struct async_struct * info; | ||
468 | |||
469 | #ifdef SERIAL_DEBUG_INTR | ||
470 | printk("ser_rx_int..."); | ||
471 | #endif | ||
472 | |||
473 | info = IRQ_ports; | ||
474 | if (!info || !info->tty) | ||
475 | return IRQ_NONE; | ||
476 | |||
477 | receive_chars(info); | ||
478 | info->last_active = jiffies; | ||
479 | #ifdef SERIAL_DEBUG_INTR | ||
480 | printk("end.\n"); | ||
481 | #endif | ||
482 | return IRQ_HANDLED; | ||
483 | } | ||
484 | |||
485 | static irqreturn_t ser_tx_int(int irq, void *dev_id) | ||
486 | { | ||
487 | struct async_struct * info; | ||
488 | |||
489 | if (custom.serdatr & SDR_TBE) { | ||
490 | #ifdef SERIAL_DEBUG_INTR | ||
491 | printk("ser_tx_int..."); | ||
492 | #endif | ||
493 | |||
494 | info = IRQ_ports; | ||
495 | if (!info || !info->tty) | ||
496 | return IRQ_NONE; | ||
497 | |||
498 | transmit_chars(info); | ||
499 | info->last_active = jiffies; | ||
500 | #ifdef SERIAL_DEBUG_INTR | ||
501 | printk("end.\n"); | ||
502 | #endif | ||
503 | } | ||
504 | return IRQ_HANDLED; | ||
505 | } | ||
506 | |||
507 | /* | ||
508 | * ------------------------------------------------------------------- | ||
509 | * Here ends the serial interrupt routines. | ||
510 | * ------------------------------------------------------------------- | ||
511 | */ | ||
512 | |||
513 | /* | ||
514 | * This routine is used to handle the "bottom half" processing for the | ||
515 | * serial driver, known also the "software interrupt" processing. | ||
516 | * This processing is done at the kernel interrupt level, after the | ||
517 | * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This | ||
518 | * is where time-consuming activities which can not be done in the | ||
519 | * interrupt driver proper are done; the interrupt driver schedules | ||
520 | * them using rs_sched_event(), and they get done here. | ||
521 | */ | ||
522 | |||
523 | static void do_softint(unsigned long private_) | ||
524 | { | ||
525 | struct async_struct *info = (struct async_struct *) private_; | ||
526 | struct tty_struct *tty; | ||
527 | |||
528 | tty = info->tty; | ||
529 | if (!tty) | ||
530 | return; | ||
531 | |||
532 | if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) | ||
533 | tty_wakeup(tty); | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | * --------------------------------------------------------------- | ||
538 | * Low level utility subroutines for the serial driver: routines to | ||
539 | * figure out the appropriate timeout for an interrupt chain, routines | ||
540 | * to initialize and startup a serial port, and routines to shutdown a | ||
541 | * serial port. Useful stuff like that. | ||
542 | * --------------------------------------------------------------- | ||
543 | */ | ||
544 | |||
545 | static int startup(struct async_struct * info) | ||
546 | { | ||
547 | unsigned long flags; | ||
548 | int retval=0; | ||
549 | unsigned long page; | ||
550 | |||
551 | page = get_zeroed_page(GFP_KERNEL); | ||
552 | if (!page) | ||
553 | return -ENOMEM; | ||
554 | |||
555 | local_irq_save(flags); | ||
556 | |||
557 | if (info->flags & ASYNC_INITIALIZED) { | ||
558 | free_page(page); | ||
559 | goto errout; | ||
560 | } | ||
561 | |||
562 | if (info->xmit.buf) | ||
563 | free_page(page); | ||
564 | else | ||
565 | info->xmit.buf = (unsigned char *) page; | ||
566 | |||
567 | #ifdef SERIAL_DEBUG_OPEN | ||
568 | printk("starting up ttys%d ...", info->line); | ||
569 | #endif | ||
570 | |||
571 | /* Clear anything in the input buffer */ | ||
572 | |||
573 | custom.intreq = IF_RBF; | ||
574 | mb(); | ||
575 | |||
576 | retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); | ||
577 | if (retval) { | ||
578 | if (serial_isroot()) { | ||
579 | if (info->tty) | ||
580 | set_bit(TTY_IO_ERROR, | ||
581 | &info->tty->flags); | ||
582 | retval = 0; | ||
583 | } | ||
584 | goto errout; | ||
585 | } | ||
586 | |||
587 | /* enable both Rx and Tx interrupts */ | ||
588 | custom.intena = IF_SETCLR | IF_RBF | IF_TBE; | ||
589 | mb(); | ||
590 | info->IER = UART_IER_MSI; | ||
591 | |||
592 | /* remember current state of the DCD and CTS bits */ | ||
593 | current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); | ||
594 | |||
595 | IRQ_ports = info; | ||
596 | |||
597 | info->MCR = 0; | ||
598 | if (info->tty->termios->c_cflag & CBAUD) | ||
599 | info->MCR = SER_DTR | SER_RTS; | ||
600 | rtsdtr_ctrl(info->MCR); | ||
601 | |||
602 | if (info->tty) | ||
603 | clear_bit(TTY_IO_ERROR, &info->tty->flags); | ||
604 | info->xmit.head = info->xmit.tail = 0; | ||
605 | |||
606 | /* | ||
607 | * Set up the tty->alt_speed kludge | ||
608 | */ | ||
609 | if (info->tty) { | ||
610 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
611 | info->tty->alt_speed = 57600; | ||
612 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
613 | info->tty->alt_speed = 115200; | ||
614 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | ||
615 | info->tty->alt_speed = 230400; | ||
616 | if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | ||
617 | info->tty->alt_speed = 460800; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * and set the speed of the serial port | ||
622 | */ | ||
623 | change_speed(info, NULL); | ||
624 | |||
625 | info->flags |= ASYNC_INITIALIZED; | ||
626 | local_irq_restore(flags); | ||
627 | return 0; | ||
628 | |||
629 | errout: | ||
630 | local_irq_restore(flags); | ||
631 | return retval; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * This routine will shutdown a serial port; interrupts are disabled, and | ||
636 | * DTR is dropped if the hangup on close termio flag is on. | ||
637 | */ | ||
638 | static void shutdown(struct async_struct * info) | ||
639 | { | ||
640 | unsigned long flags; | ||
641 | struct serial_state *state; | ||
642 | |||
643 | if (!(info->flags & ASYNC_INITIALIZED)) | ||
644 | return; | ||
645 | |||
646 | state = info->state; | ||
647 | |||
648 | #ifdef SERIAL_DEBUG_OPEN | ||
649 | printk("Shutting down serial port %d ....\n", info->line); | ||
650 | #endif | ||
651 | |||
652 | local_irq_save(flags); /* Disable interrupts */ | ||
653 | |||
654 | /* | ||
655 | * clear delta_msr_wait queue to avoid mem leaks: we may free the irq | ||
656 | * here so the queue might never be waken up | ||
657 | */ | ||
658 | wake_up_interruptible(&info->delta_msr_wait); | ||
659 | |||
660 | IRQ_ports = NULL; | ||
661 | |||
662 | /* | ||
663 | * Free the IRQ, if necessary | ||
664 | */ | ||
665 | free_irq(IRQ_AMIGA_VERTB, info); | ||
666 | |||
667 | if (info->xmit.buf) { | ||
668 | free_page((unsigned long) info->xmit.buf); | ||
669 | info->xmit.buf = NULL; | ||
670 | } | ||
671 | |||
672 | info->IER = 0; | ||
673 | custom.intena = IF_RBF | IF_TBE; | ||
674 | mb(); | ||
675 | |||
676 | /* disable break condition */ | ||
677 | custom.adkcon = AC_UARTBRK; | ||
678 | mb(); | ||
679 | |||
680 | if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) | ||
681 | info->MCR &= ~(SER_DTR|SER_RTS); | ||
682 | rtsdtr_ctrl(info->MCR); | ||
683 | |||
684 | if (info->tty) | ||
685 | set_bit(TTY_IO_ERROR, &info->tty->flags); | ||
686 | |||
687 | info->flags &= ~ASYNC_INITIALIZED; | ||
688 | local_irq_restore(flags); | ||
689 | } | ||
690 | |||
691 | |||
692 | /* | ||
693 | * This routine is called to set the UART divisor registers to match | ||
694 | * the specified baud rate for a serial port. | ||
695 | */ | ||
696 | static void change_speed(struct async_struct *info, | ||
697 | struct ktermios *old_termios) | ||
698 | { | ||
699 | int quot = 0, baud_base, baud; | ||
700 | unsigned cflag, cval = 0; | ||
701 | int bits; | ||
702 | unsigned long flags; | ||
703 | |||
704 | if (!info->tty || !info->tty->termios) | ||
705 | return; | ||
706 | cflag = info->tty->termios->c_cflag; | ||
707 | |||
708 | /* Byte size is always 8 bits plus parity bit if requested */ | ||
709 | |||
710 | cval = 3; bits = 10; | ||
711 | if (cflag & CSTOPB) { | ||
712 | cval |= 0x04; | ||
713 | bits++; | ||
714 | } | ||
715 | if (cflag & PARENB) { | ||
716 | cval |= UART_LCR_PARITY; | ||
717 | bits++; | ||
718 | } | ||
719 | if (!(cflag & PARODD)) | ||
720 | cval |= UART_LCR_EPAR; | ||
721 | #ifdef CMSPAR | ||
722 | if (cflag & CMSPAR) | ||
723 | cval |= UART_LCR_SPAR; | ||
724 | #endif | ||
725 | |||
726 | /* Determine divisor based on baud rate */ | ||
727 | baud = tty_get_baud_rate(info->tty); | ||
728 | if (!baud) | ||
729 | baud = 9600; /* B0 transition handled in rs_set_termios */ | ||
730 | baud_base = info->state->baud_base; | ||
731 | if (baud == 38400 && | ||
732 | ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) | ||
733 | quot = info->state->custom_divisor; | ||
734 | else { | ||
735 | if (baud == 134) | ||
736 | /* Special case since 134 is really 134.5 */ | ||
737 | quot = (2*baud_base / 269); | ||
738 | else if (baud) | ||
739 | quot = baud_base / baud; | ||
740 | } | ||
741 | /* If the quotient is zero refuse the change */ | ||
742 | if (!quot && old_termios) { | ||
743 | /* FIXME: Will need updating for new tty in the end */ | ||
744 | info->tty->termios->c_cflag &= ~CBAUD; | ||
745 | info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); | ||
746 | baud = tty_get_baud_rate(info->tty); | ||
747 | if (!baud) | ||
748 | baud = 9600; | ||
749 | if (baud == 38400 && | ||
750 | ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) | ||
751 | quot = info->state->custom_divisor; | ||
752 | else { | ||
753 | if (baud == 134) | ||
754 | /* Special case since 134 is really 134.5 */ | ||
755 | quot = (2*baud_base / 269); | ||
756 | else if (baud) | ||
757 | quot = baud_base / baud; | ||
758 | } | ||
759 | } | ||
760 | /* As a last resort, if the quotient is zero, default to 9600 bps */ | ||
761 | if (!quot) | ||
762 | quot = baud_base / 9600; | ||
763 | info->quot = quot; | ||
764 | info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); | ||
765 | info->timeout += HZ/50; /* Add .02 seconds of slop */ | ||
766 | |||
767 | /* CTS flow control flag and modem status interrupts */ | ||
768 | info->IER &= ~UART_IER_MSI; | ||
769 | if (info->flags & ASYNC_HARDPPS_CD) | ||
770 | info->IER |= UART_IER_MSI; | ||
771 | if (cflag & CRTSCTS) { | ||
772 | info->flags |= ASYNC_CTS_FLOW; | ||
773 | info->IER |= UART_IER_MSI; | ||
774 | } else | ||
775 | info->flags &= ~ASYNC_CTS_FLOW; | ||
776 | if (cflag & CLOCAL) | ||
777 | info->flags &= ~ASYNC_CHECK_CD; | ||
778 | else { | ||
779 | info->flags |= ASYNC_CHECK_CD; | ||
780 | info->IER |= UART_IER_MSI; | ||
781 | } | ||
782 | /* TBD: | ||
783 | * Does clearing IER_MSI imply that we should disable the VBL interrupt ? | ||
784 | */ | ||
785 | |||
786 | /* | ||
787 | * Set up parity check flag | ||
788 | */ | ||
789 | |||
790 | info->read_status_mask = UART_LSR_OE | UART_LSR_DR; | ||
791 | if (I_INPCK(info->tty)) | ||
792 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; | ||
793 | if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) | ||
794 | info->read_status_mask |= UART_LSR_BI; | ||
795 | |||
796 | /* | ||
797 | * Characters to ignore | ||
798 | */ | ||
799 | info->ignore_status_mask = 0; | ||
800 | if (I_IGNPAR(info->tty)) | ||
801 | info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; | ||
802 | if (I_IGNBRK(info->tty)) { | ||
803 | info->ignore_status_mask |= UART_LSR_BI; | ||
804 | /* | ||
805 | * If we're ignore parity and break indicators, ignore | ||
806 | * overruns too. (For real raw support). | ||
807 | */ | ||
808 | if (I_IGNPAR(info->tty)) | ||
809 | info->ignore_status_mask |= UART_LSR_OE; | ||
810 | } | ||
811 | /* | ||
812 | * !!! ignore all characters if CREAD is not set | ||
813 | */ | ||
814 | if ((cflag & CREAD) == 0) | ||
815 | info->ignore_status_mask |= UART_LSR_DR; | ||
816 | local_irq_save(flags); | ||
817 | |||
818 | { | ||
819 | short serper; | ||
820 | |||
821 | /* Set up the baud rate */ | ||
822 | serper = quot - 1; | ||
823 | |||
824 | /* Enable or disable parity bit */ | ||
825 | |||
826 | if(cval & UART_LCR_PARITY) | ||
827 | serper |= (SERPER_PARENB); | ||
828 | |||
829 | custom.serper = serper; | ||
830 | mb(); | ||
831 | } | ||
832 | |||
833 | info->LCR = cval; /* Save LCR */ | ||
834 | local_irq_restore(flags); | ||
835 | } | ||
836 | |||
837 | static int rs_put_char(struct tty_struct *tty, unsigned char ch) | ||
838 | { | ||
839 | struct async_struct *info; | ||
840 | unsigned long flags; | ||
841 | |||
842 | info = tty->driver_data; | ||
843 | |||
844 | if (serial_paranoia_check(info, tty->name, "rs_put_char")) | ||
845 | return 0; | ||
846 | |||
847 | if (!info->xmit.buf) | ||
848 | return 0; | ||
849 | |||
850 | local_irq_save(flags); | ||
851 | if (CIRC_SPACE(info->xmit.head, | ||
852 | info->xmit.tail, | ||
853 | SERIAL_XMIT_SIZE) == 0) { | ||
854 | local_irq_restore(flags); | ||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | info->xmit.buf[info->xmit.head++] = ch; | ||
859 | info->xmit.head &= SERIAL_XMIT_SIZE-1; | ||
860 | local_irq_restore(flags); | ||
861 | return 1; | ||
862 | } | ||
863 | |||
864 | static void rs_flush_chars(struct tty_struct *tty) | ||
865 | { | ||
866 | struct async_struct *info = tty->driver_data; | ||
867 | unsigned long flags; | ||
868 | |||
869 | if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) | ||
870 | return; | ||
871 | |||
872 | if (info->xmit.head == info->xmit.tail | ||
873 | || tty->stopped | ||
874 | || tty->hw_stopped | ||
875 | || !info->xmit.buf) | ||
876 | return; | ||
877 | |||
878 | local_irq_save(flags); | ||
879 | info->IER |= UART_IER_THRI; | ||
880 | custom.intena = IF_SETCLR | IF_TBE; | ||
881 | mb(); | ||
882 | /* set a pending Tx Interrupt, transmitter should restart now */ | ||
883 | custom.intreq = IF_SETCLR | IF_TBE; | ||
884 | mb(); | ||
885 | local_irq_restore(flags); | ||
886 | } | ||
887 | |||
888 | static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) | ||
889 | { | ||
890 | int c, ret = 0; | ||
891 | struct async_struct *info; | ||
892 | unsigned long flags; | ||
893 | |||
894 | info = tty->driver_data; | ||
895 | |||
896 | if (serial_paranoia_check(info, tty->name, "rs_write")) | ||
897 | return 0; | ||
898 | |||
899 | if (!info->xmit.buf) | ||
900 | return 0; | ||
901 | |||
902 | local_irq_save(flags); | ||
903 | while (1) { | ||
904 | c = CIRC_SPACE_TO_END(info->xmit.head, | ||
905 | info->xmit.tail, | ||
906 | SERIAL_XMIT_SIZE); | ||
907 | if (count < c) | ||
908 | c = count; | ||
909 | if (c <= 0) { | ||
910 | break; | ||
911 | } | ||
912 | memcpy(info->xmit.buf + info->xmit.head, buf, c); | ||
913 | info->xmit.head = ((info->xmit.head + c) & | ||
914 | (SERIAL_XMIT_SIZE-1)); | ||
915 | buf += c; | ||
916 | count -= c; | ||
917 | ret += c; | ||
918 | } | ||
919 | local_irq_restore(flags); | ||
920 | |||
921 | if (info->xmit.head != info->xmit.tail | ||
922 | && !tty->stopped | ||
923 | && !tty->hw_stopped | ||
924 | && !(info->IER & UART_IER_THRI)) { | ||
925 | info->IER |= UART_IER_THRI; | ||
926 | local_irq_disable(); | ||
927 | custom.intena = IF_SETCLR | IF_TBE; | ||
928 | mb(); | ||
929 | /* set a pending Tx Interrupt, transmitter should restart now */ | ||
930 | custom.intreq = IF_SETCLR | IF_TBE; | ||
931 | mb(); | ||
932 | local_irq_restore(flags); | ||
933 | } | ||
934 | return ret; | ||
935 | } | ||
936 | |||
937 | static int rs_write_room(struct tty_struct *tty) | ||
938 | { | ||
939 | struct async_struct *info = tty->driver_data; | ||
940 | |||
941 | if (serial_paranoia_check(info, tty->name, "rs_write_room")) | ||
942 | return 0; | ||
943 | return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); | ||
944 | } | ||
945 | |||
946 | static int rs_chars_in_buffer(struct tty_struct *tty) | ||
947 | { | ||
948 | struct async_struct *info = tty->driver_data; | ||
949 | |||
950 | if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) | ||
951 | return 0; | ||
952 | return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); | ||
953 | } | ||
954 | |||
955 | static void rs_flush_buffer(struct tty_struct *tty) | ||
956 | { | ||
957 | struct async_struct *info = tty->driver_data; | ||
958 | unsigned long flags; | ||
959 | |||
960 | if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) | ||
961 | return; | ||
962 | local_irq_save(flags); | ||
963 | info->xmit.head = info->xmit.tail = 0; | ||
964 | local_irq_restore(flags); | ||
965 | tty_wakeup(tty); | ||
966 | } | ||
967 | |||
968 | /* | ||
969 | * This function is used to send a high-priority XON/XOFF character to | ||
970 | * the device | ||
971 | */ | ||
972 | static void rs_send_xchar(struct tty_struct *tty, char ch) | ||
973 | { | ||
974 | struct async_struct *info = tty->driver_data; | ||
975 | unsigned long flags; | ||
976 | |||
977 | if (serial_paranoia_check(info, tty->name, "rs_send_char")) | ||
978 | return; | ||
979 | |||
980 | info->x_char = ch; | ||
981 | if (ch) { | ||
982 | /* Make sure transmit interrupts are on */ | ||
983 | |||
984 | /* Check this ! */ | ||
985 | local_irq_save(flags); | ||
986 | if(!(custom.intenar & IF_TBE)) { | ||
987 | custom.intena = IF_SETCLR | IF_TBE; | ||
988 | mb(); | ||
989 | /* set a pending Tx Interrupt, transmitter should restart now */ | ||
990 | custom.intreq = IF_SETCLR | IF_TBE; | ||
991 | mb(); | ||
992 | } | ||
993 | local_irq_restore(flags); | ||
994 | |||
995 | info->IER |= UART_IER_THRI; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | /* | ||
1000 | * ------------------------------------------------------------ | ||
1001 | * rs_throttle() | ||
1002 | * | ||
1003 | * This routine is called by the upper-layer tty layer to signal that | ||
1004 | * incoming characters should be throttled. | ||
1005 | * ------------------------------------------------------------ | ||
1006 | */ | ||
1007 | static void rs_throttle(struct tty_struct * tty) | ||
1008 | { | ||
1009 | struct async_struct *info = tty->driver_data; | ||
1010 | unsigned long flags; | ||
1011 | #ifdef SERIAL_DEBUG_THROTTLE | ||
1012 | char buf[64]; | ||
1013 | |||
1014 | printk("throttle %s: %d....\n", tty_name(tty, buf), | ||
1015 | tty->ldisc.chars_in_buffer(tty)); | ||
1016 | #endif | ||
1017 | |||
1018 | if (serial_paranoia_check(info, tty->name, "rs_throttle")) | ||
1019 | return; | ||
1020 | |||
1021 | if (I_IXOFF(tty)) | ||
1022 | rs_send_xchar(tty, STOP_CHAR(tty)); | ||
1023 | |||
1024 | if (tty->termios->c_cflag & CRTSCTS) | ||
1025 | info->MCR &= ~SER_RTS; | ||
1026 | |||
1027 | local_irq_save(flags); | ||
1028 | rtsdtr_ctrl(info->MCR); | ||
1029 | local_irq_restore(flags); | ||
1030 | } | ||
1031 | |||
1032 | static void rs_unthrottle(struct tty_struct * tty) | ||
1033 | { | ||
1034 | struct async_struct *info = tty->driver_data; | ||
1035 | unsigned long flags; | ||
1036 | #ifdef SERIAL_DEBUG_THROTTLE | ||
1037 | char buf[64]; | ||
1038 | |||
1039 | printk("unthrottle %s: %d....\n", tty_name(tty, buf), | ||
1040 | tty->ldisc.chars_in_buffer(tty)); | ||
1041 | #endif | ||
1042 | |||
1043 | if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) | ||
1044 | return; | ||
1045 | |||
1046 | if (I_IXOFF(tty)) { | ||
1047 | if (info->x_char) | ||
1048 | info->x_char = 0; | ||
1049 | else | ||
1050 | rs_send_xchar(tty, START_CHAR(tty)); | ||
1051 | } | ||
1052 | if (tty->termios->c_cflag & CRTSCTS) | ||
1053 | info->MCR |= SER_RTS; | ||
1054 | local_irq_save(flags); | ||
1055 | rtsdtr_ctrl(info->MCR); | ||
1056 | local_irq_restore(flags); | ||
1057 | } | ||
1058 | |||
1059 | /* | ||
1060 | * ------------------------------------------------------------ | ||
1061 | * rs_ioctl() and friends | ||
1062 | * ------------------------------------------------------------ | ||
1063 | */ | ||
1064 | |||
1065 | static int get_serial_info(struct async_struct * info, | ||
1066 | struct serial_struct __user * retinfo) | ||
1067 | { | ||
1068 | struct serial_struct tmp; | ||
1069 | struct serial_state *state = info->state; | ||
1070 | |||
1071 | if (!retinfo) | ||
1072 | return -EFAULT; | ||
1073 | memset(&tmp, 0, sizeof(tmp)); | ||
1074 | tty_lock(); | ||
1075 | tmp.type = state->type; | ||
1076 | tmp.line = state->line; | ||
1077 | tmp.port = state->port; | ||
1078 | tmp.irq = state->irq; | ||
1079 | tmp.flags = state->flags; | ||
1080 | tmp.xmit_fifo_size = state->xmit_fifo_size; | ||
1081 | tmp.baud_base = state->baud_base; | ||
1082 | tmp.close_delay = state->close_delay; | ||
1083 | tmp.closing_wait = state->closing_wait; | ||
1084 | tmp.custom_divisor = state->custom_divisor; | ||
1085 | tty_unlock(); | ||
1086 | if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) | ||
1087 | return -EFAULT; | ||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | static int set_serial_info(struct async_struct * info, | ||
1092 | struct serial_struct __user * new_info) | ||
1093 | { | ||
1094 | struct serial_struct new_serial; | ||
1095 | struct serial_state old_state, *state; | ||
1096 | unsigned int change_irq,change_port; | ||
1097 | int retval = 0; | ||
1098 | |||
1099 | if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) | ||
1100 | return -EFAULT; | ||
1101 | |||
1102 | tty_lock(); | ||
1103 | state = info->state; | ||
1104 | old_state = *state; | ||
1105 | |||
1106 | change_irq = new_serial.irq != state->irq; | ||
1107 | change_port = (new_serial.port != state->port); | ||
1108 | if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) { | ||
1109 | tty_unlock(); | ||
1110 | return -EINVAL; | ||
1111 | } | ||
1112 | |||
1113 | if (!serial_isroot()) { | ||
1114 | if ((new_serial.baud_base != state->baud_base) || | ||
1115 | (new_serial.close_delay != state->close_delay) || | ||
1116 | (new_serial.xmit_fifo_size != state->xmit_fifo_size) || | ||
1117 | ((new_serial.flags & ~ASYNC_USR_MASK) != | ||
1118 | (state->flags & ~ASYNC_USR_MASK))) | ||
1119 | return -EPERM; | ||
1120 | state->flags = ((state->flags & ~ASYNC_USR_MASK) | | ||
1121 | (new_serial.flags & ASYNC_USR_MASK)); | ||
1122 | info->flags = ((info->flags & ~ASYNC_USR_MASK) | | ||
1123 | (new_serial.flags & ASYNC_USR_MASK)); | ||
1124 | state->custom_divisor = new_serial.custom_divisor; | ||
1125 | goto check_and_exit; | ||
1126 | } | ||
1127 | |||
1128 | if (new_serial.baud_base < 9600) { | ||
1129 | tty_unlock(); | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * OK, past this point, all the error checking has been done. | ||
1135 | * At this point, we start making changes..... | ||
1136 | */ | ||
1137 | |||
1138 | state->baud_base = new_serial.baud_base; | ||
1139 | state->flags = ((state->flags & ~ASYNC_FLAGS) | | ||
1140 | (new_serial.flags & ASYNC_FLAGS)); | ||
1141 | info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | | ||
1142 | (info->flags & ASYNC_INTERNAL_FLAGS)); | ||
1143 | state->custom_divisor = new_serial.custom_divisor; | ||
1144 | state->close_delay = new_serial.close_delay * HZ/100; | ||
1145 | state->closing_wait = new_serial.closing_wait * HZ/100; | ||
1146 | info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
1147 | |||
1148 | check_and_exit: | ||
1149 | if (info->flags & ASYNC_INITIALIZED) { | ||
1150 | if (((old_state.flags & ASYNC_SPD_MASK) != | ||
1151 | (state->flags & ASYNC_SPD_MASK)) || | ||
1152 | (old_state.custom_divisor != state->custom_divisor)) { | ||
1153 | if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
1154 | info->tty->alt_speed = 57600; | ||
1155 | if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
1156 | info->tty->alt_speed = 115200; | ||
1157 | if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | ||
1158 | info->tty->alt_speed = 230400; | ||
1159 | if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | ||
1160 | info->tty->alt_speed = 460800; | ||
1161 | change_speed(info, NULL); | ||
1162 | } | ||
1163 | } else | ||
1164 | retval = startup(info); | ||
1165 | tty_unlock(); | ||
1166 | return retval; | ||
1167 | } | ||
1168 | |||
1169 | |||
1170 | /* | ||
1171 | * get_lsr_info - get line status register info | ||
1172 | * | ||
1173 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
1174 | * is emptied. On bus types like RS485, the transmitter must | ||
1175 | * release the bus after transmitting. This must be done when | ||
1176 | * the transmit shift register is empty, not be done when the | ||
1177 | * transmit holding register is empty. This functionality | ||
1178 | * allows an RS485 driver to be written in user space. | ||
1179 | */ | ||
1180 | static int get_lsr_info(struct async_struct * info, unsigned int __user *value) | ||
1181 | { | ||
1182 | unsigned char status; | ||
1183 | unsigned int result; | ||
1184 | unsigned long flags; | ||
1185 | |||
1186 | local_irq_save(flags); | ||
1187 | status = custom.serdatr; | ||
1188 | mb(); | ||
1189 | local_irq_restore(flags); | ||
1190 | result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0); | ||
1191 | if (copy_to_user(value, &result, sizeof(int))) | ||
1192 | return -EFAULT; | ||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | |||
1197 | static int rs_tiocmget(struct tty_struct *tty) | ||
1198 | { | ||
1199 | struct async_struct * info = tty->driver_data; | ||
1200 | unsigned char control, status; | ||
1201 | unsigned long flags; | ||
1202 | |||
1203 | if (serial_paranoia_check(info, tty->name, "rs_ioctl")) | ||
1204 | return -ENODEV; | ||
1205 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1206 | return -EIO; | ||
1207 | |||
1208 | control = info->MCR; | ||
1209 | local_irq_save(flags); | ||
1210 | status = ciab.pra; | ||
1211 | local_irq_restore(flags); | ||
1212 | return ((control & SER_RTS) ? TIOCM_RTS : 0) | ||
1213 | | ((control & SER_DTR) ? TIOCM_DTR : 0) | ||
1214 | | (!(status & SER_DCD) ? TIOCM_CAR : 0) | ||
1215 | | (!(status & SER_DSR) ? TIOCM_DSR : 0) | ||
1216 | | (!(status & SER_CTS) ? TIOCM_CTS : 0); | ||
1217 | } | ||
1218 | |||
1219 | static int rs_tiocmset(struct tty_struct *tty, unsigned int set, | ||
1220 | unsigned int clear) | ||
1221 | { | ||
1222 | struct async_struct * info = tty->driver_data; | ||
1223 | unsigned long flags; | ||
1224 | |||
1225 | if (serial_paranoia_check(info, tty->name, "rs_ioctl")) | ||
1226 | return -ENODEV; | ||
1227 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1228 | return -EIO; | ||
1229 | |||
1230 | local_irq_save(flags); | ||
1231 | if (set & TIOCM_RTS) | ||
1232 | info->MCR |= SER_RTS; | ||
1233 | if (set & TIOCM_DTR) | ||
1234 | info->MCR |= SER_DTR; | ||
1235 | if (clear & TIOCM_RTS) | ||
1236 | info->MCR &= ~SER_RTS; | ||
1237 | if (clear & TIOCM_DTR) | ||
1238 | info->MCR &= ~SER_DTR; | ||
1239 | rtsdtr_ctrl(info->MCR); | ||
1240 | local_irq_restore(flags); | ||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | /* | ||
1245 | * rs_break() --- routine which turns the break handling on or off | ||
1246 | */ | ||
1247 | static int rs_break(struct tty_struct *tty, int break_state) | ||
1248 | { | ||
1249 | struct async_struct * info = tty->driver_data; | ||
1250 | unsigned long flags; | ||
1251 | |||
1252 | if (serial_paranoia_check(info, tty->name, "rs_break")) | ||
1253 | return -EINVAL; | ||
1254 | |||
1255 | local_irq_save(flags); | ||
1256 | if (break_state == -1) | ||
1257 | custom.adkcon = AC_SETCLR | AC_UARTBRK; | ||
1258 | else | ||
1259 | custom.adkcon = AC_UARTBRK; | ||
1260 | mb(); | ||
1261 | local_irq_restore(flags); | ||
1262 | return 0; | ||
1263 | } | ||
1264 | |||
1265 | /* | ||
1266 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1267 | * Return: write counters to the user passed counter struct | ||
1268 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1269 | * RI where only 0->1 is counted. | ||
1270 | */ | ||
1271 | static int rs_get_icount(struct tty_struct *tty, | ||
1272 | struct serial_icounter_struct *icount) | ||
1273 | { | ||
1274 | struct async_struct *info = tty->driver_data; | ||
1275 | struct async_icount cnow; | ||
1276 | unsigned long flags; | ||
1277 | |||
1278 | local_irq_save(flags); | ||
1279 | cnow = info->state->icount; | ||
1280 | local_irq_restore(flags); | ||
1281 | icount->cts = cnow.cts; | ||
1282 | icount->dsr = cnow.dsr; | ||
1283 | icount->rng = cnow.rng; | ||
1284 | icount->dcd = cnow.dcd; | ||
1285 | icount->rx = cnow.rx; | ||
1286 | icount->tx = cnow.tx; | ||
1287 | icount->frame = cnow.frame; | ||
1288 | icount->overrun = cnow.overrun; | ||
1289 | icount->parity = cnow.parity; | ||
1290 | icount->brk = cnow.brk; | ||
1291 | icount->buf_overrun = cnow.buf_overrun; | ||
1292 | |||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | static int rs_ioctl(struct tty_struct *tty, | ||
1297 | unsigned int cmd, unsigned long arg) | ||
1298 | { | ||
1299 | struct async_struct * info = tty->driver_data; | ||
1300 | struct async_icount cprev, cnow; /* kernel counter temps */ | ||
1301 | void __user *argp = (void __user *)arg; | ||
1302 | unsigned long flags; | ||
1303 | |||
1304 | if (serial_paranoia_check(info, tty->name, "rs_ioctl")) | ||
1305 | return -ENODEV; | ||
1306 | |||
1307 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||
1308 | (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && | ||
1309 | (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { | ||
1310 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1311 | return -EIO; | ||
1312 | } | ||
1313 | |||
1314 | switch (cmd) { | ||
1315 | case TIOCGSERIAL: | ||
1316 | return get_serial_info(info, argp); | ||
1317 | case TIOCSSERIAL: | ||
1318 | return set_serial_info(info, argp); | ||
1319 | case TIOCSERCONFIG: | ||
1320 | return 0; | ||
1321 | |||
1322 | case TIOCSERGETLSR: /* Get line status register */ | ||
1323 | return get_lsr_info(info, argp); | ||
1324 | |||
1325 | case TIOCSERGSTRUCT: | ||
1326 | if (copy_to_user(argp, | ||
1327 | info, sizeof(struct async_struct))) | ||
1328 | return -EFAULT; | ||
1329 | return 0; | ||
1330 | |||
1331 | /* | ||
1332 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
1333 | * - mask passed in arg for lines of interest | ||
1334 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
1335 | * Caller should use TIOCGICOUNT to see which one it was | ||
1336 | */ | ||
1337 | case TIOCMIWAIT: | ||
1338 | local_irq_save(flags); | ||
1339 | /* note the counters on entry */ | ||
1340 | cprev = info->state->icount; | ||
1341 | local_irq_restore(flags); | ||
1342 | while (1) { | ||
1343 | interruptible_sleep_on(&info->delta_msr_wait); | ||
1344 | /* see if a signal did it */ | ||
1345 | if (signal_pending(current)) | ||
1346 | return -ERESTARTSYS; | ||
1347 | local_irq_save(flags); | ||
1348 | cnow = info->state->icount; /* atomic copy */ | ||
1349 | local_irq_restore(flags); | ||
1350 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
1351 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) | ||
1352 | return -EIO; /* no change => error */ | ||
1353 | if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | ||
1354 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | ||
1355 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || | ||
1356 | ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { | ||
1357 | return 0; | ||
1358 | } | ||
1359 | cprev = cnow; | ||
1360 | } | ||
1361 | /* NOTREACHED */ | ||
1362 | |||
1363 | case TIOCSERGWILD: | ||
1364 | case TIOCSERSWILD: | ||
1365 | /* "setserial -W" is called in Debian boot */ | ||
1366 | printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); | ||
1367 | return 0; | ||
1368 | |||
1369 | default: | ||
1370 | return -ENOIOCTLCMD; | ||
1371 | } | ||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1375 | static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
1376 | { | ||
1377 | struct async_struct *info = tty->driver_data; | ||
1378 | unsigned long flags; | ||
1379 | unsigned int cflag = tty->termios->c_cflag; | ||
1380 | |||
1381 | change_speed(info, old_termios); | ||
1382 | |||
1383 | /* Handle transition to B0 status */ | ||
1384 | if ((old_termios->c_cflag & CBAUD) && | ||
1385 | !(cflag & CBAUD)) { | ||
1386 | info->MCR &= ~(SER_DTR|SER_RTS); | ||
1387 | local_irq_save(flags); | ||
1388 | rtsdtr_ctrl(info->MCR); | ||
1389 | local_irq_restore(flags); | ||
1390 | } | ||
1391 | |||
1392 | /* Handle transition away from B0 status */ | ||
1393 | if (!(old_termios->c_cflag & CBAUD) && | ||
1394 | (cflag & CBAUD)) { | ||
1395 | info->MCR |= SER_DTR; | ||
1396 | if (!(tty->termios->c_cflag & CRTSCTS) || | ||
1397 | !test_bit(TTY_THROTTLED, &tty->flags)) { | ||
1398 | info->MCR |= SER_RTS; | ||
1399 | } | ||
1400 | local_irq_save(flags); | ||
1401 | rtsdtr_ctrl(info->MCR); | ||
1402 | local_irq_restore(flags); | ||
1403 | } | ||
1404 | |||
1405 | /* Handle turning off CRTSCTS */ | ||
1406 | if ((old_termios->c_cflag & CRTSCTS) && | ||
1407 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
1408 | tty->hw_stopped = 0; | ||
1409 | rs_start(tty); | ||
1410 | } | ||
1411 | |||
1412 | #if 0 | ||
1413 | /* | ||
1414 | * No need to wake up processes in open wait, since they | ||
1415 | * sample the CLOCAL flag once, and don't recheck it. | ||
1416 | * XXX It's not clear whether the current behavior is correct | ||
1417 | * or not. Hence, this may change..... | ||
1418 | */ | ||
1419 | if (!(old_termios->c_cflag & CLOCAL) && | ||
1420 | (tty->termios->c_cflag & CLOCAL)) | ||
1421 | wake_up_interruptible(&info->open_wait); | ||
1422 | #endif | ||
1423 | } | ||
1424 | |||
1425 | /* | ||
1426 | * ------------------------------------------------------------ | ||
1427 | * rs_close() | ||
1428 | * | ||
1429 | * This routine is called when the serial port gets closed. First, we | ||
1430 | * wait for the last remaining data to be sent. Then, we unlink its | ||
1431 | * async structure from the interrupt chain if necessary, and we free | ||
1432 | * that IRQ if nothing is left in the chain. | ||
1433 | * ------------------------------------------------------------ | ||
1434 | */ | ||
1435 | static void rs_close(struct tty_struct *tty, struct file * filp) | ||
1436 | { | ||
1437 | struct async_struct * info = tty->driver_data; | ||
1438 | struct serial_state *state; | ||
1439 | unsigned long flags; | ||
1440 | |||
1441 | if (!info || serial_paranoia_check(info, tty->name, "rs_close")) | ||
1442 | return; | ||
1443 | |||
1444 | state = info->state; | ||
1445 | |||
1446 | local_irq_save(flags); | ||
1447 | |||
1448 | if (tty_hung_up_p(filp)) { | ||
1449 | DBG_CNT("before DEC-hung"); | ||
1450 | local_irq_restore(flags); | ||
1451 | return; | ||
1452 | } | ||
1453 | |||
1454 | #ifdef SERIAL_DEBUG_OPEN | ||
1455 | printk("rs_close ttys%d, count = %d\n", info->line, state->count); | ||
1456 | #endif | ||
1457 | if ((tty->count == 1) && (state->count != 1)) { | ||
1458 | /* | ||
1459 | * Uh, oh. tty->count is 1, which means that the tty | ||
1460 | * structure will be freed. state->count should always | ||
1461 | * be one in these conditions. If it's greater than | ||
1462 | * one, we've got real problems, since it means the | ||
1463 | * serial port won't be shutdown. | ||
1464 | */ | ||
1465 | printk("rs_close: bad serial port count; tty->count is 1, " | ||
1466 | "state->count is %d\n", state->count); | ||
1467 | state->count = 1; | ||
1468 | } | ||
1469 | if (--state->count < 0) { | ||
1470 | printk("rs_close: bad serial port count for ttys%d: %d\n", | ||
1471 | info->line, state->count); | ||
1472 | state->count = 0; | ||
1473 | } | ||
1474 | if (state->count) { | ||
1475 | DBG_CNT("before DEC-2"); | ||
1476 | local_irq_restore(flags); | ||
1477 | return; | ||
1478 | } | ||
1479 | info->flags |= ASYNC_CLOSING; | ||
1480 | /* | ||
1481 | * Now we wait for the transmit buffer to clear; and we notify | ||
1482 | * the line discipline to only process XON/XOFF characters. | ||
1483 | */ | ||
1484 | tty->closing = 1; | ||
1485 | if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) | ||
1486 | tty_wait_until_sent(tty, info->closing_wait); | ||
1487 | /* | ||
1488 | * At this point we stop accepting input. To do this, we | ||
1489 | * disable the receive line status interrupts, and tell the | ||
1490 | * interrupt driver to stop checking the data ready bit in the | ||
1491 | * line status register. | ||
1492 | */ | ||
1493 | info->read_status_mask &= ~UART_LSR_DR; | ||
1494 | if (info->flags & ASYNC_INITIALIZED) { | ||
1495 | /* disable receive interrupts */ | ||
1496 | custom.intena = IF_RBF; | ||
1497 | mb(); | ||
1498 | /* clear any pending receive interrupt */ | ||
1499 | custom.intreq = IF_RBF; | ||
1500 | mb(); | ||
1501 | |||
1502 | /* | ||
1503 | * Before we drop DTR, make sure the UART transmitter | ||
1504 | * has completely drained; this is especially | ||
1505 | * important if there is a transmit FIFO! | ||
1506 | */ | ||
1507 | rs_wait_until_sent(tty, info->timeout); | ||
1508 | } | ||
1509 | shutdown(info); | ||
1510 | rs_flush_buffer(tty); | ||
1511 | |||
1512 | tty_ldisc_flush(tty); | ||
1513 | tty->closing = 0; | ||
1514 | info->event = 0; | ||
1515 | info->tty = NULL; | ||
1516 | if (info->blocked_open) { | ||
1517 | if (info->close_delay) { | ||
1518 | msleep_interruptible(jiffies_to_msecs(info->close_delay)); | ||
1519 | } | ||
1520 | wake_up_interruptible(&info->open_wait); | ||
1521 | } | ||
1522 | info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); | ||
1523 | wake_up_interruptible(&info->close_wait); | ||
1524 | local_irq_restore(flags); | ||
1525 | } | ||
1526 | |||
1527 | /* | ||
1528 | * rs_wait_until_sent() --- wait until the transmitter is empty | ||
1529 | */ | ||
1530 | static void rs_wait_until_sent(struct tty_struct *tty, int timeout) | ||
1531 | { | ||
1532 | struct async_struct * info = tty->driver_data; | ||
1533 | unsigned long orig_jiffies, char_time; | ||
1534 | int tty_was_locked = tty_locked(); | ||
1535 | int lsr; | ||
1536 | |||
1537 | if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) | ||
1538 | return; | ||
1539 | |||
1540 | if (info->xmit_fifo_size == 0) | ||
1541 | return; /* Just in case.... */ | ||
1542 | |||
1543 | orig_jiffies = jiffies; | ||
1544 | |||
1545 | /* | ||
1546 | * tty_wait_until_sent is called from lots of places, | ||
1547 | * with or without the BTM. | ||
1548 | */ | ||
1549 | if (!tty_was_locked) | ||
1550 | tty_lock(); | ||
1551 | /* | ||
1552 | * Set the check interval to be 1/5 of the estimated time to | ||
1553 | * send a single character, and make it at least 1. The check | ||
1554 | * interval should also be less than the timeout. | ||
1555 | * | ||
1556 | * Note: we have to use pretty tight timings here to satisfy | ||
1557 | * the NIST-PCTS. | ||
1558 | */ | ||
1559 | char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; | ||
1560 | char_time = char_time / 5; | ||
1561 | if (char_time == 0) | ||
1562 | char_time = 1; | ||
1563 | if (timeout) | ||
1564 | char_time = min_t(unsigned long, char_time, timeout); | ||
1565 | /* | ||
1566 | * If the transmitter hasn't cleared in twice the approximate | ||
1567 | * amount of time to send the entire FIFO, it probably won't | ||
1568 | * ever clear. This assumes the UART isn't doing flow | ||
1569 | * control, which is currently the case. Hence, if it ever | ||
1570 | * takes longer than info->timeout, this is probably due to a | ||
1571 | * UART bug of some kind. So, we clamp the timeout parameter at | ||
1572 | * 2*info->timeout. | ||
1573 | */ | ||
1574 | if (!timeout || timeout > 2*info->timeout) | ||
1575 | timeout = 2*info->timeout; | ||
1576 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
1577 | printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); | ||
1578 | printk("jiff=%lu...", jiffies); | ||
1579 | #endif | ||
1580 | while(!((lsr = custom.serdatr) & SDR_TSRE)) { | ||
1581 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
1582 | printk("serdatr = %d (jiff=%lu)...", lsr, jiffies); | ||
1583 | #endif | ||
1584 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
1585 | if (signal_pending(current)) | ||
1586 | break; | ||
1587 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
1588 | break; | ||
1589 | } | ||
1590 | __set_current_state(TASK_RUNNING); | ||
1591 | if (!tty_was_locked) | ||
1592 | tty_unlock(); | ||
1593 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
1594 | printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); | ||
1595 | #endif | ||
1596 | } | ||
1597 | |||
1598 | /* | ||
1599 | * rs_hangup() --- called by tty_hangup() when a hangup is signaled. | ||
1600 | */ | ||
1601 | static void rs_hangup(struct tty_struct *tty) | ||
1602 | { | ||
1603 | struct async_struct * info = tty->driver_data; | ||
1604 | struct serial_state *state = info->state; | ||
1605 | |||
1606 | if (serial_paranoia_check(info, tty->name, "rs_hangup")) | ||
1607 | return; | ||
1608 | |||
1609 | state = info->state; | ||
1610 | |||
1611 | rs_flush_buffer(tty); | ||
1612 | shutdown(info); | ||
1613 | info->event = 0; | ||
1614 | state->count = 0; | ||
1615 | info->flags &= ~ASYNC_NORMAL_ACTIVE; | ||
1616 | info->tty = NULL; | ||
1617 | wake_up_interruptible(&info->open_wait); | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | * ------------------------------------------------------------ | ||
1622 | * rs_open() and friends | ||
1623 | * ------------------------------------------------------------ | ||
1624 | */ | ||
1625 | static int block_til_ready(struct tty_struct *tty, struct file * filp, | ||
1626 | struct async_struct *info) | ||
1627 | { | ||
1628 | #ifdef DECLARE_WAITQUEUE | ||
1629 | DECLARE_WAITQUEUE(wait, current); | ||
1630 | #else | ||
1631 | struct wait_queue wait = { current, NULL }; | ||
1632 | #endif | ||
1633 | struct serial_state *state = info->state; | ||
1634 | int retval; | ||
1635 | int do_clocal = 0, extra_count = 0; | ||
1636 | unsigned long flags; | ||
1637 | |||
1638 | /* | ||
1639 | * If the device is in the middle of being closed, then block | ||
1640 | * until it's done, and then try again. | ||
1641 | */ | ||
1642 | if (tty_hung_up_p(filp) || | ||
1643 | (info->flags & ASYNC_CLOSING)) { | ||
1644 | if (info->flags & ASYNC_CLOSING) | ||
1645 | interruptible_sleep_on(&info->close_wait); | ||
1646 | #ifdef SERIAL_DO_RESTART | ||
1647 | return ((info->flags & ASYNC_HUP_NOTIFY) ? | ||
1648 | -EAGAIN : -ERESTARTSYS); | ||
1649 | #else | ||
1650 | return -EAGAIN; | ||
1651 | #endif | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * If non-blocking mode is set, or the port is not enabled, | ||
1656 | * then make the check up front and then exit. | ||
1657 | */ | ||
1658 | if ((filp->f_flags & O_NONBLOCK) || | ||
1659 | (tty->flags & (1 << TTY_IO_ERROR))) { | ||
1660 | info->flags |= ASYNC_NORMAL_ACTIVE; | ||
1661 | return 0; | ||
1662 | } | ||
1663 | |||
1664 | if (tty->termios->c_cflag & CLOCAL) | ||
1665 | do_clocal = 1; | ||
1666 | |||
1667 | /* | ||
1668 | * Block waiting for the carrier detect and the line to become | ||
1669 | * free (i.e., not in use by the callout). While we are in | ||
1670 | * this loop, state->count is dropped by one, so that | ||
1671 | * rs_close() knows when to free things. We restore it upon | ||
1672 | * exit, either normal or abnormal. | ||
1673 | */ | ||
1674 | retval = 0; | ||
1675 | add_wait_queue(&info->open_wait, &wait); | ||
1676 | #ifdef SERIAL_DEBUG_OPEN | ||
1677 | printk("block_til_ready before block: ttys%d, count = %d\n", | ||
1678 | state->line, state->count); | ||
1679 | #endif | ||
1680 | local_irq_save(flags); | ||
1681 | if (!tty_hung_up_p(filp)) { | ||
1682 | extra_count = 1; | ||
1683 | state->count--; | ||
1684 | } | ||
1685 | local_irq_restore(flags); | ||
1686 | info->blocked_open++; | ||
1687 | while (1) { | ||
1688 | local_irq_save(flags); | ||
1689 | if (tty->termios->c_cflag & CBAUD) | ||
1690 | rtsdtr_ctrl(SER_DTR|SER_RTS); | ||
1691 | local_irq_restore(flags); | ||
1692 | set_current_state(TASK_INTERRUPTIBLE); | ||
1693 | if (tty_hung_up_p(filp) || | ||
1694 | !(info->flags & ASYNC_INITIALIZED)) { | ||
1695 | #ifdef SERIAL_DO_RESTART | ||
1696 | if (info->flags & ASYNC_HUP_NOTIFY) | ||
1697 | retval = -EAGAIN; | ||
1698 | else | ||
1699 | retval = -ERESTARTSYS; | ||
1700 | #else | ||
1701 | retval = -EAGAIN; | ||
1702 | #endif | ||
1703 | break; | ||
1704 | } | ||
1705 | if (!(info->flags & ASYNC_CLOSING) && | ||
1706 | (do_clocal || (!(ciab.pra & SER_DCD)) )) | ||
1707 | break; | ||
1708 | if (signal_pending(current)) { | ||
1709 | retval = -ERESTARTSYS; | ||
1710 | break; | ||
1711 | } | ||
1712 | #ifdef SERIAL_DEBUG_OPEN | ||
1713 | printk("block_til_ready blocking: ttys%d, count = %d\n", | ||
1714 | info->line, state->count); | ||
1715 | #endif | ||
1716 | tty_unlock(); | ||
1717 | schedule(); | ||
1718 | tty_lock(); | ||
1719 | } | ||
1720 | __set_current_state(TASK_RUNNING); | ||
1721 | remove_wait_queue(&info->open_wait, &wait); | ||
1722 | if (extra_count) | ||
1723 | state->count++; | ||
1724 | info->blocked_open--; | ||
1725 | #ifdef SERIAL_DEBUG_OPEN | ||
1726 | printk("block_til_ready after blocking: ttys%d, count = %d\n", | ||
1727 | info->line, state->count); | ||
1728 | #endif | ||
1729 | if (retval) | ||
1730 | return retval; | ||
1731 | info->flags |= ASYNC_NORMAL_ACTIVE; | ||
1732 | return 0; | ||
1733 | } | ||
1734 | |||
1735 | static int get_async_struct(int line, struct async_struct **ret_info) | ||
1736 | { | ||
1737 | struct async_struct *info; | ||
1738 | struct serial_state *sstate; | ||
1739 | |||
1740 | sstate = rs_table + line; | ||
1741 | sstate->count++; | ||
1742 | if (sstate->info) { | ||
1743 | *ret_info = sstate->info; | ||
1744 | return 0; | ||
1745 | } | ||
1746 | info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); | ||
1747 | if (!info) { | ||
1748 | sstate->count--; | ||
1749 | return -ENOMEM; | ||
1750 | } | ||
1751 | #ifdef DECLARE_WAITQUEUE | ||
1752 | init_waitqueue_head(&info->open_wait); | ||
1753 | init_waitqueue_head(&info->close_wait); | ||
1754 | init_waitqueue_head(&info->delta_msr_wait); | ||
1755 | #endif | ||
1756 | info->magic = SERIAL_MAGIC; | ||
1757 | info->port = sstate->port; | ||
1758 | info->flags = sstate->flags; | ||
1759 | info->xmit_fifo_size = sstate->xmit_fifo_size; | ||
1760 | info->line = line; | ||
1761 | tasklet_init(&info->tlet, do_softint, (unsigned long)info); | ||
1762 | info->state = sstate; | ||
1763 | if (sstate->info) { | ||
1764 | kfree(info); | ||
1765 | *ret_info = sstate->info; | ||
1766 | return 0; | ||
1767 | } | ||
1768 | *ret_info = sstate->info = info; | ||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | /* | ||
1773 | * This routine is called whenever a serial port is opened. It | ||
1774 | * enables interrupts for a serial port, linking in its async structure into | ||
1775 | * the IRQ chain. It also performs the serial-specific | ||
1776 | * initialization for the tty structure. | ||
1777 | */ | ||
1778 | static int rs_open(struct tty_struct *tty, struct file * filp) | ||
1779 | { | ||
1780 | struct async_struct *info; | ||
1781 | int retval, line; | ||
1782 | |||
1783 | line = tty->index; | ||
1784 | if ((line < 0) || (line >= NR_PORTS)) { | ||
1785 | return -ENODEV; | ||
1786 | } | ||
1787 | retval = get_async_struct(line, &info); | ||
1788 | if (retval) { | ||
1789 | return retval; | ||
1790 | } | ||
1791 | tty->driver_data = info; | ||
1792 | info->tty = tty; | ||
1793 | if (serial_paranoia_check(info, tty->name, "rs_open")) | ||
1794 | return -ENODEV; | ||
1795 | |||
1796 | #ifdef SERIAL_DEBUG_OPEN | ||
1797 | printk("rs_open %s, count = %d\n", tty->name, info->state->count); | ||
1798 | #endif | ||
1799 | info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
1800 | |||
1801 | /* | ||
1802 | * If the port is the middle of closing, bail out now | ||
1803 | */ | ||
1804 | if (tty_hung_up_p(filp) || | ||
1805 | (info->flags & ASYNC_CLOSING)) { | ||
1806 | if (info->flags & ASYNC_CLOSING) | ||
1807 | interruptible_sleep_on(&info->close_wait); | ||
1808 | #ifdef SERIAL_DO_RESTART | ||
1809 | return ((info->flags & ASYNC_HUP_NOTIFY) ? | ||
1810 | -EAGAIN : -ERESTARTSYS); | ||
1811 | #else | ||
1812 | return -EAGAIN; | ||
1813 | #endif | ||
1814 | } | ||
1815 | |||
1816 | /* | ||
1817 | * Start up serial port | ||
1818 | */ | ||
1819 | retval = startup(info); | ||
1820 | if (retval) { | ||
1821 | return retval; | ||
1822 | } | ||
1823 | |||
1824 | retval = block_til_ready(tty, filp, info); | ||
1825 | if (retval) { | ||
1826 | #ifdef SERIAL_DEBUG_OPEN | ||
1827 | printk("rs_open returning after block_til_ready with %d\n", | ||
1828 | retval); | ||
1829 | #endif | ||
1830 | return retval; | ||
1831 | } | ||
1832 | |||
1833 | #ifdef SERIAL_DEBUG_OPEN | ||
1834 | printk("rs_open %s successful...", tty->name); | ||
1835 | #endif | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | /* | ||
1840 | * /proc fs routines.... | ||
1841 | */ | ||
1842 | |||
1843 | static inline void line_info(struct seq_file *m, struct serial_state *state) | ||
1844 | { | ||
1845 | struct async_struct *info = state->info, scr_info; | ||
1846 | char stat_buf[30], control, status; | ||
1847 | unsigned long flags; | ||
1848 | |||
1849 | seq_printf(m, "%d: uart:amiga_builtin",state->line); | ||
1850 | |||
1851 | /* | ||
1852 | * Figure out the current RS-232 lines | ||
1853 | */ | ||
1854 | if (!info) { | ||
1855 | info = &scr_info; /* This is just for serial_{in,out} */ | ||
1856 | |||
1857 | info->magic = SERIAL_MAGIC; | ||
1858 | info->flags = state->flags; | ||
1859 | info->quot = 0; | ||
1860 | info->tty = NULL; | ||
1861 | } | ||
1862 | local_irq_save(flags); | ||
1863 | status = ciab.pra; | ||
1864 | control = info ? info->MCR : status; | ||
1865 | local_irq_restore(flags); | ||
1866 | |||
1867 | stat_buf[0] = 0; | ||
1868 | stat_buf[1] = 0; | ||
1869 | if(!(control & SER_RTS)) | ||
1870 | strcat(stat_buf, "|RTS"); | ||
1871 | if(!(status & SER_CTS)) | ||
1872 | strcat(stat_buf, "|CTS"); | ||
1873 | if(!(control & SER_DTR)) | ||
1874 | strcat(stat_buf, "|DTR"); | ||
1875 | if(!(status & SER_DSR)) | ||
1876 | strcat(stat_buf, "|DSR"); | ||
1877 | if(!(status & SER_DCD)) | ||
1878 | strcat(stat_buf, "|CD"); | ||
1879 | |||
1880 | if (info->quot) { | ||
1881 | seq_printf(m, " baud:%d", state->baud_base / info->quot); | ||
1882 | } | ||
1883 | |||
1884 | seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx); | ||
1885 | |||
1886 | if (state->icount.frame) | ||
1887 | seq_printf(m, " fe:%d", state->icount.frame); | ||
1888 | |||
1889 | if (state->icount.parity) | ||
1890 | seq_printf(m, " pe:%d", state->icount.parity); | ||
1891 | |||
1892 | if (state->icount.brk) | ||
1893 | seq_printf(m, " brk:%d", state->icount.brk); | ||
1894 | |||
1895 | if (state->icount.overrun) | ||
1896 | seq_printf(m, " oe:%d", state->icount.overrun); | ||
1897 | |||
1898 | /* | ||
1899 | * Last thing is the RS-232 status lines | ||
1900 | */ | ||
1901 | seq_printf(m, " %s\n", stat_buf+1); | ||
1902 | } | ||
1903 | |||
1904 | static int rs_proc_show(struct seq_file *m, void *v) | ||
1905 | { | ||
1906 | seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); | ||
1907 | line_info(m, &rs_table[0]); | ||
1908 | return 0; | ||
1909 | } | ||
1910 | |||
1911 | static int rs_proc_open(struct inode *inode, struct file *file) | ||
1912 | { | ||
1913 | return single_open(file, rs_proc_show, NULL); | ||
1914 | } | ||
1915 | |||
1916 | static const struct file_operations rs_proc_fops = { | ||
1917 | .owner = THIS_MODULE, | ||
1918 | .open = rs_proc_open, | ||
1919 | .read = seq_read, | ||
1920 | .llseek = seq_lseek, | ||
1921 | .release = single_release, | ||
1922 | }; | ||
1923 | |||
1924 | /* | ||
1925 | * --------------------------------------------------------------------- | ||
1926 | * rs_init() and friends | ||
1927 | * | ||
1928 | * rs_init() is called at boot-time to initialize the serial driver. | ||
1929 | * --------------------------------------------------------------------- | ||
1930 | */ | ||
1931 | |||
1932 | /* | ||
1933 | * This routine prints out the appropriate serial driver version | ||
1934 | * number, and identifies which options were configured into this | ||
1935 | * driver. | ||
1936 | */ | ||
1937 | static void show_serial_version(void) | ||
1938 | { | ||
1939 | printk(KERN_INFO "%s version %s\n", serial_name, serial_version); | ||
1940 | } | ||
1941 | |||
1942 | |||
1943 | static const struct tty_operations serial_ops = { | ||
1944 | .open = rs_open, | ||
1945 | .close = rs_close, | ||
1946 | .write = rs_write, | ||
1947 | .put_char = rs_put_char, | ||
1948 | .flush_chars = rs_flush_chars, | ||
1949 | .write_room = rs_write_room, | ||
1950 | .chars_in_buffer = rs_chars_in_buffer, | ||
1951 | .flush_buffer = rs_flush_buffer, | ||
1952 | .ioctl = rs_ioctl, | ||
1953 | .throttle = rs_throttle, | ||
1954 | .unthrottle = rs_unthrottle, | ||
1955 | .set_termios = rs_set_termios, | ||
1956 | .stop = rs_stop, | ||
1957 | .start = rs_start, | ||
1958 | .hangup = rs_hangup, | ||
1959 | .break_ctl = rs_break, | ||
1960 | .send_xchar = rs_send_xchar, | ||
1961 | .wait_until_sent = rs_wait_until_sent, | ||
1962 | .tiocmget = rs_tiocmget, | ||
1963 | .tiocmset = rs_tiocmset, | ||
1964 | .get_icount = rs_get_icount, | ||
1965 | .proc_fops = &rs_proc_fops, | ||
1966 | }; | ||
1967 | |||
1968 | /* | ||
1969 | * The serial driver boot-time initialization code! | ||
1970 | */ | ||
1971 | static int __init amiga_serial_probe(struct platform_device *pdev) | ||
1972 | { | ||
1973 | unsigned long flags; | ||
1974 | struct serial_state * state; | ||
1975 | int error; | ||
1976 | |||
1977 | serial_driver = alloc_tty_driver(1); | ||
1978 | if (!serial_driver) | ||
1979 | return -ENOMEM; | ||
1980 | |||
1981 | IRQ_ports = NULL; | ||
1982 | |||
1983 | show_serial_version(); | ||
1984 | |||
1985 | /* Initialize the tty_driver structure */ | ||
1986 | |||
1987 | serial_driver->owner = THIS_MODULE; | ||
1988 | serial_driver->driver_name = "amiserial"; | ||
1989 | serial_driver->name = "ttyS"; | ||
1990 | serial_driver->major = TTY_MAJOR; | ||
1991 | serial_driver->minor_start = 64; | ||
1992 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
1993 | serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
1994 | serial_driver->init_termios = tty_std_termios; | ||
1995 | serial_driver->init_termios.c_cflag = | ||
1996 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
1997 | serial_driver->flags = TTY_DRIVER_REAL_RAW; | ||
1998 | tty_set_operations(serial_driver, &serial_ops); | ||
1999 | |||
2000 | error = tty_register_driver(serial_driver); | ||
2001 | if (error) | ||
2002 | goto fail_put_tty_driver; | ||
2003 | |||
2004 | state = rs_table; | ||
2005 | state->magic = SSTATE_MAGIC; | ||
2006 | state->port = (int)&custom.serdatr; /* Just to give it a value */ | ||
2007 | state->line = 0; | ||
2008 | state->custom_divisor = 0; | ||
2009 | state->close_delay = 5*HZ/10; | ||
2010 | state->closing_wait = 30*HZ; | ||
2011 | state->icount.cts = state->icount.dsr = | ||
2012 | state->icount.rng = state->icount.dcd = 0; | ||
2013 | state->icount.rx = state->icount.tx = 0; | ||
2014 | state->icount.frame = state->icount.parity = 0; | ||
2015 | state->icount.overrun = state->icount.brk = 0; | ||
2016 | |||
2017 | printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", | ||
2018 | state->line); | ||
2019 | |||
2020 | /* Hardware set up */ | ||
2021 | |||
2022 | state->baud_base = amiga_colorclock; | ||
2023 | state->xmit_fifo_size = 1; | ||
2024 | |||
2025 | /* set ISRs, and then disable the rx interrupts */ | ||
2026 | error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); | ||
2027 | if (error) | ||
2028 | goto fail_unregister; | ||
2029 | |||
2030 | error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, | ||
2031 | "serial RX", state); | ||
2032 | if (error) | ||
2033 | goto fail_free_irq; | ||
2034 | |||
2035 | local_irq_save(flags); | ||
2036 | |||
2037 | /* turn off Rx and Tx interrupts */ | ||
2038 | custom.intena = IF_RBF | IF_TBE; | ||
2039 | mb(); | ||
2040 | |||
2041 | /* clear any pending interrupt */ | ||
2042 | custom.intreq = IF_RBF | IF_TBE; | ||
2043 | mb(); | ||
2044 | |||
2045 | local_irq_restore(flags); | ||
2046 | |||
2047 | /* | ||
2048 | * set the appropriate directions for the modem control flags, | ||
2049 | * and clear RTS and DTR | ||
2050 | */ | ||
2051 | ciab.ddra |= (SER_DTR | SER_RTS); /* outputs */ | ||
2052 | ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ | ||
2053 | |||
2054 | platform_set_drvdata(pdev, state); | ||
2055 | |||
2056 | return 0; | ||
2057 | |||
2058 | fail_free_irq: | ||
2059 | free_irq(IRQ_AMIGA_TBE, state); | ||
2060 | fail_unregister: | ||
2061 | tty_unregister_driver(serial_driver); | ||
2062 | fail_put_tty_driver: | ||
2063 | put_tty_driver(serial_driver); | ||
2064 | return error; | ||
2065 | } | ||
2066 | |||
2067 | static int __exit amiga_serial_remove(struct platform_device *pdev) | ||
2068 | { | ||
2069 | int error; | ||
2070 | struct serial_state *state = platform_get_drvdata(pdev); | ||
2071 | struct async_struct *info = state->info; | ||
2072 | |||
2073 | /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ | ||
2074 | tasklet_kill(&info->tlet); | ||
2075 | if ((error = tty_unregister_driver(serial_driver))) | ||
2076 | printk("SERIAL: failed to unregister serial driver (%d)\n", | ||
2077 | error); | ||
2078 | put_tty_driver(serial_driver); | ||
2079 | |||
2080 | rs_table[0].info = NULL; | ||
2081 | kfree(info); | ||
2082 | |||
2083 | free_irq(IRQ_AMIGA_TBE, rs_table); | ||
2084 | free_irq(IRQ_AMIGA_RBF, rs_table); | ||
2085 | |||
2086 | platform_set_drvdata(pdev, NULL); | ||
2087 | |||
2088 | return error; | ||
2089 | } | ||
2090 | |||
2091 | static struct platform_driver amiga_serial_driver = { | ||
2092 | .remove = __exit_p(amiga_serial_remove), | ||
2093 | .driver = { | ||
2094 | .name = "amiga-serial", | ||
2095 | .owner = THIS_MODULE, | ||
2096 | }, | ||
2097 | }; | ||
2098 | |||
2099 | static int __init amiga_serial_init(void) | ||
2100 | { | ||
2101 | return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe); | ||
2102 | } | ||
2103 | |||
2104 | module_init(amiga_serial_init); | ||
2105 | |||
2106 | static void __exit amiga_serial_exit(void) | ||
2107 | { | ||
2108 | platform_driver_unregister(&amiga_serial_driver); | ||
2109 | } | ||
2110 | |||
2111 | module_exit(amiga_serial_exit); | ||
2112 | |||
2113 | |||
2114 | #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE) | ||
2115 | |||
2116 | /* | ||
2117 | * ------------------------------------------------------------ | ||
2118 | * Serial console driver | ||
2119 | * ------------------------------------------------------------ | ||
2120 | */ | ||
2121 | |||
2122 | static void amiga_serial_putc(char c) | ||
2123 | { | ||
2124 | custom.serdat = (unsigned char)c | 0x100; | ||
2125 | while (!(custom.serdatr & 0x2000)) | ||
2126 | barrier(); | ||
2127 | } | ||
2128 | |||
2129 | /* | ||
2130 | * Print a string to the serial port trying not to disturb | ||
2131 | * any possible real use of the port... | ||
2132 | * | ||
2133 | * The console must be locked when we get here. | ||
2134 | */ | ||
2135 | static void serial_console_write(struct console *co, const char *s, | ||
2136 | unsigned count) | ||
2137 | { | ||
2138 | unsigned short intena = custom.intenar; | ||
2139 | |||
2140 | custom.intena = IF_TBE; | ||
2141 | |||
2142 | while (count--) { | ||
2143 | if (*s == '\n') | ||
2144 | amiga_serial_putc('\r'); | ||
2145 | amiga_serial_putc(*s++); | ||
2146 | } | ||
2147 | |||
2148 | custom.intena = IF_SETCLR | (intena & IF_TBE); | ||
2149 | } | ||
2150 | |||
2151 | static struct tty_driver *serial_console_device(struct console *c, int *index) | ||
2152 | { | ||
2153 | *index = 0; | ||
2154 | return serial_driver; | ||
2155 | } | ||
2156 | |||
2157 | static struct console sercons = { | ||
2158 | .name = "ttyS", | ||
2159 | .write = serial_console_write, | ||
2160 | .device = serial_console_device, | ||
2161 | .flags = CON_PRINTBUFFER, | ||
2162 | .index = -1, | ||
2163 | }; | ||
2164 | |||
2165 | /* | ||
2166 | * Register console. | ||
2167 | */ | ||
2168 | static int __init amiserial_console_init(void) | ||
2169 | { | ||
2170 | register_console(&sercons); | ||
2171 | return 0; | ||
2172 | } | ||
2173 | console_initcall(amiserial_console_init); | ||
2174 | |||
2175 | #endif /* CONFIG_SERIAL_CONSOLE && !MODULE */ | ||
2176 | |||
2177 | MODULE_LICENSE("GPL"); | ||
2178 | MODULE_ALIAS("platform:amiga-serial"); | ||
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c new file mode 100644 index 000000000000..16402445f2b2 --- /dev/null +++ b/drivers/tty/bfin_jtag_comm.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | * TTY over Blackfin JTAG Communication | ||
3 | * | ||
4 | * Copyright 2008-2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Enter bugs at http://blackfin.uclinux.org/ | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #define DRV_NAME "bfin-jtag-comm" | ||
12 | #define DEV_NAME "ttyBFJC" | ||
13 | #define pr_fmt(fmt) DRV_NAME ": " fmt | ||
14 | |||
15 | #include <linux/circ_buf.h> | ||
16 | #include <linux/console.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/kthread.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/tty.h> | ||
26 | #include <linux/tty_driver.h> | ||
27 | #include <linux/tty_flip.h> | ||
28 | #include <asm/atomic.h> | ||
29 | |||
30 | #define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); }) | ||
31 | |||
32 | /* See the Debug/Emulation chapter in the HRM */ | ||
33 | #define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */ | ||
34 | #define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */ | ||
35 | #define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */ | ||
36 | #define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */ | ||
37 | |||
38 | static inline uint32_t bfin_write_emudat(uint32_t emudat) | ||
39 | { | ||
40 | __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); | ||
41 | return emudat; | ||
42 | } | ||
43 | |||
44 | static inline uint32_t bfin_read_emudat(void) | ||
45 | { | ||
46 | uint32_t emudat; | ||
47 | __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); | ||
48 | return emudat; | ||
49 | } | ||
50 | |||
51 | static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) | ||
52 | { | ||
53 | return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24)); | ||
54 | } | ||
55 | |||
56 | #define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */ | ||
57 | #define CIRC_MASK (CIRC_SIZE - 1) | ||
58 | #define circ_empty(circ) ((circ)->head == (circ)->tail) | ||
59 | #define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE) | ||
60 | #define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE) | ||
61 | #define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK]) | ||
62 | |||
63 | static struct tty_driver *bfin_jc_driver; | ||
64 | static struct task_struct *bfin_jc_kthread; | ||
65 | static struct tty_struct * volatile bfin_jc_tty; | ||
66 | static unsigned long bfin_jc_count; | ||
67 | static DEFINE_MUTEX(bfin_jc_tty_mutex); | ||
68 | static volatile struct circ_buf bfin_jc_write_buf; | ||
69 | |||
70 | static int | ||
71 | bfin_jc_emudat_manager(void *arg) | ||
72 | { | ||
73 | uint32_t inbound_len = 0, outbound_len = 0; | ||
74 | |||
75 | while (!kthread_should_stop()) { | ||
76 | /* no one left to give data to, so sleep */ | ||
77 | if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { | ||
78 | pr_debug("waiting for readers\n"); | ||
79 | __set_current_state(TASK_UNINTERRUPTIBLE); | ||
80 | schedule(); | ||
81 | __set_current_state(TASK_RUNNING); | ||
82 | } | ||
83 | |||
84 | /* no data available, so just chill */ | ||
85 | if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { | ||
86 | pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", | ||
87 | inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); | ||
88 | if (inbound_len) | ||
89 | schedule(); | ||
90 | else | ||
91 | schedule_timeout_interruptible(HZ); | ||
92 | continue; | ||
93 | } | ||
94 | |||
95 | /* if incoming data is ready, eat it */ | ||
96 | if (bfin_read_DBGSTAT() & EMUDIF) { | ||
97 | struct tty_struct *tty; | ||
98 | mutex_lock(&bfin_jc_tty_mutex); | ||
99 | tty = (struct tty_struct *)bfin_jc_tty; | ||
100 | if (tty != NULL) { | ||
101 | uint32_t emudat = bfin_read_emudat(); | ||
102 | if (inbound_len == 0) { | ||
103 | pr_debug("incoming length: 0x%08x\n", emudat); | ||
104 | inbound_len = emudat; | ||
105 | } else { | ||
106 | size_t num_chars = (4 <= inbound_len ? 4 : inbound_len); | ||
107 | pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars); | ||
108 | inbound_len -= num_chars; | ||
109 | tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars); | ||
110 | tty_flip_buffer_push(tty); | ||
111 | } | ||
112 | } | ||
113 | mutex_unlock(&bfin_jc_tty_mutex); | ||
114 | } | ||
115 | |||
116 | /* if outgoing data is ready, post it */ | ||
117 | if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) { | ||
118 | if (outbound_len == 0) { | ||
119 | outbound_len = circ_cnt(&bfin_jc_write_buf); | ||
120 | bfin_write_emudat(outbound_len); | ||
121 | pr_debug("outgoing length: 0x%08x\n", outbound_len); | ||
122 | } else { | ||
123 | struct tty_struct *tty; | ||
124 | int tail = bfin_jc_write_buf.tail; | ||
125 | size_t ate = (4 <= outbound_len ? 4 : outbound_len); | ||
126 | uint32_t emudat = | ||
127 | bfin_write_emudat_chars( | ||
128 | circ_byte(&bfin_jc_write_buf, tail + 0), | ||
129 | circ_byte(&bfin_jc_write_buf, tail + 1), | ||
130 | circ_byte(&bfin_jc_write_buf, tail + 2), | ||
131 | circ_byte(&bfin_jc_write_buf, tail + 3) | ||
132 | ); | ||
133 | bfin_jc_write_buf.tail += ate; | ||
134 | outbound_len -= ate; | ||
135 | mutex_lock(&bfin_jc_tty_mutex); | ||
136 | tty = (struct tty_struct *)bfin_jc_tty; | ||
137 | if (tty) | ||
138 | tty_wakeup(tty); | ||
139 | mutex_unlock(&bfin_jc_tty_mutex); | ||
140 | pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | __set_current_state(TASK_RUNNING); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | bfin_jc_open(struct tty_struct *tty, struct file *filp) | ||
151 | { | ||
152 | mutex_lock(&bfin_jc_tty_mutex); | ||
153 | pr_debug("open %lu\n", bfin_jc_count); | ||
154 | ++bfin_jc_count; | ||
155 | bfin_jc_tty = tty; | ||
156 | wake_up_process(bfin_jc_kthread); | ||
157 | mutex_unlock(&bfin_jc_tty_mutex); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | bfin_jc_close(struct tty_struct *tty, struct file *filp) | ||
163 | { | ||
164 | mutex_lock(&bfin_jc_tty_mutex); | ||
165 | pr_debug("close %lu\n", bfin_jc_count); | ||
166 | if (--bfin_jc_count == 0) | ||
167 | bfin_jc_tty = NULL; | ||
168 | wake_up_process(bfin_jc_kthread); | ||
169 | mutex_unlock(&bfin_jc_tty_mutex); | ||
170 | } | ||
171 | |||
172 | /* XXX: we dont handle the put_char() case where we must handle count = 1 */ | ||
173 | static int | ||
174 | bfin_jc_circ_write(const unsigned char *buf, int count) | ||
175 | { | ||
176 | int i; | ||
177 | count = min(count, circ_free(&bfin_jc_write_buf)); | ||
178 | pr_debug("going to write chunk of %i bytes\n", count); | ||
179 | for (i = 0; i < count; ++i) | ||
180 | circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i]; | ||
181 | bfin_jc_write_buf.head += i; | ||
182 | return i; | ||
183 | } | ||
184 | |||
185 | #ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE | ||
186 | # define console_lock() | ||
187 | # define console_unlock() | ||
188 | #endif | ||
189 | static int | ||
190 | bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
191 | { | ||
192 | int i; | ||
193 | console_lock(); | ||
194 | i = bfin_jc_circ_write(buf, count); | ||
195 | console_unlock(); | ||
196 | wake_up_process(bfin_jc_kthread); | ||
197 | return i; | ||
198 | } | ||
199 | |||
200 | static void | ||
201 | bfin_jc_flush_chars(struct tty_struct *tty) | ||
202 | { | ||
203 | wake_up_process(bfin_jc_kthread); | ||
204 | } | ||
205 | |||
206 | static int | ||
207 | bfin_jc_write_room(struct tty_struct *tty) | ||
208 | { | ||
209 | return circ_free(&bfin_jc_write_buf); | ||
210 | } | ||
211 | |||
212 | static int | ||
213 | bfin_jc_chars_in_buffer(struct tty_struct *tty) | ||
214 | { | ||
215 | return circ_cnt(&bfin_jc_write_buf); | ||
216 | } | ||
217 | |||
218 | static void | ||
219 | bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout) | ||
220 | { | ||
221 | unsigned long expire = jiffies + timeout; | ||
222 | while (!circ_empty(&bfin_jc_write_buf)) { | ||
223 | if (signal_pending(current)) | ||
224 | break; | ||
225 | if (time_after(jiffies, expire)) | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | static const struct tty_operations bfin_jc_ops = { | ||
231 | .open = bfin_jc_open, | ||
232 | .close = bfin_jc_close, | ||
233 | .write = bfin_jc_write, | ||
234 | /*.put_char = bfin_jc_put_char,*/ | ||
235 | .flush_chars = bfin_jc_flush_chars, | ||
236 | .write_room = bfin_jc_write_room, | ||
237 | .chars_in_buffer = bfin_jc_chars_in_buffer, | ||
238 | .wait_until_sent = bfin_jc_wait_until_sent, | ||
239 | }; | ||
240 | |||
241 | static int __init bfin_jc_init(void) | ||
242 | { | ||
243 | int ret; | ||
244 | |||
245 | bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); | ||
246 | if (IS_ERR(bfin_jc_kthread)) | ||
247 | return PTR_ERR(bfin_jc_kthread); | ||
248 | |||
249 | ret = -ENOMEM; | ||
250 | |||
251 | bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0; | ||
252 | bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL); | ||
253 | if (!bfin_jc_write_buf.buf) | ||
254 | goto err; | ||
255 | |||
256 | bfin_jc_driver = alloc_tty_driver(1); | ||
257 | if (!bfin_jc_driver) | ||
258 | goto err; | ||
259 | |||
260 | bfin_jc_driver->owner = THIS_MODULE; | ||
261 | bfin_jc_driver->driver_name = DRV_NAME; | ||
262 | bfin_jc_driver->name = DEV_NAME; | ||
263 | bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
264 | bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL; | ||
265 | bfin_jc_driver->init_termios = tty_std_termios; | ||
266 | tty_set_operations(bfin_jc_driver, &bfin_jc_ops); | ||
267 | |||
268 | ret = tty_register_driver(bfin_jc_driver); | ||
269 | if (ret) | ||
270 | goto err; | ||
271 | |||
272 | pr_init(KERN_INFO DRV_NAME ": initialized\n"); | ||
273 | |||
274 | return 0; | ||
275 | |||
276 | err: | ||
277 | put_tty_driver(bfin_jc_driver); | ||
278 | kfree(bfin_jc_write_buf.buf); | ||
279 | kthread_stop(bfin_jc_kthread); | ||
280 | return ret; | ||
281 | } | ||
282 | module_init(bfin_jc_init); | ||
283 | |||
284 | static void __exit bfin_jc_exit(void) | ||
285 | { | ||
286 | kthread_stop(bfin_jc_kthread); | ||
287 | kfree(bfin_jc_write_buf.buf); | ||
288 | tty_unregister_driver(bfin_jc_driver); | ||
289 | put_tty_driver(bfin_jc_driver); | ||
290 | } | ||
291 | module_exit(bfin_jc_exit); | ||
292 | |||
293 | #if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK) | ||
294 | static void | ||
295 | bfin_jc_straight_buffer_write(const char *buf, unsigned count) | ||
296 | { | ||
297 | unsigned ate = 0; | ||
298 | while (bfin_read_DBGSTAT() & EMUDOF) | ||
299 | continue; | ||
300 | bfin_write_emudat(count); | ||
301 | while (ate < count) { | ||
302 | while (bfin_read_DBGSTAT() & EMUDOF) | ||
303 | continue; | ||
304 | bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]); | ||
305 | ate += 4; | ||
306 | } | ||
307 | } | ||
308 | #endif | ||
309 | |||
310 | #ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE | ||
311 | static void | ||
312 | bfin_jc_console_write(struct console *co, const char *buf, unsigned count) | ||
313 | { | ||
314 | if (bfin_jc_kthread == NULL) | ||
315 | bfin_jc_straight_buffer_write(buf, count); | ||
316 | else | ||
317 | bfin_jc_circ_write(buf, count); | ||
318 | } | ||
319 | |||
320 | static struct tty_driver * | ||
321 | bfin_jc_console_device(struct console *co, int *index) | ||
322 | { | ||
323 | *index = co->index; | ||
324 | return bfin_jc_driver; | ||
325 | } | ||
326 | |||
327 | static struct console bfin_jc_console = { | ||
328 | .name = DEV_NAME, | ||
329 | .write = bfin_jc_console_write, | ||
330 | .device = bfin_jc_console_device, | ||
331 | .flags = CON_ANYTIME | CON_PRINTBUFFER, | ||
332 | .index = -1, | ||
333 | }; | ||
334 | |||
335 | static int __init bfin_jc_console_init(void) | ||
336 | { | ||
337 | register_console(&bfin_jc_console); | ||
338 | return 0; | ||
339 | } | ||
340 | console_initcall(bfin_jc_console_init); | ||
341 | #endif | ||
342 | |||
343 | #ifdef CONFIG_EARLY_PRINTK | ||
344 | static void __init | ||
345 | bfin_jc_early_write(struct console *co, const char *buf, unsigned int count) | ||
346 | { | ||
347 | bfin_jc_straight_buffer_write(buf, count); | ||
348 | } | ||
349 | |||
350 | static struct __initdata console bfin_jc_early_console = { | ||
351 | .name = "early_BFJC", | ||
352 | .write = bfin_jc_early_write, | ||
353 | .flags = CON_ANYTIME | CON_PRINTBUFFER, | ||
354 | .index = -1, | ||
355 | }; | ||
356 | |||
357 | struct console * __init | ||
358 | bfin_jc_early_init(unsigned int port, unsigned int cflag) | ||
359 | { | ||
360 | return &bfin_jc_early_console; | ||
361 | } | ||
362 | #endif | ||
363 | |||
364 | MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); | ||
365 | MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication"); | ||
366 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c new file mode 100644 index 000000000000..c99728f0cd9f --- /dev/null +++ b/drivers/tty/cyclades.c | |||
@@ -0,0 +1,4200 @@ | |||
1 | #undef BLOCKMOVE | ||
2 | #define Z_WAKE | ||
3 | #undef Z_EXT_CHARS_IN_BUFFER | ||
4 | |||
5 | /* | ||
6 | * linux/drivers/char/cyclades.c | ||
7 | * | ||
8 | * This file contains the driver for the Cyclades async multiport | ||
9 | * serial boards. | ||
10 | * | ||
11 | * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>. | ||
12 | * Modified and maintained by Marcio Saito <marcio@cyclades.com>. | ||
13 | * | ||
14 | * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com> | ||
15 | * | ||
16 | * Much of the design and some of the code came from serial.c | ||
17 | * which was copyright (C) 1991, 1992 Linus Torvalds. It was | ||
18 | * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92, | ||
19 | * and then fixed as suggested by Michael K. Johnson 12/12/92. | ||
20 | * Converted to pci probing and cleaned up by Jiri Slaby. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #define CY_VERSION "2.6" | ||
25 | |||
26 | /* If you need to install more boards than NR_CARDS, change the constant | ||
27 | in the definition below. No other change is necessary to support up to | ||
28 | eight boards. Beyond that you'll have to extend cy_isa_addresses. */ | ||
29 | |||
30 | #define NR_CARDS 4 | ||
31 | |||
32 | /* | ||
33 | If the total number of ports is larger than NR_PORTS, change this | ||
34 | constant in the definition below. No other change is necessary to | ||
35 | support more boards/ports. */ | ||
36 | |||
37 | #define NR_PORTS 256 | ||
38 | |||
39 | #define ZO_V1 0 | ||
40 | #define ZO_V2 1 | ||
41 | #define ZE_V1 2 | ||
42 | |||
43 | #define SERIAL_PARANOIA_CHECK | ||
44 | #undef CY_DEBUG_OPEN | ||
45 | #undef CY_DEBUG_THROTTLE | ||
46 | #undef CY_DEBUG_OTHER | ||
47 | #undef CY_DEBUG_IO | ||
48 | #undef CY_DEBUG_COUNT | ||
49 | #undef CY_DEBUG_DTR | ||
50 | #undef CY_DEBUG_WAIT_UNTIL_SENT | ||
51 | #undef CY_DEBUG_INTERRUPTS | ||
52 | #undef CY_16Y_HACK | ||
53 | #undef CY_ENABLE_MONITORING | ||
54 | #undef CY_PCI_DEBUG | ||
55 | |||
56 | /* | ||
57 | * Include section | ||
58 | */ | ||
59 | #include <linux/module.h> | ||
60 | #include <linux/errno.h> | ||
61 | #include <linux/signal.h> | ||
62 | #include <linux/sched.h> | ||
63 | #include <linux/timer.h> | ||
64 | #include <linux/interrupt.h> | ||
65 | #include <linux/tty.h> | ||
66 | #include <linux/tty_flip.h> | ||
67 | #include <linux/serial.h> | ||
68 | #include <linux/major.h> | ||
69 | #include <linux/string.h> | ||
70 | #include <linux/fcntl.h> | ||
71 | #include <linux/ptrace.h> | ||
72 | #include <linux/cyclades.h> | ||
73 | #include <linux/mm.h> | ||
74 | #include <linux/ioport.h> | ||
75 | #include <linux/init.h> | ||
76 | #include <linux/delay.h> | ||
77 | #include <linux/spinlock.h> | ||
78 | #include <linux/bitops.h> | ||
79 | #include <linux/firmware.h> | ||
80 | #include <linux/device.h> | ||
81 | #include <linux/slab.h> | ||
82 | |||
83 | #include <linux/io.h> | ||
84 | #include <linux/uaccess.h> | ||
85 | |||
86 | #include <linux/kernel.h> | ||
87 | #include <linux/pci.h> | ||
88 | |||
89 | #include <linux/stat.h> | ||
90 | #include <linux/proc_fs.h> | ||
91 | #include <linux/seq_file.h> | ||
92 | |||
93 | static void cy_send_xchar(struct tty_struct *tty, char ch); | ||
94 | |||
95 | #ifndef SERIAL_XMIT_SIZE | ||
96 | #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) | ||
97 | #endif | ||
98 | |||
99 | #define STD_COM_FLAGS (0) | ||
100 | |||
101 | /* firmware stuff */ | ||
102 | #define ZL_MAX_BLOCKS 16 | ||
103 | #define DRIVER_VERSION 0x02010203 | ||
104 | #define RAM_SIZE 0x80000 | ||
105 | |||
106 | enum zblock_type { | ||
107 | ZBLOCK_PRG = 0, | ||
108 | ZBLOCK_FPGA = 1 | ||
109 | }; | ||
110 | |||
111 | struct zfile_header { | ||
112 | char name[64]; | ||
113 | char date[32]; | ||
114 | char aux[32]; | ||
115 | u32 n_config; | ||
116 | u32 config_offset; | ||
117 | u32 n_blocks; | ||
118 | u32 block_offset; | ||
119 | u32 reserved[9]; | ||
120 | } __attribute__ ((packed)); | ||
121 | |||
122 | struct zfile_config { | ||
123 | char name[64]; | ||
124 | u32 mailbox; | ||
125 | u32 function; | ||
126 | u32 n_blocks; | ||
127 | u32 block_list[ZL_MAX_BLOCKS]; | ||
128 | } __attribute__ ((packed)); | ||
129 | |||
130 | struct zfile_block { | ||
131 | u32 type; | ||
132 | u32 file_offset; | ||
133 | u32 ram_offset; | ||
134 | u32 size; | ||
135 | } __attribute__ ((packed)); | ||
136 | |||
137 | static struct tty_driver *cy_serial_driver; | ||
138 | |||
139 | #ifdef CONFIG_ISA | ||
140 | /* This is the address lookup table. The driver will probe for | ||
141 | Cyclom-Y/ISA boards at all addresses in here. If you want the | ||
142 | driver to probe addresses at a different address, add it to | ||
143 | this table. If the driver is probing some other board and | ||
144 | causing problems, remove the offending address from this table. | ||
145 | */ | ||
146 | |||
147 | static unsigned int cy_isa_addresses[] = { | ||
148 | 0xD0000, | ||
149 | 0xD2000, | ||
150 | 0xD4000, | ||
151 | 0xD6000, | ||
152 | 0xD8000, | ||
153 | 0xDA000, | ||
154 | 0xDC000, | ||
155 | 0xDE000, | ||
156 | 0, 0, 0, 0, 0, 0, 0, 0 | ||
157 | }; | ||
158 | |||
159 | #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) | ||
160 | |||
161 | static long maddr[NR_CARDS]; | ||
162 | static int irq[NR_CARDS]; | ||
163 | |||
164 | module_param_array(maddr, long, NULL, 0); | ||
165 | module_param_array(irq, int, NULL, 0); | ||
166 | |||
167 | #endif /* CONFIG_ISA */ | ||
168 | |||
169 | /* This is the per-card data structure containing address, irq, number of | ||
170 | channels, etc. This driver supports a maximum of NR_CARDS cards. | ||
171 | */ | ||
172 | static struct cyclades_card cy_card[NR_CARDS]; | ||
173 | |||
174 | static int cy_next_channel; /* next minor available */ | ||
175 | |||
176 | /* | ||
177 | * This is used to look up the divisor speeds and the timeouts | ||
178 | * We're normally limited to 15 distinct baud rates. The extra | ||
179 | * are accessed via settings in info->port.flags. | ||
180 | * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | ||
181 | * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, | ||
182 | * HI VHI | ||
183 | * 20 | ||
184 | */ | ||
185 | static const int baud_table[] = { | ||
186 | 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, | ||
187 | 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, | ||
188 | 230400, 0 | ||
189 | }; | ||
190 | |||
191 | static const char baud_co_25[] = { /* 25 MHz clock option table */ | ||
192 | /* value => 00 01 02 03 04 */ | ||
193 | /* divide by 8 32 128 512 2048 */ | ||
194 | 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, | ||
195 | 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
196 | }; | ||
197 | |||
198 | static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */ | ||
199 | 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, | ||
200 | 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 | ||
201 | }; | ||
202 | |||
203 | static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ | ||
204 | /* value => 00 01 02 03 04 */ | ||
205 | /* divide by 8 32 128 512 2048 */ | ||
206 | 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, | ||
207 | 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
208 | 0x00 | ||
209 | }; | ||
210 | |||
211 | static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ | ||
212 | 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, | ||
213 | 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, | ||
214 | 0x21 | ||
215 | }; | ||
216 | |||
217 | static const char baud_cor3[] = { /* receive threshold */ | ||
218 | 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, | ||
219 | 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, | ||
220 | 0x07 | ||
221 | }; | ||
222 | |||
223 | /* | ||
224 | * The Cyclades driver implements HW flow control as any serial driver. | ||
225 | * The cyclades_port structure member rflow and the vector rflow_thr | ||
226 | * allows us to take advantage of a special feature in the CD1400 to avoid | ||
227 | * data loss even when the system interrupt latency is too high. These flags | ||
228 | * are to be used only with very special applications. Setting these flags | ||
229 | * requires the use of a special cable (DTR and RTS reversed). In the new | ||
230 | * CD1400-based boards (rev. 6.00 or later), there is no need for special | ||
231 | * cables. | ||
232 | */ | ||
233 | |||
234 | static const char rflow_thr[] = { /* rflow threshold */ | ||
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
236 | 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, | ||
237 | 0x0a | ||
238 | }; | ||
239 | |||
240 | /* The Cyclom-Ye has placed the sequential chips in non-sequential | ||
241 | * address order. This look-up table overcomes that problem. | ||
242 | */ | ||
243 | static const unsigned int cy_chip_offset[] = { 0x0000, | ||
244 | 0x0400, | ||
245 | 0x0800, | ||
246 | 0x0C00, | ||
247 | 0x0200, | ||
248 | 0x0600, | ||
249 | 0x0A00, | ||
250 | 0x0E00 | ||
251 | }; | ||
252 | |||
253 | /* PCI related definitions */ | ||
254 | |||
255 | #ifdef CONFIG_PCI | ||
256 | static const struct pci_device_id cy_pci_dev_id[] = { | ||
257 | /* PCI < 1Mb */ | ||
258 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, | ||
259 | /* PCI > 1Mb */ | ||
260 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, | ||
261 | /* 4Y PCI < 1Mb */ | ||
262 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, | ||
263 | /* 4Y PCI > 1Mb */ | ||
264 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, | ||
265 | /* 8Y PCI < 1Mb */ | ||
266 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, | ||
267 | /* 8Y PCI > 1Mb */ | ||
268 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, | ||
269 | /* Z PCI < 1Mb */ | ||
270 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, | ||
271 | /* Z PCI > 1Mb */ | ||
272 | { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, | ||
273 | { } /* end of table */ | ||
274 | }; | ||
275 | MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); | ||
276 | #endif | ||
277 | |||
278 | static void cy_start(struct tty_struct *); | ||
279 | static void cy_set_line_char(struct cyclades_port *, struct tty_struct *); | ||
280 | static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); | ||
281 | #ifdef CONFIG_ISA | ||
282 | static unsigned detect_isa_irq(void __iomem *); | ||
283 | #endif /* CONFIG_ISA */ | ||
284 | |||
285 | #ifndef CONFIG_CYZ_INTR | ||
286 | static void cyz_poll(unsigned long); | ||
287 | |||
288 | /* The Cyclades-Z polling cycle is defined by this variable */ | ||
289 | static long cyz_polling_cycle = CZ_DEF_POLL; | ||
290 | |||
291 | static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); | ||
292 | |||
293 | #else /* CONFIG_CYZ_INTR */ | ||
294 | static void cyz_rx_restart(unsigned long); | ||
295 | static struct timer_list cyz_rx_full_timer[NR_PORTS]; | ||
296 | #endif /* CONFIG_CYZ_INTR */ | ||
297 | |||
298 | static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val) | ||
299 | { | ||
300 | struct cyclades_card *card = port->card; | ||
301 | |||
302 | cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val); | ||
303 | } | ||
304 | |||
305 | static inline u8 cyy_readb(struct cyclades_port *port, u32 reg) | ||
306 | { | ||
307 | struct cyclades_card *card = port->card; | ||
308 | |||
309 | return readb(port->u.cyy.base_addr + (reg << card->bus_index)); | ||
310 | } | ||
311 | |||
312 | static inline bool cy_is_Z(struct cyclades_card *card) | ||
313 | { | ||
314 | return card->num_chips == (unsigned int)-1; | ||
315 | } | ||
316 | |||
317 | static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr) | ||
318 | { | ||
319 | return readl(&ctl_addr->init_ctrl) & (1 << 17); | ||
320 | } | ||
321 | |||
322 | static inline bool cyz_fpga_loaded(struct cyclades_card *card) | ||
323 | { | ||
324 | return __cyz_fpga_loaded(card->ctl_addr.p9060); | ||
325 | } | ||
326 | |||
327 | static inline bool cyz_is_loaded(struct cyclades_card *card) | ||
328 | { | ||
329 | struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS; | ||
330 | |||
331 | return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) && | ||
332 | readl(&fw_id->signature) == ZFIRM_ID; | ||
333 | } | ||
334 | |||
335 | static inline int serial_paranoia_check(struct cyclades_port *info, | ||
336 | const char *name, const char *routine) | ||
337 | { | ||
338 | #ifdef SERIAL_PARANOIA_CHECK | ||
339 | if (!info) { | ||
340 | printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) " | ||
341 | "in %s\n", name, routine); | ||
342 | return 1; | ||
343 | } | ||
344 | |||
345 | if (info->magic != CYCLADES_MAGIC) { | ||
346 | printk(KERN_WARNING "cyc Warning: bad magic number for serial " | ||
347 | "struct (%s) in %s\n", name, routine); | ||
348 | return 1; | ||
349 | } | ||
350 | #endif | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | /***********************************************************/ | ||
355 | /********* Start of block of Cyclom-Y specific code ********/ | ||
356 | |||
357 | /* This routine waits up to 1000 micro-seconds for the previous | ||
358 | command to the Cirrus chip to complete and then issues the | ||
359 | new command. An error is returned if the previous command | ||
360 | didn't finish within the time limit. | ||
361 | |||
362 | This function is only called from inside spinlock-protected code. | ||
363 | */ | ||
364 | static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index) | ||
365 | { | ||
366 | void __iomem *ccr = base_addr + (CyCCR << index); | ||
367 | unsigned int i; | ||
368 | |||
369 | /* Check to see that the previous command has completed */ | ||
370 | for (i = 0; i < 100; i++) { | ||
371 | if (readb(ccr) == 0) | ||
372 | break; | ||
373 | udelay(10L); | ||
374 | } | ||
375 | /* if the CCR never cleared, the previous command | ||
376 | didn't finish within the "reasonable time" */ | ||
377 | if (i == 100) | ||
378 | return -1; | ||
379 | |||
380 | /* Issue the new command */ | ||
381 | cy_writeb(ccr, cmd); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd) | ||
387 | { | ||
388 | return __cyy_issue_cmd(port->u.cyy.base_addr, cmd, | ||
389 | port->card->bus_index); | ||
390 | } | ||
391 | |||
392 | #ifdef CONFIG_ISA | ||
393 | /* ISA interrupt detection code */ | ||
394 | static unsigned detect_isa_irq(void __iomem *address) | ||
395 | { | ||
396 | int irq; | ||
397 | unsigned long irqs, flags; | ||
398 | int save_xir, save_car; | ||
399 | int index = 0; /* IRQ probing is only for ISA */ | ||
400 | |||
401 | /* forget possible initially masked and pending IRQ */ | ||
402 | irq = probe_irq_off(probe_irq_on()); | ||
403 | |||
404 | /* Clear interrupts on the board first */ | ||
405 | cy_writeb(address + (Cy_ClrIntr << index), 0); | ||
406 | /* Cy_ClrIntr is 0x1800 */ | ||
407 | |||
408 | irqs = probe_irq_on(); | ||
409 | /* Wait ... */ | ||
410 | msleep(5); | ||
411 | |||
412 | /* Enable the Tx interrupts on the CD1400 */ | ||
413 | local_irq_save(flags); | ||
414 | cy_writeb(address + (CyCAR << index), 0); | ||
415 | __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); | ||
416 | |||
417 | cy_writeb(address + (CyCAR << index), 0); | ||
418 | cy_writeb(address + (CySRER << index), | ||
419 | readb(address + (CySRER << index)) | CyTxRdy); | ||
420 | local_irq_restore(flags); | ||
421 | |||
422 | /* Wait ... */ | ||
423 | msleep(5); | ||
424 | |||
425 | /* Check which interrupt is in use */ | ||
426 | irq = probe_irq_off(irqs); | ||
427 | |||
428 | /* Clean up */ | ||
429 | save_xir = (u_char) readb(address + (CyTIR << index)); | ||
430 | save_car = readb(address + (CyCAR << index)); | ||
431 | cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); | ||
432 | cy_writeb(address + (CySRER << index), | ||
433 | readb(address + (CySRER << index)) & ~CyTxRdy); | ||
434 | cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); | ||
435 | cy_writeb(address + (CyCAR << index), (save_car)); | ||
436 | cy_writeb(address + (Cy_ClrIntr << index), 0); | ||
437 | /* Cy_ClrIntr is 0x1800 */ | ||
438 | |||
439 | return (irq > 0) ? irq : 0; | ||
440 | } | ||
441 | #endif /* CONFIG_ISA */ | ||
442 | |||
443 | static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, | ||
444 | void __iomem *base_addr) | ||
445 | { | ||
446 | struct cyclades_port *info; | ||
447 | struct tty_struct *tty; | ||
448 | int len, index = cinfo->bus_index; | ||
449 | u8 ivr, save_xir, channel, save_car, data, char_count; | ||
450 | |||
451 | #ifdef CY_DEBUG_INTERRUPTS | ||
452 | printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip); | ||
453 | #endif | ||
454 | /* determine the channel & change to that context */ | ||
455 | save_xir = readb(base_addr + (CyRIR << index)); | ||
456 | channel = save_xir & CyIRChannel; | ||
457 | info = &cinfo->ports[channel + chip * 4]; | ||
458 | save_car = cyy_readb(info, CyCAR); | ||
459 | cyy_writeb(info, CyCAR, save_xir); | ||
460 | ivr = cyy_readb(info, CyRIVR) & CyIVRMask; | ||
461 | |||
462 | tty = tty_port_tty_get(&info->port); | ||
463 | /* if there is nowhere to put the data, discard it */ | ||
464 | if (tty == NULL) { | ||
465 | if (ivr == CyIVRRxEx) { /* exception */ | ||
466 | data = cyy_readb(info, CyRDSR); | ||
467 | } else { /* normal character reception */ | ||
468 | char_count = cyy_readb(info, CyRDCR); | ||
469 | while (char_count--) | ||
470 | data = cyy_readb(info, CyRDSR); | ||
471 | } | ||
472 | goto end; | ||
473 | } | ||
474 | /* there is an open port for this data */ | ||
475 | if (ivr == CyIVRRxEx) { /* exception */ | ||
476 | data = cyy_readb(info, CyRDSR); | ||
477 | |||
478 | /* For statistics only */ | ||
479 | if (data & CyBREAK) | ||
480 | info->icount.brk++; | ||
481 | else if (data & CyFRAME) | ||
482 | info->icount.frame++; | ||
483 | else if (data & CyPARITY) | ||
484 | info->icount.parity++; | ||
485 | else if (data & CyOVERRUN) | ||
486 | info->icount.overrun++; | ||
487 | |||
488 | if (data & info->ignore_status_mask) { | ||
489 | info->icount.rx++; | ||
490 | tty_kref_put(tty); | ||
491 | return; | ||
492 | } | ||
493 | if (tty_buffer_request_room(tty, 1)) { | ||
494 | if (data & info->read_status_mask) { | ||
495 | if (data & CyBREAK) { | ||
496 | tty_insert_flip_char(tty, | ||
497 | cyy_readb(info, CyRDSR), | ||
498 | TTY_BREAK); | ||
499 | info->icount.rx++; | ||
500 | if (info->port.flags & ASYNC_SAK) | ||
501 | do_SAK(tty); | ||
502 | } else if (data & CyFRAME) { | ||
503 | tty_insert_flip_char(tty, | ||
504 | cyy_readb(info, CyRDSR), | ||
505 | TTY_FRAME); | ||
506 | info->icount.rx++; | ||
507 | info->idle_stats.frame_errs++; | ||
508 | } else if (data & CyPARITY) { | ||
509 | /* Pieces of seven... */ | ||
510 | tty_insert_flip_char(tty, | ||
511 | cyy_readb(info, CyRDSR), | ||
512 | TTY_PARITY); | ||
513 | info->icount.rx++; | ||
514 | info->idle_stats.parity_errs++; | ||
515 | } else if (data & CyOVERRUN) { | ||
516 | tty_insert_flip_char(tty, 0, | ||
517 | TTY_OVERRUN); | ||
518 | info->icount.rx++; | ||
519 | /* If the flip buffer itself is | ||
520 | overflowing, we still lose | ||
521 | the next incoming character. | ||
522 | */ | ||
523 | tty_insert_flip_char(tty, | ||
524 | cyy_readb(info, CyRDSR), | ||
525 | TTY_FRAME); | ||
526 | info->icount.rx++; | ||
527 | info->idle_stats.overruns++; | ||
528 | /* These two conditions may imply */ | ||
529 | /* a normal read should be done. */ | ||
530 | /* } else if(data & CyTIMEOUT) { */ | ||
531 | /* } else if(data & CySPECHAR) { */ | ||
532 | } else { | ||
533 | tty_insert_flip_char(tty, 0, | ||
534 | TTY_NORMAL); | ||
535 | info->icount.rx++; | ||
536 | } | ||
537 | } else { | ||
538 | tty_insert_flip_char(tty, 0, TTY_NORMAL); | ||
539 | info->icount.rx++; | ||
540 | } | ||
541 | } else { | ||
542 | /* there was a software buffer overrun and nothing | ||
543 | * could be done about it!!! */ | ||
544 | info->icount.buf_overrun++; | ||
545 | info->idle_stats.overruns++; | ||
546 | } | ||
547 | } else { /* normal character reception */ | ||
548 | /* load # chars available from the chip */ | ||
549 | char_count = cyy_readb(info, CyRDCR); | ||
550 | |||
551 | #ifdef CY_ENABLE_MONITORING | ||
552 | ++info->mon.int_count; | ||
553 | info->mon.char_count += char_count; | ||
554 | if (char_count > info->mon.char_max) | ||
555 | info->mon.char_max = char_count; | ||
556 | info->mon.char_last = char_count; | ||
557 | #endif | ||
558 | len = tty_buffer_request_room(tty, char_count); | ||
559 | while (len--) { | ||
560 | data = cyy_readb(info, CyRDSR); | ||
561 | tty_insert_flip_char(tty, data, TTY_NORMAL); | ||
562 | info->idle_stats.recv_bytes++; | ||
563 | info->icount.rx++; | ||
564 | #ifdef CY_16Y_HACK | ||
565 | udelay(10L); | ||
566 | #endif | ||
567 | } | ||
568 | info->idle_stats.recv_idle = jiffies; | ||
569 | } | ||
570 | tty_schedule_flip(tty); | ||
571 | tty_kref_put(tty); | ||
572 | end: | ||
573 | /* end of service */ | ||
574 | cyy_writeb(info, CyRIR, save_xir & 0x3f); | ||
575 | cyy_writeb(info, CyCAR, save_car); | ||
576 | } | ||
577 | |||
578 | static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip, | ||
579 | void __iomem *base_addr) | ||
580 | { | ||
581 | struct cyclades_port *info; | ||
582 | struct tty_struct *tty; | ||
583 | int char_count, index = cinfo->bus_index; | ||
584 | u8 save_xir, channel, save_car, outch; | ||
585 | |||
586 | /* Since we only get here when the transmit buffer | ||
587 | is empty, we know we can always stuff a dozen | ||
588 | characters. */ | ||
589 | #ifdef CY_DEBUG_INTERRUPTS | ||
590 | printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip); | ||
591 | #endif | ||
592 | |||
593 | /* determine the channel & change to that context */ | ||
594 | save_xir = readb(base_addr + (CyTIR << index)); | ||
595 | channel = save_xir & CyIRChannel; | ||
596 | save_car = readb(base_addr + (CyCAR << index)); | ||
597 | cy_writeb(base_addr + (CyCAR << index), save_xir); | ||
598 | |||
599 | info = &cinfo->ports[channel + chip * 4]; | ||
600 | tty = tty_port_tty_get(&info->port); | ||
601 | if (tty == NULL) { | ||
602 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); | ||
603 | goto end; | ||
604 | } | ||
605 | |||
606 | /* load the on-chip space for outbound data */ | ||
607 | char_count = info->xmit_fifo_size; | ||
608 | |||
609 | if (info->x_char) { /* send special char */ | ||
610 | outch = info->x_char; | ||
611 | cyy_writeb(info, CyTDR, outch); | ||
612 | char_count--; | ||
613 | info->icount.tx++; | ||
614 | info->x_char = 0; | ||
615 | } | ||
616 | |||
617 | if (info->breakon || info->breakoff) { | ||
618 | if (info->breakon) { | ||
619 | cyy_writeb(info, CyTDR, 0); | ||
620 | cyy_writeb(info, CyTDR, 0x81); | ||
621 | info->breakon = 0; | ||
622 | char_count -= 2; | ||
623 | } | ||
624 | if (info->breakoff) { | ||
625 | cyy_writeb(info, CyTDR, 0); | ||
626 | cyy_writeb(info, CyTDR, 0x83); | ||
627 | info->breakoff = 0; | ||
628 | char_count -= 2; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | while (char_count-- > 0) { | ||
633 | if (!info->xmit_cnt) { | ||
634 | if (cyy_readb(info, CySRER) & CyTxMpty) { | ||
635 | cyy_writeb(info, CySRER, | ||
636 | cyy_readb(info, CySRER) & ~CyTxMpty); | ||
637 | } else { | ||
638 | cyy_writeb(info, CySRER, CyTxMpty | | ||
639 | (cyy_readb(info, CySRER) & ~CyTxRdy)); | ||
640 | } | ||
641 | goto done; | ||
642 | } | ||
643 | if (info->port.xmit_buf == NULL) { | ||
644 | cyy_writeb(info, CySRER, | ||
645 | cyy_readb(info, CySRER) & ~CyTxRdy); | ||
646 | goto done; | ||
647 | } | ||
648 | if (tty->stopped || tty->hw_stopped) { | ||
649 | cyy_writeb(info, CySRER, | ||
650 | cyy_readb(info, CySRER) & ~CyTxRdy); | ||
651 | goto done; | ||
652 | } | ||
653 | /* Because the Embedded Transmit Commands have been enabled, | ||
654 | * we must check to see if the escape character, NULL, is being | ||
655 | * sent. If it is, we must ensure that there is room for it to | ||
656 | * be doubled in the output stream. Therefore we no longer | ||
657 | * advance the pointer when the character is fetched, but | ||
658 | * rather wait until after the check for a NULL output | ||
659 | * character. This is necessary because there may not be room | ||
660 | * for the two chars needed to send a NULL.) | ||
661 | */ | ||
662 | outch = info->port.xmit_buf[info->xmit_tail]; | ||
663 | if (outch) { | ||
664 | info->xmit_cnt--; | ||
665 | info->xmit_tail = (info->xmit_tail + 1) & | ||
666 | (SERIAL_XMIT_SIZE - 1); | ||
667 | cyy_writeb(info, CyTDR, outch); | ||
668 | info->icount.tx++; | ||
669 | } else { | ||
670 | if (char_count > 1) { | ||
671 | info->xmit_cnt--; | ||
672 | info->xmit_tail = (info->xmit_tail + 1) & | ||
673 | (SERIAL_XMIT_SIZE - 1); | ||
674 | cyy_writeb(info, CyTDR, outch); | ||
675 | cyy_writeb(info, CyTDR, 0); | ||
676 | info->icount.tx++; | ||
677 | char_count--; | ||
678 | } | ||
679 | } | ||
680 | } | ||
681 | |||
682 | done: | ||
683 | tty_wakeup(tty); | ||
684 | tty_kref_put(tty); | ||
685 | end: | ||
686 | /* end of service */ | ||
687 | cyy_writeb(info, CyTIR, save_xir & 0x3f); | ||
688 | cyy_writeb(info, CyCAR, save_car); | ||
689 | } | ||
690 | |||
691 | static void cyy_chip_modem(struct cyclades_card *cinfo, int chip, | ||
692 | void __iomem *base_addr) | ||
693 | { | ||
694 | struct cyclades_port *info; | ||
695 | struct tty_struct *tty; | ||
696 | int index = cinfo->bus_index; | ||
697 | u8 save_xir, channel, save_car, mdm_change, mdm_status; | ||
698 | |||
699 | /* determine the channel & change to that context */ | ||
700 | save_xir = readb(base_addr + (CyMIR << index)); | ||
701 | channel = save_xir & CyIRChannel; | ||
702 | info = &cinfo->ports[channel + chip * 4]; | ||
703 | save_car = cyy_readb(info, CyCAR); | ||
704 | cyy_writeb(info, CyCAR, save_xir); | ||
705 | |||
706 | mdm_change = cyy_readb(info, CyMISR); | ||
707 | mdm_status = cyy_readb(info, CyMSVR1); | ||
708 | |||
709 | tty = tty_port_tty_get(&info->port); | ||
710 | if (!tty) | ||
711 | goto end; | ||
712 | |||
713 | if (mdm_change & CyANY_DELTA) { | ||
714 | /* For statistics only */ | ||
715 | if (mdm_change & CyDCD) | ||
716 | info->icount.dcd++; | ||
717 | if (mdm_change & CyCTS) | ||
718 | info->icount.cts++; | ||
719 | if (mdm_change & CyDSR) | ||
720 | info->icount.dsr++; | ||
721 | if (mdm_change & CyRI) | ||
722 | info->icount.rng++; | ||
723 | |||
724 | wake_up_interruptible(&info->port.delta_msr_wait); | ||
725 | } | ||
726 | |||
727 | if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) { | ||
728 | if (mdm_status & CyDCD) | ||
729 | wake_up_interruptible(&info->port.open_wait); | ||
730 | else | ||
731 | tty_hangup(tty); | ||
732 | } | ||
733 | if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) { | ||
734 | if (tty->hw_stopped) { | ||
735 | if (mdm_status & CyCTS) { | ||
736 | /* cy_start isn't used | ||
737 | because... !!! */ | ||
738 | tty->hw_stopped = 0; | ||
739 | cyy_writeb(info, CySRER, | ||
740 | cyy_readb(info, CySRER) | CyTxRdy); | ||
741 | tty_wakeup(tty); | ||
742 | } | ||
743 | } else { | ||
744 | if (!(mdm_status & CyCTS)) { | ||
745 | /* cy_stop isn't used | ||
746 | because ... !!! */ | ||
747 | tty->hw_stopped = 1; | ||
748 | cyy_writeb(info, CySRER, | ||
749 | cyy_readb(info, CySRER) & ~CyTxRdy); | ||
750 | } | ||
751 | } | ||
752 | } | ||
753 | /* if (mdm_change & CyDSR) { | ||
754 | } | ||
755 | if (mdm_change & CyRI) { | ||
756 | }*/ | ||
757 | tty_kref_put(tty); | ||
758 | end: | ||
759 | /* end of service */ | ||
760 | cyy_writeb(info, CyMIR, save_xir & 0x3f); | ||
761 | cyy_writeb(info, CyCAR, save_car); | ||
762 | } | ||
763 | |||
764 | /* The real interrupt service routine is called | ||
765 | whenever the card wants its hand held--chars | ||
766 | received, out buffer empty, modem change, etc. | ||
767 | */ | ||
768 | static irqreturn_t cyy_interrupt(int irq, void *dev_id) | ||
769 | { | ||
770 | int status; | ||
771 | struct cyclades_card *cinfo = dev_id; | ||
772 | void __iomem *base_addr, *card_base_addr; | ||
773 | unsigned int chip, too_many, had_work; | ||
774 | int index; | ||
775 | |||
776 | if (unlikely(cinfo == NULL)) { | ||
777 | #ifdef CY_DEBUG_INTERRUPTS | ||
778 | printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n", | ||
779 | irq); | ||
780 | #endif | ||
781 | return IRQ_NONE; /* spurious interrupt */ | ||
782 | } | ||
783 | |||
784 | card_base_addr = cinfo->base_addr; | ||
785 | index = cinfo->bus_index; | ||
786 | |||
787 | /* card was not initialized yet (e.g. DEBUG_SHIRQ) */ | ||
788 | if (unlikely(card_base_addr == NULL)) | ||
789 | return IRQ_HANDLED; | ||
790 | |||
791 | /* This loop checks all chips in the card. Make a note whenever | ||
792 | _any_ chip had some work to do, as this is considered an | ||
793 | indication that there will be more to do. Only when no chip | ||
794 | has any work does this outermost loop exit. | ||
795 | */ | ||
796 | do { | ||
797 | had_work = 0; | ||
798 | for (chip = 0; chip < cinfo->num_chips; chip++) { | ||
799 | base_addr = cinfo->base_addr + | ||
800 | (cy_chip_offset[chip] << index); | ||
801 | too_many = 0; | ||
802 | while ((status = readb(base_addr + | ||
803 | (CySVRR << index))) != 0x00) { | ||
804 | had_work++; | ||
805 | /* The purpose of the following test is to ensure that | ||
806 | no chip can monopolize the driver. This forces the | ||
807 | chips to be checked in a round-robin fashion (after | ||
808 | draining each of a bunch (1000) of characters). | ||
809 | */ | ||
810 | if (1000 < too_many++) | ||
811 | break; | ||
812 | spin_lock(&cinfo->card_lock); | ||
813 | if (status & CySRReceive) /* rx intr */ | ||
814 | cyy_chip_rx(cinfo, chip, base_addr); | ||
815 | if (status & CySRTransmit) /* tx intr */ | ||
816 | cyy_chip_tx(cinfo, chip, base_addr); | ||
817 | if (status & CySRModem) /* modem intr */ | ||
818 | cyy_chip_modem(cinfo, chip, base_addr); | ||
819 | spin_unlock(&cinfo->card_lock); | ||
820 | } | ||
821 | } | ||
822 | } while (had_work); | ||
823 | |||
824 | /* clear interrupts */ | ||
825 | spin_lock(&cinfo->card_lock); | ||
826 | cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0); | ||
827 | /* Cy_ClrIntr is 0x1800 */ | ||
828 | spin_unlock(&cinfo->card_lock); | ||
829 | return IRQ_HANDLED; | ||
830 | } /* cyy_interrupt */ | ||
831 | |||
832 | static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set, | ||
833 | unsigned int clear) | ||
834 | { | ||
835 | struct cyclades_card *card = info->card; | ||
836 | int channel = info->line - card->first_line; | ||
837 | u32 rts, dtr, msvrr, msvrd; | ||
838 | |||
839 | channel &= 0x03; | ||
840 | |||
841 | if (info->rtsdtr_inv) { | ||
842 | msvrr = CyMSVR2; | ||
843 | msvrd = CyMSVR1; | ||
844 | rts = CyDTR; | ||
845 | dtr = CyRTS; | ||
846 | } else { | ||
847 | msvrr = CyMSVR1; | ||
848 | msvrd = CyMSVR2; | ||
849 | rts = CyRTS; | ||
850 | dtr = CyDTR; | ||
851 | } | ||
852 | if (set & TIOCM_RTS) { | ||
853 | cyy_writeb(info, CyCAR, channel); | ||
854 | cyy_writeb(info, msvrr, rts); | ||
855 | } | ||
856 | if (clear & TIOCM_RTS) { | ||
857 | cyy_writeb(info, CyCAR, channel); | ||
858 | cyy_writeb(info, msvrr, ~rts); | ||
859 | } | ||
860 | if (set & TIOCM_DTR) { | ||
861 | cyy_writeb(info, CyCAR, channel); | ||
862 | cyy_writeb(info, msvrd, dtr); | ||
863 | #ifdef CY_DEBUG_DTR | ||
864 | printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n"); | ||
865 | printk(KERN_DEBUG " status: 0x%x, 0x%x\n", | ||
866 | cyy_readb(info, CyMSVR1), | ||
867 | cyy_readb(info, CyMSVR2)); | ||
868 | #endif | ||
869 | } | ||
870 | if (clear & TIOCM_DTR) { | ||
871 | cyy_writeb(info, CyCAR, channel); | ||
872 | cyy_writeb(info, msvrd, ~dtr); | ||
873 | #ifdef CY_DEBUG_DTR | ||
874 | printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n"); | ||
875 | printk(KERN_DEBUG " status: 0x%x, 0x%x\n", | ||
876 | cyy_readb(info, CyMSVR1), | ||
877 | cyy_readb(info, CyMSVR2)); | ||
878 | #endif | ||
879 | } | ||
880 | } | ||
881 | |||
882 | /***********************************************************/ | ||
883 | /********* End of block of Cyclom-Y specific code **********/ | ||
884 | /******** Start of block of Cyclades-Z specific code *******/ | ||
885 | /***********************************************************/ | ||
886 | |||
887 | static int | ||
888 | cyz_fetch_msg(struct cyclades_card *cinfo, | ||
889 | __u32 *channel, __u8 *cmd, __u32 *param) | ||
890 | { | ||
891 | struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; | ||
892 | unsigned long loc_doorbell; | ||
893 | |||
894 | loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell); | ||
895 | if (loc_doorbell) { | ||
896 | *cmd = (char)(0xff & loc_doorbell); | ||
897 | *channel = readl(&board_ctrl->fwcmd_channel); | ||
898 | *param = (__u32) readl(&board_ctrl->fwcmd_param); | ||
899 | cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff); | ||
900 | return 1; | ||
901 | } | ||
902 | return 0; | ||
903 | } /* cyz_fetch_msg */ | ||
904 | |||
905 | static int | ||
906 | cyz_issue_cmd(struct cyclades_card *cinfo, | ||
907 | __u32 channel, __u8 cmd, __u32 param) | ||
908 | { | ||
909 | struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; | ||
910 | __u32 __iomem *pci_doorbell; | ||
911 | unsigned int index; | ||
912 | |||
913 | if (!cyz_is_loaded(cinfo)) | ||
914 | return -1; | ||
915 | |||
916 | index = 0; | ||
917 | pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell; | ||
918 | while ((readl(pci_doorbell) & 0xff) != 0) { | ||
919 | if (index++ == 1000) | ||
920 | return (int)(readl(pci_doorbell) & 0xff); | ||
921 | udelay(50L); | ||
922 | } | ||
923 | cy_writel(&board_ctrl->hcmd_channel, channel); | ||
924 | cy_writel(&board_ctrl->hcmd_param, param); | ||
925 | cy_writel(pci_doorbell, (long)cmd); | ||
926 | |||
927 | return 0; | ||
928 | } /* cyz_issue_cmd */ | ||
929 | |||
930 | static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) | ||
931 | { | ||
932 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; | ||
933 | struct cyclades_card *cinfo = info->card; | ||
934 | unsigned int char_count; | ||
935 | int len; | ||
936 | #ifdef BLOCKMOVE | ||
937 | unsigned char *buf; | ||
938 | #else | ||
939 | char data; | ||
940 | #endif | ||
941 | __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; | ||
942 | |||
943 | rx_get = new_rx_get = readl(&buf_ctrl->rx_get); | ||
944 | rx_put = readl(&buf_ctrl->rx_put); | ||
945 | rx_bufsize = readl(&buf_ctrl->rx_bufsize); | ||
946 | rx_bufaddr = readl(&buf_ctrl->rx_bufaddr); | ||
947 | if (rx_put >= rx_get) | ||
948 | char_count = rx_put - rx_get; | ||
949 | else | ||
950 | char_count = rx_put - rx_get + rx_bufsize; | ||
951 | |||
952 | if (char_count) { | ||
953 | #ifdef CY_ENABLE_MONITORING | ||
954 | info->mon.int_count++; | ||
955 | info->mon.char_count += char_count; | ||
956 | if (char_count > info->mon.char_max) | ||
957 | info->mon.char_max = char_count; | ||
958 | info->mon.char_last = char_count; | ||
959 | #endif | ||
960 | if (tty == NULL) { | ||
961 | /* flush received characters */ | ||
962 | new_rx_get = (new_rx_get + char_count) & | ||
963 | (rx_bufsize - 1); | ||
964 | info->rflush_count++; | ||
965 | } else { | ||
966 | #ifdef BLOCKMOVE | ||
967 | /* we'd like to use memcpy(t, f, n) and memset(s, c, count) | ||
968 | for performance, but because of buffer boundaries, there | ||
969 | may be several steps to the operation */ | ||
970 | while (1) { | ||
971 | len = tty_prepare_flip_string(tty, &buf, | ||
972 | char_count); | ||
973 | if (!len) | ||
974 | break; | ||
975 | |||
976 | len = min_t(unsigned int, min(len, char_count), | ||
977 | rx_bufsize - new_rx_get); | ||
978 | |||
979 | memcpy_fromio(buf, cinfo->base_addr + | ||
980 | rx_bufaddr + new_rx_get, len); | ||
981 | |||
982 | new_rx_get = (new_rx_get + len) & | ||
983 | (rx_bufsize - 1); | ||
984 | char_count -= len; | ||
985 | info->icount.rx += len; | ||
986 | info->idle_stats.recv_bytes += len; | ||
987 | } | ||
988 | #else | ||
989 | len = tty_buffer_request_room(tty, char_count); | ||
990 | while (len--) { | ||
991 | data = readb(cinfo->base_addr + rx_bufaddr + | ||
992 | new_rx_get); | ||
993 | new_rx_get = (new_rx_get + 1) & | ||
994 | (rx_bufsize - 1); | ||
995 | tty_insert_flip_char(tty, data, TTY_NORMAL); | ||
996 | info->idle_stats.recv_bytes++; | ||
997 | info->icount.rx++; | ||
998 | } | ||
999 | #endif | ||
1000 | #ifdef CONFIG_CYZ_INTR | ||
1001 | /* Recalculate the number of chars in the RX buffer and issue | ||
1002 | a cmd in case it's higher than the RX high water mark */ | ||
1003 | rx_put = readl(&buf_ctrl->rx_put); | ||
1004 | if (rx_put >= rx_get) | ||
1005 | char_count = rx_put - rx_get; | ||
1006 | else | ||
1007 | char_count = rx_put - rx_get + rx_bufsize; | ||
1008 | if (char_count >= readl(&buf_ctrl->rx_threshold) && | ||
1009 | !timer_pending(&cyz_rx_full_timer[ | ||
1010 | info->line])) | ||
1011 | mod_timer(&cyz_rx_full_timer[info->line], | ||
1012 | jiffies + 1); | ||
1013 | #endif | ||
1014 | info->idle_stats.recv_idle = jiffies; | ||
1015 | tty_schedule_flip(tty); | ||
1016 | } | ||
1017 | /* Update rx_get */ | ||
1018 | cy_writel(&buf_ctrl->rx_get, new_rx_get); | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) | ||
1023 | { | ||
1024 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; | ||
1025 | struct cyclades_card *cinfo = info->card; | ||
1026 | u8 data; | ||
1027 | unsigned int char_count; | ||
1028 | #ifdef BLOCKMOVE | ||
1029 | int small_count; | ||
1030 | #endif | ||
1031 | __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr; | ||
1032 | |||
1033 | if (info->xmit_cnt <= 0) /* Nothing to transmit */ | ||
1034 | return; | ||
1035 | |||
1036 | tx_get = readl(&buf_ctrl->tx_get); | ||
1037 | tx_put = readl(&buf_ctrl->tx_put); | ||
1038 | tx_bufsize = readl(&buf_ctrl->tx_bufsize); | ||
1039 | tx_bufaddr = readl(&buf_ctrl->tx_bufaddr); | ||
1040 | if (tx_put >= tx_get) | ||
1041 | char_count = tx_get - tx_put - 1 + tx_bufsize; | ||
1042 | else | ||
1043 | char_count = tx_get - tx_put - 1; | ||
1044 | |||
1045 | if (char_count) { | ||
1046 | |||
1047 | if (tty == NULL) | ||
1048 | goto ztxdone; | ||
1049 | |||
1050 | if (info->x_char) { /* send special char */ | ||
1051 | data = info->x_char; | ||
1052 | |||
1053 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); | ||
1054 | tx_put = (tx_put + 1) & (tx_bufsize - 1); | ||
1055 | info->x_char = 0; | ||
1056 | char_count--; | ||
1057 | info->icount.tx++; | ||
1058 | } | ||
1059 | #ifdef BLOCKMOVE | ||
1060 | while (0 < (small_count = min_t(unsigned int, | ||
1061 | tx_bufsize - tx_put, min_t(unsigned int, | ||
1062 | (SERIAL_XMIT_SIZE - info->xmit_tail), | ||
1063 | min_t(unsigned int, info->xmit_cnt, | ||
1064 | char_count))))) { | ||
1065 | |||
1066 | memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + | ||
1067 | tx_put), | ||
1068 | &info->port.xmit_buf[info->xmit_tail], | ||
1069 | small_count); | ||
1070 | |||
1071 | tx_put = (tx_put + small_count) & (tx_bufsize - 1); | ||
1072 | char_count -= small_count; | ||
1073 | info->icount.tx += small_count; | ||
1074 | info->xmit_cnt -= small_count; | ||
1075 | info->xmit_tail = (info->xmit_tail + small_count) & | ||
1076 | (SERIAL_XMIT_SIZE - 1); | ||
1077 | } | ||
1078 | #else | ||
1079 | while (info->xmit_cnt && char_count) { | ||
1080 | data = info->port.xmit_buf[info->xmit_tail]; | ||
1081 | info->xmit_cnt--; | ||
1082 | info->xmit_tail = (info->xmit_tail + 1) & | ||
1083 | (SERIAL_XMIT_SIZE - 1); | ||
1084 | |||
1085 | cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); | ||
1086 | tx_put = (tx_put + 1) & (tx_bufsize - 1); | ||
1087 | char_count--; | ||
1088 | info->icount.tx++; | ||
1089 | } | ||
1090 | #endif | ||
1091 | tty_wakeup(tty); | ||
1092 | ztxdone: | ||
1093 | /* Update tx_put */ | ||
1094 | cy_writel(&buf_ctrl->tx_put, tx_put); | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | static void cyz_handle_cmd(struct cyclades_card *cinfo) | ||
1099 | { | ||
1100 | struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; | ||
1101 | struct tty_struct *tty; | ||
1102 | struct cyclades_port *info; | ||
1103 | __u32 channel, param, fw_ver; | ||
1104 | __u8 cmd; | ||
1105 | int special_count; | ||
1106 | int delta_count; | ||
1107 | |||
1108 | fw_ver = readl(&board_ctrl->fw_version); | ||
1109 | |||
1110 | while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { | ||
1111 | special_count = 0; | ||
1112 | delta_count = 0; | ||
1113 | info = &cinfo->ports[channel]; | ||
1114 | tty = tty_port_tty_get(&info->port); | ||
1115 | if (tty == NULL) | ||
1116 | continue; | ||
1117 | |||
1118 | switch (cmd) { | ||
1119 | case C_CM_PR_ERROR: | ||
1120 | tty_insert_flip_char(tty, 0, TTY_PARITY); | ||
1121 | info->icount.rx++; | ||
1122 | special_count++; | ||
1123 | break; | ||
1124 | case C_CM_FR_ERROR: | ||
1125 | tty_insert_flip_char(tty, 0, TTY_FRAME); | ||
1126 | info->icount.rx++; | ||
1127 | special_count++; | ||
1128 | break; | ||
1129 | case C_CM_RXBRK: | ||
1130 | tty_insert_flip_char(tty, 0, TTY_BREAK); | ||
1131 | info->icount.rx++; | ||
1132 | special_count++; | ||
1133 | break; | ||
1134 | case C_CM_MDCD: | ||
1135 | info->icount.dcd++; | ||
1136 | delta_count++; | ||
1137 | if (info->port.flags & ASYNC_CHECK_CD) { | ||
1138 | u32 dcd = fw_ver > 241 ? param : | ||
1139 | readl(&info->u.cyz.ch_ctrl->rs_status); | ||
1140 | if (dcd & C_RS_DCD) | ||
1141 | wake_up_interruptible(&info->port.open_wait); | ||
1142 | else | ||
1143 | tty_hangup(tty); | ||
1144 | } | ||
1145 | break; | ||
1146 | case C_CM_MCTS: | ||
1147 | info->icount.cts++; | ||
1148 | delta_count++; | ||
1149 | break; | ||
1150 | case C_CM_MRI: | ||
1151 | info->icount.rng++; | ||
1152 | delta_count++; | ||
1153 | break; | ||
1154 | case C_CM_MDSR: | ||
1155 | info->icount.dsr++; | ||
1156 | delta_count++; | ||
1157 | break; | ||
1158 | #ifdef Z_WAKE | ||
1159 | case C_CM_IOCTLW: | ||
1160 | complete(&info->shutdown_wait); | ||
1161 | break; | ||
1162 | #endif | ||
1163 | #ifdef CONFIG_CYZ_INTR | ||
1164 | case C_CM_RXHIWM: | ||
1165 | case C_CM_RXNNDT: | ||
1166 | case C_CM_INTBACK2: | ||
1167 | /* Reception Interrupt */ | ||
1168 | #ifdef CY_DEBUG_INTERRUPTS | ||
1169 | printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " | ||
1170 | "port %ld\n", info->card, channel); | ||
1171 | #endif | ||
1172 | cyz_handle_rx(info, tty); | ||
1173 | break; | ||
1174 | case C_CM_TXBEMPTY: | ||
1175 | case C_CM_TXLOWWM: | ||
1176 | case C_CM_INTBACK: | ||
1177 | /* Transmission Interrupt */ | ||
1178 | #ifdef CY_DEBUG_INTERRUPTS | ||
1179 | printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " | ||
1180 | "port %ld\n", info->card, channel); | ||
1181 | #endif | ||
1182 | cyz_handle_tx(info, tty); | ||
1183 | break; | ||
1184 | #endif /* CONFIG_CYZ_INTR */ | ||
1185 | case C_CM_FATAL: | ||
1186 | /* should do something with this !!! */ | ||
1187 | break; | ||
1188 | default: | ||
1189 | break; | ||
1190 | } | ||
1191 | if (delta_count) | ||
1192 | wake_up_interruptible(&info->port.delta_msr_wait); | ||
1193 | if (special_count) | ||
1194 | tty_schedule_flip(tty); | ||
1195 | tty_kref_put(tty); | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | #ifdef CONFIG_CYZ_INTR | ||
1200 | static irqreturn_t cyz_interrupt(int irq, void *dev_id) | ||
1201 | { | ||
1202 | struct cyclades_card *cinfo = dev_id; | ||
1203 | |||
1204 | if (unlikely(!cyz_is_loaded(cinfo))) { | ||
1205 | #ifdef CY_DEBUG_INTERRUPTS | ||
1206 | printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " | ||
1207 | "(IRQ%d).\n", irq); | ||
1208 | #endif | ||
1209 | return IRQ_NONE; | ||
1210 | } | ||
1211 | |||
1212 | /* Handle the interrupts */ | ||
1213 | cyz_handle_cmd(cinfo); | ||
1214 | |||
1215 | return IRQ_HANDLED; | ||
1216 | } /* cyz_interrupt */ | ||
1217 | |||
1218 | static void cyz_rx_restart(unsigned long arg) | ||
1219 | { | ||
1220 | struct cyclades_port *info = (struct cyclades_port *)arg; | ||
1221 | struct cyclades_card *card = info->card; | ||
1222 | int retval; | ||
1223 | __u32 channel = info->line - card->first_line; | ||
1224 | unsigned long flags; | ||
1225 | |||
1226 | spin_lock_irqsave(&card->card_lock, flags); | ||
1227 | retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); | ||
1228 | if (retval != 0) { | ||
1229 | printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", | ||
1230 | info->line, retval); | ||
1231 | } | ||
1232 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1233 | } | ||
1234 | |||
1235 | #else /* CONFIG_CYZ_INTR */ | ||
1236 | |||
1237 | static void cyz_poll(unsigned long arg) | ||
1238 | { | ||
1239 | struct cyclades_card *cinfo; | ||
1240 | struct cyclades_port *info; | ||
1241 | unsigned long expires = jiffies + HZ; | ||
1242 | unsigned int port, card; | ||
1243 | |||
1244 | for (card = 0; card < NR_CARDS; card++) { | ||
1245 | cinfo = &cy_card[card]; | ||
1246 | |||
1247 | if (!cy_is_Z(cinfo)) | ||
1248 | continue; | ||
1249 | if (!cyz_is_loaded(cinfo)) | ||
1250 | continue; | ||
1251 | |||
1252 | /* Skip first polling cycle to avoid racing conditions with the FW */ | ||
1253 | if (!cinfo->intr_enabled) { | ||
1254 | cinfo->intr_enabled = 1; | ||
1255 | continue; | ||
1256 | } | ||
1257 | |||
1258 | cyz_handle_cmd(cinfo); | ||
1259 | |||
1260 | for (port = 0; port < cinfo->nports; port++) { | ||
1261 | struct tty_struct *tty; | ||
1262 | |||
1263 | info = &cinfo->ports[port]; | ||
1264 | tty = tty_port_tty_get(&info->port); | ||
1265 | /* OK to pass NULL to the handle functions below. | ||
1266 | They need to drop the data in that case. */ | ||
1267 | |||
1268 | if (!info->throttle) | ||
1269 | cyz_handle_rx(info, tty); | ||
1270 | cyz_handle_tx(info, tty); | ||
1271 | tty_kref_put(tty); | ||
1272 | } | ||
1273 | /* poll every 'cyz_polling_cycle' period */ | ||
1274 | expires = jiffies + cyz_polling_cycle; | ||
1275 | } | ||
1276 | mod_timer(&cyz_timerlist, expires); | ||
1277 | } /* cyz_poll */ | ||
1278 | |||
1279 | #endif /* CONFIG_CYZ_INTR */ | ||
1280 | |||
1281 | /********** End of block of Cyclades-Z specific code *********/ | ||
1282 | /***********************************************************/ | ||
1283 | |||
1284 | /* This is called whenever a port becomes active; | ||
1285 | interrupts are enabled and DTR & RTS are turned on. | ||
1286 | */ | ||
1287 | static int cy_startup(struct cyclades_port *info, struct tty_struct *tty) | ||
1288 | { | ||
1289 | struct cyclades_card *card; | ||
1290 | unsigned long flags; | ||
1291 | int retval = 0; | ||
1292 | int channel; | ||
1293 | unsigned long page; | ||
1294 | |||
1295 | card = info->card; | ||
1296 | channel = info->line - card->first_line; | ||
1297 | |||
1298 | page = get_zeroed_page(GFP_KERNEL); | ||
1299 | if (!page) | ||
1300 | return -ENOMEM; | ||
1301 | |||
1302 | spin_lock_irqsave(&card->card_lock, flags); | ||
1303 | |||
1304 | if (info->port.flags & ASYNC_INITIALIZED) | ||
1305 | goto errout; | ||
1306 | |||
1307 | if (!info->type) { | ||
1308 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
1309 | goto errout; | ||
1310 | } | ||
1311 | |||
1312 | if (info->port.xmit_buf) | ||
1313 | free_page(page); | ||
1314 | else | ||
1315 | info->port.xmit_buf = (unsigned char *)page; | ||
1316 | |||
1317 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1318 | |||
1319 | cy_set_line_char(info, tty); | ||
1320 | |||
1321 | if (!cy_is_Z(card)) { | ||
1322 | channel &= 0x03; | ||
1323 | |||
1324 | spin_lock_irqsave(&card->card_lock, flags); | ||
1325 | |||
1326 | cyy_writeb(info, CyCAR, channel); | ||
1327 | |||
1328 | cyy_writeb(info, CyRTPR, | ||
1329 | (info->default_timeout ? info->default_timeout : 0x02)); | ||
1330 | /* 10ms rx timeout */ | ||
1331 | |||
1332 | cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR); | ||
1333 | |||
1334 | cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0); | ||
1335 | |||
1336 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData); | ||
1337 | } else { | ||
1338 | struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; | ||
1339 | |||
1340 | if (!cyz_is_loaded(card)) | ||
1341 | return -ENODEV; | ||
1342 | |||
1343 | #ifdef CY_DEBUG_OPEN | ||
1344 | printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " | ||
1345 | "base_addr %p\n", card, channel, card->base_addr); | ||
1346 | #endif | ||
1347 | spin_lock_irqsave(&card->card_lock, flags); | ||
1348 | |||
1349 | cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE); | ||
1350 | #ifdef Z_WAKE | ||
1351 | #ifdef CONFIG_CYZ_INTR | ||
1352 | cy_writel(&ch_ctrl->intr_enable, | ||
1353 | C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | | ||
1354 | C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD); | ||
1355 | #else | ||
1356 | cy_writel(&ch_ctrl->intr_enable, | ||
1357 | C_IN_IOCTLW | C_IN_MDCD); | ||
1358 | #endif /* CONFIG_CYZ_INTR */ | ||
1359 | #else | ||
1360 | #ifdef CONFIG_CYZ_INTR | ||
1361 | cy_writel(&ch_ctrl->intr_enable, | ||
1362 | C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | | ||
1363 | C_IN_RXNNDT | C_IN_MDCD); | ||
1364 | #else | ||
1365 | cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD); | ||
1366 | #endif /* CONFIG_CYZ_INTR */ | ||
1367 | #endif /* Z_WAKE */ | ||
1368 | |||
1369 | retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); | ||
1370 | if (retval != 0) { | ||
1371 | printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " | ||
1372 | "%x\n", info->line, retval); | ||
1373 | } | ||
1374 | |||
1375 | /* Flush RX buffers before raising DTR and RTS */ | ||
1376 | retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); | ||
1377 | if (retval != 0) { | ||
1378 | printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " | ||
1379 | "%x\n", info->line, retval); | ||
1380 | } | ||
1381 | |||
1382 | /* set timeout !!! */ | ||
1383 | /* set RTS and DTR !!! */ | ||
1384 | tty_port_raise_dtr_rts(&info->port); | ||
1385 | |||
1386 | /* enable send, recv, modem !!! */ | ||
1387 | } | ||
1388 | |||
1389 | info->port.flags |= ASYNC_INITIALIZED; | ||
1390 | |||
1391 | clear_bit(TTY_IO_ERROR, &tty->flags); | ||
1392 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1393 | info->breakon = info->breakoff = 0; | ||
1394 | memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); | ||
1395 | info->idle_stats.in_use = | ||
1396 | info->idle_stats.recv_idle = | ||
1397 | info->idle_stats.xmit_idle = jiffies; | ||
1398 | |||
1399 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1400 | |||
1401 | #ifdef CY_DEBUG_OPEN | ||
1402 | printk(KERN_DEBUG "cyc startup done\n"); | ||
1403 | #endif | ||
1404 | return 0; | ||
1405 | |||
1406 | errout: | ||
1407 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1408 | free_page(page); | ||
1409 | return retval; | ||
1410 | } /* startup */ | ||
1411 | |||
1412 | static void start_xmit(struct cyclades_port *info) | ||
1413 | { | ||
1414 | struct cyclades_card *card = info->card; | ||
1415 | unsigned long flags; | ||
1416 | int channel = info->line - card->first_line; | ||
1417 | |||
1418 | if (!cy_is_Z(card)) { | ||
1419 | spin_lock_irqsave(&card->card_lock, flags); | ||
1420 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
1421 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); | ||
1422 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1423 | } else { | ||
1424 | #ifdef CONFIG_CYZ_INTR | ||
1425 | int retval; | ||
1426 | |||
1427 | spin_lock_irqsave(&card->card_lock, flags); | ||
1428 | retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); | ||
1429 | if (retval != 0) { | ||
1430 | printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " | ||
1431 | "%x\n", info->line, retval); | ||
1432 | } | ||
1433 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1434 | #else /* CONFIG_CYZ_INTR */ | ||
1435 | /* Don't have to do anything at this time */ | ||
1436 | #endif /* CONFIG_CYZ_INTR */ | ||
1437 | } | ||
1438 | } /* start_xmit */ | ||
1439 | |||
1440 | /* | ||
1441 | * This routine shuts down a serial port; interrupts are disabled, | ||
1442 | * and DTR is dropped if the hangup on close termio flag is on. | ||
1443 | */ | ||
1444 | static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty) | ||
1445 | { | ||
1446 | struct cyclades_card *card; | ||
1447 | unsigned long flags; | ||
1448 | int channel; | ||
1449 | |||
1450 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
1451 | return; | ||
1452 | |||
1453 | card = info->card; | ||
1454 | channel = info->line - card->first_line; | ||
1455 | if (!cy_is_Z(card)) { | ||
1456 | spin_lock_irqsave(&card->card_lock, flags); | ||
1457 | |||
1458 | /* Clear delta_msr_wait queue to avoid mem leaks. */ | ||
1459 | wake_up_interruptible(&info->port.delta_msr_wait); | ||
1460 | |||
1461 | if (info->port.xmit_buf) { | ||
1462 | unsigned char *temp; | ||
1463 | temp = info->port.xmit_buf; | ||
1464 | info->port.xmit_buf = NULL; | ||
1465 | free_page((unsigned long)temp); | ||
1466 | } | ||
1467 | if (tty->termios->c_cflag & HUPCL) | ||
1468 | cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR); | ||
1469 | |||
1470 | cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR); | ||
1471 | /* it may be appropriate to clear _XMIT at | ||
1472 | some later date (after testing)!!! */ | ||
1473 | |||
1474 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
1475 | info->port.flags &= ~ASYNC_INITIALIZED; | ||
1476 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1477 | } else { | ||
1478 | #ifdef CY_DEBUG_OPEN | ||
1479 | printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, " | ||
1480 | "base_addr %p\n", card, channel, card->base_addr); | ||
1481 | #endif | ||
1482 | |||
1483 | if (!cyz_is_loaded(card)) | ||
1484 | return; | ||
1485 | |||
1486 | spin_lock_irqsave(&card->card_lock, flags); | ||
1487 | |||
1488 | if (info->port.xmit_buf) { | ||
1489 | unsigned char *temp; | ||
1490 | temp = info->port.xmit_buf; | ||
1491 | info->port.xmit_buf = NULL; | ||
1492 | free_page((unsigned long)temp); | ||
1493 | } | ||
1494 | |||
1495 | if (tty->termios->c_cflag & HUPCL) | ||
1496 | tty_port_lower_dtr_rts(&info->port); | ||
1497 | |||
1498 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
1499 | info->port.flags &= ~ASYNC_INITIALIZED; | ||
1500 | |||
1501 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1502 | } | ||
1503 | |||
1504 | #ifdef CY_DEBUG_OPEN | ||
1505 | printk(KERN_DEBUG "cyc shutdown done\n"); | ||
1506 | #endif | ||
1507 | } /* shutdown */ | ||
1508 | |||
1509 | /* | ||
1510 | * ------------------------------------------------------------ | ||
1511 | * cy_open() and friends | ||
1512 | * ------------------------------------------------------------ | ||
1513 | */ | ||
1514 | |||
1515 | /* | ||
1516 | * This routine is called whenever a serial port is opened. It | ||
1517 | * performs the serial-specific initialization for the tty structure. | ||
1518 | */ | ||
1519 | static int cy_open(struct tty_struct *tty, struct file *filp) | ||
1520 | { | ||
1521 | struct cyclades_port *info; | ||
1522 | unsigned int i, line; | ||
1523 | int retval; | ||
1524 | |||
1525 | line = tty->index; | ||
1526 | if (tty->index < 0 || NR_PORTS <= line) | ||
1527 | return -ENODEV; | ||
1528 | |||
1529 | for (i = 0; i < NR_CARDS; i++) | ||
1530 | if (line < cy_card[i].first_line + cy_card[i].nports && | ||
1531 | line >= cy_card[i].first_line) | ||
1532 | break; | ||
1533 | if (i >= NR_CARDS) | ||
1534 | return -ENODEV; | ||
1535 | info = &cy_card[i].ports[line - cy_card[i].first_line]; | ||
1536 | if (info->line < 0) | ||
1537 | return -ENODEV; | ||
1538 | |||
1539 | /* If the card's firmware hasn't been loaded, | ||
1540 | treat it as absent from the system. This | ||
1541 | will make the user pay attention. | ||
1542 | */ | ||
1543 | if (cy_is_Z(info->card)) { | ||
1544 | struct cyclades_card *cinfo = info->card; | ||
1545 | struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS; | ||
1546 | |||
1547 | if (!cyz_is_loaded(cinfo)) { | ||
1548 | if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) && | ||
1549 | readl(&firm_id->signature) == | ||
1550 | ZFIRM_HLT) { | ||
1551 | printk(KERN_ERR "cyc:Cyclades-Z Error: you " | ||
1552 | "need an external power supply for " | ||
1553 | "this number of ports.\nFirmware " | ||
1554 | "halted.\n"); | ||
1555 | } else { | ||
1556 | printk(KERN_ERR "cyc:Cyclades-Z firmware not " | ||
1557 | "yet loaded\n"); | ||
1558 | } | ||
1559 | return -ENODEV; | ||
1560 | } | ||
1561 | #ifdef CONFIG_CYZ_INTR | ||
1562 | else { | ||
1563 | /* In case this Z board is operating in interrupt mode, its | ||
1564 | interrupts should be enabled as soon as the first open | ||
1565 | happens to one of its ports. */ | ||
1566 | if (!cinfo->intr_enabled) { | ||
1567 | u16 intr; | ||
1568 | |||
1569 | /* Enable interrupts on the PLX chip */ | ||
1570 | intr = readw(&cinfo->ctl_addr.p9060-> | ||
1571 | intr_ctrl_stat) | 0x0900; | ||
1572 | cy_writew(&cinfo->ctl_addr.p9060-> | ||
1573 | intr_ctrl_stat, intr); | ||
1574 | /* Enable interrupts on the FW */ | ||
1575 | retval = cyz_issue_cmd(cinfo, 0, | ||
1576 | C_CM_IRQ_ENBL, 0L); | ||
1577 | if (retval != 0) { | ||
1578 | printk(KERN_ERR "cyc:IRQ enable retval " | ||
1579 | "was %x\n", retval); | ||
1580 | } | ||
1581 | cinfo->intr_enabled = 1; | ||
1582 | } | ||
1583 | } | ||
1584 | #endif /* CONFIG_CYZ_INTR */ | ||
1585 | /* Make sure this Z port really exists in hardware */ | ||
1586 | if (info->line > (cinfo->first_line + cinfo->nports - 1)) | ||
1587 | return -ENODEV; | ||
1588 | } | ||
1589 | #ifdef CY_DEBUG_OTHER | ||
1590 | printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line); | ||
1591 | #endif | ||
1592 | tty->driver_data = info; | ||
1593 | if (serial_paranoia_check(info, tty->name, "cy_open")) | ||
1594 | return -ENODEV; | ||
1595 | |||
1596 | #ifdef CY_DEBUG_OPEN | ||
1597 | printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, | ||
1598 | info->port.count); | ||
1599 | #endif | ||
1600 | info->port.count++; | ||
1601 | #ifdef CY_DEBUG_COUNT | ||
1602 | printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n", | ||
1603 | current->pid, info->port.count); | ||
1604 | #endif | ||
1605 | |||
1606 | /* | ||
1607 | * If the port is the middle of closing, bail out now | ||
1608 | */ | ||
1609 | if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { | ||
1610 | wait_event_interruptible_tty(info->port.close_wait, | ||
1611 | !(info->port.flags & ASYNC_CLOSING)); | ||
1612 | return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; | ||
1613 | } | ||
1614 | |||
1615 | /* | ||
1616 | * Start up serial port | ||
1617 | */ | ||
1618 | retval = cy_startup(info, tty); | ||
1619 | if (retval) | ||
1620 | return retval; | ||
1621 | |||
1622 | retval = tty_port_block_til_ready(&info->port, tty, filp); | ||
1623 | if (retval) { | ||
1624 | #ifdef CY_DEBUG_OPEN | ||
1625 | printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready " | ||
1626 | "with %d\n", retval); | ||
1627 | #endif | ||
1628 | return retval; | ||
1629 | } | ||
1630 | |||
1631 | info->throttle = 0; | ||
1632 | tty_port_tty_set(&info->port, tty); | ||
1633 | |||
1634 | #ifdef CY_DEBUG_OPEN | ||
1635 | printk(KERN_DEBUG "cyc:cy_open done\n"); | ||
1636 | #endif | ||
1637 | return 0; | ||
1638 | } /* cy_open */ | ||
1639 | |||
1640 | /* | ||
1641 | * cy_wait_until_sent() --- wait until the transmitter is empty | ||
1642 | */ | ||
1643 | static void cy_wait_until_sent(struct tty_struct *tty, int timeout) | ||
1644 | { | ||
1645 | struct cyclades_card *card; | ||
1646 | struct cyclades_port *info = tty->driver_data; | ||
1647 | unsigned long orig_jiffies; | ||
1648 | int char_time; | ||
1649 | |||
1650 | if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent")) | ||
1651 | return; | ||
1652 | |||
1653 | if (info->xmit_fifo_size == 0) | ||
1654 | return; /* Just in case.... */ | ||
1655 | |||
1656 | orig_jiffies = jiffies; | ||
1657 | /* | ||
1658 | * Set the check interval to be 1/5 of the estimated time to | ||
1659 | * send a single character, and make it at least 1. The check | ||
1660 | * interval should also be less than the timeout. | ||
1661 | * | ||
1662 | * Note: we have to use pretty tight timings here to satisfy | ||
1663 | * the NIST-PCTS. | ||
1664 | */ | ||
1665 | char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size; | ||
1666 | char_time = char_time / 5; | ||
1667 | if (char_time <= 0) | ||
1668 | char_time = 1; | ||
1669 | if (timeout < 0) | ||
1670 | timeout = 0; | ||
1671 | if (timeout) | ||
1672 | char_time = min(char_time, timeout); | ||
1673 | /* | ||
1674 | * If the transmitter hasn't cleared in twice the approximate | ||
1675 | * amount of time to send the entire FIFO, it probably won't | ||
1676 | * ever clear. This assumes the UART isn't doing flow | ||
1677 | * control, which is currently the case. Hence, if it ever | ||
1678 | * takes longer than info->timeout, this is probably due to a | ||
1679 | * UART bug of some kind. So, we clamp the timeout parameter at | ||
1680 | * 2*info->timeout. | ||
1681 | */ | ||
1682 | if (!timeout || timeout > 2 * info->timeout) | ||
1683 | timeout = 2 * info->timeout; | ||
1684 | #ifdef CY_DEBUG_WAIT_UNTIL_SENT | ||
1685 | printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...", | ||
1686 | timeout, char_time, jiffies); | ||
1687 | #endif | ||
1688 | card = info->card; | ||
1689 | if (!cy_is_Z(card)) { | ||
1690 | while (cyy_readb(info, CySRER) & CyTxRdy) { | ||
1691 | #ifdef CY_DEBUG_WAIT_UNTIL_SENT | ||
1692 | printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies); | ||
1693 | #endif | ||
1694 | if (msleep_interruptible(jiffies_to_msecs(char_time))) | ||
1695 | break; | ||
1696 | if (timeout && time_after(jiffies, orig_jiffies + | ||
1697 | timeout)) | ||
1698 | break; | ||
1699 | } | ||
1700 | } | ||
1701 | /* Run one more char cycle */ | ||
1702 | msleep_interruptible(jiffies_to_msecs(char_time * 5)); | ||
1703 | #ifdef CY_DEBUG_WAIT_UNTIL_SENT | ||
1704 | printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); | ||
1705 | #endif | ||
1706 | } | ||
1707 | |||
1708 | static void cy_flush_buffer(struct tty_struct *tty) | ||
1709 | { | ||
1710 | struct cyclades_port *info = tty->driver_data; | ||
1711 | struct cyclades_card *card; | ||
1712 | int channel, retval; | ||
1713 | unsigned long flags; | ||
1714 | |||
1715 | #ifdef CY_DEBUG_IO | ||
1716 | printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); | ||
1717 | #endif | ||
1718 | |||
1719 | if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) | ||
1720 | return; | ||
1721 | |||
1722 | card = info->card; | ||
1723 | channel = info->line - card->first_line; | ||
1724 | |||
1725 | spin_lock_irqsave(&card->card_lock, flags); | ||
1726 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1727 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1728 | |||
1729 | if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board | ||
1730 | buffers as well */ | ||
1731 | spin_lock_irqsave(&card->card_lock, flags); | ||
1732 | retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); | ||
1733 | if (retval != 0) { | ||
1734 | printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " | ||
1735 | "was %x\n", info->line, retval); | ||
1736 | } | ||
1737 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1738 | } | ||
1739 | tty_wakeup(tty); | ||
1740 | } /* cy_flush_buffer */ | ||
1741 | |||
1742 | |||
1743 | static void cy_do_close(struct tty_port *port) | ||
1744 | { | ||
1745 | struct cyclades_port *info = container_of(port, struct cyclades_port, | ||
1746 | port); | ||
1747 | struct cyclades_card *card; | ||
1748 | unsigned long flags; | ||
1749 | int channel; | ||
1750 | |||
1751 | card = info->card; | ||
1752 | channel = info->line - card->first_line; | ||
1753 | spin_lock_irqsave(&card->card_lock, flags); | ||
1754 | |||
1755 | if (!cy_is_Z(card)) { | ||
1756 | /* Stop accepting input */ | ||
1757 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
1758 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData); | ||
1759 | if (info->port.flags & ASYNC_INITIALIZED) { | ||
1760 | /* Waiting for on-board buffers to be empty before | ||
1761 | closing the port */ | ||
1762 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1763 | cy_wait_until_sent(port->tty, info->timeout); | ||
1764 | spin_lock_irqsave(&card->card_lock, flags); | ||
1765 | } | ||
1766 | } else { | ||
1767 | #ifdef Z_WAKE | ||
1768 | /* Waiting for on-board buffers to be empty before closing | ||
1769 | the port */ | ||
1770 | struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; | ||
1771 | int retval; | ||
1772 | |||
1773 | if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) { | ||
1774 | retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L); | ||
1775 | if (retval != 0) { | ||
1776 | printk(KERN_DEBUG "cyc:cy_close retval on " | ||
1777 | "ttyC%d was %x\n", info->line, retval); | ||
1778 | } | ||
1779 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1780 | wait_for_completion_interruptible(&info->shutdown_wait); | ||
1781 | spin_lock_irqsave(&card->card_lock, flags); | ||
1782 | } | ||
1783 | #endif | ||
1784 | } | ||
1785 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1786 | cy_shutdown(info, port->tty); | ||
1787 | } | ||
1788 | |||
1789 | /* | ||
1790 | * This routine is called when a particular tty device is closed. | ||
1791 | */ | ||
1792 | static void cy_close(struct tty_struct *tty, struct file *filp) | ||
1793 | { | ||
1794 | struct cyclades_port *info = tty->driver_data; | ||
1795 | if (!info || serial_paranoia_check(info, tty->name, "cy_close")) | ||
1796 | return; | ||
1797 | tty_port_close(&info->port, tty, filp); | ||
1798 | } /* cy_close */ | ||
1799 | |||
1800 | /* This routine gets called when tty_write has put something into | ||
1801 | * the write_queue. The characters may come from user space or | ||
1802 | * kernel space. | ||
1803 | * | ||
1804 | * This routine will return the number of characters actually | ||
1805 | * accepted for writing. | ||
1806 | * | ||
1807 | * If the port is not already transmitting stuff, start it off by | ||
1808 | * enabling interrupts. The interrupt service routine will then | ||
1809 | * ensure that the characters are sent. | ||
1810 | * If the port is already active, there is no need to kick it. | ||
1811 | * | ||
1812 | */ | ||
1813 | static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
1814 | { | ||
1815 | struct cyclades_port *info = tty->driver_data; | ||
1816 | unsigned long flags; | ||
1817 | int c, ret = 0; | ||
1818 | |||
1819 | #ifdef CY_DEBUG_IO | ||
1820 | printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); | ||
1821 | #endif | ||
1822 | |||
1823 | if (serial_paranoia_check(info, tty->name, "cy_write")) | ||
1824 | return 0; | ||
1825 | |||
1826 | if (!info->port.xmit_buf) | ||
1827 | return 0; | ||
1828 | |||
1829 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
1830 | while (1) { | ||
1831 | c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1)); | ||
1832 | c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head)); | ||
1833 | |||
1834 | if (c <= 0) | ||
1835 | break; | ||
1836 | |||
1837 | memcpy(info->port.xmit_buf + info->xmit_head, buf, c); | ||
1838 | info->xmit_head = (info->xmit_head + c) & | ||
1839 | (SERIAL_XMIT_SIZE - 1); | ||
1840 | info->xmit_cnt += c; | ||
1841 | buf += c; | ||
1842 | count -= c; | ||
1843 | ret += c; | ||
1844 | } | ||
1845 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
1846 | |||
1847 | info->idle_stats.xmit_bytes += ret; | ||
1848 | info->idle_stats.xmit_idle = jiffies; | ||
1849 | |||
1850 | if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) | ||
1851 | start_xmit(info); | ||
1852 | |||
1853 | return ret; | ||
1854 | } /* cy_write */ | ||
1855 | |||
1856 | /* | ||
1857 | * This routine is called by the kernel to write a single | ||
1858 | * character to the tty device. If the kernel uses this routine, | ||
1859 | * it must call the flush_chars() routine (if defined) when it is | ||
1860 | * done stuffing characters into the driver. If there is no room | ||
1861 | * in the queue, the character is ignored. | ||
1862 | */ | ||
1863 | static int cy_put_char(struct tty_struct *tty, unsigned char ch) | ||
1864 | { | ||
1865 | struct cyclades_port *info = tty->driver_data; | ||
1866 | unsigned long flags; | ||
1867 | |||
1868 | #ifdef CY_DEBUG_IO | ||
1869 | printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line); | ||
1870 | #endif | ||
1871 | |||
1872 | if (serial_paranoia_check(info, tty->name, "cy_put_char")) | ||
1873 | return 0; | ||
1874 | |||
1875 | if (!info->port.xmit_buf) | ||
1876 | return 0; | ||
1877 | |||
1878 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
1879 | if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { | ||
1880 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
1881 | return 0; | ||
1882 | } | ||
1883 | |||
1884 | info->port.xmit_buf[info->xmit_head++] = ch; | ||
1885 | info->xmit_head &= SERIAL_XMIT_SIZE - 1; | ||
1886 | info->xmit_cnt++; | ||
1887 | info->idle_stats.xmit_bytes++; | ||
1888 | info->idle_stats.xmit_idle = jiffies; | ||
1889 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
1890 | return 1; | ||
1891 | } /* cy_put_char */ | ||
1892 | |||
1893 | /* | ||
1894 | * This routine is called by the kernel after it has written a | ||
1895 | * series of characters to the tty device using put_char(). | ||
1896 | */ | ||
1897 | static void cy_flush_chars(struct tty_struct *tty) | ||
1898 | { | ||
1899 | struct cyclades_port *info = tty->driver_data; | ||
1900 | |||
1901 | #ifdef CY_DEBUG_IO | ||
1902 | printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line); | ||
1903 | #endif | ||
1904 | |||
1905 | if (serial_paranoia_check(info, tty->name, "cy_flush_chars")) | ||
1906 | return; | ||
1907 | |||
1908 | if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || | ||
1909 | !info->port.xmit_buf) | ||
1910 | return; | ||
1911 | |||
1912 | start_xmit(info); | ||
1913 | } /* cy_flush_chars */ | ||
1914 | |||
1915 | /* | ||
1916 | * This routine returns the numbers of characters the tty driver | ||
1917 | * will accept for queuing to be written. This number is subject | ||
1918 | * to change as output buffers get emptied, or if the output flow | ||
1919 | * control is activated. | ||
1920 | */ | ||
1921 | static int cy_write_room(struct tty_struct *tty) | ||
1922 | { | ||
1923 | struct cyclades_port *info = tty->driver_data; | ||
1924 | int ret; | ||
1925 | |||
1926 | #ifdef CY_DEBUG_IO | ||
1927 | printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line); | ||
1928 | #endif | ||
1929 | |||
1930 | if (serial_paranoia_check(info, tty->name, "cy_write_room")) | ||
1931 | return 0; | ||
1932 | ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; | ||
1933 | if (ret < 0) | ||
1934 | ret = 0; | ||
1935 | return ret; | ||
1936 | } /* cy_write_room */ | ||
1937 | |||
1938 | static int cy_chars_in_buffer(struct tty_struct *tty) | ||
1939 | { | ||
1940 | struct cyclades_port *info = tty->driver_data; | ||
1941 | |||
1942 | if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer")) | ||
1943 | return 0; | ||
1944 | |||
1945 | #ifdef Z_EXT_CHARS_IN_BUFFER | ||
1946 | if (!cy_is_Z(info->card)) { | ||
1947 | #endif /* Z_EXT_CHARS_IN_BUFFER */ | ||
1948 | #ifdef CY_DEBUG_IO | ||
1949 | printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", | ||
1950 | info->line, info->xmit_cnt); | ||
1951 | #endif | ||
1952 | return info->xmit_cnt; | ||
1953 | #ifdef Z_EXT_CHARS_IN_BUFFER | ||
1954 | } else { | ||
1955 | struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; | ||
1956 | int char_count; | ||
1957 | __u32 tx_put, tx_get, tx_bufsize; | ||
1958 | |||
1959 | tx_get = readl(&buf_ctrl->tx_get); | ||
1960 | tx_put = readl(&buf_ctrl->tx_put); | ||
1961 | tx_bufsize = readl(&buf_ctrl->tx_bufsize); | ||
1962 | if (tx_put >= tx_get) | ||
1963 | char_count = tx_put - tx_get; | ||
1964 | else | ||
1965 | char_count = tx_put - tx_get + tx_bufsize; | ||
1966 | #ifdef CY_DEBUG_IO | ||
1967 | printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", | ||
1968 | info->line, info->xmit_cnt + char_count); | ||
1969 | #endif | ||
1970 | return info->xmit_cnt + char_count; | ||
1971 | } | ||
1972 | #endif /* Z_EXT_CHARS_IN_BUFFER */ | ||
1973 | } /* cy_chars_in_buffer */ | ||
1974 | |||
1975 | /* | ||
1976 | * ------------------------------------------------------------ | ||
1977 | * cy_ioctl() and friends | ||
1978 | * ------------------------------------------------------------ | ||
1979 | */ | ||
1980 | |||
1981 | static void cyy_baud_calc(struct cyclades_port *info, __u32 baud) | ||
1982 | { | ||
1983 | int co, co_val, bpr; | ||
1984 | __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : | ||
1985 | 25000000); | ||
1986 | |||
1987 | if (baud == 0) { | ||
1988 | info->tbpr = info->tco = info->rbpr = info->rco = 0; | ||
1989 | return; | ||
1990 | } | ||
1991 | |||
1992 | /* determine which prescaler to use */ | ||
1993 | for (co = 4, co_val = 2048; co; co--, co_val >>= 2) { | ||
1994 | if (cy_clock / co_val / baud > 63) | ||
1995 | break; | ||
1996 | } | ||
1997 | |||
1998 | bpr = (cy_clock / co_val * 2 / baud + 1) / 2; | ||
1999 | if (bpr > 255) | ||
2000 | bpr = 255; | ||
2001 | |||
2002 | info->tbpr = info->rbpr = bpr; | ||
2003 | info->tco = info->rco = co; | ||
2004 | } | ||
2005 | |||
2006 | /* | ||
2007 | * This routine finds or computes the various line characteristics. | ||
2008 | * It used to be called config_setup | ||
2009 | */ | ||
2010 | static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty) | ||
2011 | { | ||
2012 | struct cyclades_card *card; | ||
2013 | unsigned long flags; | ||
2014 | int channel; | ||
2015 | unsigned cflag, iflag; | ||
2016 | int baud, baud_rate = 0; | ||
2017 | int i; | ||
2018 | |||
2019 | if (!tty->termios) /* XXX can this happen at all? */ | ||
2020 | return; | ||
2021 | |||
2022 | if (info->line == -1) | ||
2023 | return; | ||
2024 | |||
2025 | cflag = tty->termios->c_cflag; | ||
2026 | iflag = tty->termios->c_iflag; | ||
2027 | |||
2028 | /* | ||
2029 | * Set up the tty->alt_speed kludge | ||
2030 | */ | ||
2031 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
2032 | tty->alt_speed = 57600; | ||
2033 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
2034 | tty->alt_speed = 115200; | ||
2035 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | ||
2036 | tty->alt_speed = 230400; | ||
2037 | if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | ||
2038 | tty->alt_speed = 460800; | ||
2039 | |||
2040 | card = info->card; | ||
2041 | channel = info->line - card->first_line; | ||
2042 | |||
2043 | if (!cy_is_Z(card)) { | ||
2044 | u32 cflags; | ||
2045 | |||
2046 | /* baud rate */ | ||
2047 | baud = tty_get_baud_rate(tty); | ||
2048 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | ||
2049 | ASYNC_SPD_CUST) { | ||
2050 | if (info->custom_divisor) | ||
2051 | baud_rate = info->baud / info->custom_divisor; | ||
2052 | else | ||
2053 | baud_rate = info->baud; | ||
2054 | } else if (baud > CD1400_MAX_SPEED) { | ||
2055 | baud = CD1400_MAX_SPEED; | ||
2056 | } | ||
2057 | /* find the baud index */ | ||
2058 | for (i = 0; i < 20; i++) { | ||
2059 | if (baud == baud_table[i]) | ||
2060 | break; | ||
2061 | } | ||
2062 | if (i == 20) | ||
2063 | i = 19; /* CD1400_MAX_SPEED */ | ||
2064 | |||
2065 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | ||
2066 | ASYNC_SPD_CUST) { | ||
2067 | cyy_baud_calc(info, baud_rate); | ||
2068 | } else { | ||
2069 | if (info->chip_rev >= CD1400_REV_J) { | ||
2070 | /* It is a CD1400 rev. J or later */ | ||
2071 | info->tbpr = baud_bpr_60[i]; /* Tx BPR */ | ||
2072 | info->tco = baud_co_60[i]; /* Tx CO */ | ||
2073 | info->rbpr = baud_bpr_60[i]; /* Rx BPR */ | ||
2074 | info->rco = baud_co_60[i]; /* Rx CO */ | ||
2075 | } else { | ||
2076 | info->tbpr = baud_bpr_25[i]; /* Tx BPR */ | ||
2077 | info->tco = baud_co_25[i]; /* Tx CO */ | ||
2078 | info->rbpr = baud_bpr_25[i]; /* Rx BPR */ | ||
2079 | info->rco = baud_co_25[i]; /* Rx CO */ | ||
2080 | } | ||
2081 | } | ||
2082 | if (baud_table[i] == 134) { | ||
2083 | /* get it right for 134.5 baud */ | ||
2084 | info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + | ||
2085 | 2; | ||
2086 | } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | ||
2087 | ASYNC_SPD_CUST) { | ||
2088 | info->timeout = (info->xmit_fifo_size * HZ * 15 / | ||
2089 | baud_rate) + 2; | ||
2090 | } else if (baud_table[i]) { | ||
2091 | info->timeout = (info->xmit_fifo_size * HZ * 15 / | ||
2092 | baud_table[i]) + 2; | ||
2093 | /* this needs to be propagated into the card info */ | ||
2094 | } else { | ||
2095 | info->timeout = 0; | ||
2096 | } | ||
2097 | /* By tradition (is it a standard?) a baud rate of zero | ||
2098 | implies the line should be/has been closed. A bit | ||
2099 | later in this routine such a test is performed. */ | ||
2100 | |||
2101 | /* byte size and parity */ | ||
2102 | info->cor5 = 0; | ||
2103 | info->cor4 = 0; | ||
2104 | /* receive threshold */ | ||
2105 | info->cor3 = (info->default_threshold ? | ||
2106 | info->default_threshold : baud_cor3[i]); | ||
2107 | info->cor2 = CyETC; | ||
2108 | switch (cflag & CSIZE) { | ||
2109 | case CS5: | ||
2110 | info->cor1 = Cy_5_BITS; | ||
2111 | break; | ||
2112 | case CS6: | ||
2113 | info->cor1 = Cy_6_BITS; | ||
2114 | break; | ||
2115 | case CS7: | ||
2116 | info->cor1 = Cy_7_BITS; | ||
2117 | break; | ||
2118 | case CS8: | ||
2119 | info->cor1 = Cy_8_BITS; | ||
2120 | break; | ||
2121 | } | ||
2122 | if (cflag & CSTOPB) | ||
2123 | info->cor1 |= Cy_2_STOP; | ||
2124 | |||
2125 | if (cflag & PARENB) { | ||
2126 | if (cflag & PARODD) | ||
2127 | info->cor1 |= CyPARITY_O; | ||
2128 | else | ||
2129 | info->cor1 |= CyPARITY_E; | ||
2130 | } else | ||
2131 | info->cor1 |= CyPARITY_NONE; | ||
2132 | |||
2133 | /* CTS flow control flag */ | ||
2134 | if (cflag & CRTSCTS) { | ||
2135 | info->port.flags |= ASYNC_CTS_FLOW; | ||
2136 | info->cor2 |= CyCtsAE; | ||
2137 | } else { | ||
2138 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
2139 | info->cor2 &= ~CyCtsAE; | ||
2140 | } | ||
2141 | if (cflag & CLOCAL) | ||
2142 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
2143 | else | ||
2144 | info->port.flags |= ASYNC_CHECK_CD; | ||
2145 | |||
2146 | /*********************************************** | ||
2147 | The hardware option, CyRtsAO, presents RTS when | ||
2148 | the chip has characters to send. Since most modems | ||
2149 | use RTS as reverse (inbound) flow control, this | ||
2150 | option is not used. If inbound flow control is | ||
2151 | necessary, DTR can be programmed to provide the | ||
2152 | appropriate signals for use with a non-standard | ||
2153 | cable. Contact Marcio Saito for details. | ||
2154 | ***********************************************/ | ||
2155 | |||
2156 | channel &= 0x03; | ||
2157 | |||
2158 | spin_lock_irqsave(&card->card_lock, flags); | ||
2159 | cyy_writeb(info, CyCAR, channel); | ||
2160 | |||
2161 | /* tx and rx baud rate */ | ||
2162 | |||
2163 | cyy_writeb(info, CyTCOR, info->tco); | ||
2164 | cyy_writeb(info, CyTBPR, info->tbpr); | ||
2165 | cyy_writeb(info, CyRCOR, info->rco); | ||
2166 | cyy_writeb(info, CyRBPR, info->rbpr); | ||
2167 | |||
2168 | /* set line characteristics according configuration */ | ||
2169 | |||
2170 | cyy_writeb(info, CySCHR1, START_CHAR(tty)); | ||
2171 | cyy_writeb(info, CySCHR2, STOP_CHAR(tty)); | ||
2172 | cyy_writeb(info, CyCOR1, info->cor1); | ||
2173 | cyy_writeb(info, CyCOR2, info->cor2); | ||
2174 | cyy_writeb(info, CyCOR3, info->cor3); | ||
2175 | cyy_writeb(info, CyCOR4, info->cor4); | ||
2176 | cyy_writeb(info, CyCOR5, info->cor5); | ||
2177 | |||
2178 | cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | | ||
2179 | CyCOR3ch); | ||
2180 | |||
2181 | /* !!! Is this needed? */ | ||
2182 | cyy_writeb(info, CyCAR, channel); | ||
2183 | cyy_writeb(info, CyRTPR, | ||
2184 | (info->default_timeout ? info->default_timeout : 0x02)); | ||
2185 | /* 10ms rx timeout */ | ||
2186 | |||
2187 | cflags = CyCTS; | ||
2188 | if (!C_CLOCAL(tty)) | ||
2189 | cflags |= CyDSR | CyRI | CyDCD; | ||
2190 | /* without modem intr */ | ||
2191 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh); | ||
2192 | /* act on 1->0 modem transitions */ | ||
2193 | if ((cflag & CRTSCTS) && info->rflow) | ||
2194 | cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]); | ||
2195 | else | ||
2196 | cyy_writeb(info, CyMCOR1, cflags); | ||
2197 | /* act on 0->1 modem transitions */ | ||
2198 | cyy_writeb(info, CyMCOR2, cflags); | ||
2199 | |||
2200 | if (i == 0) /* baud rate is zero, turn off line */ | ||
2201 | cyy_change_rts_dtr(info, 0, TIOCM_DTR); | ||
2202 | else | ||
2203 | cyy_change_rts_dtr(info, TIOCM_DTR, 0); | ||
2204 | |||
2205 | clear_bit(TTY_IO_ERROR, &tty->flags); | ||
2206 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2207 | |||
2208 | } else { | ||
2209 | struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; | ||
2210 | __u32 sw_flow; | ||
2211 | int retval; | ||
2212 | |||
2213 | if (!cyz_is_loaded(card)) | ||
2214 | return; | ||
2215 | |||
2216 | /* baud rate */ | ||
2217 | baud = tty_get_baud_rate(tty); | ||
2218 | if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | ||
2219 | ASYNC_SPD_CUST) { | ||
2220 | if (info->custom_divisor) | ||
2221 | baud_rate = info->baud / info->custom_divisor; | ||
2222 | else | ||
2223 | baud_rate = info->baud; | ||
2224 | } else if (baud > CYZ_MAX_SPEED) { | ||
2225 | baud = CYZ_MAX_SPEED; | ||
2226 | } | ||
2227 | cy_writel(&ch_ctrl->comm_baud, baud); | ||
2228 | |||
2229 | if (baud == 134) { | ||
2230 | /* get it right for 134.5 baud */ | ||
2231 | info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) + | ||
2232 | 2; | ||
2233 | } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) == | ||
2234 | ASYNC_SPD_CUST) { | ||
2235 | info->timeout = (info->xmit_fifo_size * HZ * 15 / | ||
2236 | baud_rate) + 2; | ||
2237 | } else if (baud) { | ||
2238 | info->timeout = (info->xmit_fifo_size * HZ * 15 / | ||
2239 | baud) + 2; | ||
2240 | /* this needs to be propagated into the card info */ | ||
2241 | } else { | ||
2242 | info->timeout = 0; | ||
2243 | } | ||
2244 | |||
2245 | /* byte size and parity */ | ||
2246 | switch (cflag & CSIZE) { | ||
2247 | case CS5: | ||
2248 | cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5); | ||
2249 | break; | ||
2250 | case CS6: | ||
2251 | cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6); | ||
2252 | break; | ||
2253 | case CS7: | ||
2254 | cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7); | ||
2255 | break; | ||
2256 | case CS8: | ||
2257 | cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8); | ||
2258 | break; | ||
2259 | } | ||
2260 | if (cflag & CSTOPB) { | ||
2261 | cy_writel(&ch_ctrl->comm_data_l, | ||
2262 | readl(&ch_ctrl->comm_data_l) | C_DL_2STOP); | ||
2263 | } else { | ||
2264 | cy_writel(&ch_ctrl->comm_data_l, | ||
2265 | readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); | ||
2266 | } | ||
2267 | if (cflag & PARENB) { | ||
2268 | if (cflag & PARODD) | ||
2269 | cy_writel(&ch_ctrl->comm_parity, C_PR_ODD); | ||
2270 | else | ||
2271 | cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN); | ||
2272 | } else | ||
2273 | cy_writel(&ch_ctrl->comm_parity, C_PR_NONE); | ||
2274 | |||
2275 | /* CTS flow control flag */ | ||
2276 | if (cflag & CRTSCTS) { | ||
2277 | cy_writel(&ch_ctrl->hw_flow, | ||
2278 | readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS); | ||
2279 | } else { | ||
2280 | cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) & | ||
2281 | ~(C_RS_CTS | C_RS_RTS)); | ||
2282 | } | ||
2283 | /* As the HW flow control is done in firmware, the driver | ||
2284 | doesn't need to care about it */ | ||
2285 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
2286 | |||
2287 | /* XON/XOFF/XANY flow control flags */ | ||
2288 | sw_flow = 0; | ||
2289 | if (iflag & IXON) { | ||
2290 | sw_flow |= C_FL_OXX; | ||
2291 | if (iflag & IXANY) | ||
2292 | sw_flow |= C_FL_OIXANY; | ||
2293 | } | ||
2294 | cy_writel(&ch_ctrl->sw_flow, sw_flow); | ||
2295 | |||
2296 | retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); | ||
2297 | if (retval != 0) { | ||
2298 | printk(KERN_ERR "cyc:set_line_char retval on ttyC%d " | ||
2299 | "was %x\n", info->line, retval); | ||
2300 | } | ||
2301 | |||
2302 | /* CD sensitivity */ | ||
2303 | if (cflag & CLOCAL) | ||
2304 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
2305 | else | ||
2306 | info->port.flags |= ASYNC_CHECK_CD; | ||
2307 | |||
2308 | if (baud == 0) { /* baud rate is zero, turn off line */ | ||
2309 | cy_writel(&ch_ctrl->rs_control, | ||
2310 | readl(&ch_ctrl->rs_control) & ~C_RS_DTR); | ||
2311 | #ifdef CY_DEBUG_DTR | ||
2312 | printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n"); | ||
2313 | #endif | ||
2314 | } else { | ||
2315 | cy_writel(&ch_ctrl->rs_control, | ||
2316 | readl(&ch_ctrl->rs_control) | C_RS_DTR); | ||
2317 | #ifdef CY_DEBUG_DTR | ||
2318 | printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n"); | ||
2319 | #endif | ||
2320 | } | ||
2321 | |||
2322 | retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); | ||
2323 | if (retval != 0) { | ||
2324 | printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " | ||
2325 | "was %x\n", info->line, retval); | ||
2326 | } | ||
2327 | |||
2328 | clear_bit(TTY_IO_ERROR, &tty->flags); | ||
2329 | } | ||
2330 | } /* set_line_char */ | ||
2331 | |||
2332 | static int cy_get_serial_info(struct cyclades_port *info, | ||
2333 | struct serial_struct __user *retinfo) | ||
2334 | { | ||
2335 | struct cyclades_card *cinfo = info->card; | ||
2336 | struct serial_struct tmp = { | ||
2337 | .type = info->type, | ||
2338 | .line = info->line, | ||
2339 | .port = (info->card - cy_card) * 0x100 + info->line - | ||
2340 | cinfo->first_line, | ||
2341 | .irq = cinfo->irq, | ||
2342 | .flags = info->port.flags, | ||
2343 | .close_delay = info->port.close_delay, | ||
2344 | .closing_wait = info->port.closing_wait, | ||
2345 | .baud_base = info->baud, | ||
2346 | .custom_divisor = info->custom_divisor, | ||
2347 | .hub6 = 0, /*!!! */ | ||
2348 | }; | ||
2349 | return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; | ||
2350 | } | ||
2351 | |||
2352 | static int | ||
2353 | cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, | ||
2354 | struct serial_struct __user *new_info) | ||
2355 | { | ||
2356 | struct serial_struct new_serial; | ||
2357 | int ret; | ||
2358 | |||
2359 | if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) | ||
2360 | return -EFAULT; | ||
2361 | |||
2362 | mutex_lock(&info->port.mutex); | ||
2363 | if (!capable(CAP_SYS_ADMIN)) { | ||
2364 | if (new_serial.close_delay != info->port.close_delay || | ||
2365 | new_serial.baud_base != info->baud || | ||
2366 | (new_serial.flags & ASYNC_FLAGS & | ||
2367 | ~ASYNC_USR_MASK) != | ||
2368 | (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) | ||
2369 | { | ||
2370 | mutex_unlock(&info->port.mutex); | ||
2371 | return -EPERM; | ||
2372 | } | ||
2373 | info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | | ||
2374 | (new_serial.flags & ASYNC_USR_MASK); | ||
2375 | info->baud = new_serial.baud_base; | ||
2376 | info->custom_divisor = new_serial.custom_divisor; | ||
2377 | goto check_and_exit; | ||
2378 | } | ||
2379 | |||
2380 | /* | ||
2381 | * OK, past this point, all the error checking has been done. | ||
2382 | * At this point, we start making changes..... | ||
2383 | */ | ||
2384 | |||
2385 | info->baud = new_serial.baud_base; | ||
2386 | info->custom_divisor = new_serial.custom_divisor; | ||
2387 | info->port.flags = (info->port.flags & ~ASYNC_FLAGS) | | ||
2388 | (new_serial.flags & ASYNC_FLAGS); | ||
2389 | info->port.close_delay = new_serial.close_delay * HZ / 100; | ||
2390 | info->port.closing_wait = new_serial.closing_wait * HZ / 100; | ||
2391 | |||
2392 | check_and_exit: | ||
2393 | if (info->port.flags & ASYNC_INITIALIZED) { | ||
2394 | cy_set_line_char(info, tty); | ||
2395 | ret = 0; | ||
2396 | } else { | ||
2397 | ret = cy_startup(info, tty); | ||
2398 | } | ||
2399 | mutex_unlock(&info->port.mutex); | ||
2400 | return ret; | ||
2401 | } /* set_serial_info */ | ||
2402 | |||
2403 | /* | ||
2404 | * get_lsr_info - get line status register info | ||
2405 | * | ||
2406 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
2407 | * is emptied. On bus types like RS485, the transmitter must | ||
2408 | * release the bus after transmitting. This must be done when | ||
2409 | * the transmit shift register is empty, not be done when the | ||
2410 | * transmit holding register is empty. This functionality | ||
2411 | * allows an RS485 driver to be written in user space. | ||
2412 | */ | ||
2413 | static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) | ||
2414 | { | ||
2415 | struct cyclades_card *card = info->card; | ||
2416 | unsigned int result; | ||
2417 | unsigned long flags; | ||
2418 | u8 status; | ||
2419 | |||
2420 | if (!cy_is_Z(card)) { | ||
2421 | spin_lock_irqsave(&card->card_lock, flags); | ||
2422 | status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty); | ||
2423 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2424 | result = (status ? 0 : TIOCSER_TEMT); | ||
2425 | } else { | ||
2426 | /* Not supported yet */ | ||
2427 | return -EINVAL; | ||
2428 | } | ||
2429 | return put_user(result, (unsigned long __user *)value); | ||
2430 | } | ||
2431 | |||
2432 | static int cy_tiocmget(struct tty_struct *tty) | ||
2433 | { | ||
2434 | struct cyclades_port *info = tty->driver_data; | ||
2435 | struct cyclades_card *card; | ||
2436 | int result; | ||
2437 | |||
2438 | if (serial_paranoia_check(info, tty->name, __func__)) | ||
2439 | return -ENODEV; | ||
2440 | |||
2441 | card = info->card; | ||
2442 | |||
2443 | if (!cy_is_Z(card)) { | ||
2444 | unsigned long flags; | ||
2445 | int channel = info->line - card->first_line; | ||
2446 | u8 status; | ||
2447 | |||
2448 | spin_lock_irqsave(&card->card_lock, flags); | ||
2449 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
2450 | status = cyy_readb(info, CyMSVR1); | ||
2451 | status |= cyy_readb(info, CyMSVR2); | ||
2452 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2453 | |||
2454 | if (info->rtsdtr_inv) { | ||
2455 | result = ((status & CyRTS) ? TIOCM_DTR : 0) | | ||
2456 | ((status & CyDTR) ? TIOCM_RTS : 0); | ||
2457 | } else { | ||
2458 | result = ((status & CyRTS) ? TIOCM_RTS : 0) | | ||
2459 | ((status & CyDTR) ? TIOCM_DTR : 0); | ||
2460 | } | ||
2461 | result |= ((status & CyDCD) ? TIOCM_CAR : 0) | | ||
2462 | ((status & CyRI) ? TIOCM_RNG : 0) | | ||
2463 | ((status & CyDSR) ? TIOCM_DSR : 0) | | ||
2464 | ((status & CyCTS) ? TIOCM_CTS : 0); | ||
2465 | } else { | ||
2466 | u32 lstatus; | ||
2467 | |||
2468 | if (!cyz_is_loaded(card)) { | ||
2469 | result = -ENODEV; | ||
2470 | goto end; | ||
2471 | } | ||
2472 | |||
2473 | lstatus = readl(&info->u.cyz.ch_ctrl->rs_status); | ||
2474 | result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) | | ||
2475 | ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) | | ||
2476 | ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) | | ||
2477 | ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) | | ||
2478 | ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) | | ||
2479 | ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); | ||
2480 | } | ||
2481 | end: | ||
2482 | return result; | ||
2483 | } /* cy_tiomget */ | ||
2484 | |||
2485 | static int | ||
2486 | cy_tiocmset(struct tty_struct *tty, | ||
2487 | unsigned int set, unsigned int clear) | ||
2488 | { | ||
2489 | struct cyclades_port *info = tty->driver_data; | ||
2490 | struct cyclades_card *card; | ||
2491 | unsigned long flags; | ||
2492 | |||
2493 | if (serial_paranoia_check(info, tty->name, __func__)) | ||
2494 | return -ENODEV; | ||
2495 | |||
2496 | card = info->card; | ||
2497 | if (!cy_is_Z(card)) { | ||
2498 | spin_lock_irqsave(&card->card_lock, flags); | ||
2499 | cyy_change_rts_dtr(info, set, clear); | ||
2500 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2501 | } else { | ||
2502 | struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; | ||
2503 | int retval, channel = info->line - card->first_line; | ||
2504 | u32 rs; | ||
2505 | |||
2506 | if (!cyz_is_loaded(card)) | ||
2507 | return -ENODEV; | ||
2508 | |||
2509 | spin_lock_irqsave(&card->card_lock, flags); | ||
2510 | rs = readl(&ch_ctrl->rs_control); | ||
2511 | if (set & TIOCM_RTS) | ||
2512 | rs |= C_RS_RTS; | ||
2513 | if (clear & TIOCM_RTS) | ||
2514 | rs &= ~C_RS_RTS; | ||
2515 | if (set & TIOCM_DTR) { | ||
2516 | rs |= C_RS_DTR; | ||
2517 | #ifdef CY_DEBUG_DTR | ||
2518 | printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n"); | ||
2519 | #endif | ||
2520 | } | ||
2521 | if (clear & TIOCM_DTR) { | ||
2522 | rs &= ~C_RS_DTR; | ||
2523 | #ifdef CY_DEBUG_DTR | ||
2524 | printk(KERN_DEBUG "cyc:set_modem_info clearing " | ||
2525 | "Z DTR\n"); | ||
2526 | #endif | ||
2527 | } | ||
2528 | cy_writel(&ch_ctrl->rs_control, rs); | ||
2529 | retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); | ||
2530 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2531 | if (retval != 0) { | ||
2532 | printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d " | ||
2533 | "was %x\n", info->line, retval); | ||
2534 | } | ||
2535 | } | ||
2536 | return 0; | ||
2537 | } | ||
2538 | |||
2539 | /* | ||
2540 | * cy_break() --- routine which turns the break handling on or off | ||
2541 | */ | ||
2542 | static int cy_break(struct tty_struct *tty, int break_state) | ||
2543 | { | ||
2544 | struct cyclades_port *info = tty->driver_data; | ||
2545 | struct cyclades_card *card; | ||
2546 | unsigned long flags; | ||
2547 | int retval = 0; | ||
2548 | |||
2549 | if (serial_paranoia_check(info, tty->name, "cy_break")) | ||
2550 | return -EINVAL; | ||
2551 | |||
2552 | card = info->card; | ||
2553 | |||
2554 | spin_lock_irqsave(&card->card_lock, flags); | ||
2555 | if (!cy_is_Z(card)) { | ||
2556 | /* Let the transmit ISR take care of this (since it | ||
2557 | requires stuffing characters into the output stream). | ||
2558 | */ | ||
2559 | if (break_state == -1) { | ||
2560 | if (!info->breakon) { | ||
2561 | info->breakon = 1; | ||
2562 | if (!info->xmit_cnt) { | ||
2563 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2564 | start_xmit(info); | ||
2565 | spin_lock_irqsave(&card->card_lock, flags); | ||
2566 | } | ||
2567 | } | ||
2568 | } else { | ||
2569 | if (!info->breakoff) { | ||
2570 | info->breakoff = 1; | ||
2571 | if (!info->xmit_cnt) { | ||
2572 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2573 | start_xmit(info); | ||
2574 | spin_lock_irqsave(&card->card_lock, flags); | ||
2575 | } | ||
2576 | } | ||
2577 | } | ||
2578 | } else { | ||
2579 | if (break_state == -1) { | ||
2580 | retval = cyz_issue_cmd(card, | ||
2581 | info->line - card->first_line, | ||
2582 | C_CM_SET_BREAK, 0L); | ||
2583 | if (retval != 0) { | ||
2584 | printk(KERN_ERR "cyc:cy_break (set) retval on " | ||
2585 | "ttyC%d was %x\n", info->line, retval); | ||
2586 | } | ||
2587 | } else { | ||
2588 | retval = cyz_issue_cmd(card, | ||
2589 | info->line - card->first_line, | ||
2590 | C_CM_CLR_BREAK, 0L); | ||
2591 | if (retval != 0) { | ||
2592 | printk(KERN_DEBUG "cyc:cy_break (clr) retval " | ||
2593 | "on ttyC%d was %x\n", info->line, | ||
2594 | retval); | ||
2595 | } | ||
2596 | } | ||
2597 | } | ||
2598 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2599 | return retval; | ||
2600 | } /* cy_break */ | ||
2601 | |||
2602 | static int set_threshold(struct cyclades_port *info, unsigned long value) | ||
2603 | { | ||
2604 | struct cyclades_card *card = info->card; | ||
2605 | unsigned long flags; | ||
2606 | |||
2607 | if (!cy_is_Z(card)) { | ||
2608 | info->cor3 &= ~CyREC_FIFO; | ||
2609 | info->cor3 |= value & CyREC_FIFO; | ||
2610 | |||
2611 | spin_lock_irqsave(&card->card_lock, flags); | ||
2612 | cyy_writeb(info, CyCOR3, info->cor3); | ||
2613 | cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch); | ||
2614 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2615 | } | ||
2616 | return 0; | ||
2617 | } /* set_threshold */ | ||
2618 | |||
2619 | static int get_threshold(struct cyclades_port *info, | ||
2620 | unsigned long __user *value) | ||
2621 | { | ||
2622 | struct cyclades_card *card = info->card; | ||
2623 | |||
2624 | if (!cy_is_Z(card)) { | ||
2625 | u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO; | ||
2626 | return put_user(tmp, value); | ||
2627 | } | ||
2628 | return 0; | ||
2629 | } /* get_threshold */ | ||
2630 | |||
2631 | static int set_timeout(struct cyclades_port *info, unsigned long value) | ||
2632 | { | ||
2633 | struct cyclades_card *card = info->card; | ||
2634 | unsigned long flags; | ||
2635 | |||
2636 | if (!cy_is_Z(card)) { | ||
2637 | spin_lock_irqsave(&card->card_lock, flags); | ||
2638 | cyy_writeb(info, CyRTPR, value & 0xff); | ||
2639 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2640 | } | ||
2641 | return 0; | ||
2642 | } /* set_timeout */ | ||
2643 | |||
2644 | static int get_timeout(struct cyclades_port *info, | ||
2645 | unsigned long __user *value) | ||
2646 | { | ||
2647 | struct cyclades_card *card = info->card; | ||
2648 | |||
2649 | if (!cy_is_Z(card)) { | ||
2650 | u8 tmp = cyy_readb(info, CyRTPR); | ||
2651 | return put_user(tmp, value); | ||
2652 | } | ||
2653 | return 0; | ||
2654 | } /* get_timeout */ | ||
2655 | |||
2656 | static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg, | ||
2657 | struct cyclades_icount *cprev) | ||
2658 | { | ||
2659 | struct cyclades_icount cnow; | ||
2660 | unsigned long flags; | ||
2661 | int ret; | ||
2662 | |||
2663 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
2664 | cnow = info->icount; /* atomic copy */ | ||
2665 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
2666 | |||
2667 | ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || | ||
2668 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || | ||
2669 | ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || | ||
2670 | ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); | ||
2671 | |||
2672 | *cprev = cnow; | ||
2673 | |||
2674 | return ret; | ||
2675 | } | ||
2676 | |||
2677 | /* | ||
2678 | * This routine allows the tty driver to implement device- | ||
2679 | * specific ioctl's. If the ioctl number passed in cmd is | ||
2680 | * not recognized by the driver, it should return ENOIOCTLCMD. | ||
2681 | */ | ||
2682 | static int | ||
2683 | cy_ioctl(struct tty_struct *tty, | ||
2684 | unsigned int cmd, unsigned long arg) | ||
2685 | { | ||
2686 | struct cyclades_port *info = tty->driver_data; | ||
2687 | struct cyclades_icount cnow; /* kernel counter temps */ | ||
2688 | int ret_val = 0; | ||
2689 | unsigned long flags; | ||
2690 | void __user *argp = (void __user *)arg; | ||
2691 | |||
2692 | if (serial_paranoia_check(info, tty->name, "cy_ioctl")) | ||
2693 | return -ENODEV; | ||
2694 | |||
2695 | #ifdef CY_DEBUG_OTHER | ||
2696 | printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", | ||
2697 | info->line, cmd, arg); | ||
2698 | #endif | ||
2699 | |||
2700 | switch (cmd) { | ||
2701 | case CYGETMON: | ||
2702 | if (copy_to_user(argp, &info->mon, sizeof(info->mon))) { | ||
2703 | ret_val = -EFAULT; | ||
2704 | break; | ||
2705 | } | ||
2706 | memset(&info->mon, 0, sizeof(info->mon)); | ||
2707 | break; | ||
2708 | case CYGETTHRESH: | ||
2709 | ret_val = get_threshold(info, argp); | ||
2710 | break; | ||
2711 | case CYSETTHRESH: | ||
2712 | ret_val = set_threshold(info, arg); | ||
2713 | break; | ||
2714 | case CYGETDEFTHRESH: | ||
2715 | ret_val = put_user(info->default_threshold, | ||
2716 | (unsigned long __user *)argp); | ||
2717 | break; | ||
2718 | case CYSETDEFTHRESH: | ||
2719 | info->default_threshold = arg & 0x0f; | ||
2720 | break; | ||
2721 | case CYGETTIMEOUT: | ||
2722 | ret_val = get_timeout(info, argp); | ||
2723 | break; | ||
2724 | case CYSETTIMEOUT: | ||
2725 | ret_val = set_timeout(info, arg); | ||
2726 | break; | ||
2727 | case CYGETDEFTIMEOUT: | ||
2728 | ret_val = put_user(info->default_timeout, | ||
2729 | (unsigned long __user *)argp); | ||
2730 | break; | ||
2731 | case CYSETDEFTIMEOUT: | ||
2732 | info->default_timeout = arg & 0xff; | ||
2733 | break; | ||
2734 | case CYSETRFLOW: | ||
2735 | info->rflow = (int)arg; | ||
2736 | break; | ||
2737 | case CYGETRFLOW: | ||
2738 | ret_val = info->rflow; | ||
2739 | break; | ||
2740 | case CYSETRTSDTR_INV: | ||
2741 | info->rtsdtr_inv = (int)arg; | ||
2742 | break; | ||
2743 | case CYGETRTSDTR_INV: | ||
2744 | ret_val = info->rtsdtr_inv; | ||
2745 | break; | ||
2746 | case CYGETCD1400VER: | ||
2747 | ret_val = info->chip_rev; | ||
2748 | break; | ||
2749 | #ifndef CONFIG_CYZ_INTR | ||
2750 | case CYZSETPOLLCYCLE: | ||
2751 | cyz_polling_cycle = (arg * HZ) / 1000; | ||
2752 | break; | ||
2753 | case CYZGETPOLLCYCLE: | ||
2754 | ret_val = (cyz_polling_cycle * 1000) / HZ; | ||
2755 | break; | ||
2756 | #endif /* CONFIG_CYZ_INTR */ | ||
2757 | case CYSETWAIT: | ||
2758 | info->port.closing_wait = (unsigned short)arg * HZ / 100; | ||
2759 | break; | ||
2760 | case CYGETWAIT: | ||
2761 | ret_val = info->port.closing_wait / (HZ / 100); | ||
2762 | break; | ||
2763 | case TIOCGSERIAL: | ||
2764 | ret_val = cy_get_serial_info(info, argp); | ||
2765 | break; | ||
2766 | case TIOCSSERIAL: | ||
2767 | ret_val = cy_set_serial_info(info, tty, argp); | ||
2768 | break; | ||
2769 | case TIOCSERGETLSR: /* Get line status register */ | ||
2770 | ret_val = get_lsr_info(info, argp); | ||
2771 | break; | ||
2772 | /* | ||
2773 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
2774 | * - mask passed in arg for lines of interest | ||
2775 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
2776 | * Caller should use TIOCGICOUNT to see which one it was | ||
2777 | */ | ||
2778 | case TIOCMIWAIT: | ||
2779 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
2780 | /* note the counters on entry */ | ||
2781 | cnow = info->icount; | ||
2782 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
2783 | ret_val = wait_event_interruptible(info->port.delta_msr_wait, | ||
2784 | cy_cflags_changed(info, arg, &cnow)); | ||
2785 | break; | ||
2786 | |||
2787 | /* | ||
2788 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2789 | * Return: write counters to the user passed counter struct | ||
2790 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
2791 | * RI where only 0->1 is counted. | ||
2792 | */ | ||
2793 | default: | ||
2794 | ret_val = -ENOIOCTLCMD; | ||
2795 | } | ||
2796 | |||
2797 | #ifdef CY_DEBUG_OTHER | ||
2798 | printk(KERN_DEBUG "cyc:cy_ioctl done\n"); | ||
2799 | #endif | ||
2800 | return ret_val; | ||
2801 | } /* cy_ioctl */ | ||
2802 | |||
2803 | static int cy_get_icount(struct tty_struct *tty, | ||
2804 | struct serial_icounter_struct *sic) | ||
2805 | { | ||
2806 | struct cyclades_port *info = tty->driver_data; | ||
2807 | struct cyclades_icount cnow; /* Used to snapshot */ | ||
2808 | unsigned long flags; | ||
2809 | |||
2810 | spin_lock_irqsave(&info->card->card_lock, flags); | ||
2811 | cnow = info->icount; | ||
2812 | spin_unlock_irqrestore(&info->card->card_lock, flags); | ||
2813 | |||
2814 | sic->cts = cnow.cts; | ||
2815 | sic->dsr = cnow.dsr; | ||
2816 | sic->rng = cnow.rng; | ||
2817 | sic->dcd = cnow.dcd; | ||
2818 | sic->rx = cnow.rx; | ||
2819 | sic->tx = cnow.tx; | ||
2820 | sic->frame = cnow.frame; | ||
2821 | sic->overrun = cnow.overrun; | ||
2822 | sic->parity = cnow.parity; | ||
2823 | sic->brk = cnow.brk; | ||
2824 | sic->buf_overrun = cnow.buf_overrun; | ||
2825 | return 0; | ||
2826 | } | ||
2827 | |||
2828 | /* | ||
2829 | * This routine allows the tty driver to be notified when | ||
2830 | * device's termios settings have changed. Note that a | ||
2831 | * well-designed tty driver should be prepared to accept the case | ||
2832 | * where old == NULL, and try to do something rational. | ||
2833 | */ | ||
2834 | static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
2835 | { | ||
2836 | struct cyclades_port *info = tty->driver_data; | ||
2837 | |||
2838 | #ifdef CY_DEBUG_OTHER | ||
2839 | printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); | ||
2840 | #endif | ||
2841 | |||
2842 | cy_set_line_char(info, tty); | ||
2843 | |||
2844 | if ((old_termios->c_cflag & CRTSCTS) && | ||
2845 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
2846 | tty->hw_stopped = 0; | ||
2847 | cy_start(tty); | ||
2848 | } | ||
2849 | #if 0 | ||
2850 | /* | ||
2851 | * No need to wake up processes in open wait, since they | ||
2852 | * sample the CLOCAL flag once, and don't recheck it. | ||
2853 | * XXX It's not clear whether the current behavior is correct | ||
2854 | * or not. Hence, this may change..... | ||
2855 | */ | ||
2856 | if (!(old_termios->c_cflag & CLOCAL) && | ||
2857 | (tty->termios->c_cflag & CLOCAL)) | ||
2858 | wake_up_interruptible(&info->port.open_wait); | ||
2859 | #endif | ||
2860 | } /* cy_set_termios */ | ||
2861 | |||
2862 | /* This function is used to send a high-priority XON/XOFF character to | ||
2863 | the device. | ||
2864 | */ | ||
2865 | static void cy_send_xchar(struct tty_struct *tty, char ch) | ||
2866 | { | ||
2867 | struct cyclades_port *info = tty->driver_data; | ||
2868 | struct cyclades_card *card; | ||
2869 | int channel; | ||
2870 | |||
2871 | if (serial_paranoia_check(info, tty->name, "cy_send_xchar")) | ||
2872 | return; | ||
2873 | |||
2874 | info->x_char = ch; | ||
2875 | |||
2876 | if (ch) | ||
2877 | cy_start(tty); | ||
2878 | |||
2879 | card = info->card; | ||
2880 | channel = info->line - card->first_line; | ||
2881 | |||
2882 | if (cy_is_Z(card)) { | ||
2883 | if (ch == STOP_CHAR(tty)) | ||
2884 | cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L); | ||
2885 | else if (ch == START_CHAR(tty)) | ||
2886 | cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L); | ||
2887 | } | ||
2888 | } | ||
2889 | |||
2890 | /* This routine is called by the upper-layer tty layer to signal | ||
2891 | that incoming characters should be throttled because the input | ||
2892 | buffers are close to full. | ||
2893 | */ | ||
2894 | static void cy_throttle(struct tty_struct *tty) | ||
2895 | { | ||
2896 | struct cyclades_port *info = tty->driver_data; | ||
2897 | struct cyclades_card *card; | ||
2898 | unsigned long flags; | ||
2899 | |||
2900 | #ifdef CY_DEBUG_THROTTLE | ||
2901 | char buf[64]; | ||
2902 | |||
2903 | printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), | ||
2904 | tty->ldisc.chars_in_buffer(tty), info->line); | ||
2905 | #endif | ||
2906 | |||
2907 | if (serial_paranoia_check(info, tty->name, "cy_throttle")) | ||
2908 | return; | ||
2909 | |||
2910 | card = info->card; | ||
2911 | |||
2912 | if (I_IXOFF(tty)) { | ||
2913 | if (!cy_is_Z(card)) | ||
2914 | cy_send_xchar(tty, STOP_CHAR(tty)); | ||
2915 | else | ||
2916 | info->throttle = 1; | ||
2917 | } | ||
2918 | |||
2919 | if (tty->termios->c_cflag & CRTSCTS) { | ||
2920 | if (!cy_is_Z(card)) { | ||
2921 | spin_lock_irqsave(&card->card_lock, flags); | ||
2922 | cyy_change_rts_dtr(info, 0, TIOCM_RTS); | ||
2923 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2924 | } else { | ||
2925 | info->throttle = 1; | ||
2926 | } | ||
2927 | } | ||
2928 | } /* cy_throttle */ | ||
2929 | |||
2930 | /* | ||
2931 | * This routine notifies the tty driver that it should signal | ||
2932 | * that characters can now be sent to the tty without fear of | ||
2933 | * overrunning the input buffers of the line disciplines. | ||
2934 | */ | ||
2935 | static void cy_unthrottle(struct tty_struct *tty) | ||
2936 | { | ||
2937 | struct cyclades_port *info = tty->driver_data; | ||
2938 | struct cyclades_card *card; | ||
2939 | unsigned long flags; | ||
2940 | |||
2941 | #ifdef CY_DEBUG_THROTTLE | ||
2942 | char buf[64]; | ||
2943 | |||
2944 | printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", | ||
2945 | tty_name(tty, buf), tty_chars_in_buffer(tty), info->line); | ||
2946 | #endif | ||
2947 | |||
2948 | if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) | ||
2949 | return; | ||
2950 | |||
2951 | if (I_IXOFF(tty)) { | ||
2952 | if (info->x_char) | ||
2953 | info->x_char = 0; | ||
2954 | else | ||
2955 | cy_send_xchar(tty, START_CHAR(tty)); | ||
2956 | } | ||
2957 | |||
2958 | if (tty->termios->c_cflag & CRTSCTS) { | ||
2959 | card = info->card; | ||
2960 | if (!cy_is_Z(card)) { | ||
2961 | spin_lock_irqsave(&card->card_lock, flags); | ||
2962 | cyy_change_rts_dtr(info, TIOCM_RTS, 0); | ||
2963 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
2964 | } else { | ||
2965 | info->throttle = 0; | ||
2966 | } | ||
2967 | } | ||
2968 | } /* cy_unthrottle */ | ||
2969 | |||
2970 | /* cy_start and cy_stop provide software output flow control as a | ||
2971 | function of XON/XOFF, software CTS, and other such stuff. | ||
2972 | */ | ||
2973 | static void cy_stop(struct tty_struct *tty) | ||
2974 | { | ||
2975 | struct cyclades_card *cinfo; | ||
2976 | struct cyclades_port *info = tty->driver_data; | ||
2977 | int channel; | ||
2978 | unsigned long flags; | ||
2979 | |||
2980 | #ifdef CY_DEBUG_OTHER | ||
2981 | printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line); | ||
2982 | #endif | ||
2983 | |||
2984 | if (serial_paranoia_check(info, tty->name, "cy_stop")) | ||
2985 | return; | ||
2986 | |||
2987 | cinfo = info->card; | ||
2988 | channel = info->line - cinfo->first_line; | ||
2989 | if (!cy_is_Z(cinfo)) { | ||
2990 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
2991 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
2992 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy); | ||
2993 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
2994 | } | ||
2995 | } /* cy_stop */ | ||
2996 | |||
2997 | static void cy_start(struct tty_struct *tty) | ||
2998 | { | ||
2999 | struct cyclades_card *cinfo; | ||
3000 | struct cyclades_port *info = tty->driver_data; | ||
3001 | int channel; | ||
3002 | unsigned long flags; | ||
3003 | |||
3004 | #ifdef CY_DEBUG_OTHER | ||
3005 | printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line); | ||
3006 | #endif | ||
3007 | |||
3008 | if (serial_paranoia_check(info, tty->name, "cy_start")) | ||
3009 | return; | ||
3010 | |||
3011 | cinfo = info->card; | ||
3012 | channel = info->line - cinfo->first_line; | ||
3013 | if (!cy_is_Z(cinfo)) { | ||
3014 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
3015 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
3016 | cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy); | ||
3017 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
3018 | } | ||
3019 | } /* cy_start */ | ||
3020 | |||
3021 | /* | ||
3022 | * cy_hangup() --- called by tty_hangup() when a hangup is signaled. | ||
3023 | */ | ||
3024 | static void cy_hangup(struct tty_struct *tty) | ||
3025 | { | ||
3026 | struct cyclades_port *info = tty->driver_data; | ||
3027 | |||
3028 | #ifdef CY_DEBUG_OTHER | ||
3029 | printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line); | ||
3030 | #endif | ||
3031 | |||
3032 | if (serial_paranoia_check(info, tty->name, "cy_hangup")) | ||
3033 | return; | ||
3034 | |||
3035 | cy_flush_buffer(tty); | ||
3036 | cy_shutdown(info, tty); | ||
3037 | tty_port_hangup(&info->port); | ||
3038 | } /* cy_hangup */ | ||
3039 | |||
3040 | static int cyy_carrier_raised(struct tty_port *port) | ||
3041 | { | ||
3042 | struct cyclades_port *info = container_of(port, struct cyclades_port, | ||
3043 | port); | ||
3044 | struct cyclades_card *cinfo = info->card; | ||
3045 | unsigned long flags; | ||
3046 | int channel = info->line - cinfo->first_line; | ||
3047 | u32 cd; | ||
3048 | |||
3049 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
3050 | cyy_writeb(info, CyCAR, channel & 0x03); | ||
3051 | cd = cyy_readb(info, CyMSVR1) & CyDCD; | ||
3052 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
3053 | |||
3054 | return cd; | ||
3055 | } | ||
3056 | |||
3057 | static void cyy_dtr_rts(struct tty_port *port, int raise) | ||
3058 | { | ||
3059 | struct cyclades_port *info = container_of(port, struct cyclades_port, | ||
3060 | port); | ||
3061 | struct cyclades_card *cinfo = info->card; | ||
3062 | unsigned long flags; | ||
3063 | |||
3064 | spin_lock_irqsave(&cinfo->card_lock, flags); | ||
3065 | cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0, | ||
3066 | raise ? 0 : TIOCM_RTS | TIOCM_DTR); | ||
3067 | spin_unlock_irqrestore(&cinfo->card_lock, flags); | ||
3068 | } | ||
3069 | |||
3070 | static int cyz_carrier_raised(struct tty_port *port) | ||
3071 | { | ||
3072 | struct cyclades_port *info = container_of(port, struct cyclades_port, | ||
3073 | port); | ||
3074 | |||
3075 | return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD; | ||
3076 | } | ||
3077 | |||
3078 | static void cyz_dtr_rts(struct tty_port *port, int raise) | ||
3079 | { | ||
3080 | struct cyclades_port *info = container_of(port, struct cyclades_port, | ||
3081 | port); | ||
3082 | struct cyclades_card *cinfo = info->card; | ||
3083 | struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl; | ||
3084 | int ret, channel = info->line - cinfo->first_line; | ||
3085 | u32 rs; | ||
3086 | |||
3087 | rs = readl(&ch_ctrl->rs_control); | ||
3088 | if (raise) | ||
3089 | rs |= C_RS_RTS | C_RS_DTR; | ||
3090 | else | ||
3091 | rs &= ~(C_RS_RTS | C_RS_DTR); | ||
3092 | cy_writel(&ch_ctrl->rs_control, rs); | ||
3093 | ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L); | ||
3094 | if (ret != 0) | ||
3095 | printk(KERN_ERR "%s: retval on ttyC%d was %x\n", | ||
3096 | __func__, info->line, ret); | ||
3097 | #ifdef CY_DEBUG_DTR | ||
3098 | printk(KERN_DEBUG "%s: raising Z DTR\n", __func__); | ||
3099 | #endif | ||
3100 | } | ||
3101 | |||
3102 | static const struct tty_port_operations cyy_port_ops = { | ||
3103 | .carrier_raised = cyy_carrier_raised, | ||
3104 | .dtr_rts = cyy_dtr_rts, | ||
3105 | .shutdown = cy_do_close, | ||
3106 | }; | ||
3107 | |||
3108 | static const struct tty_port_operations cyz_port_ops = { | ||
3109 | .carrier_raised = cyz_carrier_raised, | ||
3110 | .dtr_rts = cyz_dtr_rts, | ||
3111 | .shutdown = cy_do_close, | ||
3112 | }; | ||
3113 | |||
3114 | /* | ||
3115 | * --------------------------------------------------------------------- | ||
3116 | * cy_init() and friends | ||
3117 | * | ||
3118 | * cy_init() is called at boot-time to initialize the serial driver. | ||
3119 | * --------------------------------------------------------------------- | ||
3120 | */ | ||
3121 | |||
3122 | static int __devinit cy_init_card(struct cyclades_card *cinfo) | ||
3123 | { | ||
3124 | struct cyclades_port *info; | ||
3125 | unsigned int channel, port; | ||
3126 | |||
3127 | spin_lock_init(&cinfo->card_lock); | ||
3128 | cinfo->intr_enabled = 0; | ||
3129 | |||
3130 | cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports), | ||
3131 | GFP_KERNEL); | ||
3132 | if (cinfo->ports == NULL) { | ||
3133 | printk(KERN_ERR "Cyclades: cannot allocate ports\n"); | ||
3134 | return -ENOMEM; | ||
3135 | } | ||
3136 | |||
3137 | for (channel = 0, port = cinfo->first_line; channel < cinfo->nports; | ||
3138 | channel++, port++) { | ||
3139 | info = &cinfo->ports[channel]; | ||
3140 | tty_port_init(&info->port); | ||
3141 | info->magic = CYCLADES_MAGIC; | ||
3142 | info->card = cinfo; | ||
3143 | info->line = port; | ||
3144 | |||
3145 | info->port.closing_wait = CLOSING_WAIT_DELAY; | ||
3146 | info->port.close_delay = 5 * HZ / 10; | ||
3147 | info->port.flags = STD_COM_FLAGS; | ||
3148 | init_completion(&info->shutdown_wait); | ||
3149 | |||
3150 | if (cy_is_Z(cinfo)) { | ||
3151 | struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS; | ||
3152 | struct ZFW_CTRL *zfw_ctrl; | ||
3153 | |||
3154 | info->port.ops = &cyz_port_ops; | ||
3155 | info->type = PORT_STARTECH; | ||
3156 | |||
3157 | zfw_ctrl = cinfo->base_addr + | ||
3158 | (readl(&firm_id->zfwctrl_addr) & 0xfffff); | ||
3159 | info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel]; | ||
3160 | info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; | ||
3161 | |||
3162 | if (cinfo->hw_ver == ZO_V1) | ||
3163 | info->xmit_fifo_size = CYZ_FIFO_SIZE; | ||
3164 | else | ||
3165 | info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE; | ||
3166 | #ifdef CONFIG_CYZ_INTR | ||
3167 | setup_timer(&cyz_rx_full_timer[port], | ||
3168 | cyz_rx_restart, (unsigned long)info); | ||
3169 | #endif | ||
3170 | } else { | ||
3171 | unsigned short chip_number; | ||
3172 | int index = cinfo->bus_index; | ||
3173 | |||
3174 | info->port.ops = &cyy_port_ops; | ||
3175 | info->type = PORT_CIRRUS; | ||
3176 | info->xmit_fifo_size = CyMAX_CHAR_FIFO; | ||
3177 | info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS; | ||
3178 | info->cor2 = CyETC; | ||
3179 | info->cor3 = 0x08; /* _very_ small rcv threshold */ | ||
3180 | |||
3181 | chip_number = channel / CyPORTS_PER_CHIP; | ||
3182 | info->u.cyy.base_addr = cinfo->base_addr + | ||
3183 | (cy_chip_offset[chip_number] << index); | ||
3184 | info->chip_rev = cyy_readb(info, CyGFRCR); | ||
3185 | |||
3186 | if (info->chip_rev >= CD1400_REV_J) { | ||
3187 | /* It is a CD1400 rev. J or later */ | ||
3188 | info->tbpr = baud_bpr_60[13]; /* Tx BPR */ | ||
3189 | info->tco = baud_co_60[13]; /* Tx CO */ | ||
3190 | info->rbpr = baud_bpr_60[13]; /* Rx BPR */ | ||
3191 | info->rco = baud_co_60[13]; /* Rx CO */ | ||
3192 | info->rtsdtr_inv = 1; | ||
3193 | } else { | ||
3194 | info->tbpr = baud_bpr_25[13]; /* Tx BPR */ | ||
3195 | info->tco = baud_co_25[13]; /* Tx CO */ | ||
3196 | info->rbpr = baud_bpr_25[13]; /* Rx BPR */ | ||
3197 | info->rco = baud_co_25[13]; /* Rx CO */ | ||
3198 | info->rtsdtr_inv = 0; | ||
3199 | } | ||
3200 | info->read_status_mask = CyTIMEOUT | CySPECHAR | | ||
3201 | CyBREAK | CyPARITY | CyFRAME | CyOVERRUN; | ||
3202 | } | ||
3203 | |||
3204 | } | ||
3205 | |||
3206 | #ifndef CONFIG_CYZ_INTR | ||
3207 | if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) { | ||
3208 | mod_timer(&cyz_timerlist, jiffies + 1); | ||
3209 | #ifdef CY_PCI_DEBUG | ||
3210 | printk(KERN_DEBUG "Cyclades-Z polling initialized\n"); | ||
3211 | #endif | ||
3212 | } | ||
3213 | #endif | ||
3214 | return 0; | ||
3215 | } | ||
3216 | |||
3217 | /* initialize chips on Cyclom-Y card -- return number of valid | ||
3218 | chips (which is number of ports/4) */ | ||
3219 | static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, | ||
3220 | int index) | ||
3221 | { | ||
3222 | unsigned int chip_number; | ||
3223 | void __iomem *base_addr; | ||
3224 | |||
3225 | cy_writeb(true_base_addr + (Cy_HwReset << index), 0); | ||
3226 | /* Cy_HwReset is 0x1400 */ | ||
3227 | cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0); | ||
3228 | /* Cy_ClrIntr is 0x1800 */ | ||
3229 | udelay(500L); | ||
3230 | |||
3231 | for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; | ||
3232 | chip_number++) { | ||
3233 | base_addr = | ||
3234 | true_base_addr + (cy_chip_offset[chip_number] << index); | ||
3235 | mdelay(1); | ||
3236 | if (readb(base_addr + (CyCCR << index)) != 0x00) { | ||
3237 | /************* | ||
3238 | printk(" chip #%d at %#6lx is never idle (CCR != 0)\n", | ||
3239 | chip_number, (unsigned long)base_addr); | ||
3240 | *************/ | ||
3241 | return chip_number; | ||
3242 | } | ||
3243 | |||
3244 | cy_writeb(base_addr + (CyGFRCR << index), 0); | ||
3245 | udelay(10L); | ||
3246 | |||
3247 | /* The Cyclom-16Y does not decode address bit 9 and therefore | ||
3248 | cannot distinguish between references to chip 0 and a non- | ||
3249 | existent chip 4. If the preceding clearing of the supposed | ||
3250 | chip 4 GFRCR register appears at chip 0, there is no chip 4 | ||
3251 | and this must be a Cyclom-16Y, not a Cyclom-32Ye. | ||
3252 | */ | ||
3253 | if (chip_number == 4 && readb(true_base_addr + | ||
3254 | (cy_chip_offset[0] << index) + | ||
3255 | (CyGFRCR << index)) == 0) { | ||
3256 | return chip_number; | ||
3257 | } | ||
3258 | |||
3259 | cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET); | ||
3260 | mdelay(1); | ||
3261 | |||
3262 | if (readb(base_addr + (CyGFRCR << index)) == 0x00) { | ||
3263 | /* | ||
3264 | printk(" chip #%d at %#6lx is not responding ", | ||
3265 | chip_number, (unsigned long)base_addr); | ||
3266 | printk("(GFRCR stayed 0)\n", | ||
3267 | */ | ||
3268 | return chip_number; | ||
3269 | } | ||
3270 | if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) != | ||
3271 | 0x40) { | ||
3272 | /* | ||
3273 | printk(" chip #%d at %#6lx is not valid (GFRCR == " | ||
3274 | "%#2x)\n", | ||
3275 | chip_number, (unsigned long)base_addr, | ||
3276 | base_addr[CyGFRCR<<index]); | ||
3277 | */ | ||
3278 | return chip_number; | ||
3279 | } | ||
3280 | cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL); | ||
3281 | if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) { | ||
3282 | /* It is a CD1400 rev. J or later */ | ||
3283 | /* Impossible to reach 5ms with this chip. | ||
3284 | Changed to 2ms instead (f = 500 Hz). */ | ||
3285 | cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS); | ||
3286 | } else { | ||
3287 | /* f = 200 Hz */ | ||
3288 | cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS); | ||
3289 | } | ||
3290 | |||
3291 | /* | ||
3292 | printk(" chip #%d at %#6lx is rev 0x%2x\n", | ||
3293 | chip_number, (unsigned long)base_addr, | ||
3294 | readb(base_addr+(CyGFRCR<<index))); | ||
3295 | */ | ||
3296 | } | ||
3297 | return chip_number; | ||
3298 | } /* cyy_init_card */ | ||
3299 | |||
3300 | /* | ||
3301 | * --------------------------------------------------------------------- | ||
3302 | * cy_detect_isa() - Probe for Cyclom-Y/ISA boards. | ||
3303 | * sets global variables and return the number of ISA boards found. | ||
3304 | * --------------------------------------------------------------------- | ||
3305 | */ | ||
3306 | static int __init cy_detect_isa(void) | ||
3307 | { | ||
3308 | #ifdef CONFIG_ISA | ||
3309 | unsigned short cy_isa_irq, nboard; | ||
3310 | void __iomem *cy_isa_address; | ||
3311 | unsigned short i, j, cy_isa_nchan; | ||
3312 | int isparam = 0; | ||
3313 | |||
3314 | nboard = 0; | ||
3315 | |||
3316 | /* Check for module parameters */ | ||
3317 | for (i = 0; i < NR_CARDS; i++) { | ||
3318 | if (maddr[i] || i) { | ||
3319 | isparam = 1; | ||
3320 | cy_isa_addresses[i] = maddr[i]; | ||
3321 | } | ||
3322 | if (!maddr[i]) | ||
3323 | break; | ||
3324 | } | ||
3325 | |||
3326 | /* scan the address table probing for Cyclom-Y/ISA boards */ | ||
3327 | for (i = 0; i < NR_ISA_ADDRS; i++) { | ||
3328 | unsigned int isa_address = cy_isa_addresses[i]; | ||
3329 | if (isa_address == 0x0000) | ||
3330 | return nboard; | ||
3331 | |||
3332 | /* probe for CD1400... */ | ||
3333 | cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin); | ||
3334 | if (cy_isa_address == NULL) { | ||
3335 | printk(KERN_ERR "Cyclom-Y/ISA: can't remap base " | ||
3336 | "address\n"); | ||
3337 | continue; | ||
3338 | } | ||
3339 | cy_isa_nchan = CyPORTS_PER_CHIP * | ||
3340 | cyy_init_card(cy_isa_address, 0); | ||
3341 | if (cy_isa_nchan == 0) { | ||
3342 | iounmap(cy_isa_address); | ||
3343 | continue; | ||
3344 | } | ||
3345 | |||
3346 | if (isparam && i < NR_CARDS && irq[i]) | ||
3347 | cy_isa_irq = irq[i]; | ||
3348 | else | ||
3349 | /* find out the board's irq by probing */ | ||
3350 | cy_isa_irq = detect_isa_irq(cy_isa_address); | ||
3351 | if (cy_isa_irq == 0) { | ||
3352 | printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the " | ||
3353 | "IRQ could not be detected.\n", | ||
3354 | (unsigned long)cy_isa_address); | ||
3355 | iounmap(cy_isa_address); | ||
3356 | continue; | ||
3357 | } | ||
3358 | |||
3359 | if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) { | ||
3360 | printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " | ||
3361 | "more channels are available. Change NR_PORTS " | ||
3362 | "in cyclades.c and recompile kernel.\n", | ||
3363 | (unsigned long)cy_isa_address); | ||
3364 | iounmap(cy_isa_address); | ||
3365 | return nboard; | ||
3366 | } | ||
3367 | /* fill the next cy_card structure available */ | ||
3368 | for (j = 0; j < NR_CARDS; j++) { | ||
3369 | if (cy_card[j].base_addr == NULL) | ||
3370 | break; | ||
3371 | } | ||
3372 | if (j == NR_CARDS) { /* no more cy_cards available */ | ||
3373 | printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no " | ||
3374 | "more cards can be used. Change NR_CARDS in " | ||
3375 | "cyclades.c and recompile kernel.\n", | ||
3376 | (unsigned long)cy_isa_address); | ||
3377 | iounmap(cy_isa_address); | ||
3378 | return nboard; | ||
3379 | } | ||
3380 | |||
3381 | /* allocate IRQ */ | ||
3382 | if (request_irq(cy_isa_irq, cyy_interrupt, | ||
3383 | IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) { | ||
3384 | printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but " | ||
3385 | "could not allocate IRQ#%d.\n", | ||
3386 | (unsigned long)cy_isa_address, cy_isa_irq); | ||
3387 | iounmap(cy_isa_address); | ||
3388 | return nboard; | ||
3389 | } | ||
3390 | |||
3391 | /* set cy_card */ | ||
3392 | cy_card[j].base_addr = cy_isa_address; | ||
3393 | cy_card[j].ctl_addr.p9050 = NULL; | ||
3394 | cy_card[j].irq = (int)cy_isa_irq; | ||
3395 | cy_card[j].bus_index = 0; | ||
3396 | cy_card[j].first_line = cy_next_channel; | ||
3397 | cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP; | ||
3398 | cy_card[j].nports = cy_isa_nchan; | ||
3399 | if (cy_init_card(&cy_card[j])) { | ||
3400 | cy_card[j].base_addr = NULL; | ||
3401 | free_irq(cy_isa_irq, &cy_card[j]); | ||
3402 | iounmap(cy_isa_address); | ||
3403 | continue; | ||
3404 | } | ||
3405 | nboard++; | ||
3406 | |||
3407 | printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: " | ||
3408 | "%d channels starting from port %d\n", | ||
3409 | j + 1, (unsigned long)cy_isa_address, | ||
3410 | (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)), | ||
3411 | cy_isa_irq, cy_isa_nchan, cy_next_channel); | ||
3412 | |||
3413 | for (j = cy_next_channel; | ||
3414 | j < cy_next_channel + cy_isa_nchan; j++) | ||
3415 | tty_register_device(cy_serial_driver, j, NULL); | ||
3416 | cy_next_channel += cy_isa_nchan; | ||
3417 | } | ||
3418 | return nboard; | ||
3419 | #else | ||
3420 | return 0; | ||
3421 | #endif /* CONFIG_ISA */ | ||
3422 | } /* cy_detect_isa */ | ||
3423 | |||
3424 | #ifdef CONFIG_PCI | ||
3425 | static inline int __devinit cyc_isfwstr(const char *str, unsigned int size) | ||
3426 | { | ||
3427 | unsigned int a; | ||
3428 | |||
3429 | for (a = 0; a < size && *str; a++, str++) | ||
3430 | if (*str & 0x80) | ||
3431 | return -EINVAL; | ||
3432 | |||
3433 | for (; a < size; a++, str++) | ||
3434 | if (*str) | ||
3435 | return -EINVAL; | ||
3436 | |||
3437 | return 0; | ||
3438 | } | ||
3439 | |||
3440 | static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data, | ||
3441 | unsigned int size) | ||
3442 | { | ||
3443 | for (; size > 0; size--) { | ||
3444 | cy_writel(fpga, *data++); | ||
3445 | udelay(10); | ||
3446 | } | ||
3447 | } | ||
3448 | |||
3449 | static void __devinit plx_init(struct pci_dev *pdev, int irq, | ||
3450 | struct RUNTIME_9060 __iomem *addr) | ||
3451 | { | ||
3452 | /* Reset PLX */ | ||
3453 | cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000); | ||
3454 | udelay(100L); | ||
3455 | cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000); | ||
3456 | |||
3457 | /* Reload Config. Registers from EEPROM */ | ||
3458 | cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000); | ||
3459 | udelay(100L); | ||
3460 | cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000); | ||
3461 | |||
3462 | /* For some yet unknown reason, once the PLX9060 reloads the EEPROM, | ||
3463 | * the IRQ is lost and, thus, we have to re-write it to the PCI config. | ||
3464 | * registers. This will remain here until we find a permanent fix. | ||
3465 | */ | ||
3466 | pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq); | ||
3467 | } | ||
3468 | |||
3469 | static int __devinit __cyz_load_fw(const struct firmware *fw, | ||
3470 | const char *name, const u32 mailbox, void __iomem *base, | ||
3471 | void __iomem *fpga) | ||
3472 | { | ||
3473 | const void *ptr = fw->data; | ||
3474 | const struct zfile_header *h = ptr; | ||
3475 | const struct zfile_config *c, *cs; | ||
3476 | const struct zfile_block *b, *bs; | ||
3477 | unsigned int a, tmp, len = fw->size; | ||
3478 | #define BAD_FW KERN_ERR "Bad firmware: " | ||
3479 | if (len < sizeof(*h)) { | ||
3480 | printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h)); | ||
3481 | return -EINVAL; | ||
3482 | } | ||
3483 | |||
3484 | cs = ptr + h->config_offset; | ||
3485 | bs = ptr + h->block_offset; | ||
3486 | |||
3487 | if ((void *)(cs + h->n_config) > ptr + len || | ||
3488 | (void *)(bs + h->n_blocks) > ptr + len) { | ||
3489 | printk(BAD_FW "too short"); | ||
3490 | return -EINVAL; | ||
3491 | } | ||
3492 | |||
3493 | if (cyc_isfwstr(h->name, sizeof(h->name)) || | ||
3494 | cyc_isfwstr(h->date, sizeof(h->date))) { | ||
3495 | printk(BAD_FW "bad formatted header string\n"); | ||
3496 | return -EINVAL; | ||
3497 | } | ||
3498 | |||
3499 | if (strncmp(name, h->name, sizeof(h->name))) { | ||
3500 | printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name); | ||
3501 | return -EINVAL; | ||
3502 | } | ||
3503 | |||
3504 | tmp = 0; | ||
3505 | for (c = cs; c < cs + h->n_config; c++) { | ||
3506 | for (a = 0; a < c->n_blocks; a++) | ||
3507 | if (c->block_list[a] > h->n_blocks) { | ||
3508 | printk(BAD_FW "bad block ref number in cfgs\n"); | ||
3509 | return -EINVAL; | ||
3510 | } | ||
3511 | if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */ | ||
3512 | tmp++; | ||
3513 | } | ||
3514 | if (!tmp) { | ||
3515 | printk(BAD_FW "nothing appropriate\n"); | ||
3516 | return -EINVAL; | ||
3517 | } | ||
3518 | |||
3519 | for (b = bs; b < bs + h->n_blocks; b++) | ||
3520 | if (b->file_offset + b->size > len) { | ||
3521 | printk(BAD_FW "bad block data offset\n"); | ||
3522 | return -EINVAL; | ||
3523 | } | ||
3524 | |||
3525 | /* everything is OK, let's seek'n'load it */ | ||
3526 | for (c = cs; c < cs + h->n_config; c++) | ||
3527 | if (c->mailbox == mailbox && c->function == 0) | ||
3528 | break; | ||
3529 | |||
3530 | for (a = 0; a < c->n_blocks; a++) { | ||
3531 | b = &bs[c->block_list[a]]; | ||
3532 | if (b->type == ZBLOCK_FPGA) { | ||
3533 | if (fpga != NULL) | ||
3534 | cyz_fpga_copy(fpga, ptr + b->file_offset, | ||
3535 | b->size); | ||
3536 | } else { | ||
3537 | if (base != NULL) | ||
3538 | memcpy_toio(base + b->ram_offset, | ||
3539 | ptr + b->file_offset, b->size); | ||
3540 | } | ||
3541 | } | ||
3542 | #undef BAD_FW | ||
3543 | return 0; | ||
3544 | } | ||
3545 | |||
3546 | static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, | ||
3547 | struct RUNTIME_9060 __iomem *ctl_addr, int irq) | ||
3548 | { | ||
3549 | const struct firmware *fw; | ||
3550 | struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS; | ||
3551 | struct CUSTOM_REG __iomem *cust = base_addr; | ||
3552 | struct ZFW_CTRL __iomem *pt_zfwctrl; | ||
3553 | void __iomem *tmp; | ||
3554 | u32 mailbox, status, nchan; | ||
3555 | unsigned int i; | ||
3556 | int retval; | ||
3557 | |||
3558 | retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev); | ||
3559 | if (retval) { | ||
3560 | dev_err(&pdev->dev, "can't get firmware\n"); | ||
3561 | goto err; | ||
3562 | } | ||
3563 | |||
3564 | /* Check whether the firmware is already loaded and running. If | ||
3565 | positive, skip this board */ | ||
3566 | if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) { | ||
3567 | u32 cntval = readl(base_addr + 0x190); | ||
3568 | |||
3569 | udelay(100); | ||
3570 | if (cntval != readl(base_addr + 0x190)) { | ||
3571 | /* FW counter is working, FW is running */ | ||
3572 | dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. " | ||
3573 | "Skipping board.\n"); | ||
3574 | retval = 0; | ||
3575 | goto err_rel; | ||
3576 | } | ||
3577 | } | ||
3578 | |||
3579 | /* start boot */ | ||
3580 | cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) & | ||
3581 | ~0x00030800UL); | ||
3582 | |||
3583 | mailbox = readl(&ctl_addr->mail_box_0); | ||
3584 | |||
3585 | if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) { | ||
3586 | /* stops CPU and set window to beginning of RAM */ | ||
3587 | cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); | ||
3588 | cy_writel(&cust->cpu_stop, 0); | ||
3589 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); | ||
3590 | udelay(100); | ||
3591 | } | ||
3592 | |||
3593 | plx_init(pdev, irq, ctl_addr); | ||
3594 | |||
3595 | if (mailbox != 0) { | ||
3596 | /* load FPGA */ | ||
3597 | retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL, | ||
3598 | base_addr); | ||
3599 | if (retval) | ||
3600 | goto err_rel; | ||
3601 | if (!__cyz_fpga_loaded(ctl_addr)) { | ||
3602 | dev_err(&pdev->dev, "fw upload successful, but fw is " | ||
3603 | "not loaded\n"); | ||
3604 | goto err_rel; | ||
3605 | } | ||
3606 | } | ||
3607 | |||
3608 | /* stops CPU and set window to beginning of RAM */ | ||
3609 | cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); | ||
3610 | cy_writel(&cust->cpu_stop, 0); | ||
3611 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); | ||
3612 | udelay(100); | ||
3613 | |||
3614 | /* clear memory */ | ||
3615 | for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) | ||
3616 | cy_writeb(tmp, 255); | ||
3617 | if (mailbox != 0) { | ||
3618 | /* set window to last 512K of RAM */ | ||
3619 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE); | ||
3620 | for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) | ||
3621 | cy_writeb(tmp, 255); | ||
3622 | /* set window to beginning of RAM */ | ||
3623 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); | ||
3624 | } | ||
3625 | |||
3626 | retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL); | ||
3627 | release_firmware(fw); | ||
3628 | if (retval) | ||
3629 | goto err; | ||
3630 | |||
3631 | /* finish boot and start boards */ | ||
3632 | cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); | ||
3633 | cy_writel(&cust->cpu_start, 0); | ||
3634 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); | ||
3635 | i = 0; | ||
3636 | while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40) | ||
3637 | msleep(100); | ||
3638 | if (status != ZFIRM_ID) { | ||
3639 | if (status == ZFIRM_HLT) { | ||
3640 | dev_err(&pdev->dev, "you need an external power supply " | ||
3641 | "for this number of ports. Firmware halted and " | ||
3642 | "board reset.\n"); | ||
3643 | retval = -EIO; | ||
3644 | goto err; | ||
3645 | } | ||
3646 | dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting " | ||
3647 | "some more time\n", status); | ||
3648 | while ((status = readl(&fid->signature)) != ZFIRM_ID && | ||
3649 | i++ < 200) | ||
3650 | msleep(100); | ||
3651 | if (status != ZFIRM_ID) { | ||
3652 | dev_err(&pdev->dev, "Board not started in 20 seconds! " | ||
3653 | "Giving up. (fid->signature = 0x%x)\n", | ||
3654 | status); | ||
3655 | dev_info(&pdev->dev, "*** Warning ***: if you are " | ||
3656 | "upgrading the FW, please power cycle the " | ||
3657 | "system before loading the new FW to the " | ||
3658 | "Cyclades-Z.\n"); | ||
3659 | |||
3660 | if (__cyz_fpga_loaded(ctl_addr)) | ||
3661 | plx_init(pdev, irq, ctl_addr); | ||
3662 | |||
3663 | retval = -EIO; | ||
3664 | goto err; | ||
3665 | } | ||
3666 | dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n", | ||
3667 | i / 10); | ||
3668 | } | ||
3669 | pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr); | ||
3670 | |||
3671 | dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n", | ||
3672 | base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr), | ||
3673 | base_addr + readl(&fid->zfwctrl_addr)); | ||
3674 | |||
3675 | nchan = readl(&pt_zfwctrl->board_ctrl.n_channel); | ||
3676 | dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n", | ||
3677 | readl(&pt_zfwctrl->board_ctrl.fw_version), nchan); | ||
3678 | |||
3679 | if (nchan == 0) { | ||
3680 | dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please " | ||
3681 | "check the connection between the Z host card and the " | ||
3682 | "serial expanders.\n"); | ||
3683 | |||
3684 | if (__cyz_fpga_loaded(ctl_addr)) | ||
3685 | plx_init(pdev, irq, ctl_addr); | ||
3686 | |||
3687 | dev_info(&pdev->dev, "Null number of ports detected. Board " | ||
3688 | "reset.\n"); | ||
3689 | retval = 0; | ||
3690 | goto err; | ||
3691 | } | ||
3692 | |||
3693 | cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX); | ||
3694 | cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION); | ||
3695 | |||
3696 | /* | ||
3697 | Early firmware failed to start looking for commands. | ||
3698 | This enables firmware interrupts for those commands. | ||
3699 | */ | ||
3700 | cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | | ||
3701 | (1 << 17)); | ||
3702 | cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) | | ||
3703 | 0x00030800UL); | ||
3704 | |||
3705 | return nchan; | ||
3706 | err_rel: | ||
3707 | release_firmware(fw); | ||
3708 | err: | ||
3709 | return retval; | ||
3710 | } | ||
3711 | |||
3712 | static int __devinit cy_pci_probe(struct pci_dev *pdev, | ||
3713 | const struct pci_device_id *ent) | ||
3714 | { | ||
3715 | void __iomem *addr0 = NULL, *addr2 = NULL; | ||
3716 | char *card_name = NULL; | ||
3717 | u32 uninitialized_var(mailbox); | ||
3718 | unsigned int device_id, nchan = 0, card_no, i; | ||
3719 | unsigned char plx_ver; | ||
3720 | int retval, irq; | ||
3721 | |||
3722 | retval = pci_enable_device(pdev); | ||
3723 | if (retval) { | ||
3724 | dev_err(&pdev->dev, "cannot enable device\n"); | ||
3725 | goto err; | ||
3726 | } | ||
3727 | |||
3728 | /* read PCI configuration area */ | ||
3729 | irq = pdev->irq; | ||
3730 | device_id = pdev->device & ~PCI_DEVICE_ID_MASK; | ||
3731 | |||
3732 | #if defined(__alpha__) | ||
3733 | if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ | ||
3734 | dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low " | ||
3735 | "addresses on Alpha systems.\n"); | ||
3736 | retval = -EIO; | ||
3737 | goto err_dis; | ||
3738 | } | ||
3739 | #endif | ||
3740 | if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) { | ||
3741 | dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low " | ||
3742 | "addresses\n"); | ||
3743 | retval = -EIO; | ||
3744 | goto err_dis; | ||
3745 | } | ||
3746 | |||
3747 | if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { | ||
3748 | dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring " | ||
3749 | "it...\n"); | ||
3750 | pdev->resource[2].flags &= ~IORESOURCE_IO; | ||
3751 | } | ||
3752 | |||
3753 | retval = pci_request_regions(pdev, "cyclades"); | ||
3754 | if (retval) { | ||
3755 | dev_err(&pdev->dev, "failed to reserve resources\n"); | ||
3756 | goto err_dis; | ||
3757 | } | ||
3758 | |||
3759 | retval = -EIO; | ||
3760 | if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || | ||
3761 | device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { | ||
3762 | card_name = "Cyclom-Y"; | ||
3763 | |||
3764 | addr0 = ioremap_nocache(pci_resource_start(pdev, 0), | ||
3765 | CyPCI_Yctl); | ||
3766 | if (addr0 == NULL) { | ||
3767 | dev_err(&pdev->dev, "can't remap ctl region\n"); | ||
3768 | goto err_reg; | ||
3769 | } | ||
3770 | addr2 = ioremap_nocache(pci_resource_start(pdev, 2), | ||
3771 | CyPCI_Ywin); | ||
3772 | if (addr2 == NULL) { | ||
3773 | dev_err(&pdev->dev, "can't remap base region\n"); | ||
3774 | goto err_unmap; | ||
3775 | } | ||
3776 | |||
3777 | nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1); | ||
3778 | if (nchan == 0) { | ||
3779 | dev_err(&pdev->dev, "Cyclom-Y PCI host card with no " | ||
3780 | "Serial-Modules\n"); | ||
3781 | goto err_unmap; | ||
3782 | } | ||
3783 | } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { | ||
3784 | struct RUNTIME_9060 __iomem *ctl_addr; | ||
3785 | |||
3786 | ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0), | ||
3787 | CyPCI_Zctl); | ||
3788 | if (addr0 == NULL) { | ||
3789 | dev_err(&pdev->dev, "can't remap ctl region\n"); | ||
3790 | goto err_reg; | ||
3791 | } | ||
3792 | |||
3793 | /* Disable interrupts on the PLX before resetting it */ | ||
3794 | cy_writew(&ctl_addr->intr_ctrl_stat, | ||
3795 | readw(&ctl_addr->intr_ctrl_stat) & ~0x0900); | ||
3796 | |||
3797 | plx_init(pdev, irq, addr0); | ||
3798 | |||
3799 | mailbox = readl(&ctl_addr->mail_box_0); | ||
3800 | |||
3801 | addr2 = ioremap_nocache(pci_resource_start(pdev, 2), | ||
3802 | mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); | ||
3803 | if (addr2 == NULL) { | ||
3804 | dev_err(&pdev->dev, "can't remap base region\n"); | ||
3805 | goto err_unmap; | ||
3806 | } | ||
3807 | |||
3808 | if (mailbox == ZE_V1) { | ||
3809 | card_name = "Cyclades-Ze"; | ||
3810 | } else { | ||
3811 | card_name = "Cyclades-8Zo"; | ||
3812 | #ifdef CY_PCI_DEBUG | ||
3813 | if (mailbox == ZO_V1) { | ||
3814 | cy_writel(&ctl_addr->loc_addr_base, WIN_CREG); | ||
3815 | dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA " | ||
3816 | "id %lx, ver %lx\n", (ulong)(0xff & | ||
3817 | readl(&((struct CUSTOM_REG *)addr2)-> | ||
3818 | fpga_id)), (ulong)(0xff & | ||
3819 | readl(&((struct CUSTOM_REG *)addr2)-> | ||
3820 | fpga_version))); | ||
3821 | cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); | ||
3822 | } else { | ||
3823 | dev_info(&pdev->dev, "Cyclades-Z/PCI: New " | ||
3824 | "Cyclades-Z board. FPGA not loaded\n"); | ||
3825 | } | ||
3826 | #endif | ||
3827 | /* The following clears the firmware id word. This | ||
3828 | ensures that the driver will not attempt to talk to | ||
3829 | the board until it has been properly initialized. | ||
3830 | */ | ||
3831 | if ((mailbox == ZO_V1) || (mailbox == ZO_V2)) | ||
3832 | cy_writel(addr2 + ID_ADDRESS, 0L); | ||
3833 | } | ||
3834 | |||
3835 | retval = cyz_load_fw(pdev, addr2, addr0, irq); | ||
3836 | if (retval <= 0) | ||
3837 | goto err_unmap; | ||
3838 | nchan = retval; | ||
3839 | } | ||
3840 | |||
3841 | if ((cy_next_channel + nchan) > NR_PORTS) { | ||
3842 | dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " | ||
3843 | "channels are available. Change NR_PORTS in " | ||
3844 | "cyclades.c and recompile kernel.\n"); | ||
3845 | goto err_unmap; | ||
3846 | } | ||
3847 | /* fill the next cy_card structure available */ | ||
3848 | for (card_no = 0; card_no < NR_CARDS; card_no++) { | ||
3849 | if (cy_card[card_no].base_addr == NULL) | ||
3850 | break; | ||
3851 | } | ||
3852 | if (card_no == NR_CARDS) { /* no more cy_cards available */ | ||
3853 | dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no " | ||
3854 | "more cards can be used. Change NR_CARDS in " | ||
3855 | "cyclades.c and recompile kernel.\n"); | ||
3856 | goto err_unmap; | ||
3857 | } | ||
3858 | |||
3859 | if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || | ||
3860 | device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { | ||
3861 | /* allocate IRQ */ | ||
3862 | retval = request_irq(irq, cyy_interrupt, | ||
3863 | IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]); | ||
3864 | if (retval) { | ||
3865 | dev_err(&pdev->dev, "could not allocate IRQ\n"); | ||
3866 | goto err_unmap; | ||
3867 | } | ||
3868 | cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP; | ||
3869 | } else { | ||
3870 | struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS; | ||
3871 | struct ZFW_CTRL __iomem *zfw_ctrl; | ||
3872 | |||
3873 | zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff); | ||
3874 | |||
3875 | cy_card[card_no].hw_ver = mailbox; | ||
3876 | cy_card[card_no].num_chips = (unsigned int)-1; | ||
3877 | cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl; | ||
3878 | #ifdef CONFIG_CYZ_INTR | ||
3879 | /* allocate IRQ only if board has an IRQ */ | ||
3880 | if (irq != 0 && irq != 255) { | ||
3881 | retval = request_irq(irq, cyz_interrupt, | ||
3882 | IRQF_SHARED, "Cyclades-Z", | ||
3883 | &cy_card[card_no]); | ||
3884 | if (retval) { | ||
3885 | dev_err(&pdev->dev, "could not allocate IRQ\n"); | ||
3886 | goto err_unmap; | ||
3887 | } | ||
3888 | } | ||
3889 | #endif /* CONFIG_CYZ_INTR */ | ||
3890 | } | ||
3891 | |||
3892 | /* set cy_card */ | ||
3893 | cy_card[card_no].base_addr = addr2; | ||
3894 | cy_card[card_no].ctl_addr.p9050 = addr0; | ||
3895 | cy_card[card_no].irq = irq; | ||
3896 | cy_card[card_no].bus_index = 1; | ||
3897 | cy_card[card_no].first_line = cy_next_channel; | ||
3898 | cy_card[card_no].nports = nchan; | ||
3899 | retval = cy_init_card(&cy_card[card_no]); | ||
3900 | if (retval) | ||
3901 | goto err_null; | ||
3902 | |||
3903 | pci_set_drvdata(pdev, &cy_card[card_no]); | ||
3904 | |||
3905 | if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo || | ||
3906 | device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { | ||
3907 | /* enable interrupts in the PCI interface */ | ||
3908 | plx_ver = readb(addr2 + CyPLX_VER) & 0x0f; | ||
3909 | switch (plx_ver) { | ||
3910 | case PLX_9050: | ||
3911 | cy_writeb(addr0 + 0x4c, 0x43); | ||
3912 | break; | ||
3913 | |||
3914 | case PLX_9060: | ||
3915 | case PLX_9080: | ||
3916 | default: /* Old boards, use PLX_9060 */ | ||
3917 | { | ||
3918 | struct RUNTIME_9060 __iomem *ctl_addr = addr0; | ||
3919 | plx_init(pdev, irq, ctl_addr); | ||
3920 | cy_writew(&ctl_addr->intr_ctrl_stat, | ||
3921 | readw(&ctl_addr->intr_ctrl_stat) | 0x0900); | ||
3922 | break; | ||
3923 | } | ||
3924 | } | ||
3925 | } | ||
3926 | |||
3927 | dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from " | ||
3928 | "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel); | ||
3929 | for (i = cy_next_channel; i < cy_next_channel + nchan; i++) | ||
3930 | tty_register_device(cy_serial_driver, i, &pdev->dev); | ||
3931 | cy_next_channel += nchan; | ||
3932 | |||
3933 | return 0; | ||
3934 | err_null: | ||
3935 | cy_card[card_no].base_addr = NULL; | ||
3936 | free_irq(irq, &cy_card[card_no]); | ||
3937 | err_unmap: | ||
3938 | iounmap(addr0); | ||
3939 | if (addr2) | ||
3940 | iounmap(addr2); | ||
3941 | err_reg: | ||
3942 | pci_release_regions(pdev); | ||
3943 | err_dis: | ||
3944 | pci_disable_device(pdev); | ||
3945 | err: | ||
3946 | return retval; | ||
3947 | } | ||
3948 | |||
3949 | static void __devexit cy_pci_remove(struct pci_dev *pdev) | ||
3950 | { | ||
3951 | struct cyclades_card *cinfo = pci_get_drvdata(pdev); | ||
3952 | unsigned int i; | ||
3953 | |||
3954 | /* non-Z with old PLX */ | ||
3955 | if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) == | ||
3956 | PLX_9050) | ||
3957 | cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0); | ||
3958 | else | ||
3959 | #ifndef CONFIG_CYZ_INTR | ||
3960 | if (!cy_is_Z(cinfo)) | ||
3961 | #endif | ||
3962 | cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat, | ||
3963 | readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) & | ||
3964 | ~0x0900); | ||
3965 | |||
3966 | iounmap(cinfo->base_addr); | ||
3967 | if (cinfo->ctl_addr.p9050) | ||
3968 | iounmap(cinfo->ctl_addr.p9050); | ||
3969 | if (cinfo->irq | ||
3970 | #ifndef CONFIG_CYZ_INTR | ||
3971 | && !cy_is_Z(cinfo) | ||
3972 | #endif /* CONFIG_CYZ_INTR */ | ||
3973 | ) | ||
3974 | free_irq(cinfo->irq, cinfo); | ||
3975 | pci_release_regions(pdev); | ||
3976 | |||
3977 | cinfo->base_addr = NULL; | ||
3978 | for (i = cinfo->first_line; i < cinfo->first_line + | ||
3979 | cinfo->nports; i++) | ||
3980 | tty_unregister_device(cy_serial_driver, i); | ||
3981 | cinfo->nports = 0; | ||
3982 | kfree(cinfo->ports); | ||
3983 | } | ||
3984 | |||
3985 | static struct pci_driver cy_pci_driver = { | ||
3986 | .name = "cyclades", | ||
3987 | .id_table = cy_pci_dev_id, | ||
3988 | .probe = cy_pci_probe, | ||
3989 | .remove = __devexit_p(cy_pci_remove) | ||
3990 | }; | ||
3991 | #endif | ||
3992 | |||
3993 | static int cyclades_proc_show(struct seq_file *m, void *v) | ||
3994 | { | ||
3995 | struct cyclades_port *info; | ||
3996 | unsigned int i, j; | ||
3997 | __u32 cur_jifs = jiffies; | ||
3998 | |||
3999 | seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn " | ||
4000 | "IdleIn Overruns Ldisc\n"); | ||
4001 | |||
4002 | /* Output one line for each known port */ | ||
4003 | for (i = 0; i < NR_CARDS; i++) | ||
4004 | for (j = 0; j < cy_card[i].nports; j++) { | ||
4005 | info = &cy_card[i].ports[j]; | ||
4006 | |||
4007 | if (info->port.count) { | ||
4008 | /* XXX is the ldisc num worth this? */ | ||
4009 | struct tty_struct *tty; | ||
4010 | struct tty_ldisc *ld; | ||
4011 | int num = 0; | ||
4012 | tty = tty_port_tty_get(&info->port); | ||
4013 | if (tty) { | ||
4014 | ld = tty_ldisc_ref(tty); | ||
4015 | if (ld) { | ||
4016 | num = ld->ops->num; | ||
4017 | tty_ldisc_deref(ld); | ||
4018 | } | ||
4019 | tty_kref_put(tty); | ||
4020 | } | ||
4021 | seq_printf(m, "%3d %8lu %10lu %8lu " | ||
4022 | "%10lu %8lu %9lu %6d\n", info->line, | ||
4023 | (cur_jifs - info->idle_stats.in_use) / | ||
4024 | HZ, info->idle_stats.xmit_bytes, | ||
4025 | (cur_jifs - info->idle_stats.xmit_idle)/ | ||
4026 | HZ, info->idle_stats.recv_bytes, | ||
4027 | (cur_jifs - info->idle_stats.recv_idle)/ | ||
4028 | HZ, info->idle_stats.overruns, | ||
4029 | num); | ||
4030 | } else | ||
4031 | seq_printf(m, "%3d %8lu %10lu %8lu " | ||
4032 | "%10lu %8lu %9lu %6ld\n", | ||
4033 | info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); | ||
4034 | } | ||
4035 | return 0; | ||
4036 | } | ||
4037 | |||
4038 | static int cyclades_proc_open(struct inode *inode, struct file *file) | ||
4039 | { | ||
4040 | return single_open(file, cyclades_proc_show, NULL); | ||
4041 | } | ||
4042 | |||
4043 | static const struct file_operations cyclades_proc_fops = { | ||
4044 | .owner = THIS_MODULE, | ||
4045 | .open = cyclades_proc_open, | ||
4046 | .read = seq_read, | ||
4047 | .llseek = seq_lseek, | ||
4048 | .release = single_release, | ||
4049 | }; | ||
4050 | |||
4051 | /* The serial driver boot-time initialization code! | ||
4052 | Hardware I/O ports are mapped to character special devices on a | ||
4053 | first found, first allocated manner. That is, this code searches | ||
4054 | for Cyclom cards in the system. As each is found, it is probed | ||
4055 | to discover how many chips (and thus how many ports) are present. | ||
4056 | These ports are mapped to the tty ports 32 and upward in monotonic | ||
4057 | fashion. If an 8-port card is replaced with a 16-port card, the | ||
4058 | port mapping on a following card will shift. | ||
4059 | |||
4060 | This approach is different from what is used in the other serial | ||
4061 | device driver because the Cyclom is more properly a multiplexer, | ||
4062 | not just an aggregation of serial ports on one card. | ||
4063 | |||
4064 | If there are more cards with more ports than have been | ||
4065 | statically allocated above, a warning is printed and the | ||
4066 | extra ports are ignored. | ||
4067 | */ | ||
4068 | |||
4069 | static const struct tty_operations cy_ops = { | ||
4070 | .open = cy_open, | ||
4071 | .close = cy_close, | ||
4072 | .write = cy_write, | ||
4073 | .put_char = cy_put_char, | ||
4074 | .flush_chars = cy_flush_chars, | ||
4075 | .write_room = cy_write_room, | ||
4076 | .chars_in_buffer = cy_chars_in_buffer, | ||
4077 | .flush_buffer = cy_flush_buffer, | ||
4078 | .ioctl = cy_ioctl, | ||
4079 | .throttle = cy_throttle, | ||
4080 | .unthrottle = cy_unthrottle, | ||
4081 | .set_termios = cy_set_termios, | ||
4082 | .stop = cy_stop, | ||
4083 | .start = cy_start, | ||
4084 | .hangup = cy_hangup, | ||
4085 | .break_ctl = cy_break, | ||
4086 | .wait_until_sent = cy_wait_until_sent, | ||
4087 | .tiocmget = cy_tiocmget, | ||
4088 | .tiocmset = cy_tiocmset, | ||
4089 | .get_icount = cy_get_icount, | ||
4090 | .proc_fops = &cyclades_proc_fops, | ||
4091 | }; | ||
4092 | |||
4093 | static int __init cy_init(void) | ||
4094 | { | ||
4095 | unsigned int nboards; | ||
4096 | int retval = -ENOMEM; | ||
4097 | |||
4098 | cy_serial_driver = alloc_tty_driver(NR_PORTS); | ||
4099 | if (!cy_serial_driver) | ||
4100 | goto err; | ||
4101 | |||
4102 | printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n", | ||
4103 | __DATE__, __TIME__); | ||
4104 | |||
4105 | /* Initialize the tty_driver structure */ | ||
4106 | |||
4107 | cy_serial_driver->owner = THIS_MODULE; | ||
4108 | cy_serial_driver->driver_name = "cyclades"; | ||
4109 | cy_serial_driver->name = "ttyC"; | ||
4110 | cy_serial_driver->major = CYCLADES_MAJOR; | ||
4111 | cy_serial_driver->minor_start = 0; | ||
4112 | cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
4113 | cy_serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
4114 | cy_serial_driver->init_termios = tty_std_termios; | ||
4115 | cy_serial_driver->init_termios.c_cflag = | ||
4116 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
4117 | cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
4118 | tty_set_operations(cy_serial_driver, &cy_ops); | ||
4119 | |||
4120 | retval = tty_register_driver(cy_serial_driver); | ||
4121 | if (retval) { | ||
4122 | printk(KERN_ERR "Couldn't register Cyclades serial driver\n"); | ||
4123 | goto err_frtty; | ||
4124 | } | ||
4125 | |||
4126 | /* the code below is responsible to find the boards. Each different | ||
4127 | type of board has its own detection routine. If a board is found, | ||
4128 | the next cy_card structure available is set by the detection | ||
4129 | routine. These functions are responsible for checking the | ||
4130 | availability of cy_card and cy_port data structures and updating | ||
4131 | the cy_next_channel. */ | ||
4132 | |||
4133 | /* look for isa boards */ | ||
4134 | nboards = cy_detect_isa(); | ||
4135 | |||
4136 | #ifdef CONFIG_PCI | ||
4137 | /* look for pci boards */ | ||
4138 | retval = pci_register_driver(&cy_pci_driver); | ||
4139 | if (retval && !nboards) { | ||
4140 | tty_unregister_driver(cy_serial_driver); | ||
4141 | goto err_frtty; | ||
4142 | } | ||
4143 | #endif | ||
4144 | |||
4145 | return 0; | ||
4146 | err_frtty: | ||
4147 | put_tty_driver(cy_serial_driver); | ||
4148 | err: | ||
4149 | return retval; | ||
4150 | } /* cy_init */ | ||
4151 | |||
4152 | static void __exit cy_cleanup_module(void) | ||
4153 | { | ||
4154 | struct cyclades_card *card; | ||
4155 | unsigned int i, e1; | ||
4156 | |||
4157 | #ifndef CONFIG_CYZ_INTR | ||
4158 | del_timer_sync(&cyz_timerlist); | ||
4159 | #endif /* CONFIG_CYZ_INTR */ | ||
4160 | |||
4161 | e1 = tty_unregister_driver(cy_serial_driver); | ||
4162 | if (e1) | ||
4163 | printk(KERN_ERR "failed to unregister Cyclades serial " | ||
4164 | "driver(%d)\n", e1); | ||
4165 | |||
4166 | #ifdef CONFIG_PCI | ||
4167 | pci_unregister_driver(&cy_pci_driver); | ||
4168 | #endif | ||
4169 | |||
4170 | for (i = 0; i < NR_CARDS; i++) { | ||
4171 | card = &cy_card[i]; | ||
4172 | if (card->base_addr) { | ||
4173 | /* clear interrupt */ | ||
4174 | cy_writeb(card->base_addr + Cy_ClrIntr, 0); | ||
4175 | iounmap(card->base_addr); | ||
4176 | if (card->ctl_addr.p9050) | ||
4177 | iounmap(card->ctl_addr.p9050); | ||
4178 | if (card->irq | ||
4179 | #ifndef CONFIG_CYZ_INTR | ||
4180 | && !cy_is_Z(card) | ||
4181 | #endif /* CONFIG_CYZ_INTR */ | ||
4182 | ) | ||
4183 | free_irq(card->irq, card); | ||
4184 | for (e1 = card->first_line; e1 < card->first_line + | ||
4185 | card->nports; e1++) | ||
4186 | tty_unregister_device(cy_serial_driver, e1); | ||
4187 | kfree(card->ports); | ||
4188 | } | ||
4189 | } | ||
4190 | |||
4191 | put_tty_driver(cy_serial_driver); | ||
4192 | } /* cy_cleanup_module */ | ||
4193 | |||
4194 | module_init(cy_init); | ||
4195 | module_exit(cy_cleanup_module); | ||
4196 | |||
4197 | MODULE_LICENSE("GPL"); | ||
4198 | MODULE_VERSION(CY_VERSION); | ||
4199 | MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR); | ||
4200 | MODULE_FIRMWARE("cyzfirm.bin"); | ||
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig new file mode 100644 index 000000000000..6f2c9809f1fb --- /dev/null +++ b/drivers/tty/hvc/Kconfig | |||
@@ -0,0 +1,105 @@ | |||
1 | config HVC_DRIVER | ||
2 | bool | ||
3 | help | ||
4 | Generic "hypervisor virtual console" infrastructure for various | ||
5 | hypervisors (pSeries, iSeries, Xen, lguest). | ||
6 | It will automatically be selected if one of the back-end console drivers | ||
7 | is selected. | ||
8 | |||
9 | config HVC_IRQ | ||
10 | bool | ||
11 | |||
12 | config HVC_CONSOLE | ||
13 | bool "pSeries Hypervisor Virtual Console support" | ||
14 | depends on PPC_PSERIES | ||
15 | select HVC_DRIVER | ||
16 | select HVC_IRQ | ||
17 | help | ||
18 | pSeries machines when partitioned support a hypervisor virtual | ||
19 | console. This driver allows each pSeries partition to have a console | ||
20 | which is accessed via the HMC. | ||
21 | |||
22 | config HVC_ISERIES | ||
23 | bool "iSeries Hypervisor Virtual Console support" | ||
24 | depends on PPC_ISERIES | ||
25 | default y | ||
26 | select HVC_DRIVER | ||
27 | select HVC_IRQ | ||
28 | select VIOPATH | ||
29 | help | ||
30 | iSeries machines support a hypervisor virtual console. | ||
31 | |||
32 | config HVC_RTAS | ||
33 | bool "IBM RTAS Console support" | ||
34 | depends on PPC_RTAS | ||
35 | select HVC_DRIVER | ||
36 | help | ||
37 | IBM Console device driver which makes use of RTAS | ||
38 | |||
39 | config HVC_BEAT | ||
40 | bool "Toshiba's Beat Hypervisor Console support" | ||
41 | depends on PPC_CELLEB | ||
42 | select HVC_DRIVER | ||
43 | help | ||
44 | Toshiba's Cell Reference Set Beat Console device driver | ||
45 | |||
46 | config HVC_IUCV | ||
47 | bool "z/VM IUCV Hypervisor console support (VM only)" | ||
48 | depends on S390 | ||
49 | select HVC_DRIVER | ||
50 | select IUCV | ||
51 | default y | ||
52 | help | ||
53 | This driver provides a Hypervisor console (HVC) back-end to access | ||
54 | a Linux (console) terminal via a z/VM IUCV communication path. | ||
55 | |||
56 | config HVC_XEN | ||
57 | bool "Xen Hypervisor Console support" | ||
58 | depends on XEN | ||
59 | select HVC_DRIVER | ||
60 | select HVC_IRQ | ||
61 | default y | ||
62 | help | ||
63 | Xen virtual console device driver | ||
64 | |||
65 | config HVC_UDBG | ||
66 | bool "udbg based fake hypervisor console" | ||
67 | depends on PPC && EXPERIMENTAL | ||
68 | select HVC_DRIVER | ||
69 | default n | ||
70 | |||
71 | config HVC_DCC | ||
72 | bool "ARM JTAG DCC console" | ||
73 | depends on ARM | ||
74 | select HVC_DRIVER | ||
75 | help | ||
76 | This console uses the JTAG DCC on ARM to create a console under the HVC | ||
77 | driver. This console is used through a JTAG only on ARM. If you don't have | ||
78 | a JTAG then you probably don't want this option. | ||
79 | |||
80 | config HVC_BFIN_JTAG | ||
81 | bool "Blackfin JTAG console" | ||
82 | depends on BLACKFIN | ||
83 | select HVC_DRIVER | ||
84 | help | ||
85 | This console uses the Blackfin JTAG to create a console under the | ||
86 | the HVC driver. If you don't have JTAG, then you probably don't | ||
87 | want this option. | ||
88 | |||
89 | config HVCS | ||
90 | tristate "IBM Hypervisor Virtual Console Server support" | ||
91 | depends on PPC_PSERIES && HVC_CONSOLE | ||
92 | help | ||
93 | Partitionable IBM Power5 ppc64 machines allow hosting of | ||
94 | firmware virtual consoles from one Linux partition by | ||
95 | another Linux partition. This driver allows console data | ||
96 | from Linux partitions to be accessed through TTY device | ||
97 | interfaces in the device tree of a Linux partition running | ||
98 | this driver. | ||
99 | |||
100 | To compile this driver as a module, choose M here: the | ||
101 | module will be called hvcs. Additionally, this module | ||
102 | will depend on arch specific APIs exported from hvcserver.ko | ||
103 | which will also be compiled when this driver is built as a | ||
104 | module. | ||
105 | |||
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index d79e7e9bf9d2..40a25d93fe52 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile | |||
@@ -9,4 +9,5 @@ obj-$(CONFIG_HVC_IRQ) += hvc_irq.o | |||
9 | obj-$(CONFIG_HVC_XEN) += hvc_xen.o | 9 | obj-$(CONFIG_HVC_XEN) += hvc_xen.o |
10 | obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o | 10 | obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o |
11 | obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o | 11 | obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o |
12 | obj-$(CONFIG_HVC_BFIN_JTAG) += hvc_bfin_jtag.o | ||
12 | obj-$(CONFIG_HVCS) += hvcs.o | 13 | obj-$(CONFIG_HVCS) += hvcs.o |
diff --git a/drivers/tty/hvc/hvc_bfin_jtag.c b/drivers/tty/hvc/hvc_bfin_jtag.c new file mode 100644 index 000000000000..31d6cc6a77af --- /dev/null +++ b/drivers/tty/hvc/hvc_bfin_jtag.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Console via Blackfin JTAG Communication | ||
3 | * | ||
4 | * Copyright 2008-2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Enter bugs at http://blackfin.uclinux.org/ | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/console.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/types.h> | ||
17 | |||
18 | #include "hvc_console.h" | ||
19 | |||
20 | /* See the Debug/Emulation chapter in the HRM */ | ||
21 | #define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */ | ||
22 | #define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */ | ||
23 | #define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */ | ||
24 | #define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */ | ||
25 | |||
26 | /* Helper functions to glue the register API to simple C operations */ | ||
27 | static inline uint32_t bfin_write_emudat(uint32_t emudat) | ||
28 | { | ||
29 | __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); | ||
30 | return emudat; | ||
31 | } | ||
32 | |||
33 | static inline uint32_t bfin_read_emudat(void) | ||
34 | { | ||
35 | uint32_t emudat; | ||
36 | __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); | ||
37 | return emudat; | ||
38 | } | ||
39 | |||
40 | /* Send data to the host */ | ||
41 | static int hvc_bfin_put_chars(uint32_t vt, const char *buf, int count) | ||
42 | { | ||
43 | static uint32_t outbound_len; | ||
44 | uint32_t emudat; | ||
45 | int ret; | ||
46 | |||
47 | if (bfin_read_DBGSTAT() & EMUDOF) | ||
48 | return 0; | ||
49 | |||
50 | if (!outbound_len) { | ||
51 | outbound_len = count; | ||
52 | bfin_write_emudat(outbound_len); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | ret = min(outbound_len, (uint32_t)4); | ||
57 | memcpy(&emudat, buf, ret); | ||
58 | bfin_write_emudat(emudat); | ||
59 | outbound_len -= ret; | ||
60 | |||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | /* Receive data from the host */ | ||
65 | static int hvc_bfin_get_chars(uint32_t vt, char *buf, int count) | ||
66 | { | ||
67 | static uint32_t inbound_len; | ||
68 | uint32_t emudat; | ||
69 | int ret; | ||
70 | |||
71 | if (!(bfin_read_DBGSTAT() & EMUDIF)) | ||
72 | return 0; | ||
73 | emudat = bfin_read_emudat(); | ||
74 | |||
75 | if (!inbound_len) { | ||
76 | inbound_len = emudat; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | ret = min(inbound_len, (uint32_t)4); | ||
81 | memcpy(buf, &emudat, ret); | ||
82 | inbound_len -= ret; | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /* Glue the HVC layers to the Blackfin layers */ | ||
88 | static const struct hv_ops hvc_bfin_get_put_ops = { | ||
89 | .get_chars = hvc_bfin_get_chars, | ||
90 | .put_chars = hvc_bfin_put_chars, | ||
91 | }; | ||
92 | |||
93 | static int __init hvc_bfin_console_init(void) | ||
94 | { | ||
95 | hvc_instantiate(0, 0, &hvc_bfin_get_put_ops); | ||
96 | return 0; | ||
97 | } | ||
98 | console_initcall(hvc_bfin_console_init); | ||
99 | |||
100 | static int __init hvc_bfin_init(void) | ||
101 | { | ||
102 | hvc_alloc(0, 0, &hvc_bfin_get_put_ops, 128); | ||
103 | return 0; | ||
104 | } | ||
105 | device_initcall(hvc_bfin_init); | ||
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 6470f63deb4b..435f6facbc23 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c | |||
@@ -33,54 +33,29 @@ | |||
33 | static inline u32 __dcc_getstatus(void) | 33 | static inline u32 __dcc_getstatus(void) |
34 | { | 34 | { |
35 | u32 __ret; | 35 | u32 __ret; |
36 | 36 | asm volatile("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg" | |
37 | asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg" | ||
38 | : "=r" (__ret) : : "cc"); | 37 | : "=r" (__ret) : : "cc"); |
39 | 38 | ||
40 | return __ret; | 39 | return __ret; |
41 | } | 40 | } |
42 | 41 | ||
43 | 42 | ||
44 | #if defined(CONFIG_CPU_V7) | ||
45 | static inline char __dcc_getchar(void) | 43 | static inline char __dcc_getchar(void) |
46 | { | 44 | { |
47 | char __c; | 45 | char __c; |
48 | 46 | ||
49 | asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\ | 47 | asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" |
50 | bne get_wait \n\ | ||
51 | mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" | ||
52 | : "=r" (__c) : : "cc"); | ||
53 | |||
54 | return __c; | ||
55 | } | ||
56 | #else | ||
57 | static inline char __dcc_getchar(void) | ||
58 | { | ||
59 | char __c; | ||
60 | |||
61 | asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" | ||
62 | : "=r" (__c)); | 48 | : "=r" (__c)); |
63 | 49 | ||
64 | return __c; | 50 | return __c; |
65 | } | 51 | } |
66 | #endif | ||
67 | 52 | ||
68 | #if defined(CONFIG_CPU_V7) | ||
69 | static inline void __dcc_putchar(char c) | ||
70 | { | ||
71 | asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\ | ||
72 | bcs put_wait \n\ | ||
73 | mcr p14, 0, %0, c0, c5, 0 " | ||
74 | : : "r" (c) : "cc"); | ||
75 | } | ||
76 | #else | ||
77 | static inline void __dcc_putchar(char c) | 53 | static inline void __dcc_putchar(char c) |
78 | { | 54 | { |
79 | asm("mcr p14, 0, %0, c0, c5, 0 @ write a char" | 55 | asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char" |
80 | : /* no output register */ | 56 | : /* no output register */ |
81 | : "r" (c)); | 57 | : "r" (c)); |
82 | } | 58 | } |
83 | #endif | ||
84 | 59 | ||
85 | static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) | 60 | static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) |
86 | { | 61 | { |
@@ -90,7 +65,7 @@ static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) | |||
90 | while (__dcc_getstatus() & DCC_STATUS_TX) | 65 | while (__dcc_getstatus() & DCC_STATUS_TX) |
91 | cpu_relax(); | 66 | cpu_relax(); |
92 | 67 | ||
93 | __dcc_putchar((char)(buf[i] & 0xFF)); | 68 | __dcc_putchar(buf[i]); |
94 | } | 69 | } |
95 | 70 | ||
96 | return count; | 71 | return count; |
@@ -100,15 +75,11 @@ static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) | |||
100 | { | 75 | { |
101 | int i; | 76 | int i; |
102 | 77 | ||
103 | for (i = 0; i < count; ++i) { | 78 | for (i = 0; i < count; ++i) |
104 | int c = -1; | ||
105 | |||
106 | if (__dcc_getstatus() & DCC_STATUS_RX) | 79 | if (__dcc_getstatus() & DCC_STATUS_RX) |
107 | c = __dcc_getchar(); | 80 | buf[i] = __dcc_getchar(); |
108 | if (c < 0) | 81 | else |
109 | break; | 82 | break; |
110 | buf[i] = c; | ||
111 | } | ||
112 | 83 | ||
113 | return i; | 84 | return i; |
114 | } | 85 | } |
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 67a75a502c01..8a8d6373f164 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c | |||
@@ -1095,7 +1095,7 @@ static void hvsi_unthrottle(struct tty_struct *tty) | |||
1095 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); | 1095 | h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) | 1098 | static int hvsi_tiocmget(struct tty_struct *tty) |
1099 | { | 1099 | { |
1100 | struct hvsi_struct *hp = tty->driver_data; | 1100 | struct hvsi_struct *hp = tty->driver_data; |
1101 | 1101 | ||
@@ -1103,8 +1103,8 @@ static int hvsi_tiocmget(struct tty_struct *tty, struct file *file) | |||
1103 | return hp->mctrl; | 1103 | return hp->mctrl; |
1104 | } | 1104 | } |
1105 | 1105 | ||
1106 | static int hvsi_tiocmset(struct tty_struct *tty, struct file *file, | 1106 | static int hvsi_tiocmset(struct tty_struct *tty, |
1107 | unsigned int set, unsigned int clear) | 1107 | unsigned int set, unsigned int clear) |
1108 | { | 1108 | { |
1109 | struct hvsi_struct *hp = tty->driver_data; | 1109 | struct hvsi_struct *hp = tty->driver_data; |
1110 | unsigned long flags; | 1110 | unsigned long flags; |
diff --git a/drivers/tty/ipwireless/Makefile b/drivers/tty/ipwireless/Makefile new file mode 100644 index 000000000000..db80873d7f20 --- /dev/null +++ b/drivers/tty/ipwireless/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # drivers/char/pcmcia/ipwireless/Makefile | ||
3 | # | ||
4 | # Makefile for the IPWireless driver | ||
5 | # | ||
6 | |||
7 | obj-$(CONFIG_IPWIRELESS) += ipwireless.o | ||
8 | |||
9 | ipwireless-y := hardware.o main.o network.o tty.o | ||
10 | |||
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c new file mode 100644 index 000000000000..0aeb5a38d296 --- /dev/null +++ b/drivers/tty/ipwireless/hardware.c | |||
@@ -0,0 +1,1764 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include "hardware.h" | ||
26 | #include "setup_protocol.h" | ||
27 | #include "network.h" | ||
28 | #include "main.h" | ||
29 | |||
30 | static void ipw_send_setup_packet(struct ipw_hardware *hw); | ||
31 | static void handle_received_SETUP_packet(struct ipw_hardware *ipw, | ||
32 | unsigned int address, | ||
33 | const unsigned char *data, int len, | ||
34 | int is_last); | ||
35 | static void ipwireless_setup_timer(unsigned long data); | ||
36 | static void handle_received_CTRL_packet(struct ipw_hardware *hw, | ||
37 | unsigned int channel_idx, const unsigned char *data, int len); | ||
38 | |||
39 | /*#define TIMING_DIAGNOSTICS*/ | ||
40 | |||
41 | #ifdef TIMING_DIAGNOSTICS | ||
42 | |||
43 | static struct timing_stats { | ||
44 | unsigned long last_report_time; | ||
45 | unsigned long read_time; | ||
46 | unsigned long write_time; | ||
47 | unsigned long read_bytes; | ||
48 | unsigned long write_bytes; | ||
49 | unsigned long start_time; | ||
50 | }; | ||
51 | |||
52 | static void start_timing(void) | ||
53 | { | ||
54 | timing_stats.start_time = jiffies; | ||
55 | } | ||
56 | |||
57 | static void end_read_timing(unsigned length) | ||
58 | { | ||
59 | timing_stats.read_time += (jiffies - start_time); | ||
60 | timing_stats.read_bytes += length + 2; | ||
61 | report_timing(); | ||
62 | } | ||
63 | |||
64 | static void end_write_timing(unsigned length) | ||
65 | { | ||
66 | timing_stats.write_time += (jiffies - start_time); | ||
67 | timing_stats.write_bytes += length + 2; | ||
68 | report_timing(); | ||
69 | } | ||
70 | |||
71 | static void report_timing(void) | ||
72 | { | ||
73 | unsigned long since = jiffies - timing_stats.last_report_time; | ||
74 | |||
75 | /* If it's been more than one second... */ | ||
76 | if (since >= HZ) { | ||
77 | int first = (timing_stats.last_report_time == 0); | ||
78 | |||
79 | timing_stats.last_report_time = jiffies; | ||
80 | if (!first) | ||
81 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
82 | ": %u us elapsed - read %lu bytes in %u us, wrote %lu bytes in %u us\n", | ||
83 | jiffies_to_usecs(since), | ||
84 | timing_stats.read_bytes, | ||
85 | jiffies_to_usecs(timing_stats.read_time), | ||
86 | timing_stats.write_bytes, | ||
87 | jiffies_to_usecs(timing_stats.write_time)); | ||
88 | |||
89 | timing_stats.read_time = 0; | ||
90 | timing_stats.write_time = 0; | ||
91 | timing_stats.read_bytes = 0; | ||
92 | timing_stats.write_bytes = 0; | ||
93 | } | ||
94 | } | ||
95 | #else | ||
96 | static void start_timing(void) { } | ||
97 | static void end_read_timing(unsigned length) { } | ||
98 | static void end_write_timing(unsigned length) { } | ||
99 | #endif | ||
100 | |||
101 | /* Imported IPW definitions */ | ||
102 | |||
103 | #define LL_MTU_V1 318 | ||
104 | #define LL_MTU_V2 250 | ||
105 | #define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2) | ||
106 | |||
107 | #define PRIO_DATA 2 | ||
108 | #define PRIO_CTRL 1 | ||
109 | #define PRIO_SETUP 0 | ||
110 | |||
111 | /* Addresses */ | ||
112 | #define ADDR_SETUP_PROT 0 | ||
113 | |||
114 | /* Protocol ids */ | ||
115 | enum { | ||
116 | /* Identifier for the Com Data protocol */ | ||
117 | TL_PROTOCOLID_COM_DATA = 0, | ||
118 | |||
119 | /* Identifier for the Com Control protocol */ | ||
120 | TL_PROTOCOLID_COM_CTRL = 1, | ||
121 | |||
122 | /* Identifier for the Setup protocol */ | ||
123 | TL_PROTOCOLID_SETUP = 2 | ||
124 | }; | ||
125 | |||
126 | /* Number of bytes in NL packet header (cannot do | ||
127 | * sizeof(nl_packet_header) since it's a bitfield) */ | ||
128 | #define NL_FIRST_PACKET_HEADER_SIZE 3 | ||
129 | |||
130 | /* Number of bytes in NL packet header (cannot do | ||
131 | * sizeof(nl_packet_header) since it's a bitfield) */ | ||
132 | #define NL_FOLLOWING_PACKET_HEADER_SIZE 1 | ||
133 | |||
134 | struct nl_first_packet_header { | ||
135 | unsigned char protocol:3; | ||
136 | unsigned char address:3; | ||
137 | unsigned char packet_rank:2; | ||
138 | unsigned char length_lsb; | ||
139 | unsigned char length_msb; | ||
140 | }; | ||
141 | |||
142 | struct nl_packet_header { | ||
143 | unsigned char protocol:3; | ||
144 | unsigned char address:3; | ||
145 | unsigned char packet_rank:2; | ||
146 | }; | ||
147 | |||
148 | /* Value of 'packet_rank' above */ | ||
149 | #define NL_INTERMEDIATE_PACKET 0x0 | ||
150 | #define NL_LAST_PACKET 0x1 | ||
151 | #define NL_FIRST_PACKET 0x2 | ||
152 | |||
153 | union nl_packet { | ||
154 | /* Network packet header of the first packet (a special case) */ | ||
155 | struct nl_first_packet_header hdr_first; | ||
156 | /* Network packet header of the following packets (if any) */ | ||
157 | struct nl_packet_header hdr; | ||
158 | /* Complete network packet (header + data) */ | ||
159 | unsigned char rawpkt[LL_MTU_MAX]; | ||
160 | } __attribute__ ((__packed__)); | ||
161 | |||
162 | #define HW_VERSION_UNKNOWN -1 | ||
163 | #define HW_VERSION_1 1 | ||
164 | #define HW_VERSION_2 2 | ||
165 | |||
166 | /* IPW I/O ports */ | ||
167 | #define IOIER 0x00 /* Interrupt Enable Register */ | ||
168 | #define IOIR 0x02 /* Interrupt Source/ACK register */ | ||
169 | #define IODCR 0x04 /* Data Control Register */ | ||
170 | #define IODRR 0x06 /* Data Read Register */ | ||
171 | #define IODWR 0x08 /* Data Write Register */ | ||
172 | #define IOESR 0x0A /* Embedded Driver Status Register */ | ||
173 | #define IORXR 0x0C /* Rx Fifo Register (Host to Embedded) */ | ||
174 | #define IOTXR 0x0E /* Tx Fifo Register (Embedded to Host) */ | ||
175 | |||
176 | /* I/O ports and bit definitions for version 1 of the hardware */ | ||
177 | |||
178 | /* IER bits*/ | ||
179 | #define IER_RXENABLED 0x1 | ||
180 | #define IER_TXENABLED 0x2 | ||
181 | |||
182 | /* ISR bits */ | ||
183 | #define IR_RXINTR 0x1 | ||
184 | #define IR_TXINTR 0x2 | ||
185 | |||
186 | /* DCR bits */ | ||
187 | #define DCR_RXDONE 0x1 | ||
188 | #define DCR_TXDONE 0x2 | ||
189 | #define DCR_RXRESET 0x4 | ||
190 | #define DCR_TXRESET 0x8 | ||
191 | |||
192 | /* I/O ports and bit definitions for version 2 of the hardware */ | ||
193 | |||
194 | struct MEMCCR { | ||
195 | unsigned short reg_config_option; /* PCCOR: Configuration Option Register */ | ||
196 | unsigned short reg_config_and_status; /* PCCSR: Configuration and Status Register */ | ||
197 | unsigned short reg_pin_replacement; /* PCPRR: Pin Replacemant Register */ | ||
198 | unsigned short reg_socket_and_copy; /* PCSCR: Socket and Copy Register */ | ||
199 | unsigned short reg_ext_status; /* PCESR: Extendend Status Register */ | ||
200 | unsigned short reg_io_base; /* PCIOB: I/O Base Register */ | ||
201 | }; | ||
202 | |||
203 | struct MEMINFREG { | ||
204 | unsigned short memreg_tx_old; /* TX Register (R/W) */ | ||
205 | unsigned short pad1; | ||
206 | unsigned short memreg_rx_done; /* RXDone Register (R/W) */ | ||
207 | unsigned short pad2; | ||
208 | unsigned short memreg_rx; /* RX Register (R/W) */ | ||
209 | unsigned short pad3; | ||
210 | unsigned short memreg_pc_interrupt_ack; /* PC intr Ack Register (W) */ | ||
211 | unsigned short pad4; | ||
212 | unsigned long memreg_card_present;/* Mask for Host to check (R) for | ||
213 | * CARD_PRESENT_VALUE */ | ||
214 | unsigned short memreg_tx_new; /* TX2 (new) Register (R/W) */ | ||
215 | }; | ||
216 | |||
217 | #define CARD_PRESENT_VALUE (0xBEEFCAFEUL) | ||
218 | |||
219 | #define MEMTX_TX 0x0001 | ||
220 | #define MEMRX_RX 0x0001 | ||
221 | #define MEMRX_RX_DONE 0x0001 | ||
222 | #define MEMRX_PCINTACKK 0x0001 | ||
223 | |||
224 | #define NL_NUM_OF_PRIORITIES 3 | ||
225 | #define NL_NUM_OF_PROTOCOLS 3 | ||
226 | #define NL_NUM_OF_ADDRESSES NO_OF_IPW_CHANNELS | ||
227 | |||
228 | struct ipw_hardware { | ||
229 | unsigned int base_port; | ||
230 | short hw_version; | ||
231 | unsigned short ll_mtu; | ||
232 | spinlock_t lock; | ||
233 | |||
234 | int initializing; | ||
235 | int init_loops; | ||
236 | struct timer_list setup_timer; | ||
237 | |||
238 | /* Flag if hw is ready to send next packet */ | ||
239 | int tx_ready; | ||
240 | /* Count of pending packets to be sent */ | ||
241 | int tx_queued; | ||
242 | struct list_head tx_queue[NL_NUM_OF_PRIORITIES]; | ||
243 | |||
244 | int rx_bytes_queued; | ||
245 | struct list_head rx_queue; | ||
246 | /* Pool of rx_packet structures that are not currently used. */ | ||
247 | struct list_head rx_pool; | ||
248 | int rx_pool_size; | ||
249 | /* True if reception of data is blocked while userspace processes it. */ | ||
250 | int blocking_rx; | ||
251 | /* True if there is RX data ready on the hardware. */ | ||
252 | int rx_ready; | ||
253 | unsigned short last_memtx_serial; | ||
254 | /* | ||
255 | * Newer versions of the V2 card firmware send serial numbers in the | ||
256 | * MemTX register. 'serial_number_detected' is set true when we detect | ||
257 | * a non-zero serial number (indicating the new firmware). Thereafter, | ||
258 | * the driver can safely ignore the Timer Recovery re-sends to avoid | ||
259 | * out-of-sync problems. | ||
260 | */ | ||
261 | int serial_number_detected; | ||
262 | struct work_struct work_rx; | ||
263 | |||
264 | /* True if we are to send the set-up data to the hardware. */ | ||
265 | int to_setup; | ||
266 | |||
267 | /* Card has been removed */ | ||
268 | int removed; | ||
269 | /* Saved irq value when we disable the interrupt. */ | ||
270 | int irq; | ||
271 | /* True if this driver is shutting down. */ | ||
272 | int shutting_down; | ||
273 | /* Modem control lines */ | ||
274 | unsigned int control_lines[NL_NUM_OF_ADDRESSES]; | ||
275 | struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES]; | ||
276 | |||
277 | struct tasklet_struct tasklet; | ||
278 | |||
279 | /* The handle for the network layer, for the sending of events to it. */ | ||
280 | struct ipw_network *network; | ||
281 | struct MEMINFREG __iomem *memory_info_regs; | ||
282 | struct MEMCCR __iomem *memregs_CCR; | ||
283 | void (*reboot_callback) (void *data); | ||
284 | void *reboot_callback_data; | ||
285 | |||
286 | unsigned short __iomem *memreg_tx; | ||
287 | }; | ||
288 | |||
289 | /* | ||
290 | * Packet info structure for tx packets. | ||
291 | * Note: not all the fields defined here are required for all protocols | ||
292 | */ | ||
293 | struct ipw_tx_packet { | ||
294 | struct list_head queue; | ||
295 | /* channel idx + 1 */ | ||
296 | unsigned char dest_addr; | ||
297 | /* SETUP, CTRL or DATA */ | ||
298 | unsigned char protocol; | ||
299 | /* Length of data block, which starts at the end of this structure */ | ||
300 | unsigned short length; | ||
301 | /* Sending state */ | ||
302 | /* Offset of where we've sent up to so far */ | ||
303 | unsigned long offset; | ||
304 | /* Count of packet fragments, starting at 0 */ | ||
305 | int fragment_count; | ||
306 | |||
307 | /* Called after packet is sent and before is freed */ | ||
308 | void (*packet_callback) (void *cb_data, unsigned int packet_length); | ||
309 | void *callback_data; | ||
310 | }; | ||
311 | |||
312 | /* Signals from DTE */ | ||
313 | #define COMCTRL_RTS 0 | ||
314 | #define COMCTRL_DTR 1 | ||
315 | |||
316 | /* Signals from DCE */ | ||
317 | #define COMCTRL_CTS 2 | ||
318 | #define COMCTRL_DCD 3 | ||
319 | #define COMCTRL_DSR 4 | ||
320 | #define COMCTRL_RI 5 | ||
321 | |||
322 | struct ipw_control_packet_body { | ||
323 | /* DTE signal or DCE signal */ | ||
324 | unsigned char sig_no; | ||
325 | /* 0: set signal, 1: clear signal */ | ||
326 | unsigned char value; | ||
327 | } __attribute__ ((__packed__)); | ||
328 | |||
329 | struct ipw_control_packet { | ||
330 | struct ipw_tx_packet header; | ||
331 | struct ipw_control_packet_body body; | ||
332 | }; | ||
333 | |||
334 | struct ipw_rx_packet { | ||
335 | struct list_head queue; | ||
336 | unsigned int capacity; | ||
337 | unsigned int length; | ||
338 | unsigned int protocol; | ||
339 | unsigned int channel_idx; | ||
340 | }; | ||
341 | |||
342 | static char *data_type(const unsigned char *buf, unsigned length) | ||
343 | { | ||
344 | struct nl_packet_header *hdr = (struct nl_packet_header *) buf; | ||
345 | |||
346 | if (length == 0) | ||
347 | return " "; | ||
348 | |||
349 | if (hdr->packet_rank & NL_FIRST_PACKET) { | ||
350 | switch (hdr->protocol) { | ||
351 | case TL_PROTOCOLID_COM_DATA: return "DATA "; | ||
352 | case TL_PROTOCOLID_COM_CTRL: return "CTRL "; | ||
353 | case TL_PROTOCOLID_SETUP: return "SETUP"; | ||
354 | default: return "???? "; | ||
355 | } | ||
356 | } else | ||
357 | return " "; | ||
358 | } | ||
359 | |||
360 | #define DUMP_MAX_BYTES 64 | ||
361 | |||
362 | static void dump_data_bytes(const char *type, const unsigned char *data, | ||
363 | unsigned length) | ||
364 | { | ||
365 | char prefix[56]; | ||
366 | |||
367 | sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ", | ||
368 | type, data_type(data, length)); | ||
369 | print_hex_dump_bytes(prefix, 0, (void *)data, | ||
370 | length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES); | ||
371 | } | ||
372 | |||
373 | static void swap_packet_bitfield_to_le(unsigned char *data) | ||
374 | { | ||
375 | #ifdef __BIG_ENDIAN_BITFIELD | ||
376 | unsigned char tmp = *data, ret = 0; | ||
377 | |||
378 | /* | ||
379 | * transform bits from aa.bbb.ccc to ccc.bbb.aa | ||
380 | */ | ||
381 | ret |= tmp & 0xc0 >> 6; | ||
382 | ret |= tmp & 0x38 >> 1; | ||
383 | ret |= tmp & 0x07 << 5; | ||
384 | *data = ret & 0xff; | ||
385 | #endif | ||
386 | } | ||
387 | |||
388 | static void swap_packet_bitfield_from_le(unsigned char *data) | ||
389 | { | ||
390 | #ifdef __BIG_ENDIAN_BITFIELD | ||
391 | unsigned char tmp = *data, ret = 0; | ||
392 | |||
393 | /* | ||
394 | * transform bits from ccc.bbb.aa to aa.bbb.ccc | ||
395 | */ | ||
396 | ret |= tmp & 0xe0 >> 5; | ||
397 | ret |= tmp & 0x1c << 1; | ||
398 | ret |= tmp & 0x03 << 6; | ||
399 | *data = ret & 0xff; | ||
400 | #endif | ||
401 | } | ||
402 | |||
403 | static void do_send_fragment(struct ipw_hardware *hw, unsigned char *data, | ||
404 | unsigned length) | ||
405 | { | ||
406 | unsigned i; | ||
407 | unsigned long flags; | ||
408 | |||
409 | start_timing(); | ||
410 | BUG_ON(length > hw->ll_mtu); | ||
411 | |||
412 | if (ipwireless_debug) | ||
413 | dump_data_bytes("send", data, length); | ||
414 | |||
415 | spin_lock_irqsave(&hw->lock, flags); | ||
416 | |||
417 | hw->tx_ready = 0; | ||
418 | swap_packet_bitfield_to_le(data); | ||
419 | |||
420 | if (hw->hw_version == HW_VERSION_1) { | ||
421 | outw((unsigned short) length, hw->base_port + IODWR); | ||
422 | |||
423 | for (i = 0; i < length; i += 2) { | ||
424 | unsigned short d = data[i]; | ||
425 | __le16 raw_data; | ||
426 | |||
427 | if (i + 1 < length) | ||
428 | d |= data[i + 1] << 8; | ||
429 | raw_data = cpu_to_le16(d); | ||
430 | outw(raw_data, hw->base_port + IODWR); | ||
431 | } | ||
432 | |||
433 | outw(DCR_TXDONE, hw->base_port + IODCR); | ||
434 | } else if (hw->hw_version == HW_VERSION_2) { | ||
435 | outw((unsigned short) length, hw->base_port); | ||
436 | |||
437 | for (i = 0; i < length; i += 2) { | ||
438 | unsigned short d = data[i]; | ||
439 | __le16 raw_data; | ||
440 | |||
441 | if (i + 1 < length) | ||
442 | d |= data[i + 1] << 8; | ||
443 | raw_data = cpu_to_le16(d); | ||
444 | outw(raw_data, hw->base_port); | ||
445 | } | ||
446 | while ((i & 3) != 2) { | ||
447 | outw((unsigned short) 0xDEAD, hw->base_port); | ||
448 | i += 2; | ||
449 | } | ||
450 | writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx); | ||
451 | } | ||
452 | |||
453 | spin_unlock_irqrestore(&hw->lock, flags); | ||
454 | |||
455 | end_write_timing(length); | ||
456 | } | ||
457 | |||
458 | static void do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet) | ||
459 | { | ||
460 | unsigned short fragment_data_len; | ||
461 | unsigned short data_left = packet->length - packet->offset; | ||
462 | unsigned short header_size; | ||
463 | union nl_packet pkt; | ||
464 | |||
465 | header_size = | ||
466 | (packet->fragment_count == 0) | ||
467 | ? NL_FIRST_PACKET_HEADER_SIZE | ||
468 | : NL_FOLLOWING_PACKET_HEADER_SIZE; | ||
469 | fragment_data_len = hw->ll_mtu - header_size; | ||
470 | if (data_left < fragment_data_len) | ||
471 | fragment_data_len = data_left; | ||
472 | |||
473 | /* | ||
474 | * hdr_first is now in machine bitfield order, which will be swapped | ||
475 | * to le just before it goes to hw | ||
476 | */ | ||
477 | pkt.hdr_first.protocol = packet->protocol; | ||
478 | pkt.hdr_first.address = packet->dest_addr; | ||
479 | pkt.hdr_first.packet_rank = 0; | ||
480 | |||
481 | /* First packet? */ | ||
482 | if (packet->fragment_count == 0) { | ||
483 | pkt.hdr_first.packet_rank |= NL_FIRST_PACKET; | ||
484 | pkt.hdr_first.length_lsb = (unsigned char) packet->length; | ||
485 | pkt.hdr_first.length_msb = | ||
486 | (unsigned char) (packet->length >> 8); | ||
487 | } | ||
488 | |||
489 | memcpy(pkt.rawpkt + header_size, | ||
490 | ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) + | ||
491 | packet->offset, fragment_data_len); | ||
492 | packet->offset += fragment_data_len; | ||
493 | packet->fragment_count++; | ||
494 | |||
495 | /* Last packet? (May also be first packet.) */ | ||
496 | if (packet->offset == packet->length) | ||
497 | pkt.hdr_first.packet_rank |= NL_LAST_PACKET; | ||
498 | do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len); | ||
499 | |||
500 | /* If this packet has unsent data, then re-queue it. */ | ||
501 | if (packet->offset < packet->length) { | ||
502 | /* | ||
503 | * Re-queue it at the head of the highest priority queue so | ||
504 | * it goes before all other packets | ||
505 | */ | ||
506 | unsigned long flags; | ||
507 | |||
508 | spin_lock_irqsave(&hw->lock, flags); | ||
509 | list_add(&packet->queue, &hw->tx_queue[0]); | ||
510 | hw->tx_queued++; | ||
511 | spin_unlock_irqrestore(&hw->lock, flags); | ||
512 | } else { | ||
513 | if (packet->packet_callback) | ||
514 | packet->packet_callback(packet->callback_data, | ||
515 | packet->length); | ||
516 | kfree(packet); | ||
517 | } | ||
518 | } | ||
519 | |||
520 | static void ipw_setup_hardware(struct ipw_hardware *hw) | ||
521 | { | ||
522 | unsigned long flags; | ||
523 | |||
524 | spin_lock_irqsave(&hw->lock, flags); | ||
525 | if (hw->hw_version == HW_VERSION_1) { | ||
526 | /* Reset RX FIFO */ | ||
527 | outw(DCR_RXRESET, hw->base_port + IODCR); | ||
528 | /* SB: Reset TX FIFO */ | ||
529 | outw(DCR_TXRESET, hw->base_port + IODCR); | ||
530 | |||
531 | /* Enable TX and RX interrupts. */ | ||
532 | outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER); | ||
533 | } else { | ||
534 | /* | ||
535 | * Set INTRACK bit (bit 0), which means we must explicitly | ||
536 | * acknowledge interrupts by clearing bit 2 of reg_config_and_status. | ||
537 | */ | ||
538 | unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); | ||
539 | |||
540 | csr |= 1; | ||
541 | writew(csr, &hw->memregs_CCR->reg_config_and_status); | ||
542 | } | ||
543 | spin_unlock_irqrestore(&hw->lock, flags); | ||
544 | } | ||
545 | |||
546 | /* | ||
547 | * If 'packet' is NULL, then this function allocates a new packet, setting its | ||
548 | * length to 0 and ensuring it has the specified minimum amount of free space. | ||
549 | * | ||
550 | * If 'packet' is not NULL, then this function enlarges it if it doesn't | ||
551 | * have the specified minimum amount of free space. | ||
552 | * | ||
553 | */ | ||
554 | static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw, | ||
555 | struct ipw_rx_packet *packet, | ||
556 | int minimum_free_space) | ||
557 | { | ||
558 | |||
559 | if (!packet) { | ||
560 | unsigned long flags; | ||
561 | |||
562 | spin_lock_irqsave(&hw->lock, flags); | ||
563 | if (!list_empty(&hw->rx_pool)) { | ||
564 | packet = list_first_entry(&hw->rx_pool, | ||
565 | struct ipw_rx_packet, queue); | ||
566 | hw->rx_pool_size--; | ||
567 | spin_unlock_irqrestore(&hw->lock, flags); | ||
568 | list_del(&packet->queue); | ||
569 | } else { | ||
570 | const int min_capacity = | ||
571 | ipwireless_ppp_mru(hw->network) + 2; | ||
572 | int new_capacity; | ||
573 | |||
574 | spin_unlock_irqrestore(&hw->lock, flags); | ||
575 | new_capacity = | ||
576 | (minimum_free_space > min_capacity | ||
577 | ? minimum_free_space | ||
578 | : min_capacity); | ||
579 | packet = kmalloc(sizeof(struct ipw_rx_packet) | ||
580 | + new_capacity, GFP_ATOMIC); | ||
581 | if (!packet) | ||
582 | return NULL; | ||
583 | packet->capacity = new_capacity; | ||
584 | } | ||
585 | packet->length = 0; | ||
586 | } | ||
587 | |||
588 | if (packet->length + minimum_free_space > packet->capacity) { | ||
589 | struct ipw_rx_packet *old_packet = packet; | ||
590 | |||
591 | packet = kmalloc(sizeof(struct ipw_rx_packet) + | ||
592 | old_packet->length + minimum_free_space, | ||
593 | GFP_ATOMIC); | ||
594 | if (!packet) { | ||
595 | kfree(old_packet); | ||
596 | return NULL; | ||
597 | } | ||
598 | memcpy(packet, old_packet, | ||
599 | sizeof(struct ipw_rx_packet) | ||
600 | + old_packet->length); | ||
601 | packet->capacity = old_packet->length + minimum_free_space; | ||
602 | kfree(old_packet); | ||
603 | } | ||
604 | |||
605 | return packet; | ||
606 | } | ||
607 | |||
608 | static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet) | ||
609 | { | ||
610 | if (hw->rx_pool_size > 6) | ||
611 | kfree(packet); | ||
612 | else { | ||
613 | hw->rx_pool_size++; | ||
614 | list_add(&packet->queue, &hw->rx_pool); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | static void queue_received_packet(struct ipw_hardware *hw, | ||
619 | unsigned int protocol, | ||
620 | unsigned int address, | ||
621 | const unsigned char *data, int length, | ||
622 | int is_last) | ||
623 | { | ||
624 | unsigned int channel_idx = address - 1; | ||
625 | struct ipw_rx_packet *packet = NULL; | ||
626 | unsigned long flags; | ||
627 | |||
628 | /* Discard packet if channel index is out of range. */ | ||
629 | if (channel_idx >= NL_NUM_OF_ADDRESSES) { | ||
630 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
631 | ": data packet has bad address %u\n", address); | ||
632 | return; | ||
633 | } | ||
634 | |||
635 | /* | ||
636 | * ->packet_assembler is safe to touch unlocked, this is the only place | ||
637 | */ | ||
638 | if (protocol == TL_PROTOCOLID_COM_DATA) { | ||
639 | struct ipw_rx_packet **assem = | ||
640 | &hw->packet_assembler[channel_idx]; | ||
641 | |||
642 | /* | ||
643 | * Create a new packet, or assembler already contains one | ||
644 | * enlarge it by 'length' bytes. | ||
645 | */ | ||
646 | (*assem) = pool_allocate(hw, *assem, length); | ||
647 | if (!(*assem)) { | ||
648 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
649 | ": no memory for incomming data packet, dropped!\n"); | ||
650 | return; | ||
651 | } | ||
652 | (*assem)->protocol = protocol; | ||
653 | (*assem)->channel_idx = channel_idx; | ||
654 | |||
655 | /* Append this packet data onto existing data. */ | ||
656 | memcpy((unsigned char *)(*assem) + | ||
657 | sizeof(struct ipw_rx_packet) | ||
658 | + (*assem)->length, data, length); | ||
659 | (*assem)->length += length; | ||
660 | if (is_last) { | ||
661 | packet = *assem; | ||
662 | *assem = NULL; | ||
663 | /* Count queued DATA bytes only */ | ||
664 | spin_lock_irqsave(&hw->lock, flags); | ||
665 | hw->rx_bytes_queued += packet->length; | ||
666 | spin_unlock_irqrestore(&hw->lock, flags); | ||
667 | } | ||
668 | } else { | ||
669 | /* If it's a CTRL packet, don't assemble, just queue it. */ | ||
670 | packet = pool_allocate(hw, NULL, length); | ||
671 | if (!packet) { | ||
672 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
673 | ": no memory for incomming ctrl packet, dropped!\n"); | ||
674 | return; | ||
675 | } | ||
676 | packet->protocol = protocol; | ||
677 | packet->channel_idx = channel_idx; | ||
678 | memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet), | ||
679 | data, length); | ||
680 | packet->length = length; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * If this is the last packet, then send the assembled packet on to the | ||
685 | * network layer. | ||
686 | */ | ||
687 | if (packet) { | ||
688 | spin_lock_irqsave(&hw->lock, flags); | ||
689 | list_add_tail(&packet->queue, &hw->rx_queue); | ||
690 | /* Block reception of incoming packets if queue is full. */ | ||
691 | hw->blocking_rx = | ||
692 | (hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE); | ||
693 | |||
694 | spin_unlock_irqrestore(&hw->lock, flags); | ||
695 | schedule_work(&hw->work_rx); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | /* | ||
700 | * Workqueue callback | ||
701 | */ | ||
702 | static void ipw_receive_data_work(struct work_struct *work_rx) | ||
703 | { | ||
704 | struct ipw_hardware *hw = | ||
705 | container_of(work_rx, struct ipw_hardware, work_rx); | ||
706 | unsigned long flags; | ||
707 | |||
708 | spin_lock_irqsave(&hw->lock, flags); | ||
709 | while (!list_empty(&hw->rx_queue)) { | ||
710 | struct ipw_rx_packet *packet = | ||
711 | list_first_entry(&hw->rx_queue, | ||
712 | struct ipw_rx_packet, queue); | ||
713 | |||
714 | if (hw->shutting_down) | ||
715 | break; | ||
716 | list_del(&packet->queue); | ||
717 | |||
718 | /* | ||
719 | * Note: ipwireless_network_packet_received must be called in a | ||
720 | * process context (i.e. via schedule_work) because the tty | ||
721 | * output code can sleep in the tty_flip_buffer_push call. | ||
722 | */ | ||
723 | if (packet->protocol == TL_PROTOCOLID_COM_DATA) { | ||
724 | if (hw->network != NULL) { | ||
725 | /* If the network hasn't been disconnected. */ | ||
726 | spin_unlock_irqrestore(&hw->lock, flags); | ||
727 | /* | ||
728 | * This must run unlocked due to tty processing | ||
729 | * and mutex locking | ||
730 | */ | ||
731 | ipwireless_network_packet_received( | ||
732 | hw->network, | ||
733 | packet->channel_idx, | ||
734 | (unsigned char *)packet | ||
735 | + sizeof(struct ipw_rx_packet), | ||
736 | packet->length); | ||
737 | spin_lock_irqsave(&hw->lock, flags); | ||
738 | } | ||
739 | /* Count queued DATA bytes only */ | ||
740 | hw->rx_bytes_queued -= packet->length; | ||
741 | } else { | ||
742 | /* | ||
743 | * This is safe to be called locked, callchain does | ||
744 | * not block | ||
745 | */ | ||
746 | handle_received_CTRL_packet(hw, packet->channel_idx, | ||
747 | (unsigned char *)packet | ||
748 | + sizeof(struct ipw_rx_packet), | ||
749 | packet->length); | ||
750 | } | ||
751 | pool_free(hw, packet); | ||
752 | /* | ||
753 | * Unblock reception of incoming packets if queue is no longer | ||
754 | * full. | ||
755 | */ | ||
756 | hw->blocking_rx = | ||
757 | hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE; | ||
758 | if (hw->shutting_down) | ||
759 | break; | ||
760 | } | ||
761 | spin_unlock_irqrestore(&hw->lock, flags); | ||
762 | } | ||
763 | |||
764 | static void handle_received_CTRL_packet(struct ipw_hardware *hw, | ||
765 | unsigned int channel_idx, | ||
766 | const unsigned char *data, int len) | ||
767 | { | ||
768 | const struct ipw_control_packet_body *body = | ||
769 | (const struct ipw_control_packet_body *) data; | ||
770 | unsigned int changed_mask; | ||
771 | |||
772 | if (len != sizeof(struct ipw_control_packet_body)) { | ||
773 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
774 | ": control packet was %d bytes - wrong size!\n", | ||
775 | len); | ||
776 | return; | ||
777 | } | ||
778 | |||
779 | switch (body->sig_no) { | ||
780 | case COMCTRL_CTS: | ||
781 | changed_mask = IPW_CONTROL_LINE_CTS; | ||
782 | break; | ||
783 | case COMCTRL_DCD: | ||
784 | changed_mask = IPW_CONTROL_LINE_DCD; | ||
785 | break; | ||
786 | case COMCTRL_DSR: | ||
787 | changed_mask = IPW_CONTROL_LINE_DSR; | ||
788 | break; | ||
789 | case COMCTRL_RI: | ||
790 | changed_mask = IPW_CONTROL_LINE_RI; | ||
791 | break; | ||
792 | default: | ||
793 | changed_mask = 0; | ||
794 | } | ||
795 | |||
796 | if (changed_mask != 0) { | ||
797 | if (body->value) | ||
798 | hw->control_lines[channel_idx] |= changed_mask; | ||
799 | else | ||
800 | hw->control_lines[channel_idx] &= ~changed_mask; | ||
801 | if (hw->network) | ||
802 | ipwireless_network_notify_control_line_change( | ||
803 | hw->network, | ||
804 | channel_idx, | ||
805 | hw->control_lines[channel_idx], | ||
806 | changed_mask); | ||
807 | } | ||
808 | } | ||
809 | |||
810 | static void handle_received_packet(struct ipw_hardware *hw, | ||
811 | const union nl_packet *packet, | ||
812 | unsigned short len) | ||
813 | { | ||
814 | unsigned int protocol = packet->hdr.protocol; | ||
815 | unsigned int address = packet->hdr.address; | ||
816 | unsigned int header_length; | ||
817 | const unsigned char *data; | ||
818 | unsigned int data_len; | ||
819 | int is_last = packet->hdr.packet_rank & NL_LAST_PACKET; | ||
820 | |||
821 | if (packet->hdr.packet_rank & NL_FIRST_PACKET) | ||
822 | header_length = NL_FIRST_PACKET_HEADER_SIZE; | ||
823 | else | ||
824 | header_length = NL_FOLLOWING_PACKET_HEADER_SIZE; | ||
825 | |||
826 | data = packet->rawpkt + header_length; | ||
827 | data_len = len - header_length; | ||
828 | switch (protocol) { | ||
829 | case TL_PROTOCOLID_COM_DATA: | ||
830 | case TL_PROTOCOLID_COM_CTRL: | ||
831 | queue_received_packet(hw, protocol, address, data, data_len, | ||
832 | is_last); | ||
833 | break; | ||
834 | case TL_PROTOCOLID_SETUP: | ||
835 | handle_received_SETUP_packet(hw, address, data, data_len, | ||
836 | is_last); | ||
837 | break; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static void acknowledge_data_read(struct ipw_hardware *hw) | ||
842 | { | ||
843 | if (hw->hw_version == HW_VERSION_1) | ||
844 | outw(DCR_RXDONE, hw->base_port + IODCR); | ||
845 | else | ||
846 | writew(MEMRX_PCINTACKK, | ||
847 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | ||
848 | } | ||
849 | |||
850 | /* | ||
851 | * Retrieve a packet from the IPW hardware. | ||
852 | */ | ||
853 | static void do_receive_packet(struct ipw_hardware *hw) | ||
854 | { | ||
855 | unsigned len; | ||
856 | unsigned i; | ||
857 | unsigned char pkt[LL_MTU_MAX]; | ||
858 | |||
859 | start_timing(); | ||
860 | |||
861 | if (hw->hw_version == HW_VERSION_1) { | ||
862 | len = inw(hw->base_port + IODRR); | ||
863 | if (len > hw->ll_mtu) { | ||
864 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
865 | ": received a packet of %u bytes - longer than the MTU!\n", len); | ||
866 | outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR); | ||
867 | return; | ||
868 | } | ||
869 | |||
870 | for (i = 0; i < len; i += 2) { | ||
871 | __le16 raw_data = inw(hw->base_port + IODRR); | ||
872 | unsigned short data = le16_to_cpu(raw_data); | ||
873 | |||
874 | pkt[i] = (unsigned char) data; | ||
875 | pkt[i + 1] = (unsigned char) (data >> 8); | ||
876 | } | ||
877 | } else { | ||
878 | len = inw(hw->base_port); | ||
879 | if (len > hw->ll_mtu) { | ||
880 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
881 | ": received a packet of %u bytes - longer than the MTU!\n", len); | ||
882 | writew(MEMRX_PCINTACKK, | ||
883 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | for (i = 0; i < len; i += 2) { | ||
888 | __le16 raw_data = inw(hw->base_port); | ||
889 | unsigned short data = le16_to_cpu(raw_data); | ||
890 | |||
891 | pkt[i] = (unsigned char) data; | ||
892 | pkt[i + 1] = (unsigned char) (data >> 8); | ||
893 | } | ||
894 | |||
895 | while ((i & 3) != 2) { | ||
896 | inw(hw->base_port); | ||
897 | i += 2; | ||
898 | } | ||
899 | } | ||
900 | |||
901 | acknowledge_data_read(hw); | ||
902 | |||
903 | swap_packet_bitfield_from_le(pkt); | ||
904 | |||
905 | if (ipwireless_debug) | ||
906 | dump_data_bytes("recv", pkt, len); | ||
907 | |||
908 | handle_received_packet(hw, (union nl_packet *) pkt, len); | ||
909 | |||
910 | end_read_timing(len); | ||
911 | } | ||
912 | |||
913 | static int get_current_packet_priority(struct ipw_hardware *hw) | ||
914 | { | ||
915 | /* | ||
916 | * If we're initializing, don't send anything of higher priority than | ||
917 | * PRIO_SETUP. The network layer therefore need not care about | ||
918 | * hardware initialization - any of its stuff will simply be queued | ||
919 | * until setup is complete. | ||
920 | */ | ||
921 | return (hw->to_setup || hw->initializing | ||
922 | ? PRIO_SETUP + 1 : NL_NUM_OF_PRIORITIES); | ||
923 | } | ||
924 | |||
925 | /* | ||
926 | * return 1 if something has been received from hw | ||
927 | */ | ||
928 | static int get_packets_from_hw(struct ipw_hardware *hw) | ||
929 | { | ||
930 | int received = 0; | ||
931 | unsigned long flags; | ||
932 | |||
933 | spin_lock_irqsave(&hw->lock, flags); | ||
934 | while (hw->rx_ready && !hw->blocking_rx) { | ||
935 | received = 1; | ||
936 | hw->rx_ready--; | ||
937 | spin_unlock_irqrestore(&hw->lock, flags); | ||
938 | |||
939 | do_receive_packet(hw); | ||
940 | |||
941 | spin_lock_irqsave(&hw->lock, flags); | ||
942 | } | ||
943 | spin_unlock_irqrestore(&hw->lock, flags); | ||
944 | |||
945 | return received; | ||
946 | } | ||
947 | |||
948 | /* | ||
949 | * Send pending packet up to given priority, prioritize SETUP data until | ||
950 | * hardware is fully setup. | ||
951 | * | ||
952 | * return 1 if more packets can be sent | ||
953 | */ | ||
954 | static int send_pending_packet(struct ipw_hardware *hw, int priority_limit) | ||
955 | { | ||
956 | int more_to_send = 0; | ||
957 | unsigned long flags; | ||
958 | |||
959 | spin_lock_irqsave(&hw->lock, flags); | ||
960 | if (hw->tx_queued && hw->tx_ready) { | ||
961 | int priority; | ||
962 | struct ipw_tx_packet *packet = NULL; | ||
963 | |||
964 | /* Pick a packet */ | ||
965 | for (priority = 0; priority < priority_limit; priority++) { | ||
966 | if (!list_empty(&hw->tx_queue[priority])) { | ||
967 | packet = list_first_entry( | ||
968 | &hw->tx_queue[priority], | ||
969 | struct ipw_tx_packet, | ||
970 | queue); | ||
971 | |||
972 | hw->tx_queued--; | ||
973 | list_del(&packet->queue); | ||
974 | |||
975 | break; | ||
976 | } | ||
977 | } | ||
978 | if (!packet) { | ||
979 | hw->tx_queued = 0; | ||
980 | spin_unlock_irqrestore(&hw->lock, flags); | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | spin_unlock_irqrestore(&hw->lock, flags); | ||
985 | |||
986 | /* Send */ | ||
987 | do_send_packet(hw, packet); | ||
988 | |||
989 | /* Check if more to send */ | ||
990 | spin_lock_irqsave(&hw->lock, flags); | ||
991 | for (priority = 0; priority < priority_limit; priority++) | ||
992 | if (!list_empty(&hw->tx_queue[priority])) { | ||
993 | more_to_send = 1; | ||
994 | break; | ||
995 | } | ||
996 | |||
997 | if (!more_to_send) | ||
998 | hw->tx_queued = 0; | ||
999 | } | ||
1000 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1001 | |||
1002 | return more_to_send; | ||
1003 | } | ||
1004 | |||
1005 | /* | ||
1006 | * Send and receive all queued packets. | ||
1007 | */ | ||
1008 | static void ipwireless_do_tasklet(unsigned long hw_) | ||
1009 | { | ||
1010 | struct ipw_hardware *hw = (struct ipw_hardware *) hw_; | ||
1011 | unsigned long flags; | ||
1012 | |||
1013 | spin_lock_irqsave(&hw->lock, flags); | ||
1014 | if (hw->shutting_down) { | ||
1015 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1016 | return; | ||
1017 | } | ||
1018 | |||
1019 | if (hw->to_setup == 1) { | ||
1020 | /* | ||
1021 | * Initial setup data sent to hardware | ||
1022 | */ | ||
1023 | hw->to_setup = 2; | ||
1024 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1025 | |||
1026 | ipw_setup_hardware(hw); | ||
1027 | ipw_send_setup_packet(hw); | ||
1028 | |||
1029 | send_pending_packet(hw, PRIO_SETUP + 1); | ||
1030 | get_packets_from_hw(hw); | ||
1031 | } else { | ||
1032 | int priority_limit = get_current_packet_priority(hw); | ||
1033 | int again; | ||
1034 | |||
1035 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1036 | |||
1037 | do { | ||
1038 | again = send_pending_packet(hw, priority_limit); | ||
1039 | again |= get_packets_from_hw(hw); | ||
1040 | } while (again); | ||
1041 | } | ||
1042 | } | ||
1043 | |||
1044 | /* | ||
1045 | * return true if the card is physically present. | ||
1046 | */ | ||
1047 | static int is_card_present(struct ipw_hardware *hw) | ||
1048 | { | ||
1049 | if (hw->hw_version == HW_VERSION_1) | ||
1050 | return inw(hw->base_port + IOIR) != 0xFFFF; | ||
1051 | else | ||
1052 | return readl(&hw->memory_info_regs->memreg_card_present) == | ||
1053 | CARD_PRESENT_VALUE; | ||
1054 | } | ||
1055 | |||
1056 | static irqreturn_t ipwireless_handle_v1_interrupt(int irq, | ||
1057 | struct ipw_hardware *hw) | ||
1058 | { | ||
1059 | unsigned short irqn; | ||
1060 | |||
1061 | irqn = inw(hw->base_port + IOIR); | ||
1062 | |||
1063 | /* Check if card is present */ | ||
1064 | if (irqn == 0xFFFF) | ||
1065 | return IRQ_NONE; | ||
1066 | else if (irqn != 0) { | ||
1067 | unsigned short ack = 0; | ||
1068 | unsigned long flags; | ||
1069 | |||
1070 | /* Transmit complete. */ | ||
1071 | if (irqn & IR_TXINTR) { | ||
1072 | ack |= IR_TXINTR; | ||
1073 | spin_lock_irqsave(&hw->lock, flags); | ||
1074 | hw->tx_ready = 1; | ||
1075 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1076 | } | ||
1077 | /* Received data */ | ||
1078 | if (irqn & IR_RXINTR) { | ||
1079 | ack |= IR_RXINTR; | ||
1080 | spin_lock_irqsave(&hw->lock, flags); | ||
1081 | hw->rx_ready++; | ||
1082 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1083 | } | ||
1084 | if (ack != 0) { | ||
1085 | outw(ack, hw->base_port + IOIR); | ||
1086 | tasklet_schedule(&hw->tasklet); | ||
1087 | } | ||
1088 | return IRQ_HANDLED; | ||
1089 | } | ||
1090 | return IRQ_NONE; | ||
1091 | } | ||
1092 | |||
1093 | static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw) | ||
1094 | { | ||
1095 | unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status); | ||
1096 | |||
1097 | csr &= 0xfffd; | ||
1098 | writew(csr, &hw->memregs_CCR->reg_config_and_status); | ||
1099 | } | ||
1100 | |||
1101 | static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq, | ||
1102 | struct ipw_hardware *hw) | ||
1103 | { | ||
1104 | int tx = 0; | ||
1105 | int rx = 0; | ||
1106 | int rx_repeat = 0; | ||
1107 | int try_mem_tx_old; | ||
1108 | unsigned long flags; | ||
1109 | |||
1110 | do { | ||
1111 | |||
1112 | unsigned short memtx = readw(hw->memreg_tx); | ||
1113 | unsigned short memtx_serial; | ||
1114 | unsigned short memrxdone = | ||
1115 | readw(&hw->memory_info_regs->memreg_rx_done); | ||
1116 | |||
1117 | try_mem_tx_old = 0; | ||
1118 | |||
1119 | /* check whether the interrupt was generated by ipwireless card */ | ||
1120 | if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) { | ||
1121 | |||
1122 | /* check if the card uses memreg_tx_old register */ | ||
1123 | if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | ||
1124 | memtx = readw(&hw->memory_info_regs->memreg_tx_old); | ||
1125 | if (memtx & MEMTX_TX) { | ||
1126 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1127 | ": Using memreg_tx_old\n"); | ||
1128 | hw->memreg_tx = | ||
1129 | &hw->memory_info_regs->memreg_tx_old; | ||
1130 | } else { | ||
1131 | return IRQ_NONE; | ||
1132 | } | ||
1133 | } else | ||
1134 | return IRQ_NONE; | ||
1135 | } | ||
1136 | |||
1137 | /* | ||
1138 | * See if the card is physically present. Note that while it is | ||
1139 | * powering up, it appears not to be present. | ||
1140 | */ | ||
1141 | if (!is_card_present(hw)) { | ||
1142 | acknowledge_pcmcia_interrupt(hw); | ||
1143 | return IRQ_HANDLED; | ||
1144 | } | ||
1145 | |||
1146 | memtx_serial = memtx & (unsigned short) 0xff00; | ||
1147 | if (memtx & MEMTX_TX) { | ||
1148 | writew(memtx_serial, hw->memreg_tx); | ||
1149 | |||
1150 | if (hw->serial_number_detected) { | ||
1151 | if (memtx_serial != hw->last_memtx_serial) { | ||
1152 | hw->last_memtx_serial = memtx_serial; | ||
1153 | spin_lock_irqsave(&hw->lock, flags); | ||
1154 | hw->rx_ready++; | ||
1155 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1156 | rx = 1; | ||
1157 | } else | ||
1158 | /* Ignore 'Timer Recovery' duplicates. */ | ||
1159 | rx_repeat = 1; | ||
1160 | } else { | ||
1161 | /* | ||
1162 | * If a non-zero serial number is seen, then enable | ||
1163 | * serial number checking. | ||
1164 | */ | ||
1165 | if (memtx_serial != 0) { | ||
1166 | hw->serial_number_detected = 1; | ||
1167 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
1168 | ": memreg_tx serial num detected\n"); | ||
1169 | |||
1170 | spin_lock_irqsave(&hw->lock, flags); | ||
1171 | hw->rx_ready++; | ||
1172 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1173 | } | ||
1174 | rx = 1; | ||
1175 | } | ||
1176 | } | ||
1177 | if (memrxdone & MEMRX_RX_DONE) { | ||
1178 | writew(0, &hw->memory_info_regs->memreg_rx_done); | ||
1179 | spin_lock_irqsave(&hw->lock, flags); | ||
1180 | hw->tx_ready = 1; | ||
1181 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1182 | tx = 1; | ||
1183 | } | ||
1184 | if (tx) | ||
1185 | writew(MEMRX_PCINTACKK, | ||
1186 | &hw->memory_info_regs->memreg_pc_interrupt_ack); | ||
1187 | |||
1188 | acknowledge_pcmcia_interrupt(hw); | ||
1189 | |||
1190 | if (tx || rx) | ||
1191 | tasklet_schedule(&hw->tasklet); | ||
1192 | else if (!rx_repeat) { | ||
1193 | if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | ||
1194 | if (hw->serial_number_detected) | ||
1195 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | ||
1196 | ": spurious interrupt - new_tx mode\n"); | ||
1197 | else { | ||
1198 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | ||
1199 | ": no valid memreg_tx value - switching to the old memreg_tx\n"); | ||
1200 | hw->memreg_tx = | ||
1201 | &hw->memory_info_regs->memreg_tx_old; | ||
1202 | try_mem_tx_old = 1; | ||
1203 | } | ||
1204 | } else | ||
1205 | printk(KERN_WARNING IPWIRELESS_PCCARD_NAME | ||
1206 | ": spurious interrupt - old_tx mode\n"); | ||
1207 | } | ||
1208 | |||
1209 | } while (try_mem_tx_old == 1); | ||
1210 | |||
1211 | return IRQ_HANDLED; | ||
1212 | } | ||
1213 | |||
1214 | irqreturn_t ipwireless_interrupt(int irq, void *dev_id) | ||
1215 | { | ||
1216 | struct ipw_dev *ipw = dev_id; | ||
1217 | |||
1218 | if (ipw->hardware->hw_version == HW_VERSION_1) | ||
1219 | return ipwireless_handle_v1_interrupt(irq, ipw->hardware); | ||
1220 | else | ||
1221 | return ipwireless_handle_v2_v3_interrupt(irq, ipw->hardware); | ||
1222 | } | ||
1223 | |||
1224 | static void flush_packets_to_hw(struct ipw_hardware *hw) | ||
1225 | { | ||
1226 | int priority_limit; | ||
1227 | unsigned long flags; | ||
1228 | |||
1229 | spin_lock_irqsave(&hw->lock, flags); | ||
1230 | priority_limit = get_current_packet_priority(hw); | ||
1231 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1232 | |||
1233 | while (send_pending_packet(hw, priority_limit)); | ||
1234 | } | ||
1235 | |||
1236 | static void send_packet(struct ipw_hardware *hw, int priority, | ||
1237 | struct ipw_tx_packet *packet) | ||
1238 | { | ||
1239 | unsigned long flags; | ||
1240 | |||
1241 | spin_lock_irqsave(&hw->lock, flags); | ||
1242 | list_add_tail(&packet->queue, &hw->tx_queue[priority]); | ||
1243 | hw->tx_queued++; | ||
1244 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1245 | |||
1246 | flush_packets_to_hw(hw); | ||
1247 | } | ||
1248 | |||
1249 | /* Create data packet, non-atomic allocation */ | ||
1250 | static void *alloc_data_packet(int data_size, | ||
1251 | unsigned char dest_addr, | ||
1252 | unsigned char protocol) | ||
1253 | { | ||
1254 | struct ipw_tx_packet *packet = kzalloc( | ||
1255 | sizeof(struct ipw_tx_packet) + data_size, | ||
1256 | GFP_ATOMIC); | ||
1257 | |||
1258 | if (!packet) | ||
1259 | return NULL; | ||
1260 | |||
1261 | INIT_LIST_HEAD(&packet->queue); | ||
1262 | packet->dest_addr = dest_addr; | ||
1263 | packet->protocol = protocol; | ||
1264 | packet->length = data_size; | ||
1265 | |||
1266 | return packet; | ||
1267 | } | ||
1268 | |||
1269 | static void *alloc_ctrl_packet(int header_size, | ||
1270 | unsigned char dest_addr, | ||
1271 | unsigned char protocol, | ||
1272 | unsigned char sig_no) | ||
1273 | { | ||
1274 | /* | ||
1275 | * sig_no is located right after ipw_tx_packet struct in every | ||
1276 | * CTRL or SETUP packets, we can use ipw_control_packet as a | ||
1277 | * common struct | ||
1278 | */ | ||
1279 | struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC); | ||
1280 | |||
1281 | if (!packet) | ||
1282 | return NULL; | ||
1283 | |||
1284 | INIT_LIST_HEAD(&packet->header.queue); | ||
1285 | packet->header.dest_addr = dest_addr; | ||
1286 | packet->header.protocol = protocol; | ||
1287 | packet->header.length = header_size - sizeof(struct ipw_tx_packet); | ||
1288 | packet->body.sig_no = sig_no; | ||
1289 | |||
1290 | return packet; | ||
1291 | } | ||
1292 | |||
1293 | int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx, | ||
1294 | const unsigned char *data, unsigned int length, | ||
1295 | void (*callback) (void *cb, unsigned int length), | ||
1296 | void *callback_data) | ||
1297 | { | ||
1298 | struct ipw_tx_packet *packet; | ||
1299 | |||
1300 | packet = alloc_data_packet(length, (channel_idx + 1), | ||
1301 | TL_PROTOCOLID_COM_DATA); | ||
1302 | if (!packet) | ||
1303 | return -ENOMEM; | ||
1304 | packet->packet_callback = callback; | ||
1305 | packet->callback_data = callback_data; | ||
1306 | memcpy((unsigned char *) packet + sizeof(struct ipw_tx_packet), data, | ||
1307 | length); | ||
1308 | |||
1309 | send_packet(hw, PRIO_DATA, packet); | ||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static int set_control_line(struct ipw_hardware *hw, int prio, | ||
1314 | unsigned int channel_idx, int line, int state) | ||
1315 | { | ||
1316 | struct ipw_control_packet *packet; | ||
1317 | int protocolid = TL_PROTOCOLID_COM_CTRL; | ||
1318 | |||
1319 | if (prio == PRIO_SETUP) | ||
1320 | protocolid = TL_PROTOCOLID_SETUP; | ||
1321 | |||
1322 | packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet), | ||
1323 | (channel_idx + 1), protocolid, line); | ||
1324 | if (!packet) | ||
1325 | return -ENOMEM; | ||
1326 | packet->header.length = sizeof(struct ipw_control_packet_body); | ||
1327 | packet->body.value = (state == 0 ? 0 : 1); | ||
1328 | send_packet(hw, prio, &packet->header); | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | |||
1333 | static int set_DTR(struct ipw_hardware *hw, int priority, | ||
1334 | unsigned int channel_idx, int state) | ||
1335 | { | ||
1336 | if (state != 0) | ||
1337 | hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR; | ||
1338 | else | ||
1339 | hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR; | ||
1340 | |||
1341 | return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state); | ||
1342 | } | ||
1343 | |||
1344 | static int set_RTS(struct ipw_hardware *hw, int priority, | ||
1345 | unsigned int channel_idx, int state) | ||
1346 | { | ||
1347 | if (state != 0) | ||
1348 | hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS; | ||
1349 | else | ||
1350 | hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS; | ||
1351 | |||
1352 | return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state); | ||
1353 | } | ||
1354 | |||
1355 | int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, | ||
1356 | int state) | ||
1357 | { | ||
1358 | return set_DTR(hw, PRIO_CTRL, channel_idx, state); | ||
1359 | } | ||
1360 | |||
1361 | int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, | ||
1362 | int state) | ||
1363 | { | ||
1364 | return set_RTS(hw, PRIO_CTRL, channel_idx, state); | ||
1365 | } | ||
1366 | |||
1367 | struct ipw_setup_get_version_query_packet { | ||
1368 | struct ipw_tx_packet header; | ||
1369 | struct tl_setup_get_version_qry body; | ||
1370 | }; | ||
1371 | |||
1372 | struct ipw_setup_config_packet { | ||
1373 | struct ipw_tx_packet header; | ||
1374 | struct tl_setup_config_msg body; | ||
1375 | }; | ||
1376 | |||
1377 | struct ipw_setup_config_done_packet { | ||
1378 | struct ipw_tx_packet header; | ||
1379 | struct tl_setup_config_done_msg body; | ||
1380 | }; | ||
1381 | |||
1382 | struct ipw_setup_open_packet { | ||
1383 | struct ipw_tx_packet header; | ||
1384 | struct tl_setup_open_msg body; | ||
1385 | }; | ||
1386 | |||
1387 | struct ipw_setup_info_packet { | ||
1388 | struct ipw_tx_packet header; | ||
1389 | struct tl_setup_info_msg body; | ||
1390 | }; | ||
1391 | |||
1392 | struct ipw_setup_reboot_msg_ack { | ||
1393 | struct ipw_tx_packet header; | ||
1394 | struct TlSetupRebootMsgAck body; | ||
1395 | }; | ||
1396 | |||
1397 | /* This handles the actual initialization of the card */ | ||
1398 | static void __handle_setup_get_version_rsp(struct ipw_hardware *hw) | ||
1399 | { | ||
1400 | struct ipw_setup_config_packet *config_packet; | ||
1401 | struct ipw_setup_config_done_packet *config_done_packet; | ||
1402 | struct ipw_setup_open_packet *open_packet; | ||
1403 | struct ipw_setup_info_packet *info_packet; | ||
1404 | int port; | ||
1405 | unsigned int channel_idx; | ||
1406 | |||
1407 | /* generate config packet */ | ||
1408 | for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { | ||
1409 | config_packet = alloc_ctrl_packet( | ||
1410 | sizeof(struct ipw_setup_config_packet), | ||
1411 | ADDR_SETUP_PROT, | ||
1412 | TL_PROTOCOLID_SETUP, | ||
1413 | TL_SETUP_SIGNO_CONFIG_MSG); | ||
1414 | if (!config_packet) | ||
1415 | goto exit_nomem; | ||
1416 | config_packet->header.length = sizeof(struct tl_setup_config_msg); | ||
1417 | config_packet->body.port_no = port; | ||
1418 | config_packet->body.prio_data = PRIO_DATA; | ||
1419 | config_packet->body.prio_ctrl = PRIO_CTRL; | ||
1420 | send_packet(hw, PRIO_SETUP, &config_packet->header); | ||
1421 | } | ||
1422 | config_done_packet = alloc_ctrl_packet( | ||
1423 | sizeof(struct ipw_setup_config_done_packet), | ||
1424 | ADDR_SETUP_PROT, | ||
1425 | TL_PROTOCOLID_SETUP, | ||
1426 | TL_SETUP_SIGNO_CONFIG_DONE_MSG); | ||
1427 | if (!config_done_packet) | ||
1428 | goto exit_nomem; | ||
1429 | config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg); | ||
1430 | send_packet(hw, PRIO_SETUP, &config_done_packet->header); | ||
1431 | |||
1432 | /* generate open packet */ | ||
1433 | for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) { | ||
1434 | open_packet = alloc_ctrl_packet( | ||
1435 | sizeof(struct ipw_setup_open_packet), | ||
1436 | ADDR_SETUP_PROT, | ||
1437 | TL_PROTOCOLID_SETUP, | ||
1438 | TL_SETUP_SIGNO_OPEN_MSG); | ||
1439 | if (!open_packet) | ||
1440 | goto exit_nomem; | ||
1441 | open_packet->header.length = sizeof(struct tl_setup_open_msg); | ||
1442 | open_packet->body.port_no = port; | ||
1443 | send_packet(hw, PRIO_SETUP, &open_packet->header); | ||
1444 | } | ||
1445 | for (channel_idx = 0; | ||
1446 | channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) { | ||
1447 | int ret; | ||
1448 | |||
1449 | ret = set_DTR(hw, PRIO_SETUP, channel_idx, | ||
1450 | (hw->control_lines[channel_idx] & | ||
1451 | IPW_CONTROL_LINE_DTR) != 0); | ||
1452 | if (ret) { | ||
1453 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
1454 | ": error setting DTR (%d)\n", ret); | ||
1455 | return; | ||
1456 | } | ||
1457 | |||
1458 | set_RTS(hw, PRIO_SETUP, channel_idx, | ||
1459 | (hw->control_lines [channel_idx] & | ||
1460 | IPW_CONTROL_LINE_RTS) != 0); | ||
1461 | if (ret) { | ||
1462 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
1463 | ": error setting RTS (%d)\n", ret); | ||
1464 | return; | ||
1465 | } | ||
1466 | } | ||
1467 | /* | ||
1468 | * For NDIS we assume that we are using sync PPP frames, for COM async. | ||
1469 | * This driver uses NDIS mode too. We don't bother with translation | ||
1470 | * from async -> sync PPP. | ||
1471 | */ | ||
1472 | info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet), | ||
1473 | ADDR_SETUP_PROT, | ||
1474 | TL_PROTOCOLID_SETUP, | ||
1475 | TL_SETUP_SIGNO_INFO_MSG); | ||
1476 | if (!info_packet) | ||
1477 | goto exit_nomem; | ||
1478 | info_packet->header.length = sizeof(struct tl_setup_info_msg); | ||
1479 | info_packet->body.driver_type = NDISWAN_DRIVER; | ||
1480 | info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION; | ||
1481 | info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION; | ||
1482 | send_packet(hw, PRIO_SETUP, &info_packet->header); | ||
1483 | |||
1484 | /* Initialization is now complete, so we clear the 'to_setup' flag */ | ||
1485 | hw->to_setup = 0; | ||
1486 | |||
1487 | return; | ||
1488 | |||
1489 | exit_nomem: | ||
1490 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
1491 | ": not enough memory to alloc control packet\n"); | ||
1492 | hw->to_setup = -1; | ||
1493 | } | ||
1494 | |||
1495 | static void handle_setup_get_version_rsp(struct ipw_hardware *hw, | ||
1496 | unsigned char vers_no) | ||
1497 | { | ||
1498 | del_timer(&hw->setup_timer); | ||
1499 | hw->initializing = 0; | ||
1500 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n"); | ||
1501 | |||
1502 | if (vers_no == TL_SETUP_VERSION) | ||
1503 | __handle_setup_get_version_rsp(hw); | ||
1504 | else | ||
1505 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
1506 | ": invalid hardware version no %u\n", | ||
1507 | (unsigned int) vers_no); | ||
1508 | } | ||
1509 | |||
1510 | static void ipw_send_setup_packet(struct ipw_hardware *hw) | ||
1511 | { | ||
1512 | struct ipw_setup_get_version_query_packet *ver_packet; | ||
1513 | |||
1514 | ver_packet = alloc_ctrl_packet( | ||
1515 | sizeof(struct ipw_setup_get_version_query_packet), | ||
1516 | ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, | ||
1517 | TL_SETUP_SIGNO_GET_VERSION_QRY); | ||
1518 | ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); | ||
1519 | |||
1520 | /* | ||
1521 | * Response is handled in handle_received_SETUP_packet | ||
1522 | */ | ||
1523 | send_packet(hw, PRIO_SETUP, &ver_packet->header); | ||
1524 | } | ||
1525 | |||
1526 | static void handle_received_SETUP_packet(struct ipw_hardware *hw, | ||
1527 | unsigned int address, | ||
1528 | const unsigned char *data, int len, | ||
1529 | int is_last) | ||
1530 | { | ||
1531 | const union ipw_setup_rx_msg *rx_msg = (const union ipw_setup_rx_msg *) data; | ||
1532 | |||
1533 | if (address != ADDR_SETUP_PROT) { | ||
1534 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1535 | ": setup packet has bad address %d\n", address); | ||
1536 | return; | ||
1537 | } | ||
1538 | |||
1539 | switch (rx_msg->sig_no) { | ||
1540 | case TL_SETUP_SIGNO_GET_VERSION_RSP: | ||
1541 | if (hw->to_setup) | ||
1542 | handle_setup_get_version_rsp(hw, | ||
1543 | rx_msg->version_rsp_msg.version); | ||
1544 | break; | ||
1545 | |||
1546 | case TL_SETUP_SIGNO_OPEN_MSG: | ||
1547 | if (ipwireless_debug) { | ||
1548 | unsigned int channel_idx = rx_msg->open_msg.port_no - 1; | ||
1549 | |||
1550 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1551 | ": OPEN_MSG [channel %u] reply received\n", | ||
1552 | channel_idx); | ||
1553 | } | ||
1554 | break; | ||
1555 | |||
1556 | case TL_SETUP_SIGNO_INFO_MSG_ACK: | ||
1557 | if (ipwireless_debug) | ||
1558 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
1559 | ": card successfully configured as NDISWAN\n"); | ||
1560 | break; | ||
1561 | |||
1562 | case TL_SETUP_SIGNO_REBOOT_MSG: | ||
1563 | if (hw->to_setup) | ||
1564 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
1565 | ": Setup not completed - ignoring reboot msg\n"); | ||
1566 | else { | ||
1567 | struct ipw_setup_reboot_msg_ack *packet; | ||
1568 | |||
1569 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
1570 | ": Acknowledging REBOOT message\n"); | ||
1571 | packet = alloc_ctrl_packet( | ||
1572 | sizeof(struct ipw_setup_reboot_msg_ack), | ||
1573 | ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, | ||
1574 | TL_SETUP_SIGNO_REBOOT_MSG_ACK); | ||
1575 | packet->header.length = | ||
1576 | sizeof(struct TlSetupRebootMsgAck); | ||
1577 | send_packet(hw, PRIO_SETUP, &packet->header); | ||
1578 | if (hw->reboot_callback) | ||
1579 | hw->reboot_callback(hw->reboot_callback_data); | ||
1580 | } | ||
1581 | break; | ||
1582 | |||
1583 | default: | ||
1584 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1585 | ": unknown setup message %u received\n", | ||
1586 | (unsigned int) rx_msg->sig_no); | ||
1587 | } | ||
1588 | } | ||
1589 | |||
1590 | static void do_close_hardware(struct ipw_hardware *hw) | ||
1591 | { | ||
1592 | unsigned int irqn; | ||
1593 | |||
1594 | if (hw->hw_version == HW_VERSION_1) { | ||
1595 | /* Disable TX and RX interrupts. */ | ||
1596 | outw(0, hw->base_port + IOIER); | ||
1597 | |||
1598 | /* Acknowledge any outstanding interrupt requests */ | ||
1599 | irqn = inw(hw->base_port + IOIR); | ||
1600 | if (irqn & IR_TXINTR) | ||
1601 | outw(IR_TXINTR, hw->base_port + IOIR); | ||
1602 | if (irqn & IR_RXINTR) | ||
1603 | outw(IR_RXINTR, hw->base_port + IOIR); | ||
1604 | |||
1605 | synchronize_irq(hw->irq); | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | struct ipw_hardware *ipwireless_hardware_create(void) | ||
1610 | { | ||
1611 | int i; | ||
1612 | struct ipw_hardware *hw = | ||
1613 | kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL); | ||
1614 | |||
1615 | if (!hw) | ||
1616 | return NULL; | ||
1617 | |||
1618 | hw->irq = -1; | ||
1619 | hw->initializing = 1; | ||
1620 | hw->tx_ready = 1; | ||
1621 | hw->rx_bytes_queued = 0; | ||
1622 | hw->rx_pool_size = 0; | ||
1623 | hw->last_memtx_serial = (unsigned short) 0xffff; | ||
1624 | for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) | ||
1625 | INIT_LIST_HEAD(&hw->tx_queue[i]); | ||
1626 | |||
1627 | INIT_LIST_HEAD(&hw->rx_queue); | ||
1628 | INIT_LIST_HEAD(&hw->rx_pool); | ||
1629 | spin_lock_init(&hw->lock); | ||
1630 | tasklet_init(&hw->tasklet, ipwireless_do_tasklet, (unsigned long) hw); | ||
1631 | INIT_WORK(&hw->work_rx, ipw_receive_data_work); | ||
1632 | setup_timer(&hw->setup_timer, ipwireless_setup_timer, | ||
1633 | (unsigned long) hw); | ||
1634 | |||
1635 | return hw; | ||
1636 | } | ||
1637 | |||
1638 | void ipwireless_init_hardware_v1(struct ipw_hardware *hw, | ||
1639 | unsigned int base_port, | ||
1640 | void __iomem *attr_memory, | ||
1641 | void __iomem *common_memory, | ||
1642 | int is_v2_card, | ||
1643 | void (*reboot_callback) (void *data), | ||
1644 | void *reboot_callback_data) | ||
1645 | { | ||
1646 | if (hw->removed) { | ||
1647 | hw->removed = 0; | ||
1648 | enable_irq(hw->irq); | ||
1649 | } | ||
1650 | hw->base_port = base_port; | ||
1651 | hw->hw_version = (is_v2_card ? HW_VERSION_2 : HW_VERSION_1); | ||
1652 | hw->ll_mtu = (hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2); | ||
1653 | hw->memregs_CCR = (struct MEMCCR __iomem *) | ||
1654 | ((unsigned short __iomem *) attr_memory + 0x200); | ||
1655 | hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory; | ||
1656 | hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new; | ||
1657 | hw->reboot_callback = reboot_callback; | ||
1658 | hw->reboot_callback_data = reboot_callback_data; | ||
1659 | } | ||
1660 | |||
1661 | void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw) | ||
1662 | { | ||
1663 | hw->initializing = 1; | ||
1664 | hw->init_loops = 0; | ||
1665 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1666 | ": waiting for card to start up...\n"); | ||
1667 | ipwireless_setup_timer((unsigned long) hw); | ||
1668 | } | ||
1669 | |||
1670 | static void ipwireless_setup_timer(unsigned long data) | ||
1671 | { | ||
1672 | struct ipw_hardware *hw = (struct ipw_hardware *) data; | ||
1673 | |||
1674 | hw->init_loops++; | ||
1675 | |||
1676 | if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY && | ||
1677 | hw->hw_version == HW_VERSION_2 && | ||
1678 | hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) { | ||
1679 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1680 | ": failed to startup using TX2, trying TX\n"); | ||
1681 | |||
1682 | hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old; | ||
1683 | hw->init_loops = 0; | ||
1684 | } | ||
1685 | /* Give up after a certain number of retries */ | ||
1686 | if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) { | ||
1687 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
1688 | ": card failed to start up!\n"); | ||
1689 | hw->initializing = 0; | ||
1690 | } else { | ||
1691 | /* Do not attempt to write to the board if it is not present. */ | ||
1692 | if (is_card_present(hw)) { | ||
1693 | unsigned long flags; | ||
1694 | |||
1695 | spin_lock_irqsave(&hw->lock, flags); | ||
1696 | hw->to_setup = 1; | ||
1697 | hw->tx_ready = 1; | ||
1698 | spin_unlock_irqrestore(&hw->lock, flags); | ||
1699 | tasklet_schedule(&hw->tasklet); | ||
1700 | } | ||
1701 | |||
1702 | mod_timer(&hw->setup_timer, | ||
1703 | jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO)); | ||
1704 | } | ||
1705 | } | ||
1706 | |||
1707 | /* | ||
1708 | * Stop any interrupts from executing so that, once this function returns, | ||
1709 | * other layers of the driver can be sure they won't get any more callbacks. | ||
1710 | * Thus must be called on a proper process context. | ||
1711 | */ | ||
1712 | void ipwireless_stop_interrupts(struct ipw_hardware *hw) | ||
1713 | { | ||
1714 | if (!hw->shutting_down) { | ||
1715 | /* Tell everyone we are going down. */ | ||
1716 | hw->shutting_down = 1; | ||
1717 | del_timer(&hw->setup_timer); | ||
1718 | |||
1719 | /* Prevent the hardware from sending any more interrupts */ | ||
1720 | do_close_hardware(hw); | ||
1721 | } | ||
1722 | } | ||
1723 | |||
1724 | void ipwireless_hardware_free(struct ipw_hardware *hw) | ||
1725 | { | ||
1726 | int i; | ||
1727 | struct ipw_rx_packet *rp, *rq; | ||
1728 | struct ipw_tx_packet *tp, *tq; | ||
1729 | |||
1730 | ipwireless_stop_interrupts(hw); | ||
1731 | |||
1732 | flush_work_sync(&hw->work_rx); | ||
1733 | |||
1734 | for (i = 0; i < NL_NUM_OF_ADDRESSES; i++) | ||
1735 | if (hw->packet_assembler[i] != NULL) | ||
1736 | kfree(hw->packet_assembler[i]); | ||
1737 | |||
1738 | for (i = 0; i < NL_NUM_OF_PRIORITIES; i++) | ||
1739 | list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) { | ||
1740 | list_del(&tp->queue); | ||
1741 | kfree(tp); | ||
1742 | } | ||
1743 | |||
1744 | list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) { | ||
1745 | list_del(&rp->queue); | ||
1746 | kfree(rp); | ||
1747 | } | ||
1748 | |||
1749 | list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) { | ||
1750 | list_del(&rp->queue); | ||
1751 | kfree(rp); | ||
1752 | } | ||
1753 | kfree(hw); | ||
1754 | } | ||
1755 | |||
1756 | /* | ||
1757 | * Associate the specified network with this hardware, so it will receive events | ||
1758 | * from it. | ||
1759 | */ | ||
1760 | void ipwireless_associate_network(struct ipw_hardware *hw, | ||
1761 | struct ipw_network *network) | ||
1762 | { | ||
1763 | hw->network = network; | ||
1764 | } | ||
diff --git a/drivers/tty/ipwireless/hardware.h b/drivers/tty/ipwireless/hardware.h new file mode 100644 index 000000000000..90a8590e43b0 --- /dev/null +++ b/drivers/tty/ipwireless/hardware.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #ifndef _IPWIRELESS_CS_HARDWARE_H_ | ||
19 | #define _IPWIRELESS_CS_HARDWARE_H_ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | |||
25 | #define IPW_CONTROL_LINE_CTS 0x0001 | ||
26 | #define IPW_CONTROL_LINE_DCD 0x0002 | ||
27 | #define IPW_CONTROL_LINE_DSR 0x0004 | ||
28 | #define IPW_CONTROL_LINE_RI 0x0008 | ||
29 | #define IPW_CONTROL_LINE_DTR 0x0010 | ||
30 | #define IPW_CONTROL_LINE_RTS 0x0020 | ||
31 | |||
32 | struct ipw_hardware; | ||
33 | struct ipw_network; | ||
34 | |||
35 | struct ipw_hardware *ipwireless_hardware_create(void); | ||
36 | void ipwireless_hardware_free(struct ipw_hardware *hw); | ||
37 | irqreturn_t ipwireless_interrupt(int irq, void *dev_id); | ||
38 | int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx, | ||
39 | int state); | ||
40 | int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx, | ||
41 | int state); | ||
42 | int ipwireless_send_packet(struct ipw_hardware *hw, | ||
43 | unsigned int channel_idx, | ||
44 | const unsigned char *data, | ||
45 | unsigned int length, | ||
46 | void (*packet_sent_callback) (void *cb, | ||
47 | unsigned int length), | ||
48 | void *sent_cb_data); | ||
49 | void ipwireless_associate_network(struct ipw_hardware *hw, | ||
50 | struct ipw_network *net); | ||
51 | void ipwireless_stop_interrupts(struct ipw_hardware *hw); | ||
52 | void ipwireless_init_hardware_v1(struct ipw_hardware *hw, | ||
53 | unsigned int base_port, | ||
54 | void __iomem *attr_memory, | ||
55 | void __iomem *common_memory, | ||
56 | int is_v2_card, | ||
57 | void (*reboot_cb) (void *data), | ||
58 | void *reboot_cb_data); | ||
59 | void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); | ||
60 | void ipwireless_sleep(unsigned int tenths); | ||
61 | |||
62 | #endif | ||
diff --git a/drivers/tty/ipwireless/main.c b/drivers/tty/ipwireless/main.c new file mode 100644 index 000000000000..444155a305ae --- /dev/null +++ b/drivers/tty/ipwireless/main.c | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #include "hardware.h" | ||
19 | #include "network.h" | ||
20 | #include "main.h" | ||
21 | #include "tty.h" | ||
22 | |||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <pcmcia/cisreg.h> | ||
32 | #include <pcmcia/device_id.h> | ||
33 | #include <pcmcia/ss.h> | ||
34 | #include <pcmcia/ds.h> | ||
35 | |||
36 | static struct pcmcia_device_id ipw_ids[] = { | ||
37 | PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100), | ||
38 | PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200), | ||
39 | PCMCIA_DEVICE_NULL | ||
40 | }; | ||
41 | MODULE_DEVICE_TABLE(pcmcia, ipw_ids); | ||
42 | |||
43 | static void ipwireless_detach(struct pcmcia_device *link); | ||
44 | |||
45 | /* | ||
46 | * Module params | ||
47 | */ | ||
48 | /* Debug mode: more verbose, print sent/recv bytes */ | ||
49 | int ipwireless_debug; | ||
50 | int ipwireless_loopback; | ||
51 | int ipwireless_out_queue = 10; | ||
52 | |||
53 | module_param_named(debug, ipwireless_debug, int, 0); | ||
54 | module_param_named(loopback, ipwireless_loopback, int, 0); | ||
55 | module_param_named(out_queue, ipwireless_out_queue, int, 0); | ||
56 | MODULE_PARM_DESC(debug, "switch on debug messages [0]"); | ||
57 | MODULE_PARM_DESC(loopback, | ||
58 | "debug: enable ras_raw channel [0]"); | ||
59 | MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]"); | ||
60 | |||
61 | /* Executes in process context. */ | ||
62 | static void signalled_reboot_work(struct work_struct *work_reboot) | ||
63 | { | ||
64 | struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev, | ||
65 | work_reboot); | ||
66 | struct pcmcia_device *link = ipw->link; | ||
67 | pcmcia_reset_card(link->socket); | ||
68 | } | ||
69 | |||
70 | static void signalled_reboot_callback(void *callback_data) | ||
71 | { | ||
72 | struct ipw_dev *ipw = (struct ipw_dev *) callback_data; | ||
73 | |||
74 | /* Delegate to process context. */ | ||
75 | schedule_work(&ipw->work_reboot); | ||
76 | } | ||
77 | |||
78 | static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) | ||
79 | { | ||
80 | struct ipw_dev *ipw = priv_data; | ||
81 | int ret; | ||
82 | |||
83 | p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; | ||
84 | p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; | ||
85 | |||
86 | /* 0x40 causes it to generate level mode interrupts. */ | ||
87 | /* 0x04 enables IREQ pin. */ | ||
88 | p_dev->config_index |= 0x44; | ||
89 | p_dev->io_lines = 16; | ||
90 | ret = pcmcia_request_io(p_dev); | ||
91 | if (ret) | ||
92 | return ret; | ||
93 | |||
94 | if (!request_region(p_dev->resource[0]->start, | ||
95 | resource_size(p_dev->resource[0]), | ||
96 | IPWIRELESS_PCCARD_NAME)) { | ||
97 | ret = -EBUSY; | ||
98 | goto exit; | ||
99 | } | ||
100 | |||
101 | p_dev->resource[2]->flags |= | ||
102 | WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; | ||
103 | |||
104 | ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0); | ||
105 | if (ret != 0) | ||
106 | goto exit1; | ||
107 | |||
108 | ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr); | ||
109 | if (ret != 0) | ||
110 | goto exit1; | ||
111 | |||
112 | ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100; | ||
113 | |||
114 | ipw->common_memory = ioremap(p_dev->resource[2]->start, | ||
115 | resource_size(p_dev->resource[2])); | ||
116 | if (!request_mem_region(p_dev->resource[2]->start, | ||
117 | resource_size(p_dev->resource[2]), | ||
118 | IPWIRELESS_PCCARD_NAME)) { | ||
119 | ret = -EBUSY; | ||
120 | goto exit2; | ||
121 | } | ||
122 | |||
123 | p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | | ||
124 | WIN_ENABLE; | ||
125 | p_dev->resource[3]->end = 0; /* this used to be 0x1000 */ | ||
126 | ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0); | ||
127 | if (ret != 0) | ||
128 | goto exit3; | ||
129 | |||
130 | ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0); | ||
131 | if (ret != 0) | ||
132 | goto exit3; | ||
133 | |||
134 | ipw->attr_memory = ioremap(p_dev->resource[3]->start, | ||
135 | resource_size(p_dev->resource[3])); | ||
136 | if (!request_mem_region(p_dev->resource[3]->start, | ||
137 | resource_size(p_dev->resource[3]), | ||
138 | IPWIRELESS_PCCARD_NAME)) { | ||
139 | ret = -EBUSY; | ||
140 | goto exit4; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | |||
145 | exit4: | ||
146 | iounmap(ipw->attr_memory); | ||
147 | exit3: | ||
148 | release_mem_region(p_dev->resource[2]->start, | ||
149 | resource_size(p_dev->resource[2])); | ||
150 | exit2: | ||
151 | iounmap(ipw->common_memory); | ||
152 | exit1: | ||
153 | release_region(p_dev->resource[0]->start, | ||
154 | resource_size(p_dev->resource[0])); | ||
155 | exit: | ||
156 | pcmcia_disable_device(p_dev); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static int config_ipwireless(struct ipw_dev *ipw) | ||
161 | { | ||
162 | struct pcmcia_device *link = ipw->link; | ||
163 | int ret = 0; | ||
164 | |||
165 | ipw->is_v2_card = 0; | ||
166 | link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM | | ||
167 | CONF_ENABLE_IRQ; | ||
168 | |||
169 | ret = pcmcia_loop_config(link, ipwireless_probe, ipw); | ||
170 | if (ret != 0) | ||
171 | return ret; | ||
172 | |||
173 | INIT_WORK(&ipw->work_reboot, signalled_reboot_work); | ||
174 | |||
175 | ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start, | ||
176 | ipw->attr_memory, ipw->common_memory, | ||
177 | ipw->is_v2_card, signalled_reboot_callback, | ||
178 | ipw); | ||
179 | |||
180 | ret = pcmcia_request_irq(link, ipwireless_interrupt); | ||
181 | if (ret != 0) | ||
182 | goto exit; | ||
183 | |||
184 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", | ||
185 | ipw->is_v2_card ? "V2/V3" : "V1"); | ||
186 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
187 | ": I/O ports %pR, irq %d\n", link->resource[0], | ||
188 | (unsigned int) link->irq); | ||
189 | if (ipw->attr_memory && ipw->common_memory) | ||
190 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
191 | ": attr memory %pR, common memory %pR\n", | ||
192 | link->resource[3], | ||
193 | link->resource[2]); | ||
194 | |||
195 | ipw->network = ipwireless_network_create(ipw->hardware); | ||
196 | if (!ipw->network) | ||
197 | goto exit; | ||
198 | |||
199 | ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network); | ||
200 | if (!ipw->tty) | ||
201 | goto exit; | ||
202 | |||
203 | ipwireless_init_hardware_v2_v3(ipw->hardware); | ||
204 | |||
205 | /* | ||
206 | * Do the RequestConfiguration last, because it enables interrupts. | ||
207 | * Then we don't get any interrupts before we're ready for them. | ||
208 | */ | ||
209 | ret = pcmcia_enable_device(link); | ||
210 | if (ret != 0) | ||
211 | goto exit; | ||
212 | |||
213 | return 0; | ||
214 | |||
215 | exit: | ||
216 | if (ipw->common_memory) { | ||
217 | release_mem_region(link->resource[2]->start, | ||
218 | resource_size(link->resource[2])); | ||
219 | iounmap(ipw->common_memory); | ||
220 | } | ||
221 | if (ipw->attr_memory) { | ||
222 | release_mem_region(link->resource[3]->start, | ||
223 | resource_size(link->resource[3])); | ||
224 | iounmap(ipw->attr_memory); | ||
225 | } | ||
226 | pcmcia_disable_device(link); | ||
227 | return -1; | ||
228 | } | ||
229 | |||
230 | static void release_ipwireless(struct ipw_dev *ipw) | ||
231 | { | ||
232 | release_region(ipw->link->resource[0]->start, | ||
233 | resource_size(ipw->link->resource[0])); | ||
234 | if (ipw->common_memory) { | ||
235 | release_mem_region(ipw->link->resource[2]->start, | ||
236 | resource_size(ipw->link->resource[2])); | ||
237 | iounmap(ipw->common_memory); | ||
238 | } | ||
239 | if (ipw->attr_memory) { | ||
240 | release_mem_region(ipw->link->resource[3]->start, | ||
241 | resource_size(ipw->link->resource[3])); | ||
242 | iounmap(ipw->attr_memory); | ||
243 | } | ||
244 | pcmcia_disable_device(ipw->link); | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * ipwireless_attach() creates an "instance" of the driver, allocating | ||
249 | * local data structures for one device (one interface). The device | ||
250 | * is registered with Card Services. | ||
251 | * | ||
252 | * The pcmcia_device structure is initialized, but we don't actually | ||
253 | * configure the card at this point -- we wait until we receive a | ||
254 | * card insertion event. | ||
255 | */ | ||
256 | static int ipwireless_attach(struct pcmcia_device *link) | ||
257 | { | ||
258 | struct ipw_dev *ipw; | ||
259 | int ret; | ||
260 | |||
261 | ipw = kzalloc(sizeof(struct ipw_dev), GFP_KERNEL); | ||
262 | if (!ipw) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | ipw->link = link; | ||
266 | link->priv = ipw; | ||
267 | |||
268 | ipw->hardware = ipwireless_hardware_create(); | ||
269 | if (!ipw->hardware) { | ||
270 | kfree(ipw); | ||
271 | return -ENOMEM; | ||
272 | } | ||
273 | /* RegisterClient will call config_ipwireless */ | ||
274 | |||
275 | ret = config_ipwireless(ipw); | ||
276 | |||
277 | if (ret != 0) { | ||
278 | ipwireless_detach(link); | ||
279 | return ret; | ||
280 | } | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * This deletes a driver "instance". The device is de-registered with | ||
287 | * Card Services. If it has been released, all local data structures | ||
288 | * are freed. Otherwise, the structures will be freed when the device | ||
289 | * is released. | ||
290 | */ | ||
291 | static void ipwireless_detach(struct pcmcia_device *link) | ||
292 | { | ||
293 | struct ipw_dev *ipw = link->priv; | ||
294 | |||
295 | release_ipwireless(ipw); | ||
296 | |||
297 | if (ipw->tty != NULL) | ||
298 | ipwireless_tty_free(ipw->tty); | ||
299 | if (ipw->network != NULL) | ||
300 | ipwireless_network_free(ipw->network); | ||
301 | if (ipw->hardware != NULL) | ||
302 | ipwireless_hardware_free(ipw->hardware); | ||
303 | kfree(ipw); | ||
304 | } | ||
305 | |||
306 | static struct pcmcia_driver me = { | ||
307 | .owner = THIS_MODULE, | ||
308 | .probe = ipwireless_attach, | ||
309 | .remove = ipwireless_detach, | ||
310 | .name = IPWIRELESS_PCCARD_NAME, | ||
311 | .id_table = ipw_ids | ||
312 | }; | ||
313 | |||
314 | /* | ||
315 | * Module insertion : initialisation of the module. | ||
316 | * Register the card with cardmgr... | ||
317 | */ | ||
318 | static int __init init_ipwireless(void) | ||
319 | { | ||
320 | int ret; | ||
321 | |||
322 | ret = ipwireless_tty_init(); | ||
323 | if (ret != 0) | ||
324 | return ret; | ||
325 | |||
326 | ret = pcmcia_register_driver(&me); | ||
327 | if (ret != 0) | ||
328 | ipwireless_tty_release(); | ||
329 | |||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Module removal | ||
335 | */ | ||
336 | static void __exit exit_ipwireless(void) | ||
337 | { | ||
338 | pcmcia_unregister_driver(&me); | ||
339 | ipwireless_tty_release(); | ||
340 | } | ||
341 | |||
342 | module_init(init_ipwireless); | ||
343 | module_exit(exit_ipwireless); | ||
344 | |||
345 | MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR); | ||
346 | MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION); | ||
347 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/tty/ipwireless/main.h b/drivers/tty/ipwireless/main.h new file mode 100644 index 000000000000..f2cbb116bccb --- /dev/null +++ b/drivers/tty/ipwireless/main.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #ifndef _IPWIRELESS_CS_H_ | ||
19 | #define _IPWIRELESS_CS_H_ | ||
20 | |||
21 | #include <linux/sched.h> | ||
22 | #include <linux/types.h> | ||
23 | |||
24 | #include <pcmcia/cistpl.h> | ||
25 | #include <pcmcia/ds.h> | ||
26 | |||
27 | #include "hardware.h" | ||
28 | |||
29 | #define IPWIRELESS_PCCARD_NAME "ipwireless" | ||
30 | #define IPWIRELESS_PCMCIA_VERSION "1.1" | ||
31 | #define IPWIRELESS_PCMCIA_AUTHOR \ | ||
32 | "Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba" | ||
33 | |||
34 | #define IPWIRELESS_TX_QUEUE_SIZE 262144 | ||
35 | #define IPWIRELESS_RX_QUEUE_SIZE 262144 | ||
36 | |||
37 | #define IPWIRELESS_STATE_DEBUG | ||
38 | |||
39 | struct ipw_hardware; | ||
40 | struct ipw_network; | ||
41 | struct ipw_tty; | ||
42 | |||
43 | struct ipw_dev { | ||
44 | struct pcmcia_device *link; | ||
45 | int is_v2_card; | ||
46 | |||
47 | void __iomem *attr_memory; | ||
48 | |||
49 | void __iomem *common_memory; | ||
50 | |||
51 | /* Reference to attribute memory, containing CIS data */ | ||
52 | void *attribute_memory; | ||
53 | |||
54 | /* Hardware context */ | ||
55 | struct ipw_hardware *hardware; | ||
56 | /* Network layer context */ | ||
57 | struct ipw_network *network; | ||
58 | /* TTY device context */ | ||
59 | struct ipw_tty *tty; | ||
60 | struct work_struct work_reboot; | ||
61 | }; | ||
62 | |||
63 | /* Module parametres */ | ||
64 | extern int ipwireless_debug; | ||
65 | extern int ipwireless_loopback; | ||
66 | extern int ipwireless_out_queue; | ||
67 | |||
68 | #endif | ||
diff --git a/drivers/tty/ipwireless/network.c b/drivers/tty/ipwireless/network.c new file mode 100644 index 000000000000..f7daeea598e4 --- /dev/null +++ b/drivers/tty/ipwireless/network.c | |||
@@ -0,0 +1,508 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/netdevice.h> | ||
22 | #include <linux/ppp_channel.h> | ||
23 | #include <linux/ppp_defs.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/if_ppp.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | |||
28 | #include "network.h" | ||
29 | #include "hardware.h" | ||
30 | #include "main.h" | ||
31 | #include "tty.h" | ||
32 | |||
33 | #define MAX_ASSOCIATED_TTYS 2 | ||
34 | |||
35 | #define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) | ||
36 | |||
37 | struct ipw_network { | ||
38 | /* Hardware context, used for calls to hardware layer. */ | ||
39 | struct ipw_hardware *hardware; | ||
40 | /* Context for kernel 'generic_ppp' functionality */ | ||
41 | struct ppp_channel *ppp_channel; | ||
42 | /* tty context connected with IPW console */ | ||
43 | struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS]; | ||
44 | /* True if ppp needs waking up once we're ready to xmit */ | ||
45 | int ppp_blocked; | ||
46 | /* Number of packets queued up in hardware module. */ | ||
47 | int outgoing_packets_queued; | ||
48 | /* Spinlock to avoid interrupts during shutdown */ | ||
49 | spinlock_t lock; | ||
50 | struct mutex close_lock; | ||
51 | |||
52 | /* PPP ioctl data, not actually used anywere */ | ||
53 | unsigned int flags; | ||
54 | unsigned int rbits; | ||
55 | u32 xaccm[8]; | ||
56 | u32 raccm; | ||
57 | int mru; | ||
58 | |||
59 | int shutting_down; | ||
60 | unsigned int ras_control_lines; | ||
61 | |||
62 | struct work_struct work_go_online; | ||
63 | struct work_struct work_go_offline; | ||
64 | }; | ||
65 | |||
66 | static void notify_packet_sent(void *callback_data, unsigned int packet_length) | ||
67 | { | ||
68 | struct ipw_network *network = callback_data; | ||
69 | unsigned long flags; | ||
70 | |||
71 | spin_lock_irqsave(&network->lock, flags); | ||
72 | network->outgoing_packets_queued--; | ||
73 | if (network->ppp_channel != NULL) { | ||
74 | if (network->ppp_blocked) { | ||
75 | network->ppp_blocked = 0; | ||
76 | spin_unlock_irqrestore(&network->lock, flags); | ||
77 | ppp_output_wakeup(network->ppp_channel); | ||
78 | if (ipwireless_debug) | ||
79 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
80 | ": ppp unblocked\n"); | ||
81 | } else | ||
82 | spin_unlock_irqrestore(&network->lock, flags); | ||
83 | } else | ||
84 | spin_unlock_irqrestore(&network->lock, flags); | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Called by the ppp system when it has a packet to send to the hardware. | ||
89 | */ | ||
90 | static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel, | ||
91 | struct sk_buff *skb) | ||
92 | { | ||
93 | struct ipw_network *network = ppp_channel->private; | ||
94 | unsigned long flags; | ||
95 | |||
96 | spin_lock_irqsave(&network->lock, flags); | ||
97 | if (network->outgoing_packets_queued < ipwireless_out_queue) { | ||
98 | unsigned char *buf; | ||
99 | static unsigned char header[] = { | ||
100 | PPP_ALLSTATIONS, /* 0xff */ | ||
101 | PPP_UI, /* 0x03 */ | ||
102 | }; | ||
103 | int ret; | ||
104 | |||
105 | network->outgoing_packets_queued++; | ||
106 | spin_unlock_irqrestore(&network->lock, flags); | ||
107 | |||
108 | /* | ||
109 | * If we have the requested amount of headroom in the skb we | ||
110 | * were handed, then we can add the header efficiently. | ||
111 | */ | ||
112 | if (skb_headroom(skb) >= 2) { | ||
113 | memcpy(skb_push(skb, 2), header, 2); | ||
114 | ret = ipwireless_send_packet(network->hardware, | ||
115 | IPW_CHANNEL_RAS, skb->data, | ||
116 | skb->len, | ||
117 | notify_packet_sent, | ||
118 | network); | ||
119 | if (ret == -1) { | ||
120 | skb_pull(skb, 2); | ||
121 | return 0; | ||
122 | } | ||
123 | } else { | ||
124 | /* Otherwise (rarely) we do it inefficiently. */ | ||
125 | buf = kmalloc(skb->len + 2, GFP_ATOMIC); | ||
126 | if (!buf) | ||
127 | return 0; | ||
128 | memcpy(buf + 2, skb->data, skb->len); | ||
129 | memcpy(buf, header, 2); | ||
130 | ret = ipwireless_send_packet(network->hardware, | ||
131 | IPW_CHANNEL_RAS, buf, | ||
132 | skb->len + 2, | ||
133 | notify_packet_sent, | ||
134 | network); | ||
135 | kfree(buf); | ||
136 | if (ret == -1) | ||
137 | return 0; | ||
138 | } | ||
139 | kfree_skb(skb); | ||
140 | return 1; | ||
141 | } else { | ||
142 | /* | ||
143 | * Otherwise reject the packet, and flag that the ppp system | ||
144 | * needs to be unblocked once we are ready to send. | ||
145 | */ | ||
146 | network->ppp_blocked = 1; | ||
147 | spin_unlock_irqrestore(&network->lock, flags); | ||
148 | if (ipwireless_debug) | ||
149 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp blocked\n"); | ||
150 | return 0; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */ | ||
155 | static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel, | ||
156 | unsigned int cmd, unsigned long arg) | ||
157 | { | ||
158 | struct ipw_network *network = ppp_channel->private; | ||
159 | int err, val; | ||
160 | u32 accm[8]; | ||
161 | int __user *user_arg = (int __user *) arg; | ||
162 | |||
163 | err = -EFAULT; | ||
164 | switch (cmd) { | ||
165 | case PPPIOCGFLAGS: | ||
166 | val = network->flags | network->rbits; | ||
167 | if (put_user(val, user_arg)) | ||
168 | break; | ||
169 | err = 0; | ||
170 | break; | ||
171 | |||
172 | case PPPIOCSFLAGS: | ||
173 | if (get_user(val, user_arg)) | ||
174 | break; | ||
175 | network->flags = val & ~SC_RCV_BITS; | ||
176 | network->rbits = val & SC_RCV_BITS; | ||
177 | err = 0; | ||
178 | break; | ||
179 | |||
180 | case PPPIOCGASYNCMAP: | ||
181 | if (put_user(network->xaccm[0], user_arg)) | ||
182 | break; | ||
183 | err = 0; | ||
184 | break; | ||
185 | |||
186 | case PPPIOCSASYNCMAP: | ||
187 | if (get_user(network->xaccm[0], user_arg)) | ||
188 | break; | ||
189 | err = 0; | ||
190 | break; | ||
191 | |||
192 | case PPPIOCGRASYNCMAP: | ||
193 | if (put_user(network->raccm, user_arg)) | ||
194 | break; | ||
195 | err = 0; | ||
196 | break; | ||
197 | |||
198 | case PPPIOCSRASYNCMAP: | ||
199 | if (get_user(network->raccm, user_arg)) | ||
200 | break; | ||
201 | err = 0; | ||
202 | break; | ||
203 | |||
204 | case PPPIOCGXASYNCMAP: | ||
205 | if (copy_to_user((void __user *) arg, network->xaccm, | ||
206 | sizeof(network->xaccm))) | ||
207 | break; | ||
208 | err = 0; | ||
209 | break; | ||
210 | |||
211 | case PPPIOCSXASYNCMAP: | ||
212 | if (copy_from_user(accm, (void __user *) arg, sizeof(accm))) | ||
213 | break; | ||
214 | accm[2] &= ~0x40000000U; /* can't escape 0x5e */ | ||
215 | accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ | ||
216 | memcpy(network->xaccm, accm, sizeof(network->xaccm)); | ||
217 | err = 0; | ||
218 | break; | ||
219 | |||
220 | case PPPIOCGMRU: | ||
221 | if (put_user(network->mru, user_arg)) | ||
222 | break; | ||
223 | err = 0; | ||
224 | break; | ||
225 | |||
226 | case PPPIOCSMRU: | ||
227 | if (get_user(val, user_arg)) | ||
228 | break; | ||
229 | if (val < PPP_MRU) | ||
230 | val = PPP_MRU; | ||
231 | network->mru = val; | ||
232 | err = 0; | ||
233 | break; | ||
234 | |||
235 | default: | ||
236 | err = -ENOTTY; | ||
237 | } | ||
238 | |||
239 | return err; | ||
240 | } | ||
241 | |||
242 | static const struct ppp_channel_ops ipwireless_ppp_channel_ops = { | ||
243 | .start_xmit = ipwireless_ppp_start_xmit, | ||
244 | .ioctl = ipwireless_ppp_ioctl | ||
245 | }; | ||
246 | |||
247 | static void do_go_online(struct work_struct *work_go_online) | ||
248 | { | ||
249 | struct ipw_network *network = | ||
250 | container_of(work_go_online, struct ipw_network, | ||
251 | work_go_online); | ||
252 | unsigned long flags; | ||
253 | |||
254 | spin_lock_irqsave(&network->lock, flags); | ||
255 | if (!network->ppp_channel) { | ||
256 | struct ppp_channel *channel; | ||
257 | |||
258 | spin_unlock_irqrestore(&network->lock, flags); | ||
259 | channel = kzalloc(sizeof(struct ppp_channel), GFP_KERNEL); | ||
260 | if (!channel) { | ||
261 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
262 | ": unable to allocate PPP channel\n"); | ||
263 | return; | ||
264 | } | ||
265 | channel->private = network; | ||
266 | channel->mtu = 16384; /* Wild guess */ | ||
267 | channel->hdrlen = 2; | ||
268 | channel->ops = &ipwireless_ppp_channel_ops; | ||
269 | |||
270 | network->flags = 0; | ||
271 | network->rbits = 0; | ||
272 | network->mru = PPP_MRU; | ||
273 | memset(network->xaccm, 0, sizeof(network->xaccm)); | ||
274 | network->xaccm[0] = ~0U; | ||
275 | network->xaccm[3] = 0x60000000U; | ||
276 | network->raccm = ~0U; | ||
277 | ppp_register_channel(channel); | ||
278 | spin_lock_irqsave(&network->lock, flags); | ||
279 | network->ppp_channel = channel; | ||
280 | } | ||
281 | spin_unlock_irqrestore(&network->lock, flags); | ||
282 | } | ||
283 | |||
284 | static void do_go_offline(struct work_struct *work_go_offline) | ||
285 | { | ||
286 | struct ipw_network *network = | ||
287 | container_of(work_go_offline, struct ipw_network, | ||
288 | work_go_offline); | ||
289 | unsigned long flags; | ||
290 | |||
291 | mutex_lock(&network->close_lock); | ||
292 | spin_lock_irqsave(&network->lock, flags); | ||
293 | if (network->ppp_channel != NULL) { | ||
294 | struct ppp_channel *channel = network->ppp_channel; | ||
295 | |||
296 | network->ppp_channel = NULL; | ||
297 | spin_unlock_irqrestore(&network->lock, flags); | ||
298 | mutex_unlock(&network->close_lock); | ||
299 | ppp_unregister_channel(channel); | ||
300 | } else { | ||
301 | spin_unlock_irqrestore(&network->lock, flags); | ||
302 | mutex_unlock(&network->close_lock); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | void ipwireless_network_notify_control_line_change(struct ipw_network *network, | ||
307 | unsigned int channel_idx, | ||
308 | unsigned int control_lines, | ||
309 | unsigned int changed_mask) | ||
310 | { | ||
311 | int i; | ||
312 | |||
313 | if (channel_idx == IPW_CHANNEL_RAS) | ||
314 | network->ras_control_lines = control_lines; | ||
315 | |||
316 | for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { | ||
317 | struct ipw_tty *tty = | ||
318 | network->associated_ttys[channel_idx][i]; | ||
319 | |||
320 | /* | ||
321 | * If it's associated with a tty (other than the RAS channel | ||
322 | * when we're online), then send the data to that tty. The RAS | ||
323 | * channel's data is handled above - it always goes through | ||
324 | * ppp_generic. | ||
325 | */ | ||
326 | if (tty) | ||
327 | ipwireless_tty_notify_control_line_change(tty, | ||
328 | channel_idx, | ||
329 | control_lines, | ||
330 | changed_mask); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI) | ||
336 | * bytes, which are required on sent packet, but not always present on received | ||
337 | * packets | ||
338 | */ | ||
339 | static struct sk_buff *ipw_packet_received_skb(unsigned char *data, | ||
340 | unsigned int length) | ||
341 | { | ||
342 | struct sk_buff *skb; | ||
343 | |||
344 | if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) { | ||
345 | length -= 2; | ||
346 | data += 2; | ||
347 | } | ||
348 | |||
349 | skb = dev_alloc_skb(length + 4); | ||
350 | skb_reserve(skb, 2); | ||
351 | memcpy(skb_put(skb, length), data, length); | ||
352 | |||
353 | return skb; | ||
354 | } | ||
355 | |||
356 | void ipwireless_network_packet_received(struct ipw_network *network, | ||
357 | unsigned int channel_idx, | ||
358 | unsigned char *data, | ||
359 | unsigned int length) | ||
360 | { | ||
361 | int i; | ||
362 | unsigned long flags; | ||
363 | |||
364 | for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) { | ||
365 | struct ipw_tty *tty = network->associated_ttys[channel_idx][i]; | ||
366 | |||
367 | if (!tty) | ||
368 | continue; | ||
369 | |||
370 | /* | ||
371 | * If it's associated with a tty (other than the RAS channel | ||
372 | * when we're online), then send the data to that tty. The RAS | ||
373 | * channel's data is handled above - it always goes through | ||
374 | * ppp_generic. | ||
375 | */ | ||
376 | if (channel_idx == IPW_CHANNEL_RAS | ||
377 | && (network->ras_control_lines & | ||
378 | IPW_CONTROL_LINE_DCD) != 0 | ||
379 | && ipwireless_tty_is_modem(tty)) { | ||
380 | /* | ||
381 | * If data came in on the RAS channel and this tty is | ||
382 | * the modem tty, and we are online, then we send it to | ||
383 | * the PPP layer. | ||
384 | */ | ||
385 | mutex_lock(&network->close_lock); | ||
386 | spin_lock_irqsave(&network->lock, flags); | ||
387 | if (network->ppp_channel != NULL) { | ||
388 | struct sk_buff *skb; | ||
389 | |||
390 | spin_unlock_irqrestore(&network->lock, | ||
391 | flags); | ||
392 | |||
393 | /* Send the data to the ppp_generic module. */ | ||
394 | skb = ipw_packet_received_skb(data, length); | ||
395 | ppp_input(network->ppp_channel, skb); | ||
396 | } else | ||
397 | spin_unlock_irqrestore(&network->lock, | ||
398 | flags); | ||
399 | mutex_unlock(&network->close_lock); | ||
400 | } | ||
401 | /* Otherwise we send it out the tty. */ | ||
402 | else | ||
403 | ipwireless_tty_received(tty, data, length); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw) | ||
408 | { | ||
409 | struct ipw_network *network = | ||
410 | kzalloc(sizeof(struct ipw_network), GFP_ATOMIC); | ||
411 | |||
412 | if (!network) | ||
413 | return NULL; | ||
414 | |||
415 | spin_lock_init(&network->lock); | ||
416 | mutex_init(&network->close_lock); | ||
417 | |||
418 | network->hardware = hw; | ||
419 | |||
420 | INIT_WORK(&network->work_go_online, do_go_online); | ||
421 | INIT_WORK(&network->work_go_offline, do_go_offline); | ||
422 | |||
423 | ipwireless_associate_network(hw, network); | ||
424 | |||
425 | return network; | ||
426 | } | ||
427 | |||
428 | void ipwireless_network_free(struct ipw_network *network) | ||
429 | { | ||
430 | network->shutting_down = 1; | ||
431 | |||
432 | ipwireless_ppp_close(network); | ||
433 | flush_work_sync(&network->work_go_online); | ||
434 | flush_work_sync(&network->work_go_offline); | ||
435 | |||
436 | ipwireless_stop_interrupts(network->hardware); | ||
437 | ipwireless_associate_network(network->hardware, NULL); | ||
438 | |||
439 | kfree(network); | ||
440 | } | ||
441 | |||
442 | void ipwireless_associate_network_tty(struct ipw_network *network, | ||
443 | unsigned int channel_idx, | ||
444 | struct ipw_tty *tty) | ||
445 | { | ||
446 | int i; | ||
447 | |||
448 | for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) | ||
449 | if (network->associated_ttys[channel_idx][i] == NULL) { | ||
450 | network->associated_ttys[channel_idx][i] = tty; | ||
451 | break; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | void ipwireless_disassociate_network_ttys(struct ipw_network *network, | ||
456 | unsigned int channel_idx) | ||
457 | { | ||
458 | int i; | ||
459 | |||
460 | for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) | ||
461 | network->associated_ttys[channel_idx][i] = NULL; | ||
462 | } | ||
463 | |||
464 | void ipwireless_ppp_open(struct ipw_network *network) | ||
465 | { | ||
466 | if (ipwireless_debug) | ||
467 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n"); | ||
468 | schedule_work(&network->work_go_online); | ||
469 | } | ||
470 | |||
471 | void ipwireless_ppp_close(struct ipw_network *network) | ||
472 | { | ||
473 | /* Disconnect from the wireless network. */ | ||
474 | if (ipwireless_debug) | ||
475 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n"); | ||
476 | schedule_work(&network->work_go_offline); | ||
477 | } | ||
478 | |||
479 | int ipwireless_ppp_channel_index(struct ipw_network *network) | ||
480 | { | ||
481 | int ret = -1; | ||
482 | unsigned long flags; | ||
483 | |||
484 | spin_lock_irqsave(&network->lock, flags); | ||
485 | if (network->ppp_channel != NULL) | ||
486 | ret = ppp_channel_index(network->ppp_channel); | ||
487 | spin_unlock_irqrestore(&network->lock, flags); | ||
488 | |||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | int ipwireless_ppp_unit_number(struct ipw_network *network) | ||
493 | { | ||
494 | int ret = -1; | ||
495 | unsigned long flags; | ||
496 | |||
497 | spin_lock_irqsave(&network->lock, flags); | ||
498 | if (network->ppp_channel != NULL) | ||
499 | ret = ppp_unit_number(network->ppp_channel); | ||
500 | spin_unlock_irqrestore(&network->lock, flags); | ||
501 | |||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | int ipwireless_ppp_mru(const struct ipw_network *network) | ||
506 | { | ||
507 | return network->mru; | ||
508 | } | ||
diff --git a/drivers/tty/ipwireless/network.h b/drivers/tty/ipwireless/network.h new file mode 100644 index 000000000000..561f765b3334 --- /dev/null +++ b/drivers/tty/ipwireless/network.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #ifndef _IPWIRELESS_CS_NETWORK_H_ | ||
19 | #define _IPWIRELESS_CS_NETWORK_H_ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | struct ipw_network; | ||
24 | struct ipw_tty; | ||
25 | struct ipw_hardware; | ||
26 | |||
27 | /* Definitions of the different channels on the PCMCIA UE */ | ||
28 | #define IPW_CHANNEL_RAS 0 | ||
29 | #define IPW_CHANNEL_DIALLER 1 | ||
30 | #define IPW_CHANNEL_CONSOLE 2 | ||
31 | #define NO_OF_IPW_CHANNELS 5 | ||
32 | |||
33 | void ipwireless_network_notify_control_line_change(struct ipw_network *net, | ||
34 | unsigned int channel_idx, unsigned int control_lines, | ||
35 | unsigned int control_mask); | ||
36 | void ipwireless_network_packet_received(struct ipw_network *net, | ||
37 | unsigned int channel_idx, unsigned char *data, | ||
38 | unsigned int length); | ||
39 | struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw); | ||
40 | void ipwireless_network_free(struct ipw_network *net); | ||
41 | void ipwireless_associate_network_tty(struct ipw_network *net, | ||
42 | unsigned int channel_idx, struct ipw_tty *tty); | ||
43 | void ipwireless_disassociate_network_ttys(struct ipw_network *net, | ||
44 | unsigned int channel_idx); | ||
45 | |||
46 | void ipwireless_ppp_open(struct ipw_network *net); | ||
47 | |||
48 | void ipwireless_ppp_close(struct ipw_network *net); | ||
49 | int ipwireless_ppp_channel_index(struct ipw_network *net); | ||
50 | int ipwireless_ppp_unit_number(struct ipw_network *net); | ||
51 | int ipwireless_ppp_mru(const struct ipw_network *net); | ||
52 | |||
53 | #endif | ||
diff --git a/drivers/tty/ipwireless/setup_protocol.h b/drivers/tty/ipwireless/setup_protocol.h new file mode 100644 index 000000000000..9d6bcc77c73c --- /dev/null +++ b/drivers/tty/ipwireless/setup_protocol.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_ | ||
19 | #define _IPWIRELESS_CS_SETUP_PROTOCOL_H_ | ||
20 | |||
21 | /* Version of the setup protocol and transport protocols */ | ||
22 | #define TL_SETUP_VERSION 1 | ||
23 | |||
24 | #define TL_SETUP_VERSION_QRY_TMO 1000 | ||
25 | #define TL_SETUP_MAX_VERSION_QRY 30 | ||
26 | |||
27 | /* Message numbers 0-9 are obsoleted and must not be reused! */ | ||
28 | #define TL_SETUP_SIGNO_GET_VERSION_QRY 10 | ||
29 | #define TL_SETUP_SIGNO_GET_VERSION_RSP 11 | ||
30 | #define TL_SETUP_SIGNO_CONFIG_MSG 12 | ||
31 | #define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13 | ||
32 | #define TL_SETUP_SIGNO_OPEN_MSG 14 | ||
33 | #define TL_SETUP_SIGNO_CLOSE_MSG 15 | ||
34 | |||
35 | #define TL_SETUP_SIGNO_INFO_MSG 20 | ||
36 | #define TL_SETUP_SIGNO_INFO_MSG_ACK 21 | ||
37 | |||
38 | #define TL_SETUP_SIGNO_REBOOT_MSG 22 | ||
39 | #define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23 | ||
40 | |||
41 | /* Synchronous start-messages */ | ||
42 | struct tl_setup_get_version_qry { | ||
43 | unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */ | ||
44 | } __attribute__ ((__packed__)); | ||
45 | |||
46 | struct tl_setup_get_version_rsp { | ||
47 | unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */ | ||
48 | unsigned char version; /* TL_SETUP_VERSION */ | ||
49 | } __attribute__ ((__packed__)); | ||
50 | |||
51 | struct tl_setup_config_msg { | ||
52 | unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */ | ||
53 | unsigned char port_no; | ||
54 | unsigned char prio_data; | ||
55 | unsigned char prio_ctrl; | ||
56 | } __attribute__ ((__packed__)); | ||
57 | |||
58 | struct tl_setup_config_done_msg { | ||
59 | unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */ | ||
60 | } __attribute__ ((__packed__)); | ||
61 | |||
62 | /* Asyncronous messages */ | ||
63 | struct tl_setup_open_msg { | ||
64 | unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */ | ||
65 | unsigned char port_no; | ||
66 | } __attribute__ ((__packed__)); | ||
67 | |||
68 | struct tl_setup_close_msg { | ||
69 | unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */ | ||
70 | unsigned char port_no; | ||
71 | } __attribute__ ((__packed__)); | ||
72 | |||
73 | /* Driver type - for use in tl_setup_info_msg.driver_type */ | ||
74 | #define COMM_DRIVER 0 | ||
75 | #define NDISWAN_DRIVER 1 | ||
76 | #define NDISWAN_DRIVER_MAJOR_VERSION 2 | ||
77 | #define NDISWAN_DRIVER_MINOR_VERSION 0 | ||
78 | |||
79 | /* | ||
80 | * It should not matter when this message comes over as we just store the | ||
81 | * results and send the ACK. | ||
82 | */ | ||
83 | struct tl_setup_info_msg { | ||
84 | unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */ | ||
85 | unsigned char driver_type; | ||
86 | unsigned char major_version; | ||
87 | unsigned char minor_version; | ||
88 | } __attribute__ ((__packed__)); | ||
89 | |||
90 | struct tl_setup_info_msgAck { | ||
91 | unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */ | ||
92 | } __attribute__ ((__packed__)); | ||
93 | |||
94 | struct TlSetupRebootMsgAck { | ||
95 | unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */ | ||
96 | } __attribute__ ((__packed__)); | ||
97 | |||
98 | /* Define a union of all the msgs that the driver can receive from the card.*/ | ||
99 | union ipw_setup_rx_msg { | ||
100 | unsigned char sig_no; | ||
101 | struct tl_setup_get_version_rsp version_rsp_msg; | ||
102 | struct tl_setup_open_msg open_msg; | ||
103 | struct tl_setup_close_msg close_msg; | ||
104 | struct tl_setup_info_msg InfoMsg; | ||
105 | struct tl_setup_info_msgAck info_msg_ack; | ||
106 | } __attribute__ ((__packed__)); | ||
107 | |||
108 | #endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */ | ||
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c new file mode 100644 index 000000000000..ef92869502a7 --- /dev/null +++ b/drivers/tty/ipwireless/tty.c | |||
@@ -0,0 +1,679 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/ppp_defs.h> | ||
23 | #include <linux/if.h> | ||
24 | #include <linux/if_ppp.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/serial.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/tty_driver.h> | ||
30 | #include <linux/tty_flip.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | |||
33 | #include "tty.h" | ||
34 | #include "network.h" | ||
35 | #include "hardware.h" | ||
36 | #include "main.h" | ||
37 | |||
38 | #define IPWIRELESS_PCMCIA_START (0) | ||
39 | #define IPWIRELESS_PCMCIA_MINORS (24) | ||
40 | #define IPWIRELESS_PCMCIA_MINOR_RANGE (8) | ||
41 | |||
42 | #define TTYTYPE_MODEM (0) | ||
43 | #define TTYTYPE_MONITOR (1) | ||
44 | #define TTYTYPE_RAS_RAW (2) | ||
45 | |||
46 | struct ipw_tty { | ||
47 | int index; | ||
48 | struct ipw_hardware *hardware; | ||
49 | unsigned int channel_idx; | ||
50 | unsigned int secondary_channel_idx; | ||
51 | int tty_type; | ||
52 | struct ipw_network *network; | ||
53 | struct tty_struct *linux_tty; | ||
54 | int open_count; | ||
55 | unsigned int control_lines; | ||
56 | struct mutex ipw_tty_mutex; | ||
57 | int tx_bytes_queued; | ||
58 | int closing; | ||
59 | }; | ||
60 | |||
61 | static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; | ||
62 | |||
63 | static struct tty_driver *ipw_tty_driver; | ||
64 | |||
65 | static char *tty_type_name(int tty_type) | ||
66 | { | ||
67 | static char *channel_names[] = { | ||
68 | "modem", | ||
69 | "monitor", | ||
70 | "RAS-raw" | ||
71 | }; | ||
72 | |||
73 | return channel_names[tty_type]; | ||
74 | } | ||
75 | |||
76 | static void report_registering(struct ipw_tty *tty) | ||
77 | { | ||
78 | char *iftype = tty_type_name(tty->tty_type); | ||
79 | |||
80 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
81 | ": registering %s device ttyIPWp%d\n", iftype, tty->index); | ||
82 | } | ||
83 | |||
84 | static void report_deregistering(struct ipw_tty *tty) | ||
85 | { | ||
86 | char *iftype = tty_type_name(tty->tty_type); | ||
87 | |||
88 | printk(KERN_INFO IPWIRELESS_PCCARD_NAME | ||
89 | ": deregistering %s device ttyIPWp%d\n", iftype, | ||
90 | tty->index); | ||
91 | } | ||
92 | |||
93 | static struct ipw_tty *get_tty(int minor) | ||
94 | { | ||
95 | if (minor < ipw_tty_driver->minor_start | ||
96 | || minor >= ipw_tty_driver->minor_start + | ||
97 | IPWIRELESS_PCMCIA_MINORS) | ||
98 | return NULL; | ||
99 | else { | ||
100 | int minor_offset = minor - ipw_tty_driver->minor_start; | ||
101 | |||
102 | /* | ||
103 | * The 'ras_raw' channel is only available when 'loopback' mode | ||
104 | * is enabled. | ||
105 | * Number of minor starts with 16 (_RANGE * _RAS_RAW). | ||
106 | */ | ||
107 | if (!ipwireless_loopback && | ||
108 | minor_offset >= | ||
109 | IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW) | ||
110 | return NULL; | ||
111 | |||
112 | return ttys[minor_offset]; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static int ipw_open(struct tty_struct *linux_tty, struct file *filp) | ||
117 | { | ||
118 | int minor = linux_tty->index; | ||
119 | struct ipw_tty *tty = get_tty(minor); | ||
120 | |||
121 | if (!tty) | ||
122 | return -ENODEV; | ||
123 | |||
124 | mutex_lock(&tty->ipw_tty_mutex); | ||
125 | |||
126 | if (tty->closing) { | ||
127 | mutex_unlock(&tty->ipw_tty_mutex); | ||
128 | return -ENODEV; | ||
129 | } | ||
130 | if (tty->open_count == 0) | ||
131 | tty->tx_bytes_queued = 0; | ||
132 | |||
133 | tty->open_count++; | ||
134 | |||
135 | tty->linux_tty = linux_tty; | ||
136 | linux_tty->driver_data = tty; | ||
137 | linux_tty->low_latency = 1; | ||
138 | |||
139 | if (tty->tty_type == TTYTYPE_MODEM) | ||
140 | ipwireless_ppp_open(tty->network); | ||
141 | |||
142 | mutex_unlock(&tty->ipw_tty_mutex); | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | static void do_ipw_close(struct ipw_tty *tty) | ||
148 | { | ||
149 | tty->open_count--; | ||
150 | |||
151 | if (tty->open_count == 0) { | ||
152 | struct tty_struct *linux_tty = tty->linux_tty; | ||
153 | |||
154 | if (linux_tty != NULL) { | ||
155 | tty->linux_tty = NULL; | ||
156 | linux_tty->driver_data = NULL; | ||
157 | |||
158 | if (tty->tty_type == TTYTYPE_MODEM) | ||
159 | ipwireless_ppp_close(tty->network); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static void ipw_hangup(struct tty_struct *linux_tty) | ||
165 | { | ||
166 | struct ipw_tty *tty = linux_tty->driver_data; | ||
167 | |||
168 | if (!tty) | ||
169 | return; | ||
170 | |||
171 | mutex_lock(&tty->ipw_tty_mutex); | ||
172 | if (tty->open_count == 0) { | ||
173 | mutex_unlock(&tty->ipw_tty_mutex); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | do_ipw_close(tty); | ||
178 | |||
179 | mutex_unlock(&tty->ipw_tty_mutex); | ||
180 | } | ||
181 | |||
182 | static void ipw_close(struct tty_struct *linux_tty, struct file *filp) | ||
183 | { | ||
184 | ipw_hangup(linux_tty); | ||
185 | } | ||
186 | |||
187 | /* Take data received from hardware, and send it out the tty */ | ||
188 | void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, | ||
189 | unsigned int length) | ||
190 | { | ||
191 | struct tty_struct *linux_tty; | ||
192 | int work = 0; | ||
193 | |||
194 | mutex_lock(&tty->ipw_tty_mutex); | ||
195 | linux_tty = tty->linux_tty; | ||
196 | if (linux_tty == NULL) { | ||
197 | mutex_unlock(&tty->ipw_tty_mutex); | ||
198 | return; | ||
199 | } | ||
200 | |||
201 | if (!tty->open_count) { | ||
202 | mutex_unlock(&tty->ipw_tty_mutex); | ||
203 | return; | ||
204 | } | ||
205 | mutex_unlock(&tty->ipw_tty_mutex); | ||
206 | |||
207 | work = tty_insert_flip_string(linux_tty, data, length); | ||
208 | |||
209 | if (work != length) | ||
210 | printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME | ||
211 | ": %d chars not inserted to flip buffer!\n", | ||
212 | length - work); | ||
213 | |||
214 | /* | ||
215 | * This may sleep if ->low_latency is set | ||
216 | */ | ||
217 | if (work) | ||
218 | tty_flip_buffer_push(linux_tty); | ||
219 | } | ||
220 | |||
221 | static void ipw_write_packet_sent_callback(void *callback_data, | ||
222 | unsigned int packet_length) | ||
223 | { | ||
224 | struct ipw_tty *tty = callback_data; | ||
225 | |||
226 | /* | ||
227 | * Packet has been sent, so we subtract the number of bytes from our | ||
228 | * tally of outstanding TX bytes. | ||
229 | */ | ||
230 | tty->tx_bytes_queued -= packet_length; | ||
231 | } | ||
232 | |||
233 | static int ipw_write(struct tty_struct *linux_tty, | ||
234 | const unsigned char *buf, int count) | ||
235 | { | ||
236 | struct ipw_tty *tty = linux_tty->driver_data; | ||
237 | int room, ret; | ||
238 | |||
239 | if (!tty) | ||
240 | return -ENODEV; | ||
241 | |||
242 | mutex_lock(&tty->ipw_tty_mutex); | ||
243 | if (!tty->open_count) { | ||
244 | mutex_unlock(&tty->ipw_tty_mutex); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; | ||
249 | if (room < 0) | ||
250 | room = 0; | ||
251 | /* Don't allow caller to write any more than we have room for */ | ||
252 | if (count > room) | ||
253 | count = room; | ||
254 | |||
255 | if (count == 0) { | ||
256 | mutex_unlock(&tty->ipw_tty_mutex); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS, | ||
261 | buf, count, | ||
262 | ipw_write_packet_sent_callback, tty); | ||
263 | if (ret == -1) { | ||
264 | mutex_unlock(&tty->ipw_tty_mutex); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | tty->tx_bytes_queued += count; | ||
269 | mutex_unlock(&tty->ipw_tty_mutex); | ||
270 | |||
271 | return count; | ||
272 | } | ||
273 | |||
274 | static int ipw_write_room(struct tty_struct *linux_tty) | ||
275 | { | ||
276 | struct ipw_tty *tty = linux_tty->driver_data; | ||
277 | int room; | ||
278 | |||
279 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
280 | if (!tty) | ||
281 | return -ENODEV; | ||
282 | |||
283 | if (!tty->open_count) | ||
284 | return -EINVAL; | ||
285 | |||
286 | room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; | ||
287 | if (room < 0) | ||
288 | room = 0; | ||
289 | |||
290 | return room; | ||
291 | } | ||
292 | |||
293 | static int ipwireless_get_serial_info(struct ipw_tty *tty, | ||
294 | struct serial_struct __user *retinfo) | ||
295 | { | ||
296 | struct serial_struct tmp; | ||
297 | |||
298 | if (!retinfo) | ||
299 | return (-EFAULT); | ||
300 | |||
301 | memset(&tmp, 0, sizeof(tmp)); | ||
302 | tmp.type = PORT_UNKNOWN; | ||
303 | tmp.line = tty->index; | ||
304 | tmp.port = 0; | ||
305 | tmp.irq = 0; | ||
306 | tmp.flags = 0; | ||
307 | tmp.baud_base = 115200; | ||
308 | tmp.close_delay = 0; | ||
309 | tmp.closing_wait = 0; | ||
310 | tmp.custom_divisor = 0; | ||
311 | tmp.hub6 = 0; | ||
312 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
313 | return -EFAULT; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int ipw_chars_in_buffer(struct tty_struct *linux_tty) | ||
319 | { | ||
320 | struct ipw_tty *tty = linux_tty->driver_data; | ||
321 | |||
322 | if (!tty) | ||
323 | return 0; | ||
324 | |||
325 | if (!tty->open_count) | ||
326 | return 0; | ||
327 | |||
328 | return tty->tx_bytes_queued; | ||
329 | } | ||
330 | |||
331 | static int get_control_lines(struct ipw_tty *tty) | ||
332 | { | ||
333 | unsigned int my = tty->control_lines; | ||
334 | unsigned int out = 0; | ||
335 | |||
336 | if (my & IPW_CONTROL_LINE_RTS) | ||
337 | out |= TIOCM_RTS; | ||
338 | if (my & IPW_CONTROL_LINE_DTR) | ||
339 | out |= TIOCM_DTR; | ||
340 | if (my & IPW_CONTROL_LINE_CTS) | ||
341 | out |= TIOCM_CTS; | ||
342 | if (my & IPW_CONTROL_LINE_DSR) | ||
343 | out |= TIOCM_DSR; | ||
344 | if (my & IPW_CONTROL_LINE_DCD) | ||
345 | out |= TIOCM_CD; | ||
346 | |||
347 | return out; | ||
348 | } | ||
349 | |||
350 | static int set_control_lines(struct ipw_tty *tty, unsigned int set, | ||
351 | unsigned int clear) | ||
352 | { | ||
353 | int ret; | ||
354 | |||
355 | if (set & TIOCM_RTS) { | ||
356 | ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1); | ||
357 | if (ret) | ||
358 | return ret; | ||
359 | if (tty->secondary_channel_idx != -1) { | ||
360 | ret = ipwireless_set_RTS(tty->hardware, | ||
361 | tty->secondary_channel_idx, 1); | ||
362 | if (ret) | ||
363 | return ret; | ||
364 | } | ||
365 | } | ||
366 | if (set & TIOCM_DTR) { | ||
367 | ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1); | ||
368 | if (ret) | ||
369 | return ret; | ||
370 | if (tty->secondary_channel_idx != -1) { | ||
371 | ret = ipwireless_set_DTR(tty->hardware, | ||
372 | tty->secondary_channel_idx, 1); | ||
373 | if (ret) | ||
374 | return ret; | ||
375 | } | ||
376 | } | ||
377 | if (clear & TIOCM_RTS) { | ||
378 | ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0); | ||
379 | if (tty->secondary_channel_idx != -1) { | ||
380 | ret = ipwireless_set_RTS(tty->hardware, | ||
381 | tty->secondary_channel_idx, 0); | ||
382 | if (ret) | ||
383 | return ret; | ||
384 | } | ||
385 | } | ||
386 | if (clear & TIOCM_DTR) { | ||
387 | ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0); | ||
388 | if (tty->secondary_channel_idx != -1) { | ||
389 | ret = ipwireless_set_DTR(tty->hardware, | ||
390 | tty->secondary_channel_idx, 0); | ||
391 | if (ret) | ||
392 | return ret; | ||
393 | } | ||
394 | } | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int ipw_tiocmget(struct tty_struct *linux_tty) | ||
399 | { | ||
400 | struct ipw_tty *tty = linux_tty->driver_data; | ||
401 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
402 | |||
403 | if (!tty) | ||
404 | return -ENODEV; | ||
405 | |||
406 | if (!tty->open_count) | ||
407 | return -EINVAL; | ||
408 | |||
409 | return get_control_lines(tty); | ||
410 | } | ||
411 | |||
412 | static int | ||
413 | ipw_tiocmset(struct tty_struct *linux_tty, | ||
414 | unsigned int set, unsigned int clear) | ||
415 | { | ||
416 | struct ipw_tty *tty = linux_tty->driver_data; | ||
417 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
418 | |||
419 | if (!tty) | ||
420 | return -ENODEV; | ||
421 | |||
422 | if (!tty->open_count) | ||
423 | return -EINVAL; | ||
424 | |||
425 | return set_control_lines(tty, set, clear); | ||
426 | } | ||
427 | |||
428 | static int ipw_ioctl(struct tty_struct *linux_tty, | ||
429 | unsigned int cmd, unsigned long arg) | ||
430 | { | ||
431 | struct ipw_tty *tty = linux_tty->driver_data; | ||
432 | |||
433 | if (!tty) | ||
434 | return -ENODEV; | ||
435 | |||
436 | if (!tty->open_count) | ||
437 | return -EINVAL; | ||
438 | |||
439 | /* FIXME: Exactly how is the tty object locked here .. */ | ||
440 | |||
441 | switch (cmd) { | ||
442 | case TIOCGSERIAL: | ||
443 | return ipwireless_get_serial_info(tty, (void __user *) arg); | ||
444 | |||
445 | case TIOCSSERIAL: | ||
446 | return 0; /* Keeps the PCMCIA scripts happy. */ | ||
447 | } | ||
448 | |||
449 | if (tty->tty_type == TTYTYPE_MODEM) { | ||
450 | switch (cmd) { | ||
451 | case PPPIOCGCHAN: | ||
452 | { | ||
453 | int chan = ipwireless_ppp_channel_index( | ||
454 | tty->network); | ||
455 | |||
456 | if (chan < 0) | ||
457 | return -ENODEV; | ||
458 | if (put_user(chan, (int __user *) arg)) | ||
459 | return -EFAULT; | ||
460 | } | ||
461 | return 0; | ||
462 | |||
463 | case PPPIOCGUNIT: | ||
464 | { | ||
465 | int unit = ipwireless_ppp_unit_number( | ||
466 | tty->network); | ||
467 | |||
468 | if (unit < 0) | ||
469 | return -ENODEV; | ||
470 | if (put_user(unit, (int __user *) arg)) | ||
471 | return -EFAULT; | ||
472 | } | ||
473 | return 0; | ||
474 | |||
475 | case FIONREAD: | ||
476 | { | ||
477 | int val = 0; | ||
478 | |||
479 | if (put_user(val, (int __user *) arg)) | ||
480 | return -EFAULT; | ||
481 | } | ||
482 | return 0; | ||
483 | case TCFLSH: | ||
484 | return tty_perform_flush(linux_tty, arg); | ||
485 | } | ||
486 | } | ||
487 | return -ENOIOCTLCMD; | ||
488 | } | ||
489 | |||
490 | static int add_tty(int j, | ||
491 | struct ipw_hardware *hardware, | ||
492 | struct ipw_network *network, int channel_idx, | ||
493 | int secondary_channel_idx, int tty_type) | ||
494 | { | ||
495 | ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); | ||
496 | if (!ttys[j]) | ||
497 | return -ENOMEM; | ||
498 | ttys[j]->index = j; | ||
499 | ttys[j]->hardware = hardware; | ||
500 | ttys[j]->channel_idx = channel_idx; | ||
501 | ttys[j]->secondary_channel_idx = secondary_channel_idx; | ||
502 | ttys[j]->network = network; | ||
503 | ttys[j]->tty_type = tty_type; | ||
504 | mutex_init(&ttys[j]->ipw_tty_mutex); | ||
505 | |||
506 | tty_register_device(ipw_tty_driver, j, NULL); | ||
507 | ipwireless_associate_network_tty(network, channel_idx, ttys[j]); | ||
508 | |||
509 | if (secondary_channel_idx != -1) | ||
510 | ipwireless_associate_network_tty(network, | ||
511 | secondary_channel_idx, | ||
512 | ttys[j]); | ||
513 | if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) | ||
514 | report_registering(ttys[j]); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware, | ||
519 | struct ipw_network *network) | ||
520 | { | ||
521 | int i, j; | ||
522 | |||
523 | for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) { | ||
524 | int allfree = 1; | ||
525 | |||
526 | for (j = i; j < IPWIRELESS_PCMCIA_MINORS; | ||
527 | j += IPWIRELESS_PCMCIA_MINOR_RANGE) | ||
528 | if (ttys[j] != NULL) { | ||
529 | allfree = 0; | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | if (allfree) { | ||
534 | j = i; | ||
535 | |||
536 | if (add_tty(j, hardware, network, | ||
537 | IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS, | ||
538 | TTYTYPE_MODEM)) | ||
539 | return NULL; | ||
540 | |||
541 | j += IPWIRELESS_PCMCIA_MINOR_RANGE; | ||
542 | if (add_tty(j, hardware, network, | ||
543 | IPW_CHANNEL_DIALLER, -1, | ||
544 | TTYTYPE_MONITOR)) | ||
545 | return NULL; | ||
546 | |||
547 | j += IPWIRELESS_PCMCIA_MINOR_RANGE; | ||
548 | if (add_tty(j, hardware, network, | ||
549 | IPW_CHANNEL_RAS, -1, | ||
550 | TTYTYPE_RAS_RAW)) | ||
551 | return NULL; | ||
552 | |||
553 | return ttys[i]; | ||
554 | } | ||
555 | } | ||
556 | return NULL; | ||
557 | } | ||
558 | |||
559 | /* | ||
560 | * Must be called before ipwireless_network_free(). | ||
561 | */ | ||
562 | void ipwireless_tty_free(struct ipw_tty *tty) | ||
563 | { | ||
564 | int j; | ||
565 | struct ipw_network *network = ttys[tty->index]->network; | ||
566 | |||
567 | for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; | ||
568 | j += IPWIRELESS_PCMCIA_MINOR_RANGE) { | ||
569 | struct ipw_tty *ttyj = ttys[j]; | ||
570 | |||
571 | if (ttyj) { | ||
572 | mutex_lock(&ttyj->ipw_tty_mutex); | ||
573 | if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) | ||
574 | report_deregistering(ttyj); | ||
575 | ttyj->closing = 1; | ||
576 | if (ttyj->linux_tty != NULL) { | ||
577 | mutex_unlock(&ttyj->ipw_tty_mutex); | ||
578 | tty_hangup(ttyj->linux_tty); | ||
579 | /* Wait till the tty_hangup has completed */ | ||
580 | flush_work_sync(&ttyj->linux_tty->hangup_work); | ||
581 | /* FIXME: Exactly how is the tty object locked here | ||
582 | against a parallel ioctl etc */ | ||
583 | mutex_lock(&ttyj->ipw_tty_mutex); | ||
584 | } | ||
585 | while (ttyj->open_count) | ||
586 | do_ipw_close(ttyj); | ||
587 | ipwireless_disassociate_network_ttys(network, | ||
588 | ttyj->channel_idx); | ||
589 | tty_unregister_device(ipw_tty_driver, j); | ||
590 | ttys[j] = NULL; | ||
591 | mutex_unlock(&ttyj->ipw_tty_mutex); | ||
592 | kfree(ttyj); | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | |||
597 | static const struct tty_operations tty_ops = { | ||
598 | .open = ipw_open, | ||
599 | .close = ipw_close, | ||
600 | .hangup = ipw_hangup, | ||
601 | .write = ipw_write, | ||
602 | .write_room = ipw_write_room, | ||
603 | .ioctl = ipw_ioctl, | ||
604 | .chars_in_buffer = ipw_chars_in_buffer, | ||
605 | .tiocmget = ipw_tiocmget, | ||
606 | .tiocmset = ipw_tiocmset, | ||
607 | }; | ||
608 | |||
609 | int ipwireless_tty_init(void) | ||
610 | { | ||
611 | int result; | ||
612 | |||
613 | ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); | ||
614 | if (!ipw_tty_driver) | ||
615 | return -ENOMEM; | ||
616 | |||
617 | ipw_tty_driver->owner = THIS_MODULE; | ||
618 | ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; | ||
619 | ipw_tty_driver->name = "ttyIPWp"; | ||
620 | ipw_tty_driver->major = 0; | ||
621 | ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; | ||
622 | ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
623 | ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; | ||
624 | ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
625 | ipw_tty_driver->init_termios = tty_std_termios; | ||
626 | ipw_tty_driver->init_termios.c_cflag = | ||
627 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
628 | ipw_tty_driver->init_termios.c_ispeed = 9600; | ||
629 | ipw_tty_driver->init_termios.c_ospeed = 9600; | ||
630 | tty_set_operations(ipw_tty_driver, &tty_ops); | ||
631 | result = tty_register_driver(ipw_tty_driver); | ||
632 | if (result) { | ||
633 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
634 | ": failed to register tty driver\n"); | ||
635 | put_tty_driver(ipw_tty_driver); | ||
636 | return result; | ||
637 | } | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | void ipwireless_tty_release(void) | ||
643 | { | ||
644 | int ret; | ||
645 | |||
646 | ret = tty_unregister_driver(ipw_tty_driver); | ||
647 | put_tty_driver(ipw_tty_driver); | ||
648 | if (ret != 0) | ||
649 | printk(KERN_ERR IPWIRELESS_PCCARD_NAME | ||
650 | ": tty_unregister_driver failed with code %d\n", ret); | ||
651 | } | ||
652 | |||
653 | int ipwireless_tty_is_modem(struct ipw_tty *tty) | ||
654 | { | ||
655 | return tty->tty_type == TTYTYPE_MODEM; | ||
656 | } | ||
657 | |||
658 | void | ||
659 | ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, | ||
660 | unsigned int channel_idx, | ||
661 | unsigned int control_lines, | ||
662 | unsigned int changed_mask) | ||
663 | { | ||
664 | unsigned int old_control_lines = tty->control_lines; | ||
665 | |||
666 | tty->control_lines = (tty->control_lines & ~changed_mask) | ||
667 | | (control_lines & changed_mask); | ||
668 | |||
669 | /* | ||
670 | * If DCD is de-asserted, we close the tty so pppd can tell that we | ||
671 | * have gone offline. | ||
672 | */ | ||
673 | if ((old_control_lines & IPW_CONTROL_LINE_DCD) | ||
674 | && !(tty->control_lines & IPW_CONTROL_LINE_DCD) | ||
675 | && tty->linux_tty) { | ||
676 | tty_hangup(tty->linux_tty); | ||
677 | } | ||
678 | } | ||
679 | |||
diff --git a/drivers/tty/ipwireless/tty.h b/drivers/tty/ipwireless/tty.h new file mode 100644 index 000000000000..747b2d637860 --- /dev/null +++ b/drivers/tty/ipwireless/tty.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * IPWireless 3G PCMCIA Network Driver | ||
3 | * | ||
4 | * Original code | ||
5 | * by Stephen Blackheath <stephen@blacksapphire.com>, | ||
6 | * Ben Martel <benm@symmetric.co.nz> | ||
7 | * | ||
8 | * Copyrighted as follows: | ||
9 | * Copyright (C) 2004 by Symmetric Systems Ltd (NZ) | ||
10 | * | ||
11 | * Various driver changes and rewrites, port to new kernels | ||
12 | * Copyright (C) 2006-2007 Jiri Kosina | ||
13 | * | ||
14 | * Misc code cleanups and updates | ||
15 | * Copyright (C) 2007 David Sterba | ||
16 | */ | ||
17 | |||
18 | #ifndef _IPWIRELESS_CS_TTY_H_ | ||
19 | #define _IPWIRELESS_CS_TTY_H_ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | ||
23 | |||
24 | #include <pcmcia/cistpl.h> | ||
25 | #include <pcmcia/ds.h> | ||
26 | |||
27 | struct ipw_tty; | ||
28 | struct ipw_network; | ||
29 | struct ipw_hardware; | ||
30 | |||
31 | int ipwireless_tty_init(void); | ||
32 | void ipwireless_tty_release(void); | ||
33 | |||
34 | struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw, | ||
35 | struct ipw_network *net); | ||
36 | void ipwireless_tty_free(struct ipw_tty *tty); | ||
37 | void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, | ||
38 | unsigned int length); | ||
39 | int ipwireless_tty_is_modem(struct ipw_tty *tty); | ||
40 | void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, | ||
41 | unsigned int channel_idx, | ||
42 | unsigned int control_lines, | ||
43 | unsigned int changed_mask); | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c new file mode 100644 index 000000000000..db1cf9c328d8 --- /dev/null +++ b/drivers/tty/isicom.c | |||
@@ -0,0 +1,1736 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or | ||
3 | * modify it under the terms of the GNU General Public License | ||
4 | * as published by the Free Software Foundation; either version | ||
5 | * 2 of the License, or (at your option) any later version. | ||
6 | * | ||
7 | * Original driver code supplied by Multi-Tech | ||
8 | * | ||
9 | * Changes | ||
10 | * 1/9/98 alan@lxorguk.ukuu.org.uk | ||
11 | * Merge to 2.0.x kernel tree | ||
12 | * Obtain and use official major/minors | ||
13 | * Loader switched to a misc device | ||
14 | * (fixed range check bug as a side effect) | ||
15 | * Printk clean up | ||
16 | * 9/12/98 alan@lxorguk.ukuu.org.uk | ||
17 | * Rough port to 2.1.x | ||
18 | * | ||
19 | * 10/6/99 sameer Merged the ISA and PCI drivers to | ||
20 | * a new unified driver. | ||
21 | * | ||
22 | * 3/9/99 sameer Added support for ISI4616 cards. | ||
23 | * | ||
24 | * 16/9/99 sameer We do not force RTS low anymore. | ||
25 | * This is to prevent the firmware | ||
26 | * from getting confused. | ||
27 | * | ||
28 | * 26/10/99 sameer Cosmetic changes:The driver now | ||
29 | * dumps the Port Count information | ||
30 | * along with I/O address and IRQ. | ||
31 | * | ||
32 | * 13/12/99 sameer Fixed the problem with IRQ sharing. | ||
33 | * | ||
34 | * 10/5/00 sameer Fixed isicom_shutdown_board() | ||
35 | * to not lower DTR on all the ports | ||
36 | * when the last port on the card is | ||
37 | * closed. | ||
38 | * | ||
39 | * 10/5/00 sameer Signal mask setup command added | ||
40 | * to isicom_setup_port and | ||
41 | * isicom_shutdown_port. | ||
42 | * | ||
43 | * 24/5/00 sameer The driver is now SMP aware. | ||
44 | * | ||
45 | * | ||
46 | * 27/11/00 Vinayak P Risbud Fixed the Driver Crash Problem | ||
47 | * | ||
48 | * | ||
49 | * 03/01/01 anil .s Added support for resetting the | ||
50 | * internal modems on ISI cards. | ||
51 | * | ||
52 | * 08/02/01 anil .s Upgraded the driver for kernel | ||
53 | * 2.4.x | ||
54 | * | ||
55 | * 11/04/01 Kevin Fixed firmware load problem with | ||
56 | * ISIHP-4X card | ||
57 | * | ||
58 | * 30/04/01 anil .s Fixed the remote login through | ||
59 | * ISI port problem. Now the link | ||
60 | * does not go down before password | ||
61 | * prompt. | ||
62 | * | ||
63 | * 03/05/01 anil .s Fixed the problem with IRQ sharing | ||
64 | * among ISI-PCI cards. | ||
65 | * | ||
66 | * 03/05/01 anil .s Added support to display the version | ||
67 | * info during insmod as well as module | ||
68 | * listing by lsmod. | ||
69 | * | ||
70 | * 10/05/01 anil .s Done the modifications to the source | ||
71 | * file and Install script so that the | ||
72 | * same installation can be used for | ||
73 | * 2.2.x and 2.4.x kernel. | ||
74 | * | ||
75 | * 06/06/01 anil .s Now we drop both dtr and rts during | ||
76 | * shutdown_port as well as raise them | ||
77 | * during isicom_config_port. | ||
78 | * | ||
79 | * 09/06/01 acme@conectiva.com.br use capable, not suser, do | ||
80 | * restore_flags on failure in | ||
81 | * isicom_send_break, verify put_user | ||
82 | * result | ||
83 | * | ||
84 | * 11/02/03 ranjeeth Added support for 230 Kbps and 460 Kbps | ||
85 | * Baud index extended to 21 | ||
86 | * | ||
87 | * 20/03/03 ranjeeth Made to work for Linux Advanced server. | ||
88 | * Taken care of license warning. | ||
89 | * | ||
90 | * 10/12/03 Ravindra Made to work for Fedora Core 1 of | ||
91 | * Red Hat Distribution | ||
92 | * | ||
93 | * 06/01/05 Alan Cox Merged the ISI and base kernel strands | ||
94 | * into a single 2.6 driver | ||
95 | * | ||
96 | * *********************************************************** | ||
97 | * | ||
98 | * To use this driver you also need the support package. You | ||
99 | * can find this in RPM format on | ||
100 | * ftp://ftp.linux.org.uk/pub/linux/alan | ||
101 | * | ||
102 | * You can find the original tools for this direct from Multitech | ||
103 | * ftp://ftp.multitech.com/ISI-Cards/ | ||
104 | * | ||
105 | * Having installed the cards the module options (/etc/modprobe.conf) | ||
106 | * | ||
107 | * options isicom io=card1,card2,card3,card4 irq=card1,card2,card3,card4 | ||
108 | * | ||
109 | * Omit those entries for boards you don't have installed. | ||
110 | * | ||
111 | * TODO | ||
112 | * Merge testing | ||
113 | * 64-bit verification | ||
114 | */ | ||
115 | |||
116 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
117 | |||
118 | #include <linux/module.h> | ||
119 | #include <linux/firmware.h> | ||
120 | #include <linux/kernel.h> | ||
121 | #include <linux/tty.h> | ||
122 | #include <linux/tty_flip.h> | ||
123 | #include <linux/termios.h> | ||
124 | #include <linux/fs.h> | ||
125 | #include <linux/sched.h> | ||
126 | #include <linux/serial.h> | ||
127 | #include <linux/mm.h> | ||
128 | #include <linux/interrupt.h> | ||
129 | #include <linux/timer.h> | ||
130 | #include <linux/delay.h> | ||
131 | #include <linux/ioport.h> | ||
132 | #include <linux/slab.h> | ||
133 | |||
134 | #include <linux/uaccess.h> | ||
135 | #include <linux/io.h> | ||
136 | #include <asm/system.h> | ||
137 | |||
138 | #include <linux/pci.h> | ||
139 | |||
140 | #include <linux/isicom.h> | ||
141 | |||
142 | #define InterruptTheCard(base) outw(0, (base) + 0xc) | ||
143 | #define ClearInterrupt(base) inw((base) + 0x0a) | ||
144 | |||
145 | #ifdef DEBUG | ||
146 | #define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c)) | ||
147 | #else | ||
148 | #define isicom_paranoia_check(a, b, c) 0 | ||
149 | #endif | ||
150 | |||
151 | static int isicom_probe(struct pci_dev *, const struct pci_device_id *); | ||
152 | static void __devexit isicom_remove(struct pci_dev *); | ||
153 | |||
154 | static struct pci_device_id isicom_pci_tbl[] = { | ||
155 | { PCI_DEVICE(VENDOR_ID, 0x2028) }, | ||
156 | { PCI_DEVICE(VENDOR_ID, 0x2051) }, | ||
157 | { PCI_DEVICE(VENDOR_ID, 0x2052) }, | ||
158 | { PCI_DEVICE(VENDOR_ID, 0x2053) }, | ||
159 | { PCI_DEVICE(VENDOR_ID, 0x2054) }, | ||
160 | { PCI_DEVICE(VENDOR_ID, 0x2055) }, | ||
161 | { PCI_DEVICE(VENDOR_ID, 0x2056) }, | ||
162 | { PCI_DEVICE(VENDOR_ID, 0x2057) }, | ||
163 | { PCI_DEVICE(VENDOR_ID, 0x2058) }, | ||
164 | { 0 } | ||
165 | }; | ||
166 | MODULE_DEVICE_TABLE(pci, isicom_pci_tbl); | ||
167 | |||
168 | static struct pci_driver isicom_driver = { | ||
169 | .name = "isicom", | ||
170 | .id_table = isicom_pci_tbl, | ||
171 | .probe = isicom_probe, | ||
172 | .remove = __devexit_p(isicom_remove) | ||
173 | }; | ||
174 | |||
175 | static int prev_card = 3; /* start servicing isi_card[0] */ | ||
176 | static struct tty_driver *isicom_normal; | ||
177 | |||
178 | static void isicom_tx(unsigned long _data); | ||
179 | static void isicom_start(struct tty_struct *tty); | ||
180 | |||
181 | static DEFINE_TIMER(tx, isicom_tx, 0, 0); | ||
182 | |||
183 | /* baud index mappings from linux defns to isi */ | ||
184 | |||
185 | static signed char linuxb_to_isib[] = { | ||
186 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21 | ||
187 | }; | ||
188 | |||
189 | struct isi_board { | ||
190 | unsigned long base; | ||
191 | int irq; | ||
192 | unsigned char port_count; | ||
193 | unsigned short status; | ||
194 | unsigned short port_status; /* each bit for each port */ | ||
195 | unsigned short shift_count; | ||
196 | struct isi_port *ports; | ||
197 | signed char count; | ||
198 | spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ | ||
199 | unsigned long flags; | ||
200 | unsigned int index; | ||
201 | }; | ||
202 | |||
203 | struct isi_port { | ||
204 | unsigned short magic; | ||
205 | struct tty_port port; | ||
206 | u16 channel; | ||
207 | u16 status; | ||
208 | struct isi_board *card; | ||
209 | unsigned char *xmit_buf; | ||
210 | int xmit_head; | ||
211 | int xmit_tail; | ||
212 | int xmit_cnt; | ||
213 | }; | ||
214 | |||
215 | static struct isi_board isi_card[BOARD_COUNT]; | ||
216 | static struct isi_port isi_ports[PORT_COUNT]; | ||
217 | |||
218 | /* | ||
219 | * Locking functions for card level locking. We need to own both | ||
220 | * the kernel lock for the card and have the card in a position that | ||
221 | * it wants to talk. | ||
222 | */ | ||
223 | |||
224 | static inline int WaitTillCardIsFree(unsigned long base) | ||
225 | { | ||
226 | unsigned int count = 0; | ||
227 | unsigned int a = in_atomic(); /* do we run under spinlock? */ | ||
228 | |||
229 | while (!(inw(base + 0xe) & 0x1) && count++ < 100) | ||
230 | if (a) | ||
231 | mdelay(1); | ||
232 | else | ||
233 | msleep(1); | ||
234 | |||
235 | return !(inw(base + 0xe) & 0x1); | ||
236 | } | ||
237 | |||
238 | static int lock_card(struct isi_board *card) | ||
239 | { | ||
240 | unsigned long base = card->base; | ||
241 | unsigned int retries, a; | ||
242 | |||
243 | for (retries = 0; retries < 10; retries++) { | ||
244 | spin_lock_irqsave(&card->card_lock, card->flags); | ||
245 | for (a = 0; a < 10; a++) { | ||
246 | if (inw(base + 0xe) & 0x1) | ||
247 | return 1; | ||
248 | udelay(10); | ||
249 | } | ||
250 | spin_unlock_irqrestore(&card->card_lock, card->flags); | ||
251 | msleep(10); | ||
252 | } | ||
253 | pr_warning("Failed to lock Card (0x%lx)\n", card->base); | ||
254 | |||
255 | return 0; /* Failed to acquire the card! */ | ||
256 | } | ||
257 | |||
258 | static void unlock_card(struct isi_board *card) | ||
259 | { | ||
260 | spin_unlock_irqrestore(&card->card_lock, card->flags); | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * ISI Card specific ops ... | ||
265 | */ | ||
266 | |||
267 | /* card->lock HAS to be held */ | ||
268 | static void raise_dtr(struct isi_port *port) | ||
269 | { | ||
270 | struct isi_board *card = port->card; | ||
271 | unsigned long base = card->base; | ||
272 | u16 channel = port->channel; | ||
273 | |||
274 | if (WaitTillCardIsFree(base)) | ||
275 | return; | ||
276 | |||
277 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
278 | outw(0x0504, base); | ||
279 | InterruptTheCard(base); | ||
280 | port->status |= ISI_DTR; | ||
281 | } | ||
282 | |||
283 | /* card->lock HAS to be held */ | ||
284 | static inline void drop_dtr(struct isi_port *port) | ||
285 | { | ||
286 | struct isi_board *card = port->card; | ||
287 | unsigned long base = card->base; | ||
288 | u16 channel = port->channel; | ||
289 | |||
290 | if (WaitTillCardIsFree(base)) | ||
291 | return; | ||
292 | |||
293 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
294 | outw(0x0404, base); | ||
295 | InterruptTheCard(base); | ||
296 | port->status &= ~ISI_DTR; | ||
297 | } | ||
298 | |||
299 | /* card->lock HAS to be held */ | ||
300 | static inline void raise_rts(struct isi_port *port) | ||
301 | { | ||
302 | struct isi_board *card = port->card; | ||
303 | unsigned long base = card->base; | ||
304 | u16 channel = port->channel; | ||
305 | |||
306 | if (WaitTillCardIsFree(base)) | ||
307 | return; | ||
308 | |||
309 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
310 | outw(0x0a04, base); | ||
311 | InterruptTheCard(base); | ||
312 | port->status |= ISI_RTS; | ||
313 | } | ||
314 | |||
315 | /* card->lock HAS to be held */ | ||
316 | static inline void drop_rts(struct isi_port *port) | ||
317 | { | ||
318 | struct isi_board *card = port->card; | ||
319 | unsigned long base = card->base; | ||
320 | u16 channel = port->channel; | ||
321 | |||
322 | if (WaitTillCardIsFree(base)) | ||
323 | return; | ||
324 | |||
325 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
326 | outw(0x0804, base); | ||
327 | InterruptTheCard(base); | ||
328 | port->status &= ~ISI_RTS; | ||
329 | } | ||
330 | |||
331 | /* card->lock MUST NOT be held */ | ||
332 | |||
333 | static void isicom_dtr_rts(struct tty_port *port, int on) | ||
334 | { | ||
335 | struct isi_port *ip = container_of(port, struct isi_port, port); | ||
336 | struct isi_board *card = ip->card; | ||
337 | unsigned long base = card->base; | ||
338 | u16 channel = ip->channel; | ||
339 | |||
340 | if (!lock_card(card)) | ||
341 | return; | ||
342 | |||
343 | if (on) { | ||
344 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
345 | outw(0x0f04, base); | ||
346 | InterruptTheCard(base); | ||
347 | ip->status |= (ISI_DTR | ISI_RTS); | ||
348 | } else { | ||
349 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
350 | outw(0x0C04, base); | ||
351 | InterruptTheCard(base); | ||
352 | ip->status &= ~(ISI_DTR | ISI_RTS); | ||
353 | } | ||
354 | unlock_card(card); | ||
355 | } | ||
356 | |||
357 | /* card->lock HAS to be held */ | ||
358 | static void drop_dtr_rts(struct isi_port *port) | ||
359 | { | ||
360 | struct isi_board *card = port->card; | ||
361 | unsigned long base = card->base; | ||
362 | u16 channel = port->channel; | ||
363 | |||
364 | if (WaitTillCardIsFree(base)) | ||
365 | return; | ||
366 | |||
367 | outw(0x8000 | (channel << card->shift_count) | 0x02, base); | ||
368 | outw(0x0c04, base); | ||
369 | InterruptTheCard(base); | ||
370 | port->status &= ~(ISI_RTS | ISI_DTR); | ||
371 | } | ||
372 | |||
373 | /* | ||
374 | * ISICOM Driver specific routines ... | ||
375 | * | ||
376 | */ | ||
377 | |||
378 | static inline int __isicom_paranoia_check(struct isi_port const *port, | ||
379 | char *name, const char *routine) | ||
380 | { | ||
381 | if (!port) { | ||
382 | pr_warning("Warning: bad isicom magic for dev %s in %s.\n", | ||
383 | name, routine); | ||
384 | return 1; | ||
385 | } | ||
386 | if (port->magic != ISICOM_MAGIC) { | ||
387 | pr_warning("Warning: NULL isicom port for dev %s in %s.\n", | ||
388 | name, routine); | ||
389 | return 1; | ||
390 | } | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Transmitter. | ||
397 | * | ||
398 | * We shovel data into the card buffers on a regular basis. The card | ||
399 | * will do the rest of the work for us. | ||
400 | */ | ||
401 | |||
402 | static void isicom_tx(unsigned long _data) | ||
403 | { | ||
404 | unsigned long flags, base; | ||
405 | unsigned int retries; | ||
406 | short count = (BOARD_COUNT-1), card; | ||
407 | short txcount, wrd, residue, word_count, cnt; | ||
408 | struct isi_port *port; | ||
409 | struct tty_struct *tty; | ||
410 | |||
411 | /* find next active board */ | ||
412 | card = (prev_card + 1) & 0x0003; | ||
413 | while (count-- > 0) { | ||
414 | if (isi_card[card].status & BOARD_ACTIVE) | ||
415 | break; | ||
416 | card = (card + 1) & 0x0003; | ||
417 | } | ||
418 | if (!(isi_card[card].status & BOARD_ACTIVE)) | ||
419 | goto sched_again; | ||
420 | |||
421 | prev_card = card; | ||
422 | |||
423 | count = isi_card[card].port_count; | ||
424 | port = isi_card[card].ports; | ||
425 | base = isi_card[card].base; | ||
426 | |||
427 | spin_lock_irqsave(&isi_card[card].card_lock, flags); | ||
428 | for (retries = 0; retries < 100; retries++) { | ||
429 | if (inw(base + 0xe) & 0x1) | ||
430 | break; | ||
431 | udelay(2); | ||
432 | } | ||
433 | if (retries >= 100) | ||
434 | goto unlock; | ||
435 | |||
436 | tty = tty_port_tty_get(&port->port); | ||
437 | if (tty == NULL) | ||
438 | goto put_unlock; | ||
439 | |||
440 | for (; count > 0; count--, port++) { | ||
441 | /* port not active or tx disabled to force flow control */ | ||
442 | if (!(port->port.flags & ASYNC_INITIALIZED) || | ||
443 | !(port->status & ISI_TXOK)) | ||
444 | continue; | ||
445 | |||
446 | txcount = min_t(short, TX_SIZE, port->xmit_cnt); | ||
447 | if (txcount <= 0 || tty->stopped || tty->hw_stopped) | ||
448 | continue; | ||
449 | |||
450 | if (!(inw(base + 0x02) & (1 << port->channel))) | ||
451 | continue; | ||
452 | |||
453 | pr_debug("txing %d bytes, port%d.\n", | ||
454 | txcount, port->channel + 1); | ||
455 | outw((port->channel << isi_card[card].shift_count) | txcount, | ||
456 | base); | ||
457 | residue = NO; | ||
458 | wrd = 0; | ||
459 | while (1) { | ||
460 | cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE | ||
461 | - port->xmit_tail)); | ||
462 | if (residue == YES) { | ||
463 | residue = NO; | ||
464 | if (cnt > 0) { | ||
465 | wrd |= (port->port.xmit_buf[port->xmit_tail] | ||
466 | << 8); | ||
467 | port->xmit_tail = (port->xmit_tail + 1) | ||
468 | & (SERIAL_XMIT_SIZE - 1); | ||
469 | port->xmit_cnt--; | ||
470 | txcount--; | ||
471 | cnt--; | ||
472 | outw(wrd, base); | ||
473 | } else { | ||
474 | outw(wrd, base); | ||
475 | break; | ||
476 | } | ||
477 | } | ||
478 | if (cnt <= 0) | ||
479 | break; | ||
480 | word_count = cnt >> 1; | ||
481 | outsw(base, port->port.xmit_buf+port->xmit_tail, word_count); | ||
482 | port->xmit_tail = (port->xmit_tail | ||
483 | + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); | ||
484 | txcount -= (word_count << 1); | ||
485 | port->xmit_cnt -= (word_count << 1); | ||
486 | if (cnt & 0x0001) { | ||
487 | residue = YES; | ||
488 | wrd = port->port.xmit_buf[port->xmit_tail]; | ||
489 | port->xmit_tail = (port->xmit_tail + 1) | ||
490 | & (SERIAL_XMIT_SIZE - 1); | ||
491 | port->xmit_cnt--; | ||
492 | txcount--; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | InterruptTheCard(base); | ||
497 | if (port->xmit_cnt <= 0) | ||
498 | port->status &= ~ISI_TXOK; | ||
499 | if (port->xmit_cnt <= WAKEUP_CHARS) | ||
500 | tty_wakeup(tty); | ||
501 | } | ||
502 | |||
503 | put_unlock: | ||
504 | tty_kref_put(tty); | ||
505 | unlock: | ||
506 | spin_unlock_irqrestore(&isi_card[card].card_lock, flags); | ||
507 | /* schedule another tx for hopefully in about 10ms */ | ||
508 | sched_again: | ||
509 | mod_timer(&tx, jiffies + msecs_to_jiffies(10)); | ||
510 | } | ||
511 | |||
512 | /* | ||
513 | * Main interrupt handler routine | ||
514 | */ | ||
515 | |||
516 | static irqreturn_t isicom_interrupt(int irq, void *dev_id) | ||
517 | { | ||
518 | struct isi_board *card = dev_id; | ||
519 | struct isi_port *port; | ||
520 | struct tty_struct *tty; | ||
521 | unsigned long base; | ||
522 | u16 header, word_count, count, channel; | ||
523 | short byte_count; | ||
524 | unsigned char *rp; | ||
525 | |||
526 | if (!card || !(card->status & FIRMWARE_LOADED)) | ||
527 | return IRQ_NONE; | ||
528 | |||
529 | base = card->base; | ||
530 | |||
531 | /* did the card interrupt us? */ | ||
532 | if (!(inw(base + 0x0e) & 0x02)) | ||
533 | return IRQ_NONE; | ||
534 | |||
535 | spin_lock(&card->card_lock); | ||
536 | |||
537 | /* | ||
538 | * disable any interrupts from the PCI card and lower the | ||
539 | * interrupt line | ||
540 | */ | ||
541 | outw(0x8000, base+0x04); | ||
542 | ClearInterrupt(base); | ||
543 | |||
544 | inw(base); /* get the dummy word out */ | ||
545 | header = inw(base); | ||
546 | channel = (header & 0x7800) >> card->shift_count; | ||
547 | byte_count = header & 0xff; | ||
548 | |||
549 | if (channel + 1 > card->port_count) { | ||
550 | pr_warning("%s(0x%lx): %d(channel) > port_count.\n", | ||
551 | __func__, base, channel+1); | ||
552 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
553 | spin_unlock(&card->card_lock); | ||
554 | return IRQ_HANDLED; | ||
555 | } | ||
556 | port = card->ports + channel; | ||
557 | if (!(port->port.flags & ASYNC_INITIALIZED)) { | ||
558 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
559 | spin_unlock(&card->card_lock); | ||
560 | return IRQ_HANDLED; | ||
561 | } | ||
562 | |||
563 | tty = tty_port_tty_get(&port->port); | ||
564 | if (tty == NULL) { | ||
565 | word_count = byte_count >> 1; | ||
566 | while (byte_count > 1) { | ||
567 | inw(base); | ||
568 | byte_count -= 2; | ||
569 | } | ||
570 | if (byte_count & 0x01) | ||
571 | inw(base); | ||
572 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
573 | spin_unlock(&card->card_lock); | ||
574 | return IRQ_HANDLED; | ||
575 | } | ||
576 | |||
577 | if (header & 0x8000) { /* Status Packet */ | ||
578 | header = inw(base); | ||
579 | switch (header & 0xff) { | ||
580 | case 0: /* Change in EIA signals */ | ||
581 | if (port->port.flags & ASYNC_CHECK_CD) { | ||
582 | if (port->status & ISI_DCD) { | ||
583 | if (!(header & ISI_DCD)) { | ||
584 | /* Carrier has been lost */ | ||
585 | pr_debug("%s: DCD->low.\n", | ||
586 | __func__); | ||
587 | port->status &= ~ISI_DCD; | ||
588 | tty_hangup(tty); | ||
589 | } | ||
590 | } else if (header & ISI_DCD) { | ||
591 | /* Carrier has been detected */ | ||
592 | pr_debug("%s: DCD->high.\n", | ||
593 | __func__); | ||
594 | port->status |= ISI_DCD; | ||
595 | wake_up_interruptible(&port->port.open_wait); | ||
596 | } | ||
597 | } else { | ||
598 | if (header & ISI_DCD) | ||
599 | port->status |= ISI_DCD; | ||
600 | else | ||
601 | port->status &= ~ISI_DCD; | ||
602 | } | ||
603 | |||
604 | if (port->port.flags & ASYNC_CTS_FLOW) { | ||
605 | if (tty->hw_stopped) { | ||
606 | if (header & ISI_CTS) { | ||
607 | port->port.tty->hw_stopped = 0; | ||
608 | /* start tx ing */ | ||
609 | port->status |= (ISI_TXOK | ||
610 | | ISI_CTS); | ||
611 | tty_wakeup(tty); | ||
612 | } | ||
613 | } else if (!(header & ISI_CTS)) { | ||
614 | tty->hw_stopped = 1; | ||
615 | /* stop tx ing */ | ||
616 | port->status &= ~(ISI_TXOK | ISI_CTS); | ||
617 | } | ||
618 | } else { | ||
619 | if (header & ISI_CTS) | ||
620 | port->status |= ISI_CTS; | ||
621 | else | ||
622 | port->status &= ~ISI_CTS; | ||
623 | } | ||
624 | |||
625 | if (header & ISI_DSR) | ||
626 | port->status |= ISI_DSR; | ||
627 | else | ||
628 | port->status &= ~ISI_DSR; | ||
629 | |||
630 | if (header & ISI_RI) | ||
631 | port->status |= ISI_RI; | ||
632 | else | ||
633 | port->status &= ~ISI_RI; | ||
634 | |||
635 | break; | ||
636 | |||
637 | case 1: /* Received Break !!! */ | ||
638 | tty_insert_flip_char(tty, 0, TTY_BREAK); | ||
639 | if (port->port.flags & ASYNC_SAK) | ||
640 | do_SAK(tty); | ||
641 | tty_flip_buffer_push(tty); | ||
642 | break; | ||
643 | |||
644 | case 2: /* Statistics */ | ||
645 | pr_debug("%s: stats!!!\n", __func__); | ||
646 | break; | ||
647 | |||
648 | default: | ||
649 | pr_debug("%s: Unknown code in status packet.\n", | ||
650 | __func__); | ||
651 | break; | ||
652 | } | ||
653 | } else { /* Data Packet */ | ||
654 | |||
655 | count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); | ||
656 | pr_debug("%s: Can rx %d of %d bytes.\n", | ||
657 | __func__, count, byte_count); | ||
658 | word_count = count >> 1; | ||
659 | insw(base, rp, word_count); | ||
660 | byte_count -= (word_count << 1); | ||
661 | if (count & 0x0001) { | ||
662 | tty_insert_flip_char(tty, inw(base) & 0xff, | ||
663 | TTY_NORMAL); | ||
664 | byte_count -= 2; | ||
665 | } | ||
666 | if (byte_count > 0) { | ||
667 | pr_debug("%s(0x%lx:%d): Flip buffer overflow! dropping bytes...\n", | ||
668 | __func__, base, channel + 1); | ||
669 | /* drain out unread xtra data */ | ||
670 | while (byte_count > 0) { | ||
671 | inw(base); | ||
672 | byte_count -= 2; | ||
673 | } | ||
674 | } | ||
675 | tty_flip_buffer_push(tty); | ||
676 | } | ||
677 | outw(0x0000, base+0x04); /* enable interrupts */ | ||
678 | spin_unlock(&card->card_lock); | ||
679 | tty_kref_put(tty); | ||
680 | |||
681 | return IRQ_HANDLED; | ||
682 | } | ||
683 | |||
684 | static void isicom_config_port(struct tty_struct *tty) | ||
685 | { | ||
686 | struct isi_port *port = tty->driver_data; | ||
687 | struct isi_board *card = port->card; | ||
688 | unsigned long baud; | ||
689 | unsigned long base = card->base; | ||
690 | u16 channel_setup, channel = port->channel, | ||
691 | shift_count = card->shift_count; | ||
692 | unsigned char flow_ctrl; | ||
693 | |||
694 | /* FIXME: Switch to new tty baud API */ | ||
695 | baud = C_BAUD(tty); | ||
696 | if (baud & CBAUDEX) { | ||
697 | baud &= ~CBAUDEX; | ||
698 | |||
699 | /* if CBAUDEX bit is on and the baud is set to either 50 or 75 | ||
700 | * then the card is programmed for 57.6Kbps or 115Kbps | ||
701 | * respectively. | ||
702 | */ | ||
703 | |||
704 | /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ | ||
705 | if (baud < 1 || baud > 4) | ||
706 | tty->termios->c_cflag &= ~CBAUDEX; | ||
707 | else | ||
708 | baud += 15; | ||
709 | } | ||
710 | if (baud == 15) { | ||
711 | |||
712 | /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set | ||
713 | * by the set_serial_info ioctl ... this is done by | ||
714 | * the 'setserial' utility. | ||
715 | */ | ||
716 | |||
717 | if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) | ||
718 | baud++; /* 57.6 Kbps */ | ||
719 | if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) | ||
720 | baud += 2; /* 115 Kbps */ | ||
721 | if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) | ||
722 | baud += 3; /* 230 kbps*/ | ||
723 | if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) | ||
724 | baud += 4; /* 460 kbps*/ | ||
725 | } | ||
726 | if (linuxb_to_isib[baud] == -1) { | ||
727 | /* hang up */ | ||
728 | drop_dtr(port); | ||
729 | return; | ||
730 | } else | ||
731 | raise_dtr(port); | ||
732 | |||
733 | if (WaitTillCardIsFree(base) == 0) { | ||
734 | outw(0x8000 | (channel << shift_count) | 0x03, base); | ||
735 | outw(linuxb_to_isib[baud] << 8 | 0x03, base); | ||
736 | channel_setup = 0; | ||
737 | switch (C_CSIZE(tty)) { | ||
738 | case CS5: | ||
739 | channel_setup |= ISICOM_CS5; | ||
740 | break; | ||
741 | case CS6: | ||
742 | channel_setup |= ISICOM_CS6; | ||
743 | break; | ||
744 | case CS7: | ||
745 | channel_setup |= ISICOM_CS7; | ||
746 | break; | ||
747 | case CS8: | ||
748 | channel_setup |= ISICOM_CS8; | ||
749 | break; | ||
750 | } | ||
751 | |||
752 | if (C_CSTOPB(tty)) | ||
753 | channel_setup |= ISICOM_2SB; | ||
754 | if (C_PARENB(tty)) { | ||
755 | channel_setup |= ISICOM_EVPAR; | ||
756 | if (C_PARODD(tty)) | ||
757 | channel_setup |= ISICOM_ODPAR; | ||
758 | } | ||
759 | outw(channel_setup, base); | ||
760 | InterruptTheCard(base); | ||
761 | } | ||
762 | if (C_CLOCAL(tty)) | ||
763 | port->port.flags &= ~ASYNC_CHECK_CD; | ||
764 | else | ||
765 | port->port.flags |= ASYNC_CHECK_CD; | ||
766 | |||
767 | /* flow control settings ...*/ | ||
768 | flow_ctrl = 0; | ||
769 | port->port.flags &= ~ASYNC_CTS_FLOW; | ||
770 | if (C_CRTSCTS(tty)) { | ||
771 | port->port.flags |= ASYNC_CTS_FLOW; | ||
772 | flow_ctrl |= ISICOM_CTSRTS; | ||
773 | } | ||
774 | if (I_IXON(tty)) | ||
775 | flow_ctrl |= ISICOM_RESPOND_XONXOFF; | ||
776 | if (I_IXOFF(tty)) | ||
777 | flow_ctrl |= ISICOM_INITIATE_XONXOFF; | ||
778 | |||
779 | if (WaitTillCardIsFree(base) == 0) { | ||
780 | outw(0x8000 | (channel << shift_count) | 0x04, base); | ||
781 | outw(flow_ctrl << 8 | 0x05, base); | ||
782 | outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); | ||
783 | InterruptTheCard(base); | ||
784 | } | ||
785 | |||
786 | /* rx enabled -> enable port for rx on the card */ | ||
787 | if (C_CREAD(tty)) { | ||
788 | card->port_status |= (1 << channel); | ||
789 | outw(card->port_status, base + 0x02); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | /* open et all */ | ||
794 | |||
795 | static inline void isicom_setup_board(struct isi_board *bp) | ||
796 | { | ||
797 | int channel; | ||
798 | struct isi_port *port; | ||
799 | |||
800 | bp->count++; | ||
801 | if (!(bp->status & BOARD_INIT)) { | ||
802 | port = bp->ports; | ||
803 | for (channel = 0; channel < bp->port_count; channel++, port++) | ||
804 | drop_dtr_rts(port); | ||
805 | } | ||
806 | bp->status |= BOARD_ACTIVE | BOARD_INIT; | ||
807 | } | ||
808 | |||
809 | /* Activate and thus setup board are protected from races against shutdown | ||
810 | by the tty_port mutex */ | ||
811 | |||
812 | static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) | ||
813 | { | ||
814 | struct isi_port *port = container_of(tport, struct isi_port, port); | ||
815 | struct isi_board *card = port->card; | ||
816 | unsigned long flags; | ||
817 | |||
818 | if (tty_port_alloc_xmit_buf(tport) < 0) | ||
819 | return -ENOMEM; | ||
820 | |||
821 | spin_lock_irqsave(&card->card_lock, flags); | ||
822 | isicom_setup_board(card); | ||
823 | |||
824 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; | ||
825 | |||
826 | /* discard any residual data */ | ||
827 | if (WaitTillCardIsFree(card->base) == 0) { | ||
828 | outw(0x8000 | (port->channel << card->shift_count) | 0x02, | ||
829 | card->base); | ||
830 | outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base); | ||
831 | InterruptTheCard(card->base); | ||
832 | } | ||
833 | isicom_config_port(tty); | ||
834 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
835 | |||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static int isicom_carrier_raised(struct tty_port *port) | ||
840 | { | ||
841 | struct isi_port *ip = container_of(port, struct isi_port, port); | ||
842 | return (ip->status & ISI_DCD)?1 : 0; | ||
843 | } | ||
844 | |||
845 | static struct tty_port *isicom_find_port(struct tty_struct *tty) | ||
846 | { | ||
847 | struct isi_port *port; | ||
848 | struct isi_board *card; | ||
849 | unsigned int board; | ||
850 | int line = tty->index; | ||
851 | |||
852 | if (line < 0 || line > PORT_COUNT-1) | ||
853 | return NULL; | ||
854 | board = BOARD(line); | ||
855 | card = &isi_card[board]; | ||
856 | |||
857 | if (!(card->status & FIRMWARE_LOADED)) | ||
858 | return NULL; | ||
859 | |||
860 | /* open on a port greater than the port count for the card !!! */ | ||
861 | if (line > ((board * 16) + card->port_count - 1)) | ||
862 | return NULL; | ||
863 | |||
864 | port = &isi_ports[line]; | ||
865 | if (isicom_paranoia_check(port, tty->name, "isicom_open")) | ||
866 | return NULL; | ||
867 | |||
868 | return &port->port; | ||
869 | } | ||
870 | |||
871 | static int isicom_open(struct tty_struct *tty, struct file *filp) | ||
872 | { | ||
873 | struct isi_port *port; | ||
874 | struct tty_port *tport; | ||
875 | |||
876 | tport = isicom_find_port(tty); | ||
877 | if (tport == NULL) | ||
878 | return -ENODEV; | ||
879 | port = container_of(tport, struct isi_port, port); | ||
880 | |||
881 | tty->driver_data = port; | ||
882 | return tty_port_open(tport, tty, filp); | ||
883 | } | ||
884 | |||
885 | /* close et all */ | ||
886 | |||
887 | /* card->lock HAS to be held */ | ||
888 | static void isicom_shutdown_port(struct isi_port *port) | ||
889 | { | ||
890 | struct isi_board *card = port->card; | ||
891 | |||
892 | if (--card->count < 0) { | ||
893 | pr_debug("%s: bad board(0x%lx) count %d.\n", | ||
894 | __func__, card->base, card->count); | ||
895 | card->count = 0; | ||
896 | } | ||
897 | /* last port was closed, shutdown that board too */ | ||
898 | if (!card->count) | ||
899 | card->status &= BOARD_ACTIVE; | ||
900 | } | ||
901 | |||
902 | static void isicom_flush_buffer(struct tty_struct *tty) | ||
903 | { | ||
904 | struct isi_port *port = tty->driver_data; | ||
905 | struct isi_board *card = port->card; | ||
906 | unsigned long flags; | ||
907 | |||
908 | if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) | ||
909 | return; | ||
910 | |||
911 | spin_lock_irqsave(&card->card_lock, flags); | ||
912 | port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; | ||
913 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
914 | |||
915 | tty_wakeup(tty); | ||
916 | } | ||
917 | |||
918 | static void isicom_shutdown(struct tty_port *port) | ||
919 | { | ||
920 | struct isi_port *ip = container_of(port, struct isi_port, port); | ||
921 | struct isi_board *card = ip->card; | ||
922 | unsigned long flags; | ||
923 | |||
924 | /* indicate to the card that no more data can be received | ||
925 | on this port */ | ||
926 | spin_lock_irqsave(&card->card_lock, flags); | ||
927 | card->port_status &= ~(1 << ip->channel); | ||
928 | outw(card->port_status, card->base + 0x02); | ||
929 | isicom_shutdown_port(ip); | ||
930 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
931 | tty_port_free_xmit_buf(port); | ||
932 | } | ||
933 | |||
934 | static void isicom_close(struct tty_struct *tty, struct file *filp) | ||
935 | { | ||
936 | struct isi_port *ip = tty->driver_data; | ||
937 | struct tty_port *port; | ||
938 | |||
939 | if (ip == NULL) | ||
940 | return; | ||
941 | |||
942 | port = &ip->port; | ||
943 | if (isicom_paranoia_check(ip, tty->name, "isicom_close")) | ||
944 | return; | ||
945 | tty_port_close(port, tty, filp); | ||
946 | } | ||
947 | |||
948 | /* write et all */ | ||
949 | static int isicom_write(struct tty_struct *tty, const unsigned char *buf, | ||
950 | int count) | ||
951 | { | ||
952 | struct isi_port *port = tty->driver_data; | ||
953 | struct isi_board *card = port->card; | ||
954 | unsigned long flags; | ||
955 | int cnt, total = 0; | ||
956 | |||
957 | if (isicom_paranoia_check(port, tty->name, "isicom_write")) | ||
958 | return 0; | ||
959 | |||
960 | spin_lock_irqsave(&card->card_lock, flags); | ||
961 | |||
962 | while (1) { | ||
963 | cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt | ||
964 | - 1, SERIAL_XMIT_SIZE - port->xmit_head)); | ||
965 | if (cnt <= 0) | ||
966 | break; | ||
967 | |||
968 | memcpy(port->port.xmit_buf + port->xmit_head, buf, cnt); | ||
969 | port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE | ||
970 | - 1); | ||
971 | port->xmit_cnt += cnt; | ||
972 | buf += cnt; | ||
973 | count -= cnt; | ||
974 | total += cnt; | ||
975 | } | ||
976 | if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) | ||
977 | port->status |= ISI_TXOK; | ||
978 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
979 | return total; | ||
980 | } | ||
981 | |||
982 | /* put_char et all */ | ||
983 | static int isicom_put_char(struct tty_struct *tty, unsigned char ch) | ||
984 | { | ||
985 | struct isi_port *port = tty->driver_data; | ||
986 | struct isi_board *card = port->card; | ||
987 | unsigned long flags; | ||
988 | |||
989 | if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) | ||
990 | return 0; | ||
991 | |||
992 | spin_lock_irqsave(&card->card_lock, flags); | ||
993 | if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { | ||
994 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | port->port.xmit_buf[port->xmit_head++] = ch; | ||
999 | port->xmit_head &= (SERIAL_XMIT_SIZE - 1); | ||
1000 | port->xmit_cnt++; | ||
1001 | spin_unlock_irqrestore(&card->card_lock, flags); | ||
1002 | return 1; | ||
1003 | } | ||
1004 | |||
1005 | /* flush_chars et all */ | ||
1006 | static void isicom_flush_chars(struct tty_struct *tty) | ||
1007 | { | ||
1008 | struct isi_port *port = tty->driver_data; | ||
1009 | |||
1010 | if (isicom_paranoia_check(port, tty->name, "isicom_flush_chars")) | ||
1011 | return; | ||
1012 | |||
1013 | if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || | ||
1014 | !port->port.xmit_buf) | ||
1015 | return; | ||
1016 | |||
1017 | /* this tells the transmitter to consider this port for | ||
1018 | data output to the card ... that's the best we can do. */ | ||
1019 | port->status |= ISI_TXOK; | ||
1020 | } | ||
1021 | |||
1022 | /* write_room et all */ | ||
1023 | static int isicom_write_room(struct tty_struct *tty) | ||
1024 | { | ||
1025 | struct isi_port *port = tty->driver_data; | ||
1026 | int free; | ||
1027 | |||
1028 | if (isicom_paranoia_check(port, tty->name, "isicom_write_room")) | ||
1029 | return 0; | ||
1030 | |||
1031 | free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; | ||
1032 | if (free < 0) | ||
1033 | free = 0; | ||
1034 | return free; | ||
1035 | } | ||
1036 | |||
1037 | /* chars_in_buffer et all */ | ||
1038 | static int isicom_chars_in_buffer(struct tty_struct *tty) | ||
1039 | { | ||
1040 | struct isi_port *port = tty->driver_data; | ||
1041 | if (isicom_paranoia_check(port, tty->name, "isicom_chars_in_buffer")) | ||
1042 | return 0; | ||
1043 | return port->xmit_cnt; | ||
1044 | } | ||
1045 | |||
1046 | /* ioctl et all */ | ||
1047 | static int isicom_send_break(struct tty_struct *tty, int length) | ||
1048 | { | ||
1049 | struct isi_port *port = tty->driver_data; | ||
1050 | struct isi_board *card = port->card; | ||
1051 | unsigned long base = card->base; | ||
1052 | |||
1053 | if (length == -1) | ||
1054 | return -EOPNOTSUPP; | ||
1055 | |||
1056 | if (!lock_card(card)) | ||
1057 | return -EINVAL; | ||
1058 | |||
1059 | outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); | ||
1060 | outw((length & 0xff) << 8 | 0x00, base); | ||
1061 | outw((length & 0xff00), base); | ||
1062 | InterruptTheCard(base); | ||
1063 | |||
1064 | unlock_card(card); | ||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | static int isicom_tiocmget(struct tty_struct *tty) | ||
1069 | { | ||
1070 | struct isi_port *port = tty->driver_data; | ||
1071 | /* just send the port status */ | ||
1072 | u16 status = port->status; | ||
1073 | |||
1074 | if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | return ((status & ISI_RTS) ? TIOCM_RTS : 0) | | ||
1078 | ((status & ISI_DTR) ? TIOCM_DTR : 0) | | ||
1079 | ((status & ISI_DCD) ? TIOCM_CAR : 0) | | ||
1080 | ((status & ISI_DSR) ? TIOCM_DSR : 0) | | ||
1081 | ((status & ISI_CTS) ? TIOCM_CTS : 0) | | ||
1082 | ((status & ISI_RI ) ? TIOCM_RI : 0); | ||
1083 | } | ||
1084 | |||
1085 | static int isicom_tiocmset(struct tty_struct *tty, | ||
1086 | unsigned int set, unsigned int clear) | ||
1087 | { | ||
1088 | struct isi_port *port = tty->driver_data; | ||
1089 | unsigned long flags; | ||
1090 | |||
1091 | if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) | ||
1092 | return -ENODEV; | ||
1093 | |||
1094 | spin_lock_irqsave(&port->card->card_lock, flags); | ||
1095 | if (set & TIOCM_RTS) | ||
1096 | raise_rts(port); | ||
1097 | if (set & TIOCM_DTR) | ||
1098 | raise_dtr(port); | ||
1099 | |||
1100 | if (clear & TIOCM_RTS) | ||
1101 | drop_rts(port); | ||
1102 | if (clear & TIOCM_DTR) | ||
1103 | drop_dtr(port); | ||
1104 | spin_unlock_irqrestore(&port->card->card_lock, flags); | ||
1105 | |||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | static int isicom_set_serial_info(struct tty_struct *tty, | ||
1110 | struct serial_struct __user *info) | ||
1111 | { | ||
1112 | struct isi_port *port = tty->driver_data; | ||
1113 | struct serial_struct newinfo; | ||
1114 | int reconfig_port; | ||
1115 | |||
1116 | if (copy_from_user(&newinfo, info, sizeof(newinfo))) | ||
1117 | return -EFAULT; | ||
1118 | |||
1119 | mutex_lock(&port->port.mutex); | ||
1120 | reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != | ||
1121 | (newinfo.flags & ASYNC_SPD_MASK)); | ||
1122 | |||
1123 | if (!capable(CAP_SYS_ADMIN)) { | ||
1124 | if ((newinfo.close_delay != port->port.close_delay) || | ||
1125 | (newinfo.closing_wait != port->port.closing_wait) || | ||
1126 | ((newinfo.flags & ~ASYNC_USR_MASK) != | ||
1127 | (port->port.flags & ~ASYNC_USR_MASK))) { | ||
1128 | mutex_unlock(&port->port.mutex); | ||
1129 | return -EPERM; | ||
1130 | } | ||
1131 | port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | | ||
1132 | (newinfo.flags & ASYNC_USR_MASK)); | ||
1133 | } else { | ||
1134 | port->port.close_delay = newinfo.close_delay; | ||
1135 | port->port.closing_wait = newinfo.closing_wait; | ||
1136 | port->port.flags = ((port->port.flags & ~ASYNC_FLAGS) | | ||
1137 | (newinfo.flags & ASYNC_FLAGS)); | ||
1138 | } | ||
1139 | if (reconfig_port) { | ||
1140 | unsigned long flags; | ||
1141 | spin_lock_irqsave(&port->card->card_lock, flags); | ||
1142 | isicom_config_port(tty); | ||
1143 | spin_unlock_irqrestore(&port->card->card_lock, flags); | ||
1144 | } | ||
1145 | mutex_unlock(&port->port.mutex); | ||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | static int isicom_get_serial_info(struct isi_port *port, | ||
1150 | struct serial_struct __user *info) | ||
1151 | { | ||
1152 | struct serial_struct out_info; | ||
1153 | |||
1154 | mutex_lock(&port->port.mutex); | ||
1155 | memset(&out_info, 0, sizeof(out_info)); | ||
1156 | /* out_info.type = ? */ | ||
1157 | out_info.line = port - isi_ports; | ||
1158 | out_info.port = port->card->base; | ||
1159 | out_info.irq = port->card->irq; | ||
1160 | out_info.flags = port->port.flags; | ||
1161 | /* out_info.baud_base = ? */ | ||
1162 | out_info.close_delay = port->port.close_delay; | ||
1163 | out_info.closing_wait = port->port.closing_wait; | ||
1164 | mutex_unlock(&port->port.mutex); | ||
1165 | if (copy_to_user(info, &out_info, sizeof(out_info))) | ||
1166 | return -EFAULT; | ||
1167 | return 0; | ||
1168 | } | ||
1169 | |||
1170 | static int isicom_ioctl(struct tty_struct *tty, | ||
1171 | unsigned int cmd, unsigned long arg) | ||
1172 | { | ||
1173 | struct isi_port *port = tty->driver_data; | ||
1174 | void __user *argp = (void __user *)arg; | ||
1175 | |||
1176 | if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) | ||
1177 | return -ENODEV; | ||
1178 | |||
1179 | switch (cmd) { | ||
1180 | case TIOCGSERIAL: | ||
1181 | return isicom_get_serial_info(port, argp); | ||
1182 | |||
1183 | case TIOCSSERIAL: | ||
1184 | return isicom_set_serial_info(tty, argp); | ||
1185 | |||
1186 | default: | ||
1187 | return -ENOIOCTLCMD; | ||
1188 | } | ||
1189 | return 0; | ||
1190 | } | ||
1191 | |||
1192 | /* set_termios et all */ | ||
1193 | static void isicom_set_termios(struct tty_struct *tty, | ||
1194 | struct ktermios *old_termios) | ||
1195 | { | ||
1196 | struct isi_port *port = tty->driver_data; | ||
1197 | unsigned long flags; | ||
1198 | |||
1199 | if (isicom_paranoia_check(port, tty->name, "isicom_set_termios")) | ||
1200 | return; | ||
1201 | |||
1202 | if (tty->termios->c_cflag == old_termios->c_cflag && | ||
1203 | tty->termios->c_iflag == old_termios->c_iflag) | ||
1204 | return; | ||
1205 | |||
1206 | spin_lock_irqsave(&port->card->card_lock, flags); | ||
1207 | isicom_config_port(tty); | ||
1208 | spin_unlock_irqrestore(&port->card->card_lock, flags); | ||
1209 | |||
1210 | if ((old_termios->c_cflag & CRTSCTS) && | ||
1211 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
1212 | tty->hw_stopped = 0; | ||
1213 | isicom_start(tty); | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | /* throttle et all */ | ||
1218 | static void isicom_throttle(struct tty_struct *tty) | ||
1219 | { | ||
1220 | struct isi_port *port = tty->driver_data; | ||
1221 | struct isi_board *card = port->card; | ||
1222 | |||
1223 | if (isicom_paranoia_check(port, tty->name, "isicom_throttle")) | ||
1224 | return; | ||
1225 | |||
1226 | /* tell the card that this port cannot handle any more data for now */ | ||
1227 | card->port_status &= ~(1 << port->channel); | ||
1228 | outw(card->port_status, card->base + 0x02); | ||
1229 | } | ||
1230 | |||
1231 | /* unthrottle et all */ | ||
1232 | static void isicom_unthrottle(struct tty_struct *tty) | ||
1233 | { | ||
1234 | struct isi_port *port = tty->driver_data; | ||
1235 | struct isi_board *card = port->card; | ||
1236 | |||
1237 | if (isicom_paranoia_check(port, tty->name, "isicom_unthrottle")) | ||
1238 | return; | ||
1239 | |||
1240 | /* tell the card that this port is ready to accept more data */ | ||
1241 | card->port_status |= (1 << port->channel); | ||
1242 | outw(card->port_status, card->base + 0x02); | ||
1243 | } | ||
1244 | |||
1245 | /* stop et all */ | ||
1246 | static void isicom_stop(struct tty_struct *tty) | ||
1247 | { | ||
1248 | struct isi_port *port = tty->driver_data; | ||
1249 | |||
1250 | if (isicom_paranoia_check(port, tty->name, "isicom_stop")) | ||
1251 | return; | ||
1252 | |||
1253 | /* this tells the transmitter not to consider this port for | ||
1254 | data output to the card. */ | ||
1255 | port->status &= ~ISI_TXOK; | ||
1256 | } | ||
1257 | |||
1258 | /* start et all */ | ||
1259 | static void isicom_start(struct tty_struct *tty) | ||
1260 | { | ||
1261 | struct isi_port *port = tty->driver_data; | ||
1262 | |||
1263 | if (isicom_paranoia_check(port, tty->name, "isicom_start")) | ||
1264 | return; | ||
1265 | |||
1266 | /* this tells the transmitter to consider this port for | ||
1267 | data output to the card. */ | ||
1268 | port->status |= ISI_TXOK; | ||
1269 | } | ||
1270 | |||
1271 | static void isicom_hangup(struct tty_struct *tty) | ||
1272 | { | ||
1273 | struct isi_port *port = tty->driver_data; | ||
1274 | |||
1275 | if (isicom_paranoia_check(port, tty->name, "isicom_hangup")) | ||
1276 | return; | ||
1277 | tty_port_hangup(&port->port); | ||
1278 | } | ||
1279 | |||
1280 | |||
1281 | /* | ||
1282 | * Driver init and deinit functions | ||
1283 | */ | ||
1284 | |||
1285 | static const struct tty_operations isicom_ops = { | ||
1286 | .open = isicom_open, | ||
1287 | .close = isicom_close, | ||
1288 | .write = isicom_write, | ||
1289 | .put_char = isicom_put_char, | ||
1290 | .flush_chars = isicom_flush_chars, | ||
1291 | .write_room = isicom_write_room, | ||
1292 | .chars_in_buffer = isicom_chars_in_buffer, | ||
1293 | .ioctl = isicom_ioctl, | ||
1294 | .set_termios = isicom_set_termios, | ||
1295 | .throttle = isicom_throttle, | ||
1296 | .unthrottle = isicom_unthrottle, | ||
1297 | .stop = isicom_stop, | ||
1298 | .start = isicom_start, | ||
1299 | .hangup = isicom_hangup, | ||
1300 | .flush_buffer = isicom_flush_buffer, | ||
1301 | .tiocmget = isicom_tiocmget, | ||
1302 | .tiocmset = isicom_tiocmset, | ||
1303 | .break_ctl = isicom_send_break, | ||
1304 | }; | ||
1305 | |||
1306 | static const struct tty_port_operations isicom_port_ops = { | ||
1307 | .carrier_raised = isicom_carrier_raised, | ||
1308 | .dtr_rts = isicom_dtr_rts, | ||
1309 | .activate = isicom_activate, | ||
1310 | .shutdown = isicom_shutdown, | ||
1311 | }; | ||
1312 | |||
1313 | static int __devinit reset_card(struct pci_dev *pdev, | ||
1314 | const unsigned int card, unsigned int *signature) | ||
1315 | { | ||
1316 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1317 | unsigned long base = board->base; | ||
1318 | unsigned int sig, portcount = 0; | ||
1319 | int retval = 0; | ||
1320 | |||
1321 | dev_dbg(&pdev->dev, "ISILoad:Resetting Card%d at 0x%lx\n", card + 1, | ||
1322 | base); | ||
1323 | |||
1324 | inw(base + 0x8); | ||
1325 | |||
1326 | msleep(10); | ||
1327 | |||
1328 | outw(0, base + 0x8); /* Reset */ | ||
1329 | |||
1330 | msleep(1000); | ||
1331 | |||
1332 | sig = inw(base + 0x4) & 0xff; | ||
1333 | |||
1334 | if (sig != 0xa5 && sig != 0xbb && sig != 0xcc && sig != 0xdd && | ||
1335 | sig != 0xee) { | ||
1336 | dev_warn(&pdev->dev, "ISILoad:Card%u reset failure (Possible " | ||
1337 | "bad I/O Port Address 0x%lx).\n", card + 1, base); | ||
1338 | dev_dbg(&pdev->dev, "Sig=0x%x\n", sig); | ||
1339 | retval = -EIO; | ||
1340 | goto end; | ||
1341 | } | ||
1342 | |||
1343 | msleep(10); | ||
1344 | |||
1345 | portcount = inw(base + 0x2); | ||
1346 | if (!(inw(base + 0xe) & 0x1) || (portcount != 0 && portcount != 4 && | ||
1347 | portcount != 8 && portcount != 16)) { | ||
1348 | dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n", | ||
1349 | card + 1); | ||
1350 | retval = -EIO; | ||
1351 | goto end; | ||
1352 | } | ||
1353 | |||
1354 | switch (sig) { | ||
1355 | case 0xa5: | ||
1356 | case 0xbb: | ||
1357 | case 0xdd: | ||
1358 | board->port_count = (portcount == 4) ? 4 : 8; | ||
1359 | board->shift_count = 12; | ||
1360 | break; | ||
1361 | case 0xcc: | ||
1362 | case 0xee: | ||
1363 | board->port_count = 16; | ||
1364 | board->shift_count = 11; | ||
1365 | break; | ||
1366 | } | ||
1367 | dev_info(&pdev->dev, "-Done\n"); | ||
1368 | *signature = sig; | ||
1369 | |||
1370 | end: | ||
1371 | return retval; | ||
1372 | } | ||
1373 | |||
1374 | static int __devinit load_firmware(struct pci_dev *pdev, | ||
1375 | const unsigned int index, const unsigned int signature) | ||
1376 | { | ||
1377 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1378 | const struct firmware *fw; | ||
1379 | unsigned long base = board->base; | ||
1380 | unsigned int a; | ||
1381 | u16 word_count, status; | ||
1382 | int retval = -EIO; | ||
1383 | char *name; | ||
1384 | u8 *data; | ||
1385 | |||
1386 | struct stframe { | ||
1387 | u16 addr; | ||
1388 | u16 count; | ||
1389 | u8 data[0]; | ||
1390 | } *frame; | ||
1391 | |||
1392 | switch (signature) { | ||
1393 | case 0xa5: | ||
1394 | name = "isi608.bin"; | ||
1395 | break; | ||
1396 | case 0xbb: | ||
1397 | name = "isi608em.bin"; | ||
1398 | break; | ||
1399 | case 0xcc: | ||
1400 | name = "isi616em.bin"; | ||
1401 | break; | ||
1402 | case 0xdd: | ||
1403 | name = "isi4608.bin"; | ||
1404 | break; | ||
1405 | case 0xee: | ||
1406 | name = "isi4616.bin"; | ||
1407 | break; | ||
1408 | default: | ||
1409 | dev_err(&pdev->dev, "Unknown signature.\n"); | ||
1410 | goto end; | ||
1411 | } | ||
1412 | |||
1413 | retval = request_firmware(&fw, name, &pdev->dev); | ||
1414 | if (retval) | ||
1415 | goto end; | ||
1416 | |||
1417 | retval = -EIO; | ||
1418 | |||
1419 | for (frame = (struct stframe *)fw->data; | ||
1420 | frame < (struct stframe *)(fw->data + fw->size); | ||
1421 | frame = (struct stframe *)((u8 *)(frame + 1) + | ||
1422 | frame->count)) { | ||
1423 | if (WaitTillCardIsFree(base)) | ||
1424 | goto errrelfw; | ||
1425 | |||
1426 | outw(0xf0, base); /* start upload sequence */ | ||
1427 | outw(0x00, base); | ||
1428 | outw(frame->addr, base); /* lsb of address */ | ||
1429 | |||
1430 | word_count = frame->count / 2 + frame->count % 2; | ||
1431 | outw(word_count, base); | ||
1432 | InterruptTheCard(base); | ||
1433 | |||
1434 | udelay(100); /* 0x2f */ | ||
1435 | |||
1436 | if (WaitTillCardIsFree(base)) | ||
1437 | goto errrelfw; | ||
1438 | |||
1439 | status = inw(base + 0x4); | ||
1440 | if (status != 0) { | ||
1441 | dev_warn(&pdev->dev, "Card%d rejected load header:\n" | ||
1442 | "Address:0x%x\n" | ||
1443 | "Count:0x%x\n" | ||
1444 | "Status:0x%x\n", | ||
1445 | index + 1, frame->addr, frame->count, status); | ||
1446 | goto errrelfw; | ||
1447 | } | ||
1448 | outsw(base, frame->data, word_count); | ||
1449 | |||
1450 | InterruptTheCard(base); | ||
1451 | |||
1452 | udelay(50); /* 0x0f */ | ||
1453 | |||
1454 | if (WaitTillCardIsFree(base)) | ||
1455 | goto errrelfw; | ||
1456 | |||
1457 | status = inw(base + 0x4); | ||
1458 | if (status != 0) { | ||
1459 | dev_err(&pdev->dev, "Card%d got out of sync.Card " | ||
1460 | "Status:0x%x\n", index + 1, status); | ||
1461 | goto errrelfw; | ||
1462 | } | ||
1463 | } | ||
1464 | |||
1465 | /* XXX: should we test it by reading it back and comparing with original like | ||
1466 | * in load firmware package? */ | ||
1467 | for (frame = (struct stframe *)fw->data; | ||
1468 | frame < (struct stframe *)(fw->data + fw->size); | ||
1469 | frame = (struct stframe *)((u8 *)(frame + 1) + | ||
1470 | frame->count)) { | ||
1471 | if (WaitTillCardIsFree(base)) | ||
1472 | goto errrelfw; | ||
1473 | |||
1474 | outw(0xf1, base); /* start download sequence */ | ||
1475 | outw(0x00, base); | ||
1476 | outw(frame->addr, base); /* lsb of address */ | ||
1477 | |||
1478 | word_count = (frame->count >> 1) + frame->count % 2; | ||
1479 | outw(word_count + 1, base); | ||
1480 | InterruptTheCard(base); | ||
1481 | |||
1482 | udelay(50); /* 0xf */ | ||
1483 | |||
1484 | if (WaitTillCardIsFree(base)) | ||
1485 | goto errrelfw; | ||
1486 | |||
1487 | status = inw(base + 0x4); | ||
1488 | if (status != 0) { | ||
1489 | dev_warn(&pdev->dev, "Card%d rejected verify header:\n" | ||
1490 | "Address:0x%x\n" | ||
1491 | "Count:0x%x\n" | ||
1492 | "Status: 0x%x\n", | ||
1493 | index + 1, frame->addr, frame->count, status); | ||
1494 | goto errrelfw; | ||
1495 | } | ||
1496 | |||
1497 | data = kmalloc(word_count * 2, GFP_KERNEL); | ||
1498 | if (data == NULL) { | ||
1499 | dev_err(&pdev->dev, "Card%d, firmware upload " | ||
1500 | "failed, not enough memory\n", index + 1); | ||
1501 | goto errrelfw; | ||
1502 | } | ||
1503 | inw(base); | ||
1504 | insw(base, data, word_count); | ||
1505 | InterruptTheCard(base); | ||
1506 | |||
1507 | for (a = 0; a < frame->count; a++) | ||
1508 | if (data[a] != frame->data[a]) { | ||
1509 | kfree(data); | ||
1510 | dev_err(&pdev->dev, "Card%d, firmware upload " | ||
1511 | "failed\n", index + 1); | ||
1512 | goto errrelfw; | ||
1513 | } | ||
1514 | kfree(data); | ||
1515 | |||
1516 | udelay(50); /* 0xf */ | ||
1517 | |||
1518 | if (WaitTillCardIsFree(base)) | ||
1519 | goto errrelfw; | ||
1520 | |||
1521 | status = inw(base + 0x4); | ||
1522 | if (status != 0) { | ||
1523 | dev_err(&pdev->dev, "Card%d verify got out of sync. " | ||
1524 | "Card Status:0x%x\n", index + 1, status); | ||
1525 | goto errrelfw; | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | /* xfer ctrl */ | ||
1530 | if (WaitTillCardIsFree(base)) | ||
1531 | goto errrelfw; | ||
1532 | |||
1533 | outw(0xf2, base); | ||
1534 | outw(0x800, base); | ||
1535 | outw(0x0, base); | ||
1536 | outw(0x0, base); | ||
1537 | InterruptTheCard(base); | ||
1538 | outw(0x0, base + 0x4); /* for ISI4608 cards */ | ||
1539 | |||
1540 | board->status |= FIRMWARE_LOADED; | ||
1541 | retval = 0; | ||
1542 | |||
1543 | errrelfw: | ||
1544 | release_firmware(fw); | ||
1545 | end: | ||
1546 | return retval; | ||
1547 | } | ||
1548 | |||
1549 | /* | ||
1550 | * Insmod can set static symbols so keep these static | ||
1551 | */ | ||
1552 | static unsigned int card_count; | ||
1553 | |||
1554 | static int __devinit isicom_probe(struct pci_dev *pdev, | ||
1555 | const struct pci_device_id *ent) | ||
1556 | { | ||
1557 | unsigned int uninitialized_var(signature), index; | ||
1558 | int retval = -EPERM; | ||
1559 | struct isi_board *board = NULL; | ||
1560 | |||
1561 | if (card_count >= BOARD_COUNT) | ||
1562 | goto err; | ||
1563 | |||
1564 | retval = pci_enable_device(pdev); | ||
1565 | if (retval) { | ||
1566 | dev_err(&pdev->dev, "failed to enable\n"); | ||
1567 | goto err; | ||
1568 | } | ||
1569 | |||
1570 | dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device); | ||
1571 | |||
1572 | /* allot the first empty slot in the array */ | ||
1573 | for (index = 0; index < BOARD_COUNT; index++) { | ||
1574 | if (isi_card[index].base == 0) { | ||
1575 | board = &isi_card[index]; | ||
1576 | break; | ||
1577 | } | ||
1578 | } | ||
1579 | if (index == BOARD_COUNT) { | ||
1580 | retval = -ENODEV; | ||
1581 | goto err_disable; | ||
1582 | } | ||
1583 | |||
1584 | board->index = index; | ||
1585 | board->base = pci_resource_start(pdev, 3); | ||
1586 | board->irq = pdev->irq; | ||
1587 | card_count++; | ||
1588 | |||
1589 | pci_set_drvdata(pdev, board); | ||
1590 | |||
1591 | retval = pci_request_region(pdev, 3, ISICOM_NAME); | ||
1592 | if (retval) { | ||
1593 | dev_err(&pdev->dev, "I/O Region 0x%lx-0x%lx is busy. Card%d " | ||
1594 | "will be disabled.\n", board->base, board->base + 15, | ||
1595 | index + 1); | ||
1596 | retval = -EBUSY; | ||
1597 | goto errdec; | ||
1598 | } | ||
1599 | |||
1600 | retval = request_irq(board->irq, isicom_interrupt, | ||
1601 | IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board); | ||
1602 | if (retval < 0) { | ||
1603 | dev_err(&pdev->dev, "Could not install handler at Irq %d. " | ||
1604 | "Card%d will be disabled.\n", board->irq, index + 1); | ||
1605 | goto errunrr; | ||
1606 | } | ||
1607 | |||
1608 | retval = reset_card(pdev, index, &signature); | ||
1609 | if (retval < 0) | ||
1610 | goto errunri; | ||
1611 | |||
1612 | retval = load_firmware(pdev, index, signature); | ||
1613 | if (retval < 0) | ||
1614 | goto errunri; | ||
1615 | |||
1616 | for (index = 0; index < board->port_count; index++) | ||
1617 | tty_register_device(isicom_normal, board->index * 16 + index, | ||
1618 | &pdev->dev); | ||
1619 | |||
1620 | return 0; | ||
1621 | |||
1622 | errunri: | ||
1623 | free_irq(board->irq, board); | ||
1624 | errunrr: | ||
1625 | pci_release_region(pdev, 3); | ||
1626 | errdec: | ||
1627 | board->base = 0; | ||
1628 | card_count--; | ||
1629 | err_disable: | ||
1630 | pci_disable_device(pdev); | ||
1631 | err: | ||
1632 | return retval; | ||
1633 | } | ||
1634 | |||
1635 | static void __devexit isicom_remove(struct pci_dev *pdev) | ||
1636 | { | ||
1637 | struct isi_board *board = pci_get_drvdata(pdev); | ||
1638 | unsigned int i; | ||
1639 | |||
1640 | for (i = 0; i < board->port_count; i++) | ||
1641 | tty_unregister_device(isicom_normal, board->index * 16 + i); | ||
1642 | |||
1643 | free_irq(board->irq, board); | ||
1644 | pci_release_region(pdev, 3); | ||
1645 | board->base = 0; | ||
1646 | card_count--; | ||
1647 | pci_disable_device(pdev); | ||
1648 | } | ||
1649 | |||
1650 | static int __init isicom_init(void) | ||
1651 | { | ||
1652 | int retval, idx, channel; | ||
1653 | struct isi_port *port; | ||
1654 | |||
1655 | for (idx = 0; idx < BOARD_COUNT; idx++) { | ||
1656 | port = &isi_ports[idx * 16]; | ||
1657 | isi_card[idx].ports = port; | ||
1658 | spin_lock_init(&isi_card[idx].card_lock); | ||
1659 | for (channel = 0; channel < 16; channel++, port++) { | ||
1660 | tty_port_init(&port->port); | ||
1661 | port->port.ops = &isicom_port_ops; | ||
1662 | port->magic = ISICOM_MAGIC; | ||
1663 | port->card = &isi_card[idx]; | ||
1664 | port->channel = channel; | ||
1665 | port->port.close_delay = 50 * HZ/100; | ||
1666 | port->port.closing_wait = 3000 * HZ/100; | ||
1667 | port->status = 0; | ||
1668 | /* . . . */ | ||
1669 | } | ||
1670 | isi_card[idx].base = 0; | ||
1671 | isi_card[idx].irq = 0; | ||
1672 | } | ||
1673 | |||
1674 | /* tty driver structure initialization */ | ||
1675 | isicom_normal = alloc_tty_driver(PORT_COUNT); | ||
1676 | if (!isicom_normal) { | ||
1677 | retval = -ENOMEM; | ||
1678 | goto error; | ||
1679 | } | ||
1680 | |||
1681 | isicom_normal->owner = THIS_MODULE; | ||
1682 | isicom_normal->name = "ttyM"; | ||
1683 | isicom_normal->major = ISICOM_NMAJOR; | ||
1684 | isicom_normal->minor_start = 0; | ||
1685 | isicom_normal->type = TTY_DRIVER_TYPE_SERIAL; | ||
1686 | isicom_normal->subtype = SERIAL_TYPE_NORMAL; | ||
1687 | isicom_normal->init_termios = tty_std_termios; | ||
1688 | isicom_normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | | ||
1689 | CLOCAL; | ||
1690 | isicom_normal->flags = TTY_DRIVER_REAL_RAW | | ||
1691 | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK; | ||
1692 | tty_set_operations(isicom_normal, &isicom_ops); | ||
1693 | |||
1694 | retval = tty_register_driver(isicom_normal); | ||
1695 | if (retval) { | ||
1696 | pr_debug("Couldn't register the dialin driver\n"); | ||
1697 | goto err_puttty; | ||
1698 | } | ||
1699 | |||
1700 | retval = pci_register_driver(&isicom_driver); | ||
1701 | if (retval < 0) { | ||
1702 | pr_err("Unable to register pci driver.\n"); | ||
1703 | goto err_unrtty; | ||
1704 | } | ||
1705 | |||
1706 | mod_timer(&tx, jiffies + 1); | ||
1707 | |||
1708 | return 0; | ||
1709 | err_unrtty: | ||
1710 | tty_unregister_driver(isicom_normal); | ||
1711 | err_puttty: | ||
1712 | put_tty_driver(isicom_normal); | ||
1713 | error: | ||
1714 | return retval; | ||
1715 | } | ||
1716 | |||
1717 | static void __exit isicom_exit(void) | ||
1718 | { | ||
1719 | del_timer_sync(&tx); | ||
1720 | |||
1721 | pci_unregister_driver(&isicom_driver); | ||
1722 | tty_unregister_driver(isicom_normal); | ||
1723 | put_tty_driver(isicom_normal); | ||
1724 | } | ||
1725 | |||
1726 | module_init(isicom_init); | ||
1727 | module_exit(isicom_exit); | ||
1728 | |||
1729 | MODULE_AUTHOR("MultiTech"); | ||
1730 | MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech"); | ||
1731 | MODULE_LICENSE("GPL"); | ||
1732 | MODULE_FIRMWARE("isi608.bin"); | ||
1733 | MODULE_FIRMWARE("isi608em.bin"); | ||
1734 | MODULE_FIRMWARE("isi616em.bin"); | ||
1735 | MODULE_FIRMWARE("isi4608.bin"); | ||
1736 | MODULE_FIRMWARE("isi4616.bin"); | ||
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c new file mode 100644 index 000000000000..35b0c38590e6 --- /dev/null +++ b/drivers/tty/moxa.c | |||
@@ -0,0 +1,2092 @@ | |||
1 | /*****************************************************************************/ | ||
2 | /* | ||
3 | * moxa.c -- MOXA Intellio family multiport serial driver. | ||
4 | * | ||
5 | * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com). | ||
6 | * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> | ||
7 | * | ||
8 | * This code is loosely based on the Linux serial driver, written by | ||
9 | * Linus Torvalds, Theodore T'so and others. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * MOXA Intellio Series Driver | ||
19 | * for : LINUX | ||
20 | * date : 1999/1/7 | ||
21 | * version : 5.1 | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/firmware.h> | ||
30 | #include <linux/signal.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/timer.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/tty.h> | ||
35 | #include <linux/tty_flip.h> | ||
36 | #include <linux/major.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/fcntl.h> | ||
39 | #include <linux/ptrace.h> | ||
40 | #include <linux/serial.h> | ||
41 | #include <linux/tty_driver.h> | ||
42 | #include <linux/delay.h> | ||
43 | #include <linux/pci.h> | ||
44 | #include <linux/init.h> | ||
45 | #include <linux/bitops.h> | ||
46 | #include <linux/slab.h> | ||
47 | |||
48 | #include <asm/system.h> | ||
49 | #include <asm/io.h> | ||
50 | #include <asm/uaccess.h> | ||
51 | |||
52 | #include "moxa.h" | ||
53 | |||
54 | #define MOXA_VERSION "6.0k" | ||
55 | |||
56 | #define MOXA_FW_HDRLEN 32 | ||
57 | |||
58 | #define MOXAMAJOR 172 | ||
59 | |||
60 | #define MAX_BOARDS 4 /* Don't change this value */ | ||
61 | #define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ | ||
62 | #define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD) | ||
63 | |||
64 | #define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \ | ||
65 | (brd)->boardType == MOXA_BOARD_C320_PCI) | ||
66 | |||
67 | /* | ||
68 | * Define the Moxa PCI vendor and device IDs. | ||
69 | */ | ||
70 | #define MOXA_BUS_TYPE_ISA 0 | ||
71 | #define MOXA_BUS_TYPE_PCI 1 | ||
72 | |||
73 | enum { | ||
74 | MOXA_BOARD_C218_PCI = 1, | ||
75 | MOXA_BOARD_C218_ISA, | ||
76 | MOXA_BOARD_C320_PCI, | ||
77 | MOXA_BOARD_C320_ISA, | ||
78 | MOXA_BOARD_CP204J, | ||
79 | }; | ||
80 | |||
81 | static char *moxa_brdname[] = | ||
82 | { | ||
83 | "C218 Turbo PCI series", | ||
84 | "C218 Turbo ISA series", | ||
85 | "C320 Turbo PCI series", | ||
86 | "C320 Turbo ISA series", | ||
87 | "CP-204J series", | ||
88 | }; | ||
89 | |||
90 | #ifdef CONFIG_PCI | ||
91 | static struct pci_device_id moxa_pcibrds[] = { | ||
92 | { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), | ||
93 | .driver_data = MOXA_BOARD_C218_PCI }, | ||
94 | { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), | ||
95 | .driver_data = MOXA_BOARD_C320_PCI }, | ||
96 | { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP204J), | ||
97 | .driver_data = MOXA_BOARD_CP204J }, | ||
98 | { 0 } | ||
99 | }; | ||
100 | MODULE_DEVICE_TABLE(pci, moxa_pcibrds); | ||
101 | #endif /* CONFIG_PCI */ | ||
102 | |||
103 | struct moxa_port; | ||
104 | |||
105 | static struct moxa_board_conf { | ||
106 | int boardType; | ||
107 | int numPorts; | ||
108 | int busType; | ||
109 | |||
110 | unsigned int ready; | ||
111 | |||
112 | struct moxa_port *ports; | ||
113 | |||
114 | void __iomem *basemem; | ||
115 | void __iomem *intNdx; | ||
116 | void __iomem *intPend; | ||
117 | void __iomem *intTable; | ||
118 | } moxa_boards[MAX_BOARDS]; | ||
119 | |||
120 | struct mxser_mstatus { | ||
121 | tcflag_t cflag; | ||
122 | int cts; | ||
123 | int dsr; | ||
124 | int ri; | ||
125 | int dcd; | ||
126 | }; | ||
127 | |||
128 | struct moxaq_str { | ||
129 | int inq; | ||
130 | int outq; | ||
131 | }; | ||
132 | |||
133 | struct moxa_port { | ||
134 | struct tty_port port; | ||
135 | struct moxa_board_conf *board; | ||
136 | void __iomem *tableAddr; | ||
137 | |||
138 | int type; | ||
139 | int cflag; | ||
140 | unsigned long statusflags; | ||
141 | |||
142 | u8 DCDState; /* Protected by the port lock */ | ||
143 | u8 lineCtrl; | ||
144 | u8 lowChkFlag; | ||
145 | }; | ||
146 | |||
147 | struct mon_str { | ||
148 | int tick; | ||
149 | int rxcnt[MAX_PORTS]; | ||
150 | int txcnt[MAX_PORTS]; | ||
151 | }; | ||
152 | |||
153 | /* statusflags */ | ||
154 | #define TXSTOPPED 1 | ||
155 | #define LOWWAIT 2 | ||
156 | #define EMPTYWAIT 3 | ||
157 | |||
158 | #define SERIAL_DO_RESTART | ||
159 | |||
160 | #define WAKEUP_CHARS 256 | ||
161 | |||
162 | static int ttymajor = MOXAMAJOR; | ||
163 | static struct mon_str moxaLog; | ||
164 | static unsigned int moxaFuncTout = HZ / 2; | ||
165 | static unsigned int moxaLowWaterChk; | ||
166 | static DEFINE_MUTEX(moxa_openlock); | ||
167 | static DEFINE_SPINLOCK(moxa_lock); | ||
168 | |||
169 | static unsigned long baseaddr[MAX_BOARDS]; | ||
170 | static unsigned int type[MAX_BOARDS]; | ||
171 | static unsigned int numports[MAX_BOARDS]; | ||
172 | |||
173 | MODULE_AUTHOR("William Chen"); | ||
174 | MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); | ||
175 | MODULE_LICENSE("GPL"); | ||
176 | MODULE_FIRMWARE("c218tunx.cod"); | ||
177 | MODULE_FIRMWARE("cp204unx.cod"); | ||
178 | MODULE_FIRMWARE("c320tunx.cod"); | ||
179 | |||
180 | module_param_array(type, uint, NULL, 0); | ||
181 | MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); | ||
182 | module_param_array(baseaddr, ulong, NULL, 0); | ||
183 | MODULE_PARM_DESC(baseaddr, "base address"); | ||
184 | module_param_array(numports, uint, NULL, 0); | ||
185 | MODULE_PARM_DESC(numports, "numports (ignored for C218)"); | ||
186 | |||
187 | module_param(ttymajor, int, 0); | ||
188 | |||
189 | /* | ||
190 | * static functions: | ||
191 | */ | ||
192 | static int moxa_open(struct tty_struct *, struct file *); | ||
193 | static void moxa_close(struct tty_struct *, struct file *); | ||
194 | static int moxa_write(struct tty_struct *, const unsigned char *, int); | ||
195 | static int moxa_write_room(struct tty_struct *); | ||
196 | static void moxa_flush_buffer(struct tty_struct *); | ||
197 | static int moxa_chars_in_buffer(struct tty_struct *); | ||
198 | static void moxa_set_termios(struct tty_struct *, struct ktermios *); | ||
199 | static void moxa_stop(struct tty_struct *); | ||
200 | static void moxa_start(struct tty_struct *); | ||
201 | static void moxa_hangup(struct tty_struct *); | ||
202 | static int moxa_tiocmget(struct tty_struct *tty); | ||
203 | static int moxa_tiocmset(struct tty_struct *tty, | ||
204 | unsigned int set, unsigned int clear); | ||
205 | static void moxa_poll(unsigned long); | ||
206 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); | ||
207 | static void moxa_shutdown(struct tty_port *); | ||
208 | static int moxa_carrier_raised(struct tty_port *); | ||
209 | static void moxa_dtr_rts(struct tty_port *, int); | ||
210 | /* | ||
211 | * moxa board interface functions: | ||
212 | */ | ||
213 | static void MoxaPortEnable(struct moxa_port *); | ||
214 | static void MoxaPortDisable(struct moxa_port *); | ||
215 | static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t); | ||
216 | static int MoxaPortGetLineOut(struct moxa_port *, int *, int *); | ||
217 | static void MoxaPortLineCtrl(struct moxa_port *, int, int); | ||
218 | static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); | ||
219 | static int MoxaPortLineStatus(struct moxa_port *); | ||
220 | static void MoxaPortFlushData(struct moxa_port *, int); | ||
221 | static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); | ||
222 | static int MoxaPortReadData(struct moxa_port *); | ||
223 | static int MoxaPortTxQueue(struct moxa_port *); | ||
224 | static int MoxaPortRxQueue(struct moxa_port *); | ||
225 | static int MoxaPortTxFree(struct moxa_port *); | ||
226 | static void MoxaPortTxDisable(struct moxa_port *); | ||
227 | static void MoxaPortTxEnable(struct moxa_port *); | ||
228 | static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); | ||
229 | static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); | ||
230 | static void MoxaSetFifo(struct moxa_port *port, int enable); | ||
231 | |||
232 | /* | ||
233 | * I/O functions | ||
234 | */ | ||
235 | |||
236 | static DEFINE_SPINLOCK(moxafunc_lock); | ||
237 | |||
238 | static void moxa_wait_finish(void __iomem *ofsAddr) | ||
239 | { | ||
240 | unsigned long end = jiffies + moxaFuncTout; | ||
241 | |||
242 | while (readw(ofsAddr + FuncCode) != 0) | ||
243 | if (time_after(jiffies, end)) | ||
244 | return; | ||
245 | if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit()) | ||
246 | printk(KERN_WARNING "moxa function expired\n"); | ||
247 | } | ||
248 | |||
249 | static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) | ||
250 | { | ||
251 | unsigned long flags; | ||
252 | spin_lock_irqsave(&moxafunc_lock, flags); | ||
253 | writew(arg, ofsAddr + FuncArg); | ||
254 | writew(cmd, ofsAddr + FuncCode); | ||
255 | moxa_wait_finish(ofsAddr); | ||
256 | spin_unlock_irqrestore(&moxafunc_lock, flags); | ||
257 | } | ||
258 | |||
259 | static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg) | ||
260 | { | ||
261 | unsigned long flags; | ||
262 | u16 ret; | ||
263 | spin_lock_irqsave(&moxafunc_lock, flags); | ||
264 | writew(arg, ofsAddr + FuncArg); | ||
265 | writew(cmd, ofsAddr + FuncCode); | ||
266 | moxa_wait_finish(ofsAddr); | ||
267 | ret = readw(ofsAddr + FuncArg); | ||
268 | spin_unlock_irqrestore(&moxafunc_lock, flags); | ||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | static void moxa_low_water_check(void __iomem *ofsAddr) | ||
273 | { | ||
274 | u16 rptr, wptr, mask, len; | ||
275 | |||
276 | if (readb(ofsAddr + FlagStat) & Xoff_state) { | ||
277 | rptr = readw(ofsAddr + RXrptr); | ||
278 | wptr = readw(ofsAddr + RXwptr); | ||
279 | mask = readw(ofsAddr + RX_mask); | ||
280 | len = (wptr - rptr) & mask; | ||
281 | if (len <= Low_water) | ||
282 | moxafunc(ofsAddr, FC_SendXon, 0); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * TTY operations | ||
288 | */ | ||
289 | |||
290 | static int moxa_ioctl(struct tty_struct *tty, | ||
291 | unsigned int cmd, unsigned long arg) | ||
292 | { | ||
293 | struct moxa_port *ch = tty->driver_data; | ||
294 | void __user *argp = (void __user *)arg; | ||
295 | int status, ret = 0; | ||
296 | |||
297 | if (tty->index == MAX_PORTS) { | ||
298 | if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && | ||
299 | cmd != MOXA_GETMSTATUS) | ||
300 | return -EINVAL; | ||
301 | } else if (!ch) | ||
302 | return -ENODEV; | ||
303 | |||
304 | switch (cmd) { | ||
305 | case MOXA_GETDATACOUNT: | ||
306 | moxaLog.tick = jiffies; | ||
307 | if (copy_to_user(argp, &moxaLog, sizeof(moxaLog))) | ||
308 | ret = -EFAULT; | ||
309 | break; | ||
310 | case MOXA_FLUSH_QUEUE: | ||
311 | MoxaPortFlushData(ch, arg); | ||
312 | break; | ||
313 | case MOXA_GET_IOQUEUE: { | ||
314 | struct moxaq_str __user *argm = argp; | ||
315 | struct moxaq_str tmp; | ||
316 | struct moxa_port *p; | ||
317 | unsigned int i, j; | ||
318 | |||
319 | for (i = 0; i < MAX_BOARDS; i++) { | ||
320 | p = moxa_boards[i].ports; | ||
321 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | ||
322 | memset(&tmp, 0, sizeof(tmp)); | ||
323 | spin_lock_bh(&moxa_lock); | ||
324 | if (moxa_boards[i].ready) { | ||
325 | tmp.inq = MoxaPortRxQueue(p); | ||
326 | tmp.outq = MoxaPortTxQueue(p); | ||
327 | } | ||
328 | spin_unlock_bh(&moxa_lock); | ||
329 | if (copy_to_user(argm, &tmp, sizeof(tmp))) | ||
330 | return -EFAULT; | ||
331 | } | ||
332 | } | ||
333 | break; | ||
334 | } case MOXA_GET_OQUEUE: | ||
335 | status = MoxaPortTxQueue(ch); | ||
336 | ret = put_user(status, (unsigned long __user *)argp); | ||
337 | break; | ||
338 | case MOXA_GET_IQUEUE: | ||
339 | status = MoxaPortRxQueue(ch); | ||
340 | ret = put_user(status, (unsigned long __user *)argp); | ||
341 | break; | ||
342 | case MOXA_GETMSTATUS: { | ||
343 | struct mxser_mstatus __user *argm = argp; | ||
344 | struct mxser_mstatus tmp; | ||
345 | struct moxa_port *p; | ||
346 | unsigned int i, j; | ||
347 | |||
348 | for (i = 0; i < MAX_BOARDS; i++) { | ||
349 | p = moxa_boards[i].ports; | ||
350 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | ||
351 | struct tty_struct *ttyp; | ||
352 | memset(&tmp, 0, sizeof(tmp)); | ||
353 | spin_lock_bh(&moxa_lock); | ||
354 | if (!moxa_boards[i].ready) { | ||
355 | spin_unlock_bh(&moxa_lock); | ||
356 | goto copy; | ||
357 | } | ||
358 | |||
359 | status = MoxaPortLineStatus(p); | ||
360 | spin_unlock_bh(&moxa_lock); | ||
361 | |||
362 | if (status & 1) | ||
363 | tmp.cts = 1; | ||
364 | if (status & 2) | ||
365 | tmp.dsr = 1; | ||
366 | if (status & 4) | ||
367 | tmp.dcd = 1; | ||
368 | |||
369 | ttyp = tty_port_tty_get(&p->port); | ||
370 | if (!ttyp || !ttyp->termios) | ||
371 | tmp.cflag = p->cflag; | ||
372 | else | ||
373 | tmp.cflag = ttyp->termios->c_cflag; | ||
374 | tty_kref_put(tty); | ||
375 | copy: | ||
376 | if (copy_to_user(argm, &tmp, sizeof(tmp))) | ||
377 | return -EFAULT; | ||
378 | } | ||
379 | } | ||
380 | break; | ||
381 | } | ||
382 | case TIOCGSERIAL: | ||
383 | mutex_lock(&ch->port.mutex); | ||
384 | ret = moxa_get_serial_info(ch, argp); | ||
385 | mutex_unlock(&ch->port.mutex); | ||
386 | break; | ||
387 | case TIOCSSERIAL: | ||
388 | mutex_lock(&ch->port.mutex); | ||
389 | ret = moxa_set_serial_info(ch, argp); | ||
390 | mutex_unlock(&ch->port.mutex); | ||
391 | break; | ||
392 | default: | ||
393 | ret = -ENOIOCTLCMD; | ||
394 | } | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int moxa_break_ctl(struct tty_struct *tty, int state) | ||
399 | { | ||
400 | struct moxa_port *port = tty->driver_data; | ||
401 | |||
402 | moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak, | ||
403 | Magic_code); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static const struct tty_operations moxa_ops = { | ||
408 | .open = moxa_open, | ||
409 | .close = moxa_close, | ||
410 | .write = moxa_write, | ||
411 | .write_room = moxa_write_room, | ||
412 | .flush_buffer = moxa_flush_buffer, | ||
413 | .chars_in_buffer = moxa_chars_in_buffer, | ||
414 | .ioctl = moxa_ioctl, | ||
415 | .set_termios = moxa_set_termios, | ||
416 | .stop = moxa_stop, | ||
417 | .start = moxa_start, | ||
418 | .hangup = moxa_hangup, | ||
419 | .break_ctl = moxa_break_ctl, | ||
420 | .tiocmget = moxa_tiocmget, | ||
421 | .tiocmset = moxa_tiocmset, | ||
422 | }; | ||
423 | |||
424 | static const struct tty_port_operations moxa_port_ops = { | ||
425 | .carrier_raised = moxa_carrier_raised, | ||
426 | .dtr_rts = moxa_dtr_rts, | ||
427 | .shutdown = moxa_shutdown, | ||
428 | }; | ||
429 | |||
430 | static struct tty_driver *moxaDriver; | ||
431 | static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); | ||
432 | |||
433 | /* | ||
434 | * HW init | ||
435 | */ | ||
436 | |||
437 | static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model) | ||
438 | { | ||
439 | switch (brd->boardType) { | ||
440 | case MOXA_BOARD_C218_ISA: | ||
441 | case MOXA_BOARD_C218_PCI: | ||
442 | if (model != 1) | ||
443 | goto err; | ||
444 | break; | ||
445 | case MOXA_BOARD_CP204J: | ||
446 | if (model != 3) | ||
447 | goto err; | ||
448 | break; | ||
449 | default: | ||
450 | if (model != 2) | ||
451 | goto err; | ||
452 | break; | ||
453 | } | ||
454 | return 0; | ||
455 | err: | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | static int moxa_check_fw(const void *ptr) | ||
460 | { | ||
461 | const __le16 *lptr = ptr; | ||
462 | |||
463 | if (*lptr != cpu_to_le16(0x7980)) | ||
464 | return -EINVAL; | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf, | ||
470 | size_t len) | ||
471 | { | ||
472 | void __iomem *baseAddr = brd->basemem; | ||
473 | u16 tmp; | ||
474 | |||
475 | writeb(HW_reset, baseAddr + Control_reg); /* reset */ | ||
476 | msleep(10); | ||
477 | memset_io(baseAddr, 0, 4096); | ||
478 | memcpy_toio(baseAddr, buf, len); /* download BIOS */ | ||
479 | writeb(0, baseAddr + Control_reg); /* restart */ | ||
480 | |||
481 | msleep(2000); | ||
482 | |||
483 | switch (brd->boardType) { | ||
484 | case MOXA_BOARD_C218_ISA: | ||
485 | case MOXA_BOARD_C218_PCI: | ||
486 | tmp = readw(baseAddr + C218_key); | ||
487 | if (tmp != C218_KeyCode) | ||
488 | goto err; | ||
489 | break; | ||
490 | case MOXA_BOARD_CP204J: | ||
491 | tmp = readw(baseAddr + C218_key); | ||
492 | if (tmp != CP204J_KeyCode) | ||
493 | goto err; | ||
494 | break; | ||
495 | default: | ||
496 | tmp = readw(baseAddr + C320_key); | ||
497 | if (tmp != C320_KeyCode) | ||
498 | goto err; | ||
499 | tmp = readw(baseAddr + C320_status); | ||
500 | if (tmp != STS_init) { | ||
501 | printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic " | ||
502 | "module not found\n"); | ||
503 | return -EIO; | ||
504 | } | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | return 0; | ||
509 | err: | ||
510 | printk(KERN_ERR "MOXA: bios upload failed -- board not found\n"); | ||
511 | return -EIO; | ||
512 | } | ||
513 | |||
514 | static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr, | ||
515 | size_t len) | ||
516 | { | ||
517 | void __iomem *baseAddr = brd->basemem; | ||
518 | |||
519 | if (len < 7168) { | ||
520 | printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n"); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | writew(len - 7168 - 2, baseAddr + C320bapi_len); | ||
525 | writeb(1, baseAddr + Control_reg); /* Select Page 1 */ | ||
526 | memcpy_toio(baseAddr + DynPage_addr, ptr, 7168); | ||
527 | writeb(2, baseAddr + Control_reg); /* Select Page 2 */ | ||
528 | memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr, | ||
534 | size_t len) | ||
535 | { | ||
536 | void __iomem *baseAddr = brd->basemem; | ||
537 | const __le16 *uptr = ptr; | ||
538 | size_t wlen, len2, j; | ||
539 | unsigned long key, loadbuf, loadlen, checksum, checksum_ok; | ||
540 | unsigned int i, retry; | ||
541 | u16 usum, keycode; | ||
542 | |||
543 | keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode : | ||
544 | C218_KeyCode; | ||
545 | |||
546 | switch (brd->boardType) { | ||
547 | case MOXA_BOARD_CP204J: | ||
548 | case MOXA_BOARD_C218_ISA: | ||
549 | case MOXA_BOARD_C218_PCI: | ||
550 | key = C218_key; | ||
551 | loadbuf = C218_LoadBuf; | ||
552 | loadlen = C218DLoad_len; | ||
553 | checksum = C218check_sum; | ||
554 | checksum_ok = C218chksum_ok; | ||
555 | break; | ||
556 | default: | ||
557 | key = C320_key; | ||
558 | keycode = C320_KeyCode; | ||
559 | loadbuf = C320_LoadBuf; | ||
560 | loadlen = C320DLoad_len; | ||
561 | checksum = C320check_sum; | ||
562 | checksum_ok = C320chksum_ok; | ||
563 | break; | ||
564 | } | ||
565 | |||
566 | usum = 0; | ||
567 | wlen = len >> 1; | ||
568 | for (i = 0; i < wlen; i++) | ||
569 | usum += le16_to_cpu(uptr[i]); | ||
570 | retry = 0; | ||
571 | do { | ||
572 | wlen = len >> 1; | ||
573 | j = 0; | ||
574 | while (wlen) { | ||
575 | len2 = (wlen > 2048) ? 2048 : wlen; | ||
576 | wlen -= len2; | ||
577 | memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1); | ||
578 | j += len2 << 1; | ||
579 | |||
580 | writew(len2, baseAddr + loadlen); | ||
581 | writew(0, baseAddr + key); | ||
582 | for (i = 0; i < 100; i++) { | ||
583 | if (readw(baseAddr + key) == keycode) | ||
584 | break; | ||
585 | msleep(10); | ||
586 | } | ||
587 | if (readw(baseAddr + key) != keycode) | ||
588 | return -EIO; | ||
589 | } | ||
590 | writew(0, baseAddr + loadlen); | ||
591 | writew(usum, baseAddr + checksum); | ||
592 | writew(0, baseAddr + key); | ||
593 | for (i = 0; i < 100; i++) { | ||
594 | if (readw(baseAddr + key) == keycode) | ||
595 | break; | ||
596 | msleep(10); | ||
597 | } | ||
598 | retry++; | ||
599 | } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3)); | ||
600 | if (readb(baseAddr + checksum_ok) != 1) | ||
601 | return -EIO; | ||
602 | |||
603 | writew(0, baseAddr + key); | ||
604 | for (i = 0; i < 600; i++) { | ||
605 | if (readw(baseAddr + Magic_no) == Magic_code) | ||
606 | break; | ||
607 | msleep(10); | ||
608 | } | ||
609 | if (readw(baseAddr + Magic_no) != Magic_code) | ||
610 | return -EIO; | ||
611 | |||
612 | if (MOXA_IS_320(brd)) { | ||
613 | if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */ | ||
614 | writew(0x3800, baseAddr + TMS320_PORT1); | ||
615 | writew(0x3900, baseAddr + TMS320_PORT2); | ||
616 | writew(28499, baseAddr + TMS320_CLOCK); | ||
617 | } else { | ||
618 | writew(0x3200, baseAddr + TMS320_PORT1); | ||
619 | writew(0x3400, baseAddr + TMS320_PORT2); | ||
620 | writew(19999, baseAddr + TMS320_CLOCK); | ||
621 | } | ||
622 | } | ||
623 | writew(1, baseAddr + Disable_IRQ); | ||
624 | writew(0, baseAddr + Magic_no); | ||
625 | for (i = 0; i < 500; i++) { | ||
626 | if (readw(baseAddr + Magic_no) == Magic_code) | ||
627 | break; | ||
628 | msleep(10); | ||
629 | } | ||
630 | if (readw(baseAddr + Magic_no) != Magic_code) | ||
631 | return -EIO; | ||
632 | |||
633 | if (MOXA_IS_320(brd)) { | ||
634 | j = readw(baseAddr + Module_cnt); | ||
635 | if (j <= 0) | ||
636 | return -EIO; | ||
637 | brd->numPorts = j * 8; | ||
638 | writew(j, baseAddr + Module_no); | ||
639 | writew(0, baseAddr + Magic_no); | ||
640 | for (i = 0; i < 600; i++) { | ||
641 | if (readw(baseAddr + Magic_no) == Magic_code) | ||
642 | break; | ||
643 | msleep(10); | ||
644 | } | ||
645 | if (readw(baseAddr + Magic_no) != Magic_code) | ||
646 | return -EIO; | ||
647 | } | ||
648 | brd->intNdx = baseAddr + IRQindex; | ||
649 | brd->intPend = baseAddr + IRQpending; | ||
650 | brd->intTable = baseAddr + IRQtable; | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr, | ||
656 | size_t len) | ||
657 | { | ||
658 | void __iomem *ofsAddr, *baseAddr = brd->basemem; | ||
659 | struct moxa_port *port; | ||
660 | int retval, i; | ||
661 | |||
662 | if (len % 2) { | ||
663 | printk(KERN_ERR "MOXA: bios length is not even\n"); | ||
664 | return -EINVAL; | ||
665 | } | ||
666 | |||
667 | retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */ | ||
668 | if (retval) | ||
669 | return retval; | ||
670 | |||
671 | switch (brd->boardType) { | ||
672 | case MOXA_BOARD_C218_ISA: | ||
673 | case MOXA_BOARD_C218_PCI: | ||
674 | case MOXA_BOARD_CP204J: | ||
675 | port = brd->ports; | ||
676 | for (i = 0; i < brd->numPorts; i++, port++) { | ||
677 | port->board = brd; | ||
678 | port->DCDState = 0; | ||
679 | port->tableAddr = baseAddr + Extern_table + | ||
680 | Extern_size * i; | ||
681 | ofsAddr = port->tableAddr; | ||
682 | writew(C218rx_mask, ofsAddr + RX_mask); | ||
683 | writew(C218tx_mask, ofsAddr + TX_mask); | ||
684 | writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); | ||
685 | writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); | ||
686 | |||
687 | writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); | ||
688 | writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); | ||
689 | |||
690 | } | ||
691 | break; | ||
692 | default: | ||
693 | port = brd->ports; | ||
694 | for (i = 0; i < brd->numPorts; i++, port++) { | ||
695 | port->board = brd; | ||
696 | port->DCDState = 0; | ||
697 | port->tableAddr = baseAddr + Extern_table + | ||
698 | Extern_size * i; | ||
699 | ofsAddr = port->tableAddr; | ||
700 | switch (brd->numPorts) { | ||
701 | case 8: | ||
702 | writew(C320p8rx_mask, ofsAddr + RX_mask); | ||
703 | writew(C320p8tx_mask, ofsAddr + TX_mask); | ||
704 | writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); | ||
705 | writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); | ||
706 | writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); | ||
707 | writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); | ||
708 | |||
709 | break; | ||
710 | case 16: | ||
711 | writew(C320p16rx_mask, ofsAddr + RX_mask); | ||
712 | writew(C320p16tx_mask, ofsAddr + TX_mask); | ||
713 | writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); | ||
714 | writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); | ||
715 | writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); | ||
716 | writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); | ||
717 | break; | ||
718 | |||
719 | case 24: | ||
720 | writew(C320p24rx_mask, ofsAddr + RX_mask); | ||
721 | writew(C320p24tx_mask, ofsAddr + TX_mask); | ||
722 | writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); | ||
723 | writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); | ||
724 | writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); | ||
725 | writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); | ||
726 | break; | ||
727 | case 32: | ||
728 | writew(C320p32rx_mask, ofsAddr + RX_mask); | ||
729 | writew(C320p32tx_mask, ofsAddr + TX_mask); | ||
730 | writew(C320p32tx_ofs, ofsAddr + Ofs_txb); | ||
731 | writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); | ||
732 | writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); | ||
733 | writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); | ||
734 | writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | break; | ||
739 | } | ||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw) | ||
744 | { | ||
745 | const void *ptr = fw->data; | ||
746 | char rsn[64]; | ||
747 | u16 lens[5]; | ||
748 | size_t len; | ||
749 | unsigned int a, lenp, lencnt; | ||
750 | int ret = -EINVAL; | ||
751 | struct { | ||
752 | __le32 magic; /* 0x34303430 */ | ||
753 | u8 reserved1[2]; | ||
754 | u8 type; /* UNIX = 3 */ | ||
755 | u8 model; /* C218T=1, C320T=2, CP204=3 */ | ||
756 | u8 reserved2[8]; | ||
757 | __le16 len[5]; | ||
758 | } const *hdr = ptr; | ||
759 | |||
760 | BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens)); | ||
761 | |||
762 | if (fw->size < MOXA_FW_HDRLEN) { | ||
763 | strcpy(rsn, "too short (even header won't fit)"); | ||
764 | goto err; | ||
765 | } | ||
766 | if (hdr->magic != cpu_to_le32(0x30343034)) { | ||
767 | sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic)); | ||
768 | goto err; | ||
769 | } | ||
770 | if (hdr->type != 3) { | ||
771 | sprintf(rsn, "not for linux, type is %u", hdr->type); | ||
772 | goto err; | ||
773 | } | ||
774 | if (moxa_check_fw_model(brd, hdr->model)) { | ||
775 | sprintf(rsn, "not for this card, model is %u", hdr->model); | ||
776 | goto err; | ||
777 | } | ||
778 | |||
779 | len = MOXA_FW_HDRLEN; | ||
780 | lencnt = hdr->model == 2 ? 5 : 3; | ||
781 | for (a = 0; a < ARRAY_SIZE(lens); a++) { | ||
782 | lens[a] = le16_to_cpu(hdr->len[a]); | ||
783 | if (lens[a] && len + lens[a] <= fw->size && | ||
784 | moxa_check_fw(&fw->data[len])) | ||
785 | printk(KERN_WARNING "MOXA firmware: unexpected input " | ||
786 | "at offset %u, but going on\n", (u32)len); | ||
787 | if (!lens[a] && a < lencnt) { | ||
788 | sprintf(rsn, "too few entries in fw file"); | ||
789 | goto err; | ||
790 | } | ||
791 | len += lens[a]; | ||
792 | } | ||
793 | |||
794 | if (len != fw->size) { | ||
795 | sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size, | ||
796 | (u32)len); | ||
797 | goto err; | ||
798 | } | ||
799 | |||
800 | ptr += MOXA_FW_HDRLEN; | ||
801 | lenp = 0; /* bios */ | ||
802 | |||
803 | strcpy(rsn, "read above"); | ||
804 | |||
805 | ret = moxa_load_bios(brd, ptr, lens[lenp]); | ||
806 | if (ret) | ||
807 | goto err; | ||
808 | |||
809 | /* we skip the tty section (lens[1]), since we don't need it */ | ||
810 | ptr += lens[lenp] + lens[lenp + 1]; | ||
811 | lenp += 2; /* comm */ | ||
812 | |||
813 | if (hdr->model == 2) { | ||
814 | ret = moxa_load_320b(brd, ptr, lens[lenp]); | ||
815 | if (ret) | ||
816 | goto err; | ||
817 | /* skip another tty */ | ||
818 | ptr += lens[lenp] + lens[lenp + 1]; | ||
819 | lenp += 2; | ||
820 | } | ||
821 | |||
822 | ret = moxa_load_code(brd, ptr, lens[lenp]); | ||
823 | if (ret) | ||
824 | goto err; | ||
825 | |||
826 | return 0; | ||
827 | err: | ||
828 | printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn); | ||
829 | return ret; | ||
830 | } | ||
831 | |||
832 | static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) | ||
833 | { | ||
834 | const struct firmware *fw; | ||
835 | const char *file; | ||
836 | struct moxa_port *p; | ||
837 | unsigned int i; | ||
838 | int ret; | ||
839 | |||
840 | brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), | ||
841 | GFP_KERNEL); | ||
842 | if (brd->ports == NULL) { | ||
843 | printk(KERN_ERR "cannot allocate memory for ports\n"); | ||
844 | ret = -ENOMEM; | ||
845 | goto err; | ||
846 | } | ||
847 | |||
848 | for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { | ||
849 | tty_port_init(&p->port); | ||
850 | p->port.ops = &moxa_port_ops; | ||
851 | p->type = PORT_16550A; | ||
852 | p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; | ||
853 | } | ||
854 | |||
855 | switch (brd->boardType) { | ||
856 | case MOXA_BOARD_C218_ISA: | ||
857 | case MOXA_BOARD_C218_PCI: | ||
858 | file = "c218tunx.cod"; | ||
859 | break; | ||
860 | case MOXA_BOARD_CP204J: | ||
861 | file = "cp204unx.cod"; | ||
862 | break; | ||
863 | default: | ||
864 | file = "c320tunx.cod"; | ||
865 | break; | ||
866 | } | ||
867 | |||
868 | ret = request_firmware(&fw, file, dev); | ||
869 | if (ret) { | ||
870 | printk(KERN_ERR "MOXA: request_firmware failed. Make sure " | ||
871 | "you've placed '%s' file into your firmware " | ||
872 | "loader directory (e.g. /lib/firmware)\n", | ||
873 | file); | ||
874 | goto err_free; | ||
875 | } | ||
876 | |||
877 | ret = moxa_load_fw(brd, fw); | ||
878 | |||
879 | release_firmware(fw); | ||
880 | |||
881 | if (ret) | ||
882 | goto err_free; | ||
883 | |||
884 | spin_lock_bh(&moxa_lock); | ||
885 | brd->ready = 1; | ||
886 | if (!timer_pending(&moxaTimer)) | ||
887 | mod_timer(&moxaTimer, jiffies + HZ / 50); | ||
888 | spin_unlock_bh(&moxa_lock); | ||
889 | |||
890 | return 0; | ||
891 | err_free: | ||
892 | kfree(brd->ports); | ||
893 | err: | ||
894 | return ret; | ||
895 | } | ||
896 | |||
897 | static void moxa_board_deinit(struct moxa_board_conf *brd) | ||
898 | { | ||
899 | unsigned int a, opened; | ||
900 | |||
901 | mutex_lock(&moxa_openlock); | ||
902 | spin_lock_bh(&moxa_lock); | ||
903 | brd->ready = 0; | ||
904 | spin_unlock_bh(&moxa_lock); | ||
905 | |||
906 | /* pci hot-un-plug support */ | ||
907 | for (a = 0; a < brd->numPorts; a++) | ||
908 | if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { | ||
909 | struct tty_struct *tty = tty_port_tty_get( | ||
910 | &brd->ports[a].port); | ||
911 | if (tty) { | ||
912 | tty_hangup(tty); | ||
913 | tty_kref_put(tty); | ||
914 | } | ||
915 | } | ||
916 | while (1) { | ||
917 | opened = 0; | ||
918 | for (a = 0; a < brd->numPorts; a++) | ||
919 | if (brd->ports[a].port.flags & ASYNC_INITIALIZED) | ||
920 | opened++; | ||
921 | mutex_unlock(&moxa_openlock); | ||
922 | if (!opened) | ||
923 | break; | ||
924 | msleep(50); | ||
925 | mutex_lock(&moxa_openlock); | ||
926 | } | ||
927 | |||
928 | iounmap(brd->basemem); | ||
929 | brd->basemem = NULL; | ||
930 | kfree(brd->ports); | ||
931 | } | ||
932 | |||
933 | #ifdef CONFIG_PCI | ||
934 | static int __devinit moxa_pci_probe(struct pci_dev *pdev, | ||
935 | const struct pci_device_id *ent) | ||
936 | { | ||
937 | struct moxa_board_conf *board; | ||
938 | unsigned int i; | ||
939 | int board_type = ent->driver_data; | ||
940 | int retval; | ||
941 | |||
942 | retval = pci_enable_device(pdev); | ||
943 | if (retval) { | ||
944 | dev_err(&pdev->dev, "can't enable pci device\n"); | ||
945 | goto err; | ||
946 | } | ||
947 | |||
948 | for (i = 0; i < MAX_BOARDS; i++) | ||
949 | if (moxa_boards[i].basemem == NULL) | ||
950 | break; | ||
951 | |||
952 | retval = -ENODEV; | ||
953 | if (i >= MAX_BOARDS) { | ||
954 | dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards " | ||
955 | "found. Board is ignored.\n", MAX_BOARDS); | ||
956 | goto err; | ||
957 | } | ||
958 | |||
959 | board = &moxa_boards[i]; | ||
960 | |||
961 | retval = pci_request_region(pdev, 2, "moxa-base"); | ||
962 | if (retval) { | ||
963 | dev_err(&pdev->dev, "can't request pci region 2\n"); | ||
964 | goto err; | ||
965 | } | ||
966 | |||
967 | board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000); | ||
968 | if (board->basemem == NULL) { | ||
969 | dev_err(&pdev->dev, "can't remap io space 2\n"); | ||
970 | goto err_reg; | ||
971 | } | ||
972 | |||
973 | board->boardType = board_type; | ||
974 | switch (board_type) { | ||
975 | case MOXA_BOARD_C218_ISA: | ||
976 | case MOXA_BOARD_C218_PCI: | ||
977 | board->numPorts = 8; | ||
978 | break; | ||
979 | |||
980 | case MOXA_BOARD_CP204J: | ||
981 | board->numPorts = 4; | ||
982 | break; | ||
983 | default: | ||
984 | board->numPorts = 0; | ||
985 | break; | ||
986 | } | ||
987 | board->busType = MOXA_BUS_TYPE_PCI; | ||
988 | |||
989 | retval = moxa_init_board(board, &pdev->dev); | ||
990 | if (retval) | ||
991 | goto err_base; | ||
992 | |||
993 | pci_set_drvdata(pdev, board); | ||
994 | |||
995 | dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n", | ||
996 | moxa_brdname[board_type - 1], board->numPorts); | ||
997 | |||
998 | return 0; | ||
999 | err_base: | ||
1000 | iounmap(board->basemem); | ||
1001 | board->basemem = NULL; | ||
1002 | err_reg: | ||
1003 | pci_release_region(pdev, 2); | ||
1004 | err: | ||
1005 | return retval; | ||
1006 | } | ||
1007 | |||
1008 | static void __devexit moxa_pci_remove(struct pci_dev *pdev) | ||
1009 | { | ||
1010 | struct moxa_board_conf *brd = pci_get_drvdata(pdev); | ||
1011 | |||
1012 | moxa_board_deinit(brd); | ||
1013 | |||
1014 | pci_release_region(pdev, 2); | ||
1015 | } | ||
1016 | |||
1017 | static struct pci_driver moxa_pci_driver = { | ||
1018 | .name = "moxa", | ||
1019 | .id_table = moxa_pcibrds, | ||
1020 | .probe = moxa_pci_probe, | ||
1021 | .remove = __devexit_p(moxa_pci_remove) | ||
1022 | }; | ||
1023 | #endif /* CONFIG_PCI */ | ||
1024 | |||
1025 | static int __init moxa_init(void) | ||
1026 | { | ||
1027 | unsigned int isabrds = 0; | ||
1028 | int retval = 0; | ||
1029 | struct moxa_board_conf *brd = moxa_boards; | ||
1030 | unsigned int i; | ||
1031 | |||
1032 | printk(KERN_INFO "MOXA Intellio family driver version %s\n", | ||
1033 | MOXA_VERSION); | ||
1034 | moxaDriver = alloc_tty_driver(MAX_PORTS + 1); | ||
1035 | if (!moxaDriver) | ||
1036 | return -ENOMEM; | ||
1037 | |||
1038 | moxaDriver->owner = THIS_MODULE; | ||
1039 | moxaDriver->name = "ttyMX"; | ||
1040 | moxaDriver->major = ttymajor; | ||
1041 | moxaDriver->minor_start = 0; | ||
1042 | moxaDriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
1043 | moxaDriver->subtype = SERIAL_TYPE_NORMAL; | ||
1044 | moxaDriver->init_termios = tty_std_termios; | ||
1045 | moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; | ||
1046 | moxaDriver->init_termios.c_ispeed = 9600; | ||
1047 | moxaDriver->init_termios.c_ospeed = 9600; | ||
1048 | moxaDriver->flags = TTY_DRIVER_REAL_RAW; | ||
1049 | tty_set_operations(moxaDriver, &moxa_ops); | ||
1050 | |||
1051 | if (tty_register_driver(moxaDriver)) { | ||
1052 | printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); | ||
1053 | put_tty_driver(moxaDriver); | ||
1054 | return -1; | ||
1055 | } | ||
1056 | |||
1057 | /* Find the boards defined from module args. */ | ||
1058 | |||
1059 | for (i = 0; i < MAX_BOARDS; i++) { | ||
1060 | if (!baseaddr[i]) | ||
1061 | break; | ||
1062 | if (type[i] == MOXA_BOARD_C218_ISA || | ||
1063 | type[i] == MOXA_BOARD_C320_ISA) { | ||
1064 | pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", | ||
1065 | isabrds + 1, moxa_brdname[type[i] - 1], | ||
1066 | baseaddr[i]); | ||
1067 | brd->boardType = type[i]; | ||
1068 | brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 : | ||
1069 | numports[i]; | ||
1070 | brd->busType = MOXA_BUS_TYPE_ISA; | ||
1071 | brd->basemem = ioremap_nocache(baseaddr[i], 0x4000); | ||
1072 | if (!brd->basemem) { | ||
1073 | printk(KERN_ERR "MOXA: can't remap %lx\n", | ||
1074 | baseaddr[i]); | ||
1075 | continue; | ||
1076 | } | ||
1077 | if (moxa_init_board(brd, NULL)) { | ||
1078 | iounmap(brd->basemem); | ||
1079 | brd->basemem = NULL; | ||
1080 | continue; | ||
1081 | } | ||
1082 | |||
1083 | printk(KERN_INFO "MOXA isa board found at 0x%.8lu and " | ||
1084 | "ready (%u ports, firmware loaded)\n", | ||
1085 | baseaddr[i], brd->numPorts); | ||
1086 | |||
1087 | brd++; | ||
1088 | isabrds++; | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | #ifdef CONFIG_PCI | ||
1093 | retval = pci_register_driver(&moxa_pci_driver); | ||
1094 | if (retval) { | ||
1095 | printk(KERN_ERR "Can't register MOXA pci driver!\n"); | ||
1096 | if (isabrds) | ||
1097 | retval = 0; | ||
1098 | } | ||
1099 | #endif | ||
1100 | |||
1101 | return retval; | ||
1102 | } | ||
1103 | |||
1104 | static void __exit moxa_exit(void) | ||
1105 | { | ||
1106 | unsigned int i; | ||
1107 | |||
1108 | #ifdef CONFIG_PCI | ||
1109 | pci_unregister_driver(&moxa_pci_driver); | ||
1110 | #endif | ||
1111 | |||
1112 | for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */ | ||
1113 | if (moxa_boards[i].ready) | ||
1114 | moxa_board_deinit(&moxa_boards[i]); | ||
1115 | |||
1116 | del_timer_sync(&moxaTimer); | ||
1117 | |||
1118 | if (tty_unregister_driver(moxaDriver)) | ||
1119 | printk(KERN_ERR "Couldn't unregister MOXA Intellio family " | ||
1120 | "serial driver\n"); | ||
1121 | put_tty_driver(moxaDriver); | ||
1122 | } | ||
1123 | |||
1124 | module_init(moxa_init); | ||
1125 | module_exit(moxa_exit); | ||
1126 | |||
1127 | static void moxa_shutdown(struct tty_port *port) | ||
1128 | { | ||
1129 | struct moxa_port *ch = container_of(port, struct moxa_port, port); | ||
1130 | MoxaPortDisable(ch); | ||
1131 | MoxaPortFlushData(ch, 2); | ||
1132 | clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); | ||
1133 | } | ||
1134 | |||
1135 | static int moxa_carrier_raised(struct tty_port *port) | ||
1136 | { | ||
1137 | struct moxa_port *ch = container_of(port, struct moxa_port, port); | ||
1138 | int dcd; | ||
1139 | |||
1140 | spin_lock_irq(&port->lock); | ||
1141 | dcd = ch->DCDState; | ||
1142 | spin_unlock_irq(&port->lock); | ||
1143 | return dcd; | ||
1144 | } | ||
1145 | |||
1146 | static void moxa_dtr_rts(struct tty_port *port, int onoff) | ||
1147 | { | ||
1148 | struct moxa_port *ch = container_of(port, struct moxa_port, port); | ||
1149 | MoxaPortLineCtrl(ch, onoff, onoff); | ||
1150 | } | ||
1151 | |||
1152 | |||
1153 | static int moxa_open(struct tty_struct *tty, struct file *filp) | ||
1154 | { | ||
1155 | struct moxa_board_conf *brd; | ||
1156 | struct moxa_port *ch; | ||
1157 | int port; | ||
1158 | int retval; | ||
1159 | |||
1160 | port = tty->index; | ||
1161 | if (port == MAX_PORTS) { | ||
1162 | return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; | ||
1163 | } | ||
1164 | if (mutex_lock_interruptible(&moxa_openlock)) | ||
1165 | return -ERESTARTSYS; | ||
1166 | brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; | ||
1167 | if (!brd->ready) { | ||
1168 | mutex_unlock(&moxa_openlock); | ||
1169 | return -ENODEV; | ||
1170 | } | ||
1171 | |||
1172 | if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) { | ||
1173 | mutex_unlock(&moxa_openlock); | ||
1174 | return -ENODEV; | ||
1175 | } | ||
1176 | |||
1177 | ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; | ||
1178 | ch->port.count++; | ||
1179 | tty->driver_data = ch; | ||
1180 | tty_port_tty_set(&ch->port, tty); | ||
1181 | mutex_lock(&ch->port.mutex); | ||
1182 | if (!(ch->port.flags & ASYNC_INITIALIZED)) { | ||
1183 | ch->statusflags = 0; | ||
1184 | moxa_set_tty_param(tty, tty->termios); | ||
1185 | MoxaPortLineCtrl(ch, 1, 1); | ||
1186 | MoxaPortEnable(ch); | ||
1187 | MoxaSetFifo(ch, ch->type == PORT_16550A); | ||
1188 | ch->port.flags |= ASYNC_INITIALIZED; | ||
1189 | } | ||
1190 | mutex_unlock(&ch->port.mutex); | ||
1191 | mutex_unlock(&moxa_openlock); | ||
1192 | |||
1193 | retval = tty_port_block_til_ready(&ch->port, tty, filp); | ||
1194 | if (retval == 0) | ||
1195 | set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags); | ||
1196 | return retval; | ||
1197 | } | ||
1198 | |||
1199 | static void moxa_close(struct tty_struct *tty, struct file *filp) | ||
1200 | { | ||
1201 | struct moxa_port *ch = tty->driver_data; | ||
1202 | ch->cflag = tty->termios->c_cflag; | ||
1203 | tty_port_close(&ch->port, tty, filp); | ||
1204 | } | ||
1205 | |||
1206 | static int moxa_write(struct tty_struct *tty, | ||
1207 | const unsigned char *buf, int count) | ||
1208 | { | ||
1209 | struct moxa_port *ch = tty->driver_data; | ||
1210 | int len; | ||
1211 | |||
1212 | if (ch == NULL) | ||
1213 | return 0; | ||
1214 | |||
1215 | spin_lock_bh(&moxa_lock); | ||
1216 | len = MoxaPortWriteData(tty, buf, count); | ||
1217 | spin_unlock_bh(&moxa_lock); | ||
1218 | |||
1219 | set_bit(LOWWAIT, &ch->statusflags); | ||
1220 | return len; | ||
1221 | } | ||
1222 | |||
1223 | static int moxa_write_room(struct tty_struct *tty) | ||
1224 | { | ||
1225 | struct moxa_port *ch; | ||
1226 | |||
1227 | if (tty->stopped) | ||
1228 | return 0; | ||
1229 | ch = tty->driver_data; | ||
1230 | if (ch == NULL) | ||
1231 | return 0; | ||
1232 | return MoxaPortTxFree(ch); | ||
1233 | } | ||
1234 | |||
1235 | static void moxa_flush_buffer(struct tty_struct *tty) | ||
1236 | { | ||
1237 | struct moxa_port *ch = tty->driver_data; | ||
1238 | |||
1239 | if (ch == NULL) | ||
1240 | return; | ||
1241 | MoxaPortFlushData(ch, 1); | ||
1242 | tty_wakeup(tty); | ||
1243 | } | ||
1244 | |||
1245 | static int moxa_chars_in_buffer(struct tty_struct *tty) | ||
1246 | { | ||
1247 | struct moxa_port *ch = tty->driver_data; | ||
1248 | int chars; | ||
1249 | |||
1250 | chars = MoxaPortTxQueue(ch); | ||
1251 | if (chars) | ||
1252 | /* | ||
1253 | * Make it possible to wakeup anything waiting for output | ||
1254 | * in tty_ioctl.c, etc. | ||
1255 | */ | ||
1256 | set_bit(EMPTYWAIT, &ch->statusflags); | ||
1257 | return chars; | ||
1258 | } | ||
1259 | |||
1260 | static int moxa_tiocmget(struct tty_struct *tty) | ||
1261 | { | ||
1262 | struct moxa_port *ch = tty->driver_data; | ||
1263 | int flag = 0, dtr, rts; | ||
1264 | |||
1265 | MoxaPortGetLineOut(ch, &dtr, &rts); | ||
1266 | if (dtr) | ||
1267 | flag |= TIOCM_DTR; | ||
1268 | if (rts) | ||
1269 | flag |= TIOCM_RTS; | ||
1270 | dtr = MoxaPortLineStatus(ch); | ||
1271 | if (dtr & 1) | ||
1272 | flag |= TIOCM_CTS; | ||
1273 | if (dtr & 2) | ||
1274 | flag |= TIOCM_DSR; | ||
1275 | if (dtr & 4) | ||
1276 | flag |= TIOCM_CD; | ||
1277 | return flag; | ||
1278 | } | ||
1279 | |||
1280 | static int moxa_tiocmset(struct tty_struct *tty, | ||
1281 | unsigned int set, unsigned int clear) | ||
1282 | { | ||
1283 | struct moxa_port *ch; | ||
1284 | int port; | ||
1285 | int dtr, rts; | ||
1286 | |||
1287 | port = tty->index; | ||
1288 | mutex_lock(&moxa_openlock); | ||
1289 | ch = tty->driver_data; | ||
1290 | if (!ch) { | ||
1291 | mutex_unlock(&moxa_openlock); | ||
1292 | return -EINVAL; | ||
1293 | } | ||
1294 | |||
1295 | MoxaPortGetLineOut(ch, &dtr, &rts); | ||
1296 | if (set & TIOCM_RTS) | ||
1297 | rts = 1; | ||
1298 | if (set & TIOCM_DTR) | ||
1299 | dtr = 1; | ||
1300 | if (clear & TIOCM_RTS) | ||
1301 | rts = 0; | ||
1302 | if (clear & TIOCM_DTR) | ||
1303 | dtr = 0; | ||
1304 | MoxaPortLineCtrl(ch, dtr, rts); | ||
1305 | mutex_unlock(&moxa_openlock); | ||
1306 | return 0; | ||
1307 | } | ||
1308 | |||
1309 | static void moxa_set_termios(struct tty_struct *tty, | ||
1310 | struct ktermios *old_termios) | ||
1311 | { | ||
1312 | struct moxa_port *ch = tty->driver_data; | ||
1313 | |||
1314 | if (ch == NULL) | ||
1315 | return; | ||
1316 | moxa_set_tty_param(tty, old_termios); | ||
1317 | if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) | ||
1318 | wake_up_interruptible(&ch->port.open_wait); | ||
1319 | } | ||
1320 | |||
1321 | static void moxa_stop(struct tty_struct *tty) | ||
1322 | { | ||
1323 | struct moxa_port *ch = tty->driver_data; | ||
1324 | |||
1325 | if (ch == NULL) | ||
1326 | return; | ||
1327 | MoxaPortTxDisable(ch); | ||
1328 | set_bit(TXSTOPPED, &ch->statusflags); | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | static void moxa_start(struct tty_struct *tty) | ||
1333 | { | ||
1334 | struct moxa_port *ch = tty->driver_data; | ||
1335 | |||
1336 | if (ch == NULL) | ||
1337 | return; | ||
1338 | |||
1339 | if (!(ch->statusflags & TXSTOPPED)) | ||
1340 | return; | ||
1341 | |||
1342 | MoxaPortTxEnable(ch); | ||
1343 | clear_bit(TXSTOPPED, &ch->statusflags); | ||
1344 | } | ||
1345 | |||
1346 | static void moxa_hangup(struct tty_struct *tty) | ||
1347 | { | ||
1348 | struct moxa_port *ch = tty->driver_data; | ||
1349 | tty_port_hangup(&ch->port); | ||
1350 | } | ||
1351 | |||
1352 | static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) | ||
1353 | { | ||
1354 | struct tty_struct *tty; | ||
1355 | unsigned long flags; | ||
1356 | dcd = !!dcd; | ||
1357 | |||
1358 | spin_lock_irqsave(&p->port.lock, flags); | ||
1359 | if (dcd != p->DCDState) { | ||
1360 | p->DCDState = dcd; | ||
1361 | spin_unlock_irqrestore(&p->port.lock, flags); | ||
1362 | tty = tty_port_tty_get(&p->port); | ||
1363 | if (tty && C_CLOCAL(tty) && !dcd) | ||
1364 | tty_hangup(tty); | ||
1365 | tty_kref_put(tty); | ||
1366 | } | ||
1367 | else | ||
1368 | spin_unlock_irqrestore(&p->port.lock, flags); | ||
1369 | } | ||
1370 | |||
1371 | static int moxa_poll_port(struct moxa_port *p, unsigned int handle, | ||
1372 | u16 __iomem *ip) | ||
1373 | { | ||
1374 | struct tty_struct *tty = tty_port_tty_get(&p->port); | ||
1375 | void __iomem *ofsAddr; | ||
1376 | unsigned int inited = p->port.flags & ASYNC_INITIALIZED; | ||
1377 | u16 intr; | ||
1378 | |||
1379 | if (tty) { | ||
1380 | if (test_bit(EMPTYWAIT, &p->statusflags) && | ||
1381 | MoxaPortTxQueue(p) == 0) { | ||
1382 | clear_bit(EMPTYWAIT, &p->statusflags); | ||
1383 | tty_wakeup(tty); | ||
1384 | } | ||
1385 | if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped && | ||
1386 | MoxaPortTxQueue(p) <= WAKEUP_CHARS) { | ||
1387 | clear_bit(LOWWAIT, &p->statusflags); | ||
1388 | tty_wakeup(tty); | ||
1389 | } | ||
1390 | |||
1391 | if (inited && !test_bit(TTY_THROTTLED, &tty->flags) && | ||
1392 | MoxaPortRxQueue(p) > 0) { /* RX */ | ||
1393 | MoxaPortReadData(p); | ||
1394 | tty_schedule_flip(tty); | ||
1395 | } | ||
1396 | } else { | ||
1397 | clear_bit(EMPTYWAIT, &p->statusflags); | ||
1398 | MoxaPortFlushData(p, 0); /* flush RX */ | ||
1399 | } | ||
1400 | |||
1401 | if (!handle) /* nothing else to do */ | ||
1402 | goto put; | ||
1403 | |||
1404 | intr = readw(ip); /* port irq status */ | ||
1405 | if (intr == 0) | ||
1406 | goto put; | ||
1407 | |||
1408 | writew(0, ip); /* ACK port */ | ||
1409 | ofsAddr = p->tableAddr; | ||
1410 | if (intr & IntrTx) /* disable tx intr */ | ||
1411 | writew(readw(ofsAddr + HostStat) & ~WakeupTx, | ||
1412 | ofsAddr + HostStat); | ||
1413 | |||
1414 | if (!inited) | ||
1415 | goto put; | ||
1416 | |||
1417 | if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ | ||
1418 | tty_insert_flip_char(tty, 0, TTY_BREAK); | ||
1419 | tty_schedule_flip(tty); | ||
1420 | } | ||
1421 | |||
1422 | if (intr & IntrLine) | ||
1423 | moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); | ||
1424 | put: | ||
1425 | tty_kref_put(tty); | ||
1426 | |||
1427 | return 0; | ||
1428 | } | ||
1429 | |||
1430 | static void moxa_poll(unsigned long ignored) | ||
1431 | { | ||
1432 | struct moxa_board_conf *brd; | ||
1433 | u16 __iomem *ip; | ||
1434 | unsigned int card, port, served = 0; | ||
1435 | |||
1436 | spin_lock(&moxa_lock); | ||
1437 | for (card = 0; card < MAX_BOARDS; card++) { | ||
1438 | brd = &moxa_boards[card]; | ||
1439 | if (!brd->ready) | ||
1440 | continue; | ||
1441 | |||
1442 | served++; | ||
1443 | |||
1444 | ip = NULL; | ||
1445 | if (readb(brd->intPend) == 0xff) | ||
1446 | ip = brd->intTable + readb(brd->intNdx); | ||
1447 | |||
1448 | for (port = 0; port < brd->numPorts; port++) | ||
1449 | moxa_poll_port(&brd->ports[port], !!ip, ip + port); | ||
1450 | |||
1451 | if (ip) | ||
1452 | writeb(0, brd->intPend); /* ACK */ | ||
1453 | |||
1454 | if (moxaLowWaterChk) { | ||
1455 | struct moxa_port *p = brd->ports; | ||
1456 | for (port = 0; port < brd->numPorts; port++, p++) | ||
1457 | if (p->lowChkFlag) { | ||
1458 | p->lowChkFlag = 0; | ||
1459 | moxa_low_water_check(p->tableAddr); | ||
1460 | } | ||
1461 | } | ||
1462 | } | ||
1463 | moxaLowWaterChk = 0; | ||
1464 | |||
1465 | if (served) | ||
1466 | mod_timer(&moxaTimer, jiffies + HZ / 50); | ||
1467 | spin_unlock(&moxa_lock); | ||
1468 | } | ||
1469 | |||
1470 | /******************************************************************************/ | ||
1471 | |||
1472 | static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) | ||
1473 | { | ||
1474 | register struct ktermios *ts = tty->termios; | ||
1475 | struct moxa_port *ch = tty->driver_data; | ||
1476 | int rts, cts, txflow, rxflow, xany, baud; | ||
1477 | |||
1478 | rts = cts = txflow = rxflow = xany = 0; | ||
1479 | if (ts->c_cflag & CRTSCTS) | ||
1480 | rts = cts = 1; | ||
1481 | if (ts->c_iflag & IXON) | ||
1482 | txflow = 1; | ||
1483 | if (ts->c_iflag & IXOFF) | ||
1484 | rxflow = 1; | ||
1485 | if (ts->c_iflag & IXANY) | ||
1486 | xany = 1; | ||
1487 | |||
1488 | /* Clear the features we don't support */ | ||
1489 | ts->c_cflag &= ~CMSPAR; | ||
1490 | MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany); | ||
1491 | baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty)); | ||
1492 | if (baud == -1) | ||
1493 | baud = tty_termios_baud_rate(old_termios); | ||
1494 | /* Not put the baud rate into the termios data */ | ||
1495 | tty_encode_baud_rate(tty, baud, baud); | ||
1496 | } | ||
1497 | |||
1498 | /***************************************************************************** | ||
1499 | * Driver level functions: * | ||
1500 | *****************************************************************************/ | ||
1501 | |||
1502 | static void MoxaPortFlushData(struct moxa_port *port, int mode) | ||
1503 | { | ||
1504 | void __iomem *ofsAddr; | ||
1505 | if (mode < 0 || mode > 2) | ||
1506 | return; | ||
1507 | ofsAddr = port->tableAddr; | ||
1508 | moxafunc(ofsAddr, FC_FlushQueue, mode); | ||
1509 | if (mode != 1) { | ||
1510 | port->lowChkFlag = 0; | ||
1511 | moxa_low_water_check(ofsAddr); | ||
1512 | } | ||
1513 | } | ||
1514 | |||
1515 | /* | ||
1516 | * Moxa Port Number Description: | ||
1517 | * | ||
1518 | * MOXA serial driver supports up to 4 MOXA-C218/C320 boards. And, | ||
1519 | * the port number using in MOXA driver functions will be 0 to 31 for | ||
1520 | * first MOXA board, 32 to 63 for second, 64 to 95 for third and 96 | ||
1521 | * to 127 for fourth. For example, if you setup three MOXA boards, | ||
1522 | * first board is C218, second board is C320-16 and third board is | ||
1523 | * C320-32. The port number of first board (C218 - 8 ports) is from | ||
1524 | * 0 to 7. The port number of second board (C320 - 16 ports) is form | ||
1525 | * 32 to 47. The port number of third board (C320 - 32 ports) is from | ||
1526 | * 64 to 95. And those port numbers form 8 to 31, 48 to 63 and 96 to | ||
1527 | * 127 will be invalid. | ||
1528 | * | ||
1529 | * | ||
1530 | * Moxa Functions Description: | ||
1531 | * | ||
1532 | * Function 1: Driver initialization routine, this routine must be | ||
1533 | * called when initialized driver. | ||
1534 | * Syntax: | ||
1535 | * void MoxaDriverInit(); | ||
1536 | * | ||
1537 | * | ||
1538 | * Function 2: Moxa driver private IOCTL command processing. | ||
1539 | * Syntax: | ||
1540 | * int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); | ||
1541 | * | ||
1542 | * unsigned int cmd : IOCTL command | ||
1543 | * unsigned long arg : IOCTL argument | ||
1544 | * int port : port number (0 - 127) | ||
1545 | * | ||
1546 | * return: 0 (OK) | ||
1547 | * -EINVAL | ||
1548 | * -ENOIOCTLCMD | ||
1549 | * | ||
1550 | * | ||
1551 | * Function 6: Enable this port to start Tx/Rx data. | ||
1552 | * Syntax: | ||
1553 | * void MoxaPortEnable(int port); | ||
1554 | * int port : port number (0 - 127) | ||
1555 | * | ||
1556 | * | ||
1557 | * Function 7: Disable this port | ||
1558 | * Syntax: | ||
1559 | * void MoxaPortDisable(int port); | ||
1560 | * int port : port number (0 - 127) | ||
1561 | * | ||
1562 | * | ||
1563 | * Function 10: Setting baud rate of this port. | ||
1564 | * Syntax: | ||
1565 | * speed_t MoxaPortSetBaud(int port, speed_t baud); | ||
1566 | * int port : port number (0 - 127) | ||
1567 | * long baud : baud rate (50 - 115200) | ||
1568 | * | ||
1569 | * return: 0 : this port is invalid or baud < 50 | ||
1570 | * 50 - 115200 : the real baud rate set to the port, if | ||
1571 | * the argument baud is large than maximun | ||
1572 | * available baud rate, the real setting | ||
1573 | * baud rate will be the maximun baud rate. | ||
1574 | * | ||
1575 | * | ||
1576 | * Function 12: Configure the port. | ||
1577 | * Syntax: | ||
1578 | * int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud); | ||
1579 | * int port : port number (0 - 127) | ||
1580 | * struct ktermios * termio : termio structure pointer | ||
1581 | * speed_t baud : baud rate | ||
1582 | * | ||
1583 | * return: -1 : this port is invalid or termio == NULL | ||
1584 | * 0 : setting O.K. | ||
1585 | * | ||
1586 | * | ||
1587 | * Function 13: Get the DTR/RTS state of this port. | ||
1588 | * Syntax: | ||
1589 | * int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); | ||
1590 | * int port : port number (0 - 127) | ||
1591 | * int * dtrState : pointer to INT to receive the current DTR | ||
1592 | * state. (if NULL, this function will not | ||
1593 | * write to this address) | ||
1594 | * int * rtsState : pointer to INT to receive the current RTS | ||
1595 | * state. (if NULL, this function will not | ||
1596 | * write to this address) | ||
1597 | * | ||
1598 | * return: -1 : this port is invalid | ||
1599 | * 0 : O.K. | ||
1600 | * | ||
1601 | * | ||
1602 | * Function 14: Setting the DTR/RTS output state of this port. | ||
1603 | * Syntax: | ||
1604 | * void MoxaPortLineCtrl(int port, int dtrState, int rtsState); | ||
1605 | * int port : port number (0 - 127) | ||
1606 | * int dtrState : DTR output state (0: off, 1: on) | ||
1607 | * int rtsState : RTS output state (0: off, 1: on) | ||
1608 | * | ||
1609 | * | ||
1610 | * Function 15: Setting the flow control of this port. | ||
1611 | * Syntax: | ||
1612 | * void MoxaPortFlowCtrl(int port, int rtsFlow, int ctsFlow, int rxFlow, | ||
1613 | * int txFlow,int xany); | ||
1614 | * int port : port number (0 - 127) | ||
1615 | * int rtsFlow : H/W RTS flow control (0: no, 1: yes) | ||
1616 | * int ctsFlow : H/W CTS flow control (0: no, 1: yes) | ||
1617 | * int rxFlow : S/W Rx XON/XOFF flow control (0: no, 1: yes) | ||
1618 | * int txFlow : S/W Tx XON/XOFF flow control (0: no, 1: yes) | ||
1619 | * int xany : S/W XANY flow control (0: no, 1: yes) | ||
1620 | * | ||
1621 | * | ||
1622 | * Function 16: Get ths line status of this port | ||
1623 | * Syntax: | ||
1624 | * int MoxaPortLineStatus(int port); | ||
1625 | * int port : port number (0 - 127) | ||
1626 | * | ||
1627 | * return: Bit 0 - CTS state (0: off, 1: on) | ||
1628 | * Bit 1 - DSR state (0: off, 1: on) | ||
1629 | * Bit 2 - DCD state (0: off, 1: on) | ||
1630 | * | ||
1631 | * | ||
1632 | * Function 19: Flush the Rx/Tx buffer data of this port. | ||
1633 | * Syntax: | ||
1634 | * void MoxaPortFlushData(int port, int mode); | ||
1635 | * int port : port number (0 - 127) | ||
1636 | * int mode | ||
1637 | * 0 : flush the Rx buffer | ||
1638 | * 1 : flush the Tx buffer | ||
1639 | * 2 : flush the Rx and Tx buffer | ||
1640 | * | ||
1641 | * | ||
1642 | * Function 20: Write data. | ||
1643 | * Syntax: | ||
1644 | * int MoxaPortWriteData(int port, unsigned char * buffer, int length); | ||
1645 | * int port : port number (0 - 127) | ||
1646 | * unsigned char * buffer : pointer to write data buffer. | ||
1647 | * int length : write data length | ||
1648 | * | ||
1649 | * return: 0 - length : real write data length | ||
1650 | * | ||
1651 | * | ||
1652 | * Function 21: Read data. | ||
1653 | * Syntax: | ||
1654 | * int MoxaPortReadData(int port, struct tty_struct *tty); | ||
1655 | * int port : port number (0 - 127) | ||
1656 | * struct tty_struct *tty : tty for data | ||
1657 | * | ||
1658 | * return: 0 - length : real read data length | ||
1659 | * | ||
1660 | * | ||
1661 | * Function 24: Get the Tx buffer current queued data bytes | ||
1662 | * Syntax: | ||
1663 | * int MoxaPortTxQueue(int port); | ||
1664 | * int port : port number (0 - 127) | ||
1665 | * | ||
1666 | * return: .. : Tx buffer current queued data bytes | ||
1667 | * | ||
1668 | * | ||
1669 | * Function 25: Get the Tx buffer current free space | ||
1670 | * Syntax: | ||
1671 | * int MoxaPortTxFree(int port); | ||
1672 | * int port : port number (0 - 127) | ||
1673 | * | ||
1674 | * return: .. : Tx buffer current free space | ||
1675 | * | ||
1676 | * | ||
1677 | * Function 26: Get the Rx buffer current queued data bytes | ||
1678 | * Syntax: | ||
1679 | * int MoxaPortRxQueue(int port); | ||
1680 | * int port : port number (0 - 127) | ||
1681 | * | ||
1682 | * return: .. : Rx buffer current queued data bytes | ||
1683 | * | ||
1684 | * | ||
1685 | * Function 28: Disable port data transmission. | ||
1686 | * Syntax: | ||
1687 | * void MoxaPortTxDisable(int port); | ||
1688 | * int port : port number (0 - 127) | ||
1689 | * | ||
1690 | * | ||
1691 | * Function 29: Enable port data transmission. | ||
1692 | * Syntax: | ||
1693 | * void MoxaPortTxEnable(int port); | ||
1694 | * int port : port number (0 - 127) | ||
1695 | * | ||
1696 | * | ||
1697 | * Function 31: Get the received BREAK signal count and reset it. | ||
1698 | * Syntax: | ||
1699 | * int MoxaPortResetBrkCnt(int port); | ||
1700 | * int port : port number (0 - 127) | ||
1701 | * | ||
1702 | * return: 0 - .. : BREAK signal count | ||
1703 | * | ||
1704 | * | ||
1705 | */ | ||
1706 | |||
1707 | static void MoxaPortEnable(struct moxa_port *port) | ||
1708 | { | ||
1709 | void __iomem *ofsAddr; | ||
1710 | u16 lowwater = 512; | ||
1711 | |||
1712 | ofsAddr = port->tableAddr; | ||
1713 | writew(lowwater, ofsAddr + Low_water); | ||
1714 | if (MOXA_IS_320(port->board)) | ||
1715 | moxafunc(ofsAddr, FC_SetBreakIrq, 0); | ||
1716 | else | ||
1717 | writew(readw(ofsAddr + HostStat) | WakeupBreak, | ||
1718 | ofsAddr + HostStat); | ||
1719 | |||
1720 | moxafunc(ofsAddr, FC_SetLineIrq, Magic_code); | ||
1721 | moxafunc(ofsAddr, FC_FlushQueue, 2); | ||
1722 | |||
1723 | moxafunc(ofsAddr, FC_EnableCH, Magic_code); | ||
1724 | MoxaPortLineStatus(port); | ||
1725 | } | ||
1726 | |||
1727 | static void MoxaPortDisable(struct moxa_port *port) | ||
1728 | { | ||
1729 | void __iomem *ofsAddr = port->tableAddr; | ||
1730 | |||
1731 | moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ | ||
1732 | moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); | ||
1733 | writew(0, ofsAddr + HostStat); | ||
1734 | moxafunc(ofsAddr, FC_DisableCH, Magic_code); | ||
1735 | } | ||
1736 | |||
1737 | static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud) | ||
1738 | { | ||
1739 | void __iomem *ofsAddr = port->tableAddr; | ||
1740 | unsigned int clock, val; | ||
1741 | speed_t max; | ||
1742 | |||
1743 | max = MOXA_IS_320(port->board) ? 460800 : 921600; | ||
1744 | if (baud < 50) | ||
1745 | return 0; | ||
1746 | if (baud > max) | ||
1747 | baud = max; | ||
1748 | clock = 921600; | ||
1749 | val = clock / baud; | ||
1750 | moxafunc(ofsAddr, FC_SetBaud, val); | ||
1751 | baud = clock / val; | ||
1752 | return baud; | ||
1753 | } | ||
1754 | |||
1755 | static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, | ||
1756 | speed_t baud) | ||
1757 | { | ||
1758 | void __iomem *ofsAddr; | ||
1759 | tcflag_t cflag; | ||
1760 | tcflag_t mode = 0; | ||
1761 | |||
1762 | ofsAddr = port->tableAddr; | ||
1763 | cflag = termio->c_cflag; /* termio->c_cflag */ | ||
1764 | |||
1765 | mode = termio->c_cflag & CSIZE; | ||
1766 | if (mode == CS5) | ||
1767 | mode = MX_CS5; | ||
1768 | else if (mode == CS6) | ||
1769 | mode = MX_CS6; | ||
1770 | else if (mode == CS7) | ||
1771 | mode = MX_CS7; | ||
1772 | else if (mode == CS8) | ||
1773 | mode = MX_CS8; | ||
1774 | |||
1775 | if (termio->c_cflag & CSTOPB) { | ||
1776 | if (mode == MX_CS5) | ||
1777 | mode |= MX_STOP15; | ||
1778 | else | ||
1779 | mode |= MX_STOP2; | ||
1780 | } else | ||
1781 | mode |= MX_STOP1; | ||
1782 | |||
1783 | if (termio->c_cflag & PARENB) { | ||
1784 | if (termio->c_cflag & PARODD) | ||
1785 | mode |= MX_PARODD; | ||
1786 | else | ||
1787 | mode |= MX_PAREVEN; | ||
1788 | } else | ||
1789 | mode |= MX_PARNONE; | ||
1790 | |||
1791 | moxafunc(ofsAddr, FC_SetDataMode, (u16)mode); | ||
1792 | |||
1793 | if (MOXA_IS_320(port->board) && baud >= 921600) | ||
1794 | return -1; | ||
1795 | |||
1796 | baud = MoxaPortSetBaud(port, baud); | ||
1797 | |||
1798 | if (termio->c_iflag & (IXON | IXOFF | IXANY)) { | ||
1799 | spin_lock_irq(&moxafunc_lock); | ||
1800 | writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); | ||
1801 | writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); | ||
1802 | writeb(FC_SetXonXoff, ofsAddr + FuncCode); | ||
1803 | moxa_wait_finish(ofsAddr); | ||
1804 | spin_unlock_irq(&moxafunc_lock); | ||
1805 | |||
1806 | } | ||
1807 | return baud; | ||
1808 | } | ||
1809 | |||
1810 | static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState, | ||
1811 | int *rtsState) | ||
1812 | { | ||
1813 | if (dtrState) | ||
1814 | *dtrState = !!(port->lineCtrl & DTR_ON); | ||
1815 | if (rtsState) | ||
1816 | *rtsState = !!(port->lineCtrl & RTS_ON); | ||
1817 | |||
1818 | return 0; | ||
1819 | } | ||
1820 | |||
1821 | static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts) | ||
1822 | { | ||
1823 | u8 mode = 0; | ||
1824 | |||
1825 | if (dtr) | ||
1826 | mode |= DTR_ON; | ||
1827 | if (rts) | ||
1828 | mode |= RTS_ON; | ||
1829 | port->lineCtrl = mode; | ||
1830 | moxafunc(port->tableAddr, FC_LineControl, mode); | ||
1831 | } | ||
1832 | |||
1833 | static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts, | ||
1834 | int txflow, int rxflow, int txany) | ||
1835 | { | ||
1836 | int mode = 0; | ||
1837 | |||
1838 | if (rts) | ||
1839 | mode |= RTS_FlowCtl; | ||
1840 | if (cts) | ||
1841 | mode |= CTS_FlowCtl; | ||
1842 | if (txflow) | ||
1843 | mode |= Tx_FlowCtl; | ||
1844 | if (rxflow) | ||
1845 | mode |= Rx_FlowCtl; | ||
1846 | if (txany) | ||
1847 | mode |= IXM_IXANY; | ||
1848 | moxafunc(port->tableAddr, FC_SetFlowCtl, mode); | ||
1849 | } | ||
1850 | |||
1851 | static int MoxaPortLineStatus(struct moxa_port *port) | ||
1852 | { | ||
1853 | void __iomem *ofsAddr; | ||
1854 | int val; | ||
1855 | |||
1856 | ofsAddr = port->tableAddr; | ||
1857 | if (MOXA_IS_320(port->board)) | ||
1858 | val = moxafuncret(ofsAddr, FC_LineStatus, 0); | ||
1859 | else | ||
1860 | val = readw(ofsAddr + FlagStat) >> 4; | ||
1861 | val &= 0x0B; | ||
1862 | if (val & 8) | ||
1863 | val |= 4; | ||
1864 | moxa_new_dcdstate(port, val & 8); | ||
1865 | val &= 7; | ||
1866 | return val; | ||
1867 | } | ||
1868 | |||
1869 | static int MoxaPortWriteData(struct tty_struct *tty, | ||
1870 | const unsigned char *buffer, int len) | ||
1871 | { | ||
1872 | struct moxa_port *port = tty->driver_data; | ||
1873 | void __iomem *baseAddr, *ofsAddr, *ofs; | ||
1874 | unsigned int c, total; | ||
1875 | u16 head, tail, tx_mask, spage, epage; | ||
1876 | u16 pageno, pageofs, bufhead; | ||
1877 | |||
1878 | ofsAddr = port->tableAddr; | ||
1879 | baseAddr = port->board->basemem; | ||
1880 | tx_mask = readw(ofsAddr + TX_mask); | ||
1881 | spage = readw(ofsAddr + Page_txb); | ||
1882 | epage = readw(ofsAddr + EndPage_txb); | ||
1883 | tail = readw(ofsAddr + TXwptr); | ||
1884 | head = readw(ofsAddr + TXrptr); | ||
1885 | c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask); | ||
1886 | if (c > len) | ||
1887 | c = len; | ||
1888 | moxaLog.txcnt[port->port.tty->index] += c; | ||
1889 | total = c; | ||
1890 | if (spage == epage) { | ||
1891 | bufhead = readw(ofsAddr + Ofs_txb); | ||
1892 | writew(spage, baseAddr + Control_reg); | ||
1893 | while (c > 0) { | ||
1894 | if (head > tail) | ||
1895 | len = head - tail - 1; | ||
1896 | else | ||
1897 | len = tx_mask + 1 - tail; | ||
1898 | len = (c > len) ? len : c; | ||
1899 | ofs = baseAddr + DynPage_addr + bufhead + tail; | ||
1900 | memcpy_toio(ofs, buffer, len); | ||
1901 | buffer += len; | ||
1902 | tail = (tail + len) & tx_mask; | ||
1903 | c -= len; | ||
1904 | } | ||
1905 | } else { | ||
1906 | pageno = spage + (tail >> 13); | ||
1907 | pageofs = tail & Page_mask; | ||
1908 | while (c > 0) { | ||
1909 | len = Page_size - pageofs; | ||
1910 | if (len > c) | ||
1911 | len = c; | ||
1912 | writeb(pageno, baseAddr + Control_reg); | ||
1913 | ofs = baseAddr + DynPage_addr + pageofs; | ||
1914 | memcpy_toio(ofs, buffer, len); | ||
1915 | buffer += len; | ||
1916 | if (++pageno == epage) | ||
1917 | pageno = spage; | ||
1918 | pageofs = 0; | ||
1919 | c -= len; | ||
1920 | } | ||
1921 | tail = (tail + total) & tx_mask; | ||
1922 | } | ||
1923 | writew(tail, ofsAddr + TXwptr); | ||
1924 | writeb(1, ofsAddr + CD180TXirq); /* start to send */ | ||
1925 | return total; | ||
1926 | } | ||
1927 | |||
1928 | static int MoxaPortReadData(struct moxa_port *port) | ||
1929 | { | ||
1930 | struct tty_struct *tty = port->port.tty; | ||
1931 | unsigned char *dst; | ||
1932 | void __iomem *baseAddr, *ofsAddr, *ofs; | ||
1933 | unsigned int count, len, total; | ||
1934 | u16 tail, rx_mask, spage, epage; | ||
1935 | u16 pageno, pageofs, bufhead, head; | ||
1936 | |||
1937 | ofsAddr = port->tableAddr; | ||
1938 | baseAddr = port->board->basemem; | ||
1939 | head = readw(ofsAddr + RXrptr); | ||
1940 | tail = readw(ofsAddr + RXwptr); | ||
1941 | rx_mask = readw(ofsAddr + RX_mask); | ||
1942 | spage = readw(ofsAddr + Page_rxb); | ||
1943 | epage = readw(ofsAddr + EndPage_rxb); | ||
1944 | count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1); | ||
1945 | if (count == 0) | ||
1946 | return 0; | ||
1947 | |||
1948 | total = count; | ||
1949 | moxaLog.rxcnt[tty->index] += total; | ||
1950 | if (spage == epage) { | ||
1951 | bufhead = readw(ofsAddr + Ofs_rxb); | ||
1952 | writew(spage, baseAddr + Control_reg); | ||
1953 | while (count > 0) { | ||
1954 | ofs = baseAddr + DynPage_addr + bufhead + head; | ||
1955 | len = (tail >= head) ? (tail - head) : | ||
1956 | (rx_mask + 1 - head); | ||
1957 | len = tty_prepare_flip_string(tty, &dst, | ||
1958 | min(len, count)); | ||
1959 | memcpy_fromio(dst, ofs, len); | ||
1960 | head = (head + len) & rx_mask; | ||
1961 | count -= len; | ||
1962 | } | ||
1963 | } else { | ||
1964 | pageno = spage + (head >> 13); | ||
1965 | pageofs = head & Page_mask; | ||
1966 | while (count > 0) { | ||
1967 | writew(pageno, baseAddr + Control_reg); | ||
1968 | ofs = baseAddr + DynPage_addr + pageofs; | ||
1969 | len = tty_prepare_flip_string(tty, &dst, | ||
1970 | min(Page_size - pageofs, count)); | ||
1971 | memcpy_fromio(dst, ofs, len); | ||
1972 | |||
1973 | count -= len; | ||
1974 | pageofs = (pageofs + len) & Page_mask; | ||
1975 | if (pageofs == 0 && ++pageno == epage) | ||
1976 | pageno = spage; | ||
1977 | } | ||
1978 | head = (head + total) & rx_mask; | ||
1979 | } | ||
1980 | writew(head, ofsAddr + RXrptr); | ||
1981 | if (readb(ofsAddr + FlagStat) & Xoff_state) { | ||
1982 | moxaLowWaterChk = 1; | ||
1983 | port->lowChkFlag = 1; | ||
1984 | } | ||
1985 | return total; | ||
1986 | } | ||
1987 | |||
1988 | |||
1989 | static int MoxaPortTxQueue(struct moxa_port *port) | ||
1990 | { | ||
1991 | void __iomem *ofsAddr = port->tableAddr; | ||
1992 | u16 rptr, wptr, mask; | ||
1993 | |||
1994 | rptr = readw(ofsAddr + TXrptr); | ||
1995 | wptr = readw(ofsAddr + TXwptr); | ||
1996 | mask = readw(ofsAddr + TX_mask); | ||
1997 | return (wptr - rptr) & mask; | ||
1998 | } | ||
1999 | |||
2000 | static int MoxaPortTxFree(struct moxa_port *port) | ||
2001 | { | ||
2002 | void __iomem *ofsAddr = port->tableAddr; | ||
2003 | u16 rptr, wptr, mask; | ||
2004 | |||
2005 | rptr = readw(ofsAddr + TXrptr); | ||
2006 | wptr = readw(ofsAddr + TXwptr); | ||
2007 | mask = readw(ofsAddr + TX_mask); | ||
2008 | return mask - ((wptr - rptr) & mask); | ||
2009 | } | ||
2010 | |||
2011 | static int MoxaPortRxQueue(struct moxa_port *port) | ||
2012 | { | ||
2013 | void __iomem *ofsAddr = port->tableAddr; | ||
2014 | u16 rptr, wptr, mask; | ||
2015 | |||
2016 | rptr = readw(ofsAddr + RXrptr); | ||
2017 | wptr = readw(ofsAddr + RXwptr); | ||
2018 | mask = readw(ofsAddr + RX_mask); | ||
2019 | return (wptr - rptr) & mask; | ||
2020 | } | ||
2021 | |||
2022 | static void MoxaPortTxDisable(struct moxa_port *port) | ||
2023 | { | ||
2024 | moxafunc(port->tableAddr, FC_SetXoffState, Magic_code); | ||
2025 | } | ||
2026 | |||
2027 | static void MoxaPortTxEnable(struct moxa_port *port) | ||
2028 | { | ||
2029 | moxafunc(port->tableAddr, FC_SetXonState, Magic_code); | ||
2030 | } | ||
2031 | |||
2032 | static int moxa_get_serial_info(struct moxa_port *info, | ||
2033 | struct serial_struct __user *retinfo) | ||
2034 | { | ||
2035 | struct serial_struct tmp = { | ||
2036 | .type = info->type, | ||
2037 | .line = info->port.tty->index, | ||
2038 | .flags = info->port.flags, | ||
2039 | .baud_base = 921600, | ||
2040 | .close_delay = info->port.close_delay | ||
2041 | }; | ||
2042 | return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; | ||
2043 | } | ||
2044 | |||
2045 | |||
2046 | static int moxa_set_serial_info(struct moxa_port *info, | ||
2047 | struct serial_struct __user *new_info) | ||
2048 | { | ||
2049 | struct serial_struct new_serial; | ||
2050 | |||
2051 | if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) | ||
2052 | return -EFAULT; | ||
2053 | |||
2054 | if (new_serial.irq != 0 || new_serial.port != 0 || | ||
2055 | new_serial.custom_divisor != 0 || | ||
2056 | new_serial.baud_base != 921600) | ||
2057 | return -EPERM; | ||
2058 | |||
2059 | if (!capable(CAP_SYS_ADMIN)) { | ||
2060 | if (((new_serial.flags & ~ASYNC_USR_MASK) != | ||
2061 | (info->port.flags & ~ASYNC_USR_MASK))) | ||
2062 | return -EPERM; | ||
2063 | } else | ||
2064 | info->port.close_delay = new_serial.close_delay * HZ / 100; | ||
2065 | |||
2066 | new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); | ||
2067 | new_serial.flags |= (info->port.flags & ASYNC_FLAGS); | ||
2068 | |||
2069 | MoxaSetFifo(info, new_serial.type == PORT_16550A); | ||
2070 | |||
2071 | info->type = new_serial.type; | ||
2072 | return 0; | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | |||
2077 | /***************************************************************************** | ||
2078 | * Static local functions: * | ||
2079 | *****************************************************************************/ | ||
2080 | |||
2081 | static void MoxaSetFifo(struct moxa_port *port, int enable) | ||
2082 | { | ||
2083 | void __iomem *ofsAddr = port->tableAddr; | ||
2084 | |||
2085 | if (!enable) { | ||
2086 | moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); | ||
2087 | moxafunc(ofsAddr, FC_SetTxFIFOCnt, 1); | ||
2088 | } else { | ||
2089 | moxafunc(ofsAddr, FC_SetRxFIFOTrig, 3); | ||
2090 | moxafunc(ofsAddr, FC_SetTxFIFOCnt, 16); | ||
2091 | } | ||
2092 | } | ||
diff --git a/drivers/tty/moxa.h b/drivers/tty/moxa.h new file mode 100644 index 000000000000..87d16ce57be7 --- /dev/null +++ b/drivers/tty/moxa.h | |||
@@ -0,0 +1,304 @@ | |||
1 | #ifndef MOXA_H_FILE | ||
2 | #define MOXA_H_FILE | ||
3 | |||
4 | #define MOXA 0x400 | ||
5 | #define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ | ||
6 | #define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ | ||
7 | #define MOXA_GETDATACOUNT (MOXA + 23) | ||
8 | #define MOXA_GET_IOQUEUE (MOXA + 27) | ||
9 | #define MOXA_FLUSH_QUEUE (MOXA + 28) | ||
10 | #define MOXA_GETMSTATUS (MOXA + 65) | ||
11 | |||
12 | /* | ||
13 | * System Configuration | ||
14 | */ | ||
15 | |||
16 | #define Magic_code 0x404 | ||
17 | |||
18 | /* | ||
19 | * for C218 BIOS initialization | ||
20 | */ | ||
21 | #define C218_ConfBase 0x800 | ||
22 | #define C218_status (C218_ConfBase + 0) /* BIOS running status */ | ||
23 | #define C218_diag (C218_ConfBase + 2) /* diagnostic status */ | ||
24 | #define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ | ||
25 | #define C218DLoad_len (C218_ConfBase + 6) /* WORD */ | ||
26 | #define C218check_sum (C218_ConfBase + 8) /* BYTE */ | ||
27 | #define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ | ||
28 | #define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ | ||
29 | #define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ | ||
30 | #define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ | ||
31 | #define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ | ||
32 | |||
33 | #define C218_LoadBuf 0x0F00 | ||
34 | #define C218_KeyCode 0x218 | ||
35 | #define CP204J_KeyCode 0x204 | ||
36 | |||
37 | /* | ||
38 | * for C320 BIOS initialization | ||
39 | */ | ||
40 | #define C320_ConfBase 0x800 | ||
41 | #define C320_LoadBuf 0x0f00 | ||
42 | #define STS_init 0x05 /* for C320_status */ | ||
43 | |||
44 | #define C320_status C320_ConfBase + 0 /* BIOS running status */ | ||
45 | #define C320_diag C320_ConfBase + 2 /* diagnostic status */ | ||
46 | #define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ | ||
47 | #define C320DLoad_len C320_ConfBase + 6 /* WORD */ | ||
48 | #define C320check_sum C320_ConfBase + 8 /* WORD */ | ||
49 | #define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ | ||
50 | #define C320bapi_len C320_ConfBase + 0x0c /* WORD */ | ||
51 | #define C320UART_no C320_ConfBase + 0x0e /* WORD */ | ||
52 | |||
53 | #define C320_KeyCode 0x320 | ||
54 | |||
55 | #define FixPage_addr 0x0000 /* starting addr of static page */ | ||
56 | #define DynPage_addr 0x2000 /* starting addr of dynamic page */ | ||
57 | #define C218_start 0x3000 /* starting addr of C218 BIOS prg */ | ||
58 | #define Control_reg 0x1ff0 /* select page and reset control */ | ||
59 | #define HW_reset 0x80 | ||
60 | |||
61 | /* | ||
62 | * Function Codes | ||
63 | */ | ||
64 | #define FC_CardReset 0x80 | ||
65 | #define FC_ChannelReset 1 /* C320 firmware not supported */ | ||
66 | #define FC_EnableCH 2 | ||
67 | #define FC_DisableCH 3 | ||
68 | #define FC_SetParam 4 | ||
69 | #define FC_SetMode 5 | ||
70 | #define FC_SetRate 6 | ||
71 | #define FC_LineControl 7 | ||
72 | #define FC_LineStatus 8 | ||
73 | #define FC_XmitControl 9 | ||
74 | #define FC_FlushQueue 10 | ||
75 | #define FC_SendBreak 11 | ||
76 | #define FC_StopBreak 12 | ||
77 | #define FC_LoopbackON 13 | ||
78 | #define FC_LoopbackOFF 14 | ||
79 | #define FC_ClrIrqTable 15 | ||
80 | #define FC_SendXon 16 | ||
81 | #define FC_SetTermIrq 17 /* C320 firmware not supported */ | ||
82 | #define FC_SetCntIrq 18 /* C320 firmware not supported */ | ||
83 | #define FC_SetBreakIrq 19 | ||
84 | #define FC_SetLineIrq 20 | ||
85 | #define FC_SetFlowCtl 21 | ||
86 | #define FC_GenIrq 22 | ||
87 | #define FC_InCD180 23 | ||
88 | #define FC_OutCD180 24 | ||
89 | #define FC_InUARTreg 23 | ||
90 | #define FC_OutUARTreg 24 | ||
91 | #define FC_SetXonXoff 25 | ||
92 | #define FC_OutCD180CCR 26 | ||
93 | #define FC_ExtIQueue 27 | ||
94 | #define FC_ExtOQueue 28 | ||
95 | #define FC_ClrLineIrq 29 | ||
96 | #define FC_HWFlowCtl 30 | ||
97 | #define FC_GetClockRate 35 | ||
98 | #define FC_SetBaud 36 | ||
99 | #define FC_SetDataMode 41 | ||
100 | #define FC_GetCCSR 43 | ||
101 | #define FC_GetDataError 45 | ||
102 | #define FC_RxControl 50 | ||
103 | #define FC_ImmSend 51 | ||
104 | #define FC_SetXonState 52 | ||
105 | #define FC_SetXoffState 53 | ||
106 | #define FC_SetRxFIFOTrig 54 | ||
107 | #define FC_SetTxFIFOCnt 55 | ||
108 | #define FC_UnixRate 56 | ||
109 | #define FC_UnixResetTimer 57 | ||
110 | |||
111 | #define RxFIFOTrig1 0 | ||
112 | #define RxFIFOTrig4 1 | ||
113 | #define RxFIFOTrig8 2 | ||
114 | #define RxFIFOTrig14 3 | ||
115 | |||
116 | /* | ||
117 | * Dual-Ported RAM | ||
118 | */ | ||
119 | #define DRAM_global 0 | ||
120 | #define INT_data (DRAM_global + 0) | ||
121 | #define Config_base (DRAM_global + 0x108) | ||
122 | |||
123 | #define IRQindex (INT_data + 0) | ||
124 | #define IRQpending (INT_data + 4) | ||
125 | #define IRQtable (INT_data + 8) | ||
126 | |||
127 | /* | ||
128 | * Interrupt Status | ||
129 | */ | ||
130 | #define IntrRx 0x01 /* receiver data O.K. */ | ||
131 | #define IntrTx 0x02 /* transmit buffer empty */ | ||
132 | #define IntrFunc 0x04 /* function complete */ | ||
133 | #define IntrBreak 0x08 /* received break */ | ||
134 | #define IntrLine 0x10 /* line status change | ||
135 | for transmitter */ | ||
136 | #define IntrIntr 0x20 /* received INTR code */ | ||
137 | #define IntrQuit 0x40 /* received QUIT code */ | ||
138 | #define IntrEOF 0x80 /* received EOF code */ | ||
139 | |||
140 | #define IntrRxTrigger 0x100 /* rx data count reach tigger value */ | ||
141 | #define IntrTxTrigger 0x200 /* tx data count below trigger value */ | ||
142 | |||
143 | #define Magic_no (Config_base + 0) | ||
144 | #define Card_model_no (Config_base + 2) | ||
145 | #define Total_ports (Config_base + 4) | ||
146 | #define Module_cnt (Config_base + 8) | ||
147 | #define Module_no (Config_base + 10) | ||
148 | #define Timer_10ms (Config_base + 14) | ||
149 | #define Disable_IRQ (Config_base + 20) | ||
150 | #define TMS320_PORT1 (Config_base + 22) | ||
151 | #define TMS320_PORT2 (Config_base + 24) | ||
152 | #define TMS320_CLOCK (Config_base + 26) | ||
153 | |||
154 | /* | ||
155 | * DATA BUFFER in DRAM | ||
156 | */ | ||
157 | #define Extern_table 0x400 /* Base address of the external table | ||
158 | (24 words * 64) total 3K bytes | ||
159 | (24 words * 128) total 6K bytes */ | ||
160 | #define Extern_size 0x60 /* 96 bytes */ | ||
161 | #define RXrptr 0x00 /* read pointer for RX buffer */ | ||
162 | #define RXwptr 0x02 /* write pointer for RX buffer */ | ||
163 | #define TXrptr 0x04 /* read pointer for TX buffer */ | ||
164 | #define TXwptr 0x06 /* write pointer for TX buffer */ | ||
165 | #define HostStat 0x08 /* IRQ flag and general flag */ | ||
166 | #define FlagStat 0x0A | ||
167 | #define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ | ||
168 | /* x x x x | | | | */ | ||
169 | /* | | | + CTS flow */ | ||
170 | /* | | +--- RTS flow */ | ||
171 | /* | +------ TX Xon/Xoff */ | ||
172 | /* +--------- RX Xon/Xoff */ | ||
173 | #define Break_cnt 0x0E /* received break count */ | ||
174 | #define CD180TXirq 0x10 /* if non-0: enable TX irq */ | ||
175 | #define RX_mask 0x12 | ||
176 | #define TX_mask 0x14 | ||
177 | #define Ofs_rxb 0x16 | ||
178 | #define Ofs_txb 0x18 | ||
179 | #define Page_rxb 0x1A | ||
180 | #define Page_txb 0x1C | ||
181 | #define EndPage_rxb 0x1E | ||
182 | #define EndPage_txb 0x20 | ||
183 | #define Data_error 0x22 | ||
184 | #define RxTrigger 0x28 | ||
185 | #define TxTrigger 0x2a | ||
186 | |||
187 | #define rRXwptr 0x34 | ||
188 | #define Low_water 0x36 | ||
189 | |||
190 | #define FuncCode 0x40 | ||
191 | #define FuncArg 0x42 | ||
192 | #define FuncArg1 0x44 | ||
193 | |||
194 | #define C218rx_size 0x2000 /* 8K bytes */ | ||
195 | #define C218tx_size 0x8000 /* 32K bytes */ | ||
196 | |||
197 | #define C218rx_mask (C218rx_size - 1) | ||
198 | #define C218tx_mask (C218tx_size - 1) | ||
199 | |||
200 | #define C320p8rx_size 0x2000 | ||
201 | #define C320p8tx_size 0x8000 | ||
202 | #define C320p8rx_mask (C320p8rx_size - 1) | ||
203 | #define C320p8tx_mask (C320p8tx_size - 1) | ||
204 | |||
205 | #define C320p16rx_size 0x2000 | ||
206 | #define C320p16tx_size 0x4000 | ||
207 | #define C320p16rx_mask (C320p16rx_size - 1) | ||
208 | #define C320p16tx_mask (C320p16tx_size - 1) | ||
209 | |||
210 | #define C320p24rx_size 0x2000 | ||
211 | #define C320p24tx_size 0x2000 | ||
212 | #define C320p24rx_mask (C320p24rx_size - 1) | ||
213 | #define C320p24tx_mask (C320p24tx_size - 1) | ||
214 | |||
215 | #define C320p32rx_size 0x1000 | ||
216 | #define C320p32tx_size 0x1000 | ||
217 | #define C320p32rx_mask (C320p32rx_size - 1) | ||
218 | #define C320p32tx_mask (C320p32tx_size - 1) | ||
219 | |||
220 | #define Page_size 0x2000U | ||
221 | #define Page_mask (Page_size - 1) | ||
222 | #define C218rx_spage 3 | ||
223 | #define C218tx_spage 4 | ||
224 | #define C218rx_pageno 1 | ||
225 | #define C218tx_pageno 4 | ||
226 | #define C218buf_pageno 5 | ||
227 | |||
228 | #define C320p8rx_spage 3 | ||
229 | #define C320p8tx_spage 4 | ||
230 | #define C320p8rx_pgno 1 | ||
231 | #define C320p8tx_pgno 4 | ||
232 | #define C320p8buf_pgno 5 | ||
233 | |||
234 | #define C320p16rx_spage 3 | ||
235 | #define C320p16tx_spage 4 | ||
236 | #define C320p16rx_pgno 1 | ||
237 | #define C320p16tx_pgno 2 | ||
238 | #define C320p16buf_pgno 3 | ||
239 | |||
240 | #define C320p24rx_spage 3 | ||
241 | #define C320p24tx_spage 4 | ||
242 | #define C320p24rx_pgno 1 | ||
243 | #define C320p24tx_pgno 1 | ||
244 | #define C320p24buf_pgno 2 | ||
245 | |||
246 | #define C320p32rx_spage 3 | ||
247 | #define C320p32tx_ofs C320p32rx_size | ||
248 | #define C320p32tx_spage 3 | ||
249 | #define C320p32buf_pgno 1 | ||
250 | |||
251 | /* | ||
252 | * Host Status | ||
253 | */ | ||
254 | #define WakeupRx 0x01 | ||
255 | #define WakeupTx 0x02 | ||
256 | #define WakeupBreak 0x08 | ||
257 | #define WakeupLine 0x10 | ||
258 | #define WakeupIntr 0x20 | ||
259 | #define WakeupQuit 0x40 | ||
260 | #define WakeupEOF 0x80 /* used in VTIME control */ | ||
261 | #define WakeupRxTrigger 0x100 | ||
262 | #define WakeupTxTrigger 0x200 | ||
263 | /* | ||
264 | * Flag status | ||
265 | */ | ||
266 | #define Rx_over 0x01 | ||
267 | #define Xoff_state 0x02 | ||
268 | #define Tx_flowOff 0x04 | ||
269 | #define Tx_enable 0x08 | ||
270 | #define CTS_state 0x10 | ||
271 | #define DSR_state 0x20 | ||
272 | #define DCD_state 0x80 | ||
273 | /* | ||
274 | * FlowControl | ||
275 | */ | ||
276 | #define CTS_FlowCtl 1 | ||
277 | #define RTS_FlowCtl 2 | ||
278 | #define Tx_FlowCtl 4 | ||
279 | #define Rx_FlowCtl 8 | ||
280 | #define IXM_IXANY 0x10 | ||
281 | |||
282 | #define LowWater 128 | ||
283 | |||
284 | #define DTR_ON 1 | ||
285 | #define RTS_ON 2 | ||
286 | #define CTS_ON 1 | ||
287 | #define DSR_ON 2 | ||
288 | #define DCD_ON 8 | ||
289 | |||
290 | /* mode definition */ | ||
291 | #define MX_CS8 0x03 | ||
292 | #define MX_CS7 0x02 | ||
293 | #define MX_CS6 0x01 | ||
294 | #define MX_CS5 0x00 | ||
295 | |||
296 | #define MX_STOP1 0x00 | ||
297 | #define MX_STOP15 0x04 | ||
298 | #define MX_STOP2 0x08 | ||
299 | |||
300 | #define MX_PARNONE 0x00 | ||
301 | #define MX_PAREVEN 0x40 | ||
302 | #define MX_PARODD 0xC0 | ||
303 | |||
304 | #endif | ||
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c new file mode 100644 index 000000000000..d188f378684d --- /dev/null +++ b/drivers/tty/mxser.c | |||
@@ -0,0 +1,2757 @@ | |||
1 | /* | ||
2 | * mxser.c -- MOXA Smartio/Industio family multiport serial driver. | ||
3 | * | ||
4 | * Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com). | ||
5 | * Copyright (C) 2006-2008 Jiri Slaby <jirislaby@gmail.com> | ||
6 | * | ||
7 | * This code is loosely based on the 1.8 moxa driver which is based on | ||
8 | * Linux serial driver, written by Linus Torvalds, Theodore T'so and | ||
9 | * others. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox | ||
17 | * <alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on | ||
18 | * www.moxa.com. | ||
19 | * - Fixed x86_64 cleanness | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/signal.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/timer.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/tty.h> | ||
29 | #include <linux/tty_flip.h> | ||
30 | #include <linux/serial.h> | ||
31 | #include <linux/serial_reg.h> | ||
32 | #include <linux/major.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/fcntl.h> | ||
35 | #include <linux/ptrace.h> | ||
36 | #include <linux/ioport.h> | ||
37 | #include <linux/mm.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/pci.h> | ||
40 | #include <linux/bitops.h> | ||
41 | #include <linux/slab.h> | ||
42 | |||
43 | #include <asm/system.h> | ||
44 | #include <asm/io.h> | ||
45 | #include <asm/irq.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | |||
48 | #include "mxser.h" | ||
49 | |||
50 | #define MXSER_VERSION "2.0.5" /* 1.14 */ | ||
51 | #define MXSERMAJOR 174 | ||
52 | |||
53 | #define MXSER_BOARDS 4 /* Max. boards */ | ||
54 | #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */ | ||
55 | #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) | ||
56 | #define MXSER_ISR_PASS_LIMIT 100 | ||
57 | |||
58 | /*CheckIsMoxaMust return value*/ | ||
59 | #define MOXA_OTHER_UART 0x00 | ||
60 | #define MOXA_MUST_MU150_HWID 0x01 | ||
61 | #define MOXA_MUST_MU860_HWID 0x02 | ||
62 | |||
63 | #define WAKEUP_CHARS 256 | ||
64 | |||
65 | #define UART_MCR_AFE 0x20 | ||
66 | #define UART_LSR_SPECIAL 0x1E | ||
67 | |||
68 | #define PCI_DEVICE_ID_POS104UL 0x1044 | ||
69 | #define PCI_DEVICE_ID_CB108 0x1080 | ||
70 | #define PCI_DEVICE_ID_CP102UF 0x1023 | ||
71 | #define PCI_DEVICE_ID_CP112UL 0x1120 | ||
72 | #define PCI_DEVICE_ID_CB114 0x1142 | ||
73 | #define PCI_DEVICE_ID_CP114UL 0x1143 | ||
74 | #define PCI_DEVICE_ID_CB134I 0x1341 | ||
75 | #define PCI_DEVICE_ID_CP138U 0x1380 | ||
76 | |||
77 | |||
78 | #define C168_ASIC_ID 1 | ||
79 | #define C104_ASIC_ID 2 | ||
80 | #define C102_ASIC_ID 0xB | ||
81 | #define CI132_ASIC_ID 4 | ||
82 | #define CI134_ASIC_ID 3 | ||
83 | #define CI104J_ASIC_ID 5 | ||
84 | |||
85 | #define MXSER_HIGHBAUD 1 | ||
86 | #define MXSER_HAS2 2 | ||
87 | |||
88 | /* This is only for PCI */ | ||
89 | static const struct { | ||
90 | int type; | ||
91 | int tx_fifo; | ||
92 | int rx_fifo; | ||
93 | int xmit_fifo_size; | ||
94 | int rx_high_water; | ||
95 | int rx_trigger; | ||
96 | int rx_low_water; | ||
97 | long max_baud; | ||
98 | } Gpci_uart_info[] = { | ||
99 | {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L}, | ||
100 | {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L}, | ||
101 | {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} | ||
102 | }; | ||
103 | #define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info) | ||
104 | |||
105 | struct mxser_cardinfo { | ||
106 | char *name; | ||
107 | unsigned int nports; | ||
108 | unsigned int flags; | ||
109 | }; | ||
110 | |||
111 | static const struct mxser_cardinfo mxser_cards[] = { | ||
112 | /* 0*/ { "C168 series", 8, }, | ||
113 | { "C104 series", 4, }, | ||
114 | { "CI-104J series", 4, }, | ||
115 | { "C168H/PCI series", 8, }, | ||
116 | { "C104H/PCI series", 4, }, | ||
117 | /* 5*/ { "C102 series", 4, MXSER_HAS2 }, /* C102-ISA */ | ||
118 | { "CI-132 series", 4, MXSER_HAS2 }, | ||
119 | { "CI-134 series", 4, }, | ||
120 | { "CP-132 series", 2, }, | ||
121 | { "CP-114 series", 4, }, | ||
122 | /*10*/ { "CT-114 series", 4, }, | ||
123 | { "CP-102 series", 2, MXSER_HIGHBAUD }, | ||
124 | { "CP-104U series", 4, }, | ||
125 | { "CP-168U series", 8, }, | ||
126 | { "CP-132U series", 2, }, | ||
127 | /*15*/ { "CP-134U series", 4, }, | ||
128 | { "CP-104JU series", 4, }, | ||
129 | { "Moxa UC7000 Serial", 8, }, /* RC7000 */ | ||
130 | { "CP-118U series", 8, }, | ||
131 | { "CP-102UL series", 2, }, | ||
132 | /*20*/ { "CP-102U series", 2, }, | ||
133 | { "CP-118EL series", 8, }, | ||
134 | { "CP-168EL series", 8, }, | ||
135 | { "CP-104EL series", 4, }, | ||
136 | { "CB-108 series", 8, }, | ||
137 | /*25*/ { "CB-114 series", 4, }, | ||
138 | { "CB-134I series", 4, }, | ||
139 | { "CP-138U series", 8, }, | ||
140 | { "POS-104UL series", 4, }, | ||
141 | { "CP-114UL series", 4, }, | ||
142 | /*30*/ { "CP-102UF series", 2, }, | ||
143 | { "CP-112UL series", 2, }, | ||
144 | }; | ||
145 | |||
146 | /* driver_data correspond to the lines in the structure above | ||
147 | see also ISA probe function before you change something */ | ||
148 | static struct pci_device_id mxser_pcibrds[] = { | ||
149 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 }, | ||
150 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, | ||
151 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 }, | ||
152 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 }, | ||
153 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 }, | ||
154 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 }, | ||
155 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 }, | ||
156 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 }, | ||
157 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 }, | ||
158 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 }, | ||
159 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 }, | ||
160 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 }, | ||
161 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 }, | ||
162 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 }, | ||
163 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 }, | ||
164 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 }, | ||
165 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 }, | ||
166 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 }, | ||
167 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 }, | ||
168 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 }, | ||
169 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 }, | ||
170 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 }, | ||
171 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 }, | ||
172 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 }, | ||
173 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 }, | ||
174 | { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 }, | ||
175 | { } | ||
176 | }; | ||
177 | MODULE_DEVICE_TABLE(pci, mxser_pcibrds); | ||
178 | |||
179 | static unsigned long ioaddr[MXSER_BOARDS]; | ||
180 | static int ttymajor = MXSERMAJOR; | ||
181 | |||
182 | /* Variables for insmod */ | ||
183 | |||
184 | MODULE_AUTHOR("Casper Yang"); | ||
185 | MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); | ||
186 | module_param_array(ioaddr, ulong, NULL, 0); | ||
187 | MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board"); | ||
188 | module_param(ttymajor, int, 0); | ||
189 | MODULE_LICENSE("GPL"); | ||
190 | |||
191 | struct mxser_log { | ||
192 | int tick; | ||
193 | unsigned long rxcnt[MXSER_PORTS]; | ||
194 | unsigned long txcnt[MXSER_PORTS]; | ||
195 | }; | ||
196 | |||
197 | struct mxser_mon { | ||
198 | unsigned long rxcnt; | ||
199 | unsigned long txcnt; | ||
200 | unsigned long up_rxcnt; | ||
201 | unsigned long up_txcnt; | ||
202 | int modem_status; | ||
203 | unsigned char hold_reason; | ||
204 | }; | ||
205 | |||
206 | struct mxser_mon_ext { | ||
207 | unsigned long rx_cnt[32]; | ||
208 | unsigned long tx_cnt[32]; | ||
209 | unsigned long up_rxcnt[32]; | ||
210 | unsigned long up_txcnt[32]; | ||
211 | int modem_status[32]; | ||
212 | |||
213 | long baudrate[32]; | ||
214 | int databits[32]; | ||
215 | int stopbits[32]; | ||
216 | int parity[32]; | ||
217 | int flowctrl[32]; | ||
218 | int fifo[32]; | ||
219 | int iftype[32]; | ||
220 | }; | ||
221 | |||
222 | struct mxser_board; | ||
223 | |||
224 | struct mxser_port { | ||
225 | struct tty_port port; | ||
226 | struct mxser_board *board; | ||
227 | |||
228 | unsigned long ioaddr; | ||
229 | unsigned long opmode_ioaddr; | ||
230 | int max_baud; | ||
231 | |||
232 | int rx_high_water; | ||
233 | int rx_trigger; /* Rx fifo trigger level */ | ||
234 | int rx_low_water; | ||
235 | int baud_base; /* max. speed */ | ||
236 | int type; /* UART type */ | ||
237 | |||
238 | int x_char; /* xon/xoff character */ | ||
239 | int IER; /* Interrupt Enable Register */ | ||
240 | int MCR; /* Modem control register */ | ||
241 | |||
242 | unsigned char stop_rx; | ||
243 | unsigned char ldisc_stop_rx; | ||
244 | |||
245 | int custom_divisor; | ||
246 | unsigned char err_shadow; | ||
247 | |||
248 | struct async_icount icount; /* kernel counters for 4 input interrupts */ | ||
249 | int timeout; | ||
250 | |||
251 | int read_status_mask; | ||
252 | int ignore_status_mask; | ||
253 | int xmit_fifo_size; | ||
254 | int xmit_head; | ||
255 | int xmit_tail; | ||
256 | int xmit_cnt; | ||
257 | |||
258 | struct ktermios normal_termios; | ||
259 | |||
260 | struct mxser_mon mon_data; | ||
261 | |||
262 | spinlock_t slock; | ||
263 | }; | ||
264 | |||
265 | struct mxser_board { | ||
266 | unsigned int idx; | ||
267 | int irq; | ||
268 | const struct mxser_cardinfo *info; | ||
269 | unsigned long vector; | ||
270 | unsigned long vector_mask; | ||
271 | |||
272 | int chip_flag; | ||
273 | int uart_type; | ||
274 | |||
275 | struct mxser_port ports[MXSER_PORTS_PER_BOARD]; | ||
276 | }; | ||
277 | |||
278 | struct mxser_mstatus { | ||
279 | tcflag_t cflag; | ||
280 | int cts; | ||
281 | int dsr; | ||
282 | int ri; | ||
283 | int dcd; | ||
284 | }; | ||
285 | |||
286 | static struct mxser_board mxser_boards[MXSER_BOARDS]; | ||
287 | static struct tty_driver *mxvar_sdriver; | ||
288 | static struct mxser_log mxvar_log; | ||
289 | static int mxser_set_baud_method[MXSER_PORTS + 1]; | ||
290 | |||
291 | static void mxser_enable_must_enchance_mode(unsigned long baseio) | ||
292 | { | ||
293 | u8 oldlcr; | ||
294 | u8 efr; | ||
295 | |||
296 | oldlcr = inb(baseio + UART_LCR); | ||
297 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
298 | |||
299 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
300 | efr |= MOXA_MUST_EFR_EFRB_ENABLE; | ||
301 | |||
302 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
303 | outb(oldlcr, baseio + UART_LCR); | ||
304 | } | ||
305 | |||
306 | #ifdef CONFIG_PCI | ||
307 | static void mxser_disable_must_enchance_mode(unsigned long baseio) | ||
308 | { | ||
309 | u8 oldlcr; | ||
310 | u8 efr; | ||
311 | |||
312 | oldlcr = inb(baseio + UART_LCR); | ||
313 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
314 | |||
315 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
316 | efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; | ||
317 | |||
318 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
319 | outb(oldlcr, baseio + UART_LCR); | ||
320 | } | ||
321 | #endif | ||
322 | |||
323 | static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) | ||
324 | { | ||
325 | u8 oldlcr; | ||
326 | u8 efr; | ||
327 | |||
328 | oldlcr = inb(baseio + UART_LCR); | ||
329 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
330 | |||
331 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
332 | efr &= ~MOXA_MUST_EFR_BANK_MASK; | ||
333 | efr |= MOXA_MUST_EFR_BANK0; | ||
334 | |||
335 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
336 | outb(value, baseio + MOXA_MUST_XON1_REGISTER); | ||
337 | outb(oldlcr, baseio + UART_LCR); | ||
338 | } | ||
339 | |||
340 | static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value) | ||
341 | { | ||
342 | u8 oldlcr; | ||
343 | u8 efr; | ||
344 | |||
345 | oldlcr = inb(baseio + UART_LCR); | ||
346 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
347 | |||
348 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
349 | efr &= ~MOXA_MUST_EFR_BANK_MASK; | ||
350 | efr |= MOXA_MUST_EFR_BANK0; | ||
351 | |||
352 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
353 | outb(value, baseio + MOXA_MUST_XOFF1_REGISTER); | ||
354 | outb(oldlcr, baseio + UART_LCR); | ||
355 | } | ||
356 | |||
357 | static void mxser_set_must_fifo_value(struct mxser_port *info) | ||
358 | { | ||
359 | u8 oldlcr; | ||
360 | u8 efr; | ||
361 | |||
362 | oldlcr = inb(info->ioaddr + UART_LCR); | ||
363 | outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR); | ||
364 | |||
365 | efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER); | ||
366 | efr &= ~MOXA_MUST_EFR_BANK_MASK; | ||
367 | efr |= MOXA_MUST_EFR_BANK1; | ||
368 | |||
369 | outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER); | ||
370 | outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); | ||
371 | outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); | ||
372 | outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); | ||
373 | outb(oldlcr, info->ioaddr + UART_LCR); | ||
374 | } | ||
375 | |||
376 | static void mxser_set_must_enum_value(unsigned long baseio, u8 value) | ||
377 | { | ||
378 | u8 oldlcr; | ||
379 | u8 efr; | ||
380 | |||
381 | oldlcr = inb(baseio + UART_LCR); | ||
382 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
383 | |||
384 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
385 | efr &= ~MOXA_MUST_EFR_BANK_MASK; | ||
386 | efr |= MOXA_MUST_EFR_BANK2; | ||
387 | |||
388 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
389 | outb(value, baseio + MOXA_MUST_ENUM_REGISTER); | ||
390 | outb(oldlcr, baseio + UART_LCR); | ||
391 | } | ||
392 | |||
393 | #ifdef CONFIG_PCI | ||
394 | static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) | ||
395 | { | ||
396 | u8 oldlcr; | ||
397 | u8 efr; | ||
398 | |||
399 | oldlcr = inb(baseio + UART_LCR); | ||
400 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
401 | |||
402 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
403 | efr &= ~MOXA_MUST_EFR_BANK_MASK; | ||
404 | efr |= MOXA_MUST_EFR_BANK2; | ||
405 | |||
406 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
407 | *pId = inb(baseio + MOXA_MUST_HWID_REGISTER); | ||
408 | outb(oldlcr, baseio + UART_LCR); | ||
409 | } | ||
410 | #endif | ||
411 | |||
412 | static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio) | ||
413 | { | ||
414 | u8 oldlcr; | ||
415 | u8 efr; | ||
416 | |||
417 | oldlcr = inb(baseio + UART_LCR); | ||
418 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
419 | |||
420 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
421 | efr &= ~MOXA_MUST_EFR_SF_MASK; | ||
422 | |||
423 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
424 | outb(oldlcr, baseio + UART_LCR); | ||
425 | } | ||
426 | |||
427 | static void mxser_enable_must_tx_software_flow_control(unsigned long baseio) | ||
428 | { | ||
429 | u8 oldlcr; | ||
430 | u8 efr; | ||
431 | |||
432 | oldlcr = inb(baseio + UART_LCR); | ||
433 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
434 | |||
435 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
436 | efr &= ~MOXA_MUST_EFR_SF_TX_MASK; | ||
437 | efr |= MOXA_MUST_EFR_SF_TX1; | ||
438 | |||
439 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
440 | outb(oldlcr, baseio + UART_LCR); | ||
441 | } | ||
442 | |||
443 | static void mxser_disable_must_tx_software_flow_control(unsigned long baseio) | ||
444 | { | ||
445 | u8 oldlcr; | ||
446 | u8 efr; | ||
447 | |||
448 | oldlcr = inb(baseio + UART_LCR); | ||
449 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
450 | |||
451 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
452 | efr &= ~MOXA_MUST_EFR_SF_TX_MASK; | ||
453 | |||
454 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
455 | outb(oldlcr, baseio + UART_LCR); | ||
456 | } | ||
457 | |||
458 | static void mxser_enable_must_rx_software_flow_control(unsigned long baseio) | ||
459 | { | ||
460 | u8 oldlcr; | ||
461 | u8 efr; | ||
462 | |||
463 | oldlcr = inb(baseio + UART_LCR); | ||
464 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
465 | |||
466 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
467 | efr &= ~MOXA_MUST_EFR_SF_RX_MASK; | ||
468 | efr |= MOXA_MUST_EFR_SF_RX1; | ||
469 | |||
470 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
471 | outb(oldlcr, baseio + UART_LCR); | ||
472 | } | ||
473 | |||
474 | static void mxser_disable_must_rx_software_flow_control(unsigned long baseio) | ||
475 | { | ||
476 | u8 oldlcr; | ||
477 | u8 efr; | ||
478 | |||
479 | oldlcr = inb(baseio + UART_LCR); | ||
480 | outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); | ||
481 | |||
482 | efr = inb(baseio + MOXA_MUST_EFR_REGISTER); | ||
483 | efr &= ~MOXA_MUST_EFR_SF_RX_MASK; | ||
484 | |||
485 | outb(efr, baseio + MOXA_MUST_EFR_REGISTER); | ||
486 | outb(oldlcr, baseio + UART_LCR); | ||
487 | } | ||
488 | |||
489 | #ifdef CONFIG_PCI | ||
490 | static int __devinit CheckIsMoxaMust(unsigned long io) | ||
491 | { | ||
492 | u8 oldmcr, hwid; | ||
493 | int i; | ||
494 | |||
495 | outb(0, io + UART_LCR); | ||
496 | mxser_disable_must_enchance_mode(io); | ||
497 | oldmcr = inb(io + UART_MCR); | ||
498 | outb(0, io + UART_MCR); | ||
499 | mxser_set_must_xon1_value(io, 0x11); | ||
500 | if ((hwid = inb(io + UART_MCR)) != 0) { | ||
501 | outb(oldmcr, io + UART_MCR); | ||
502 | return MOXA_OTHER_UART; | ||
503 | } | ||
504 | |||
505 | mxser_get_must_hardware_id(io, &hwid); | ||
506 | for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */ | ||
507 | if (hwid == Gpci_uart_info[i].type) | ||
508 | return (int)hwid; | ||
509 | } | ||
510 | return MOXA_OTHER_UART; | ||
511 | } | ||
512 | #endif | ||
513 | |||
514 | static void process_txrx_fifo(struct mxser_port *info) | ||
515 | { | ||
516 | int i; | ||
517 | |||
518 | if ((info->type == PORT_16450) || (info->type == PORT_8250)) { | ||
519 | info->rx_trigger = 1; | ||
520 | info->rx_high_water = 1; | ||
521 | info->rx_low_water = 1; | ||
522 | info->xmit_fifo_size = 1; | ||
523 | } else | ||
524 | for (i = 0; i < UART_INFO_NUM; i++) | ||
525 | if (info->board->chip_flag == Gpci_uart_info[i].type) { | ||
526 | info->rx_trigger = Gpci_uart_info[i].rx_trigger; | ||
527 | info->rx_low_water = Gpci_uart_info[i].rx_low_water; | ||
528 | info->rx_high_water = Gpci_uart_info[i].rx_high_water; | ||
529 | info->xmit_fifo_size = Gpci_uart_info[i].xmit_fifo_size; | ||
530 | break; | ||
531 | } | ||
532 | } | ||
533 | |||
534 | static unsigned char mxser_get_msr(int baseaddr, int mode, int port) | ||
535 | { | ||
536 | static unsigned char mxser_msr[MXSER_PORTS + 1]; | ||
537 | unsigned char status = 0; | ||
538 | |||
539 | status = inb(baseaddr + UART_MSR); | ||
540 | |||
541 | mxser_msr[port] &= 0x0F; | ||
542 | mxser_msr[port] |= status; | ||
543 | status = mxser_msr[port]; | ||
544 | if (mode) | ||
545 | mxser_msr[port] = 0; | ||
546 | |||
547 | return status; | ||
548 | } | ||
549 | |||
550 | static int mxser_carrier_raised(struct tty_port *port) | ||
551 | { | ||
552 | struct mxser_port *mp = container_of(port, struct mxser_port, port); | ||
553 | return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0; | ||
554 | } | ||
555 | |||
556 | static void mxser_dtr_rts(struct tty_port *port, int on) | ||
557 | { | ||
558 | struct mxser_port *mp = container_of(port, struct mxser_port, port); | ||
559 | unsigned long flags; | ||
560 | |||
561 | spin_lock_irqsave(&mp->slock, flags); | ||
562 | if (on) | ||
563 | outb(inb(mp->ioaddr + UART_MCR) | | ||
564 | UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); | ||
565 | else | ||
566 | outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS), | ||
567 | mp->ioaddr + UART_MCR); | ||
568 | spin_unlock_irqrestore(&mp->slock, flags); | ||
569 | } | ||
570 | |||
571 | static int mxser_set_baud(struct tty_struct *tty, long newspd) | ||
572 | { | ||
573 | struct mxser_port *info = tty->driver_data; | ||
574 | int quot = 0, baud; | ||
575 | unsigned char cval; | ||
576 | |||
577 | if (!info->ioaddr) | ||
578 | return -1; | ||
579 | |||
580 | if (newspd > info->max_baud) | ||
581 | return -1; | ||
582 | |||
583 | if (newspd == 134) { | ||
584 | quot = 2 * info->baud_base / 269; | ||
585 | tty_encode_baud_rate(tty, 134, 134); | ||
586 | } else if (newspd) { | ||
587 | quot = info->baud_base / newspd; | ||
588 | if (quot == 0) | ||
589 | quot = 1; | ||
590 | baud = info->baud_base/quot; | ||
591 | tty_encode_baud_rate(tty, baud, baud); | ||
592 | } else { | ||
593 | quot = 0; | ||
594 | } | ||
595 | |||
596 | info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base); | ||
597 | info->timeout += HZ / 50; /* Add .02 seconds of slop */ | ||
598 | |||
599 | if (quot) { | ||
600 | info->MCR |= UART_MCR_DTR; | ||
601 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
602 | } else { | ||
603 | info->MCR &= ~UART_MCR_DTR; | ||
604 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | cval = inb(info->ioaddr + UART_LCR); | ||
609 | |||
610 | outb(cval | UART_LCR_DLAB, info->ioaddr + UART_LCR); /* set DLAB */ | ||
611 | |||
612 | outb(quot & 0xff, info->ioaddr + UART_DLL); /* LS of divisor */ | ||
613 | outb(quot >> 8, info->ioaddr + UART_DLM); /* MS of divisor */ | ||
614 | outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
615 | |||
616 | #ifdef BOTHER | ||
617 | if (C_BAUD(tty) == BOTHER) { | ||
618 | quot = info->baud_base % newspd; | ||
619 | quot *= 8; | ||
620 | if (quot % newspd > newspd / 2) { | ||
621 | quot /= newspd; | ||
622 | quot++; | ||
623 | } else | ||
624 | quot /= newspd; | ||
625 | |||
626 | mxser_set_must_enum_value(info->ioaddr, quot); | ||
627 | } else | ||
628 | #endif | ||
629 | mxser_set_must_enum_value(info->ioaddr, 0); | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * This routine is called to set the UART divisor registers to match | ||
636 | * the specified baud rate for a serial port. | ||
637 | */ | ||
638 | static int mxser_change_speed(struct tty_struct *tty, | ||
639 | struct ktermios *old_termios) | ||
640 | { | ||
641 | struct mxser_port *info = tty->driver_data; | ||
642 | unsigned cflag, cval, fcr; | ||
643 | int ret = 0; | ||
644 | unsigned char status; | ||
645 | |||
646 | cflag = tty->termios->c_cflag; | ||
647 | if (!info->ioaddr) | ||
648 | return ret; | ||
649 | |||
650 | if (mxser_set_baud_method[tty->index] == 0) | ||
651 | mxser_set_baud(tty, tty_get_baud_rate(tty)); | ||
652 | |||
653 | /* byte size and parity */ | ||
654 | switch (cflag & CSIZE) { | ||
655 | case CS5: | ||
656 | cval = 0x00; | ||
657 | break; | ||
658 | case CS6: | ||
659 | cval = 0x01; | ||
660 | break; | ||
661 | case CS7: | ||
662 | cval = 0x02; | ||
663 | break; | ||
664 | case CS8: | ||
665 | cval = 0x03; | ||
666 | break; | ||
667 | default: | ||
668 | cval = 0x00; | ||
669 | break; /* too keep GCC shut... */ | ||
670 | } | ||
671 | if (cflag & CSTOPB) | ||
672 | cval |= 0x04; | ||
673 | if (cflag & PARENB) | ||
674 | cval |= UART_LCR_PARITY; | ||
675 | if (!(cflag & PARODD)) | ||
676 | cval |= UART_LCR_EPAR; | ||
677 | if (cflag & CMSPAR) | ||
678 | cval |= UART_LCR_SPAR; | ||
679 | |||
680 | if ((info->type == PORT_8250) || (info->type == PORT_16450)) { | ||
681 | if (info->board->chip_flag) { | ||
682 | fcr = UART_FCR_ENABLE_FIFO; | ||
683 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
684 | mxser_set_must_fifo_value(info); | ||
685 | } else | ||
686 | fcr = 0; | ||
687 | } else { | ||
688 | fcr = UART_FCR_ENABLE_FIFO; | ||
689 | if (info->board->chip_flag) { | ||
690 | fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; | ||
691 | mxser_set_must_fifo_value(info); | ||
692 | } else { | ||
693 | switch (info->rx_trigger) { | ||
694 | case 1: | ||
695 | fcr |= UART_FCR_TRIGGER_1; | ||
696 | break; | ||
697 | case 4: | ||
698 | fcr |= UART_FCR_TRIGGER_4; | ||
699 | break; | ||
700 | case 8: | ||
701 | fcr |= UART_FCR_TRIGGER_8; | ||
702 | break; | ||
703 | default: | ||
704 | fcr |= UART_FCR_TRIGGER_14; | ||
705 | break; | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | |||
710 | /* CTS flow control flag and modem status interrupts */ | ||
711 | info->IER &= ~UART_IER_MSI; | ||
712 | info->MCR &= ~UART_MCR_AFE; | ||
713 | if (cflag & CRTSCTS) { | ||
714 | info->port.flags |= ASYNC_CTS_FLOW; | ||
715 | info->IER |= UART_IER_MSI; | ||
716 | if ((info->type == PORT_16550A) || (info->board->chip_flag)) { | ||
717 | info->MCR |= UART_MCR_AFE; | ||
718 | } else { | ||
719 | status = inb(info->ioaddr + UART_MSR); | ||
720 | if (tty->hw_stopped) { | ||
721 | if (status & UART_MSR_CTS) { | ||
722 | tty->hw_stopped = 0; | ||
723 | if (info->type != PORT_16550A && | ||
724 | !info->board->chip_flag) { | ||
725 | outb(info->IER & ~UART_IER_THRI, | ||
726 | info->ioaddr + | ||
727 | UART_IER); | ||
728 | info->IER |= UART_IER_THRI; | ||
729 | outb(info->IER, info->ioaddr + | ||
730 | UART_IER); | ||
731 | } | ||
732 | tty_wakeup(tty); | ||
733 | } | ||
734 | } else { | ||
735 | if (!(status & UART_MSR_CTS)) { | ||
736 | tty->hw_stopped = 1; | ||
737 | if ((info->type != PORT_16550A) && | ||
738 | (!info->board->chip_flag)) { | ||
739 | info->IER &= ~UART_IER_THRI; | ||
740 | outb(info->IER, info->ioaddr + | ||
741 | UART_IER); | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | } else { | ||
747 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
748 | } | ||
749 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
750 | if (cflag & CLOCAL) { | ||
751 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
752 | } else { | ||
753 | info->port.flags |= ASYNC_CHECK_CD; | ||
754 | info->IER |= UART_IER_MSI; | ||
755 | } | ||
756 | outb(info->IER, info->ioaddr + UART_IER); | ||
757 | |||
758 | /* | ||
759 | * Set up parity check flag | ||
760 | */ | ||
761 | info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; | ||
762 | if (I_INPCK(tty)) | ||
763 | info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; | ||
764 | if (I_BRKINT(tty) || I_PARMRK(tty)) | ||
765 | info->read_status_mask |= UART_LSR_BI; | ||
766 | |||
767 | info->ignore_status_mask = 0; | ||
768 | |||
769 | if (I_IGNBRK(tty)) { | ||
770 | info->ignore_status_mask |= UART_LSR_BI; | ||
771 | info->read_status_mask |= UART_LSR_BI; | ||
772 | /* | ||
773 | * If we're ignore parity and break indicators, ignore | ||
774 | * overruns too. (For real raw support). | ||
775 | */ | ||
776 | if (I_IGNPAR(tty)) { | ||
777 | info->ignore_status_mask |= | ||
778 | UART_LSR_OE | | ||
779 | UART_LSR_PE | | ||
780 | UART_LSR_FE; | ||
781 | info->read_status_mask |= | ||
782 | UART_LSR_OE | | ||
783 | UART_LSR_PE | | ||
784 | UART_LSR_FE; | ||
785 | } | ||
786 | } | ||
787 | if (info->board->chip_flag) { | ||
788 | mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); | ||
789 | mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); | ||
790 | if (I_IXON(tty)) { | ||
791 | mxser_enable_must_rx_software_flow_control( | ||
792 | info->ioaddr); | ||
793 | } else { | ||
794 | mxser_disable_must_rx_software_flow_control( | ||
795 | info->ioaddr); | ||
796 | } | ||
797 | if (I_IXOFF(tty)) { | ||
798 | mxser_enable_must_tx_software_flow_control( | ||
799 | info->ioaddr); | ||
800 | } else { | ||
801 | mxser_disable_must_tx_software_flow_control( | ||
802 | info->ioaddr); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | |||
807 | outb(fcr, info->ioaddr + UART_FCR); /* set fcr */ | ||
808 | outb(cval, info->ioaddr + UART_LCR); | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | static void mxser_check_modem_status(struct tty_struct *tty, | ||
814 | struct mxser_port *port, int status) | ||
815 | { | ||
816 | /* update input line counters */ | ||
817 | if (status & UART_MSR_TERI) | ||
818 | port->icount.rng++; | ||
819 | if (status & UART_MSR_DDSR) | ||
820 | port->icount.dsr++; | ||
821 | if (status & UART_MSR_DDCD) | ||
822 | port->icount.dcd++; | ||
823 | if (status & UART_MSR_DCTS) | ||
824 | port->icount.cts++; | ||
825 | port->mon_data.modem_status = status; | ||
826 | wake_up_interruptible(&port->port.delta_msr_wait); | ||
827 | |||
828 | if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { | ||
829 | if (status & UART_MSR_DCD) | ||
830 | wake_up_interruptible(&port->port.open_wait); | ||
831 | } | ||
832 | |||
833 | if (port->port.flags & ASYNC_CTS_FLOW) { | ||
834 | if (tty->hw_stopped) { | ||
835 | if (status & UART_MSR_CTS) { | ||
836 | tty->hw_stopped = 0; | ||
837 | |||
838 | if ((port->type != PORT_16550A) && | ||
839 | (!port->board->chip_flag)) { | ||
840 | outb(port->IER & ~UART_IER_THRI, | ||
841 | port->ioaddr + UART_IER); | ||
842 | port->IER |= UART_IER_THRI; | ||
843 | outb(port->IER, port->ioaddr + | ||
844 | UART_IER); | ||
845 | } | ||
846 | tty_wakeup(tty); | ||
847 | } | ||
848 | } else { | ||
849 | if (!(status & UART_MSR_CTS)) { | ||
850 | tty->hw_stopped = 1; | ||
851 | if (port->type != PORT_16550A && | ||
852 | !port->board->chip_flag) { | ||
853 | port->IER &= ~UART_IER_THRI; | ||
854 | outb(port->IER, port->ioaddr + | ||
855 | UART_IER); | ||
856 | } | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | } | ||
861 | |||
862 | static int mxser_activate(struct tty_port *port, struct tty_struct *tty) | ||
863 | { | ||
864 | struct mxser_port *info = container_of(port, struct mxser_port, port); | ||
865 | unsigned long page; | ||
866 | unsigned long flags; | ||
867 | |||
868 | page = __get_free_page(GFP_KERNEL); | ||
869 | if (!page) | ||
870 | return -ENOMEM; | ||
871 | |||
872 | spin_lock_irqsave(&info->slock, flags); | ||
873 | |||
874 | if (!info->ioaddr || !info->type) { | ||
875 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
876 | free_page(page); | ||
877 | spin_unlock_irqrestore(&info->slock, flags); | ||
878 | return 0; | ||
879 | } | ||
880 | info->port.xmit_buf = (unsigned char *) page; | ||
881 | |||
882 | /* | ||
883 | * Clear the FIFO buffers and disable them | ||
884 | * (they will be reenabled in mxser_change_speed()) | ||
885 | */ | ||
886 | if (info->board->chip_flag) | ||
887 | outb((UART_FCR_CLEAR_RCVR | | ||
888 | UART_FCR_CLEAR_XMIT | | ||
889 | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); | ||
890 | else | ||
891 | outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), | ||
892 | info->ioaddr + UART_FCR); | ||
893 | |||
894 | /* | ||
895 | * At this point there's no way the LSR could still be 0xFF; | ||
896 | * if it is, then bail out, because there's likely no UART | ||
897 | * here. | ||
898 | */ | ||
899 | if (inb(info->ioaddr + UART_LSR) == 0xff) { | ||
900 | spin_unlock_irqrestore(&info->slock, flags); | ||
901 | if (capable(CAP_SYS_ADMIN)) { | ||
902 | set_bit(TTY_IO_ERROR, &tty->flags); | ||
903 | return 0; | ||
904 | } else | ||
905 | return -ENODEV; | ||
906 | } | ||
907 | |||
908 | /* | ||
909 | * Clear the interrupt registers. | ||
910 | */ | ||
911 | (void) inb(info->ioaddr + UART_LSR); | ||
912 | (void) inb(info->ioaddr + UART_RX); | ||
913 | (void) inb(info->ioaddr + UART_IIR); | ||
914 | (void) inb(info->ioaddr + UART_MSR); | ||
915 | |||
916 | /* | ||
917 | * Now, initialize the UART | ||
918 | */ | ||
919 | outb(UART_LCR_WLEN8, info->ioaddr + UART_LCR); /* reset DLAB */ | ||
920 | info->MCR = UART_MCR_DTR | UART_MCR_RTS; | ||
921 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
922 | |||
923 | /* | ||
924 | * Finally, enable interrupts | ||
925 | */ | ||
926 | info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; | ||
927 | |||
928 | if (info->board->chip_flag) | ||
929 | info->IER |= MOXA_MUST_IER_EGDAI; | ||
930 | outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */ | ||
931 | |||
932 | /* | ||
933 | * And clear the interrupt registers again for luck. | ||
934 | */ | ||
935 | (void) inb(info->ioaddr + UART_LSR); | ||
936 | (void) inb(info->ioaddr + UART_RX); | ||
937 | (void) inb(info->ioaddr + UART_IIR); | ||
938 | (void) inb(info->ioaddr + UART_MSR); | ||
939 | |||
940 | clear_bit(TTY_IO_ERROR, &tty->flags); | ||
941 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
942 | |||
943 | /* | ||
944 | * and set the speed of the serial port | ||
945 | */ | ||
946 | mxser_change_speed(tty, NULL); | ||
947 | spin_unlock_irqrestore(&info->slock, flags); | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | /* | ||
953 | * This routine will shutdown a serial port | ||
954 | */ | ||
955 | static void mxser_shutdown_port(struct tty_port *port) | ||
956 | { | ||
957 | struct mxser_port *info = container_of(port, struct mxser_port, port); | ||
958 | unsigned long flags; | ||
959 | |||
960 | spin_lock_irqsave(&info->slock, flags); | ||
961 | |||
962 | /* | ||
963 | * clear delta_msr_wait queue to avoid mem leaks: we may free the irq | ||
964 | * here so the queue might never be waken up | ||
965 | */ | ||
966 | wake_up_interruptible(&info->port.delta_msr_wait); | ||
967 | |||
968 | /* | ||
969 | * Free the xmit buffer, if necessary | ||
970 | */ | ||
971 | if (info->port.xmit_buf) { | ||
972 | free_page((unsigned long) info->port.xmit_buf); | ||
973 | info->port.xmit_buf = NULL; | ||
974 | } | ||
975 | |||
976 | info->IER = 0; | ||
977 | outb(0x00, info->ioaddr + UART_IER); | ||
978 | |||
979 | /* clear Rx/Tx FIFO's */ | ||
980 | if (info->board->chip_flag) | ||
981 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | | ||
982 | MOXA_MUST_FCR_GDA_MODE_ENABLE, | ||
983 | info->ioaddr + UART_FCR); | ||
984 | else | ||
985 | outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, | ||
986 | info->ioaddr + UART_FCR); | ||
987 | |||
988 | /* read data port to reset things */ | ||
989 | (void) inb(info->ioaddr + UART_RX); | ||
990 | |||
991 | |||
992 | if (info->board->chip_flag) | ||
993 | SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); | ||
994 | |||
995 | spin_unlock_irqrestore(&info->slock, flags); | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | * This routine is called whenever a serial port is opened. It | ||
1000 | * enables interrupts for a serial port, linking in its async structure into | ||
1001 | * the IRQ chain. It also performs the serial-specific | ||
1002 | * initialization for the tty structure. | ||
1003 | */ | ||
1004 | static int mxser_open(struct tty_struct *tty, struct file *filp) | ||
1005 | { | ||
1006 | struct mxser_port *info; | ||
1007 | int line; | ||
1008 | |||
1009 | line = tty->index; | ||
1010 | if (line == MXSER_PORTS) | ||
1011 | return 0; | ||
1012 | if (line < 0 || line > MXSER_PORTS) | ||
1013 | return -ENODEV; | ||
1014 | info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; | ||
1015 | if (!info->ioaddr) | ||
1016 | return -ENODEV; | ||
1017 | |||
1018 | tty->driver_data = info; | ||
1019 | return tty_port_open(&info->port, tty, filp); | ||
1020 | } | ||
1021 | |||
1022 | static void mxser_flush_buffer(struct tty_struct *tty) | ||
1023 | { | ||
1024 | struct mxser_port *info = tty->driver_data; | ||
1025 | char fcr; | ||
1026 | unsigned long flags; | ||
1027 | |||
1028 | |||
1029 | spin_lock_irqsave(&info->slock, flags); | ||
1030 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1031 | |||
1032 | fcr = inb(info->ioaddr + UART_FCR); | ||
1033 | outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), | ||
1034 | info->ioaddr + UART_FCR); | ||
1035 | outb(fcr, info->ioaddr + UART_FCR); | ||
1036 | |||
1037 | spin_unlock_irqrestore(&info->slock, flags); | ||
1038 | |||
1039 | tty_wakeup(tty); | ||
1040 | } | ||
1041 | |||
1042 | |||
1043 | static void mxser_close_port(struct tty_port *port) | ||
1044 | { | ||
1045 | struct mxser_port *info = container_of(port, struct mxser_port, port); | ||
1046 | unsigned long timeout; | ||
1047 | /* | ||
1048 | * At this point we stop accepting input. To do this, we | ||
1049 | * disable the receive line status interrupts, and tell the | ||
1050 | * interrupt driver to stop checking the data ready bit in the | ||
1051 | * line status register. | ||
1052 | */ | ||
1053 | info->IER &= ~UART_IER_RLSI; | ||
1054 | if (info->board->chip_flag) | ||
1055 | info->IER &= ~MOXA_MUST_RECV_ISR; | ||
1056 | |||
1057 | outb(info->IER, info->ioaddr + UART_IER); | ||
1058 | /* | ||
1059 | * Before we drop DTR, make sure the UART transmitter | ||
1060 | * has completely drained; this is especially | ||
1061 | * important if there is a transmit FIFO! | ||
1062 | */ | ||
1063 | timeout = jiffies + HZ; | ||
1064 | while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) { | ||
1065 | schedule_timeout_interruptible(5); | ||
1066 | if (time_after(jiffies, timeout)) | ||
1067 | break; | ||
1068 | } | ||
1069 | } | ||
1070 | |||
1071 | /* | ||
1072 | * This routine is called when the serial port gets closed. First, we | ||
1073 | * wait for the last remaining data to be sent. Then, we unlink its | ||
1074 | * async structure from the interrupt chain if necessary, and we free | ||
1075 | * that IRQ if nothing is left in the chain. | ||
1076 | */ | ||
1077 | static void mxser_close(struct tty_struct *tty, struct file *filp) | ||
1078 | { | ||
1079 | struct mxser_port *info = tty->driver_data; | ||
1080 | struct tty_port *port = &info->port; | ||
1081 | |||
1082 | if (tty->index == MXSER_PORTS || info == NULL) | ||
1083 | return; | ||
1084 | if (tty_port_close_start(port, tty, filp) == 0) | ||
1085 | return; | ||
1086 | mutex_lock(&port->mutex); | ||
1087 | mxser_close_port(port); | ||
1088 | mxser_flush_buffer(tty); | ||
1089 | mxser_shutdown_port(port); | ||
1090 | clear_bit(ASYNCB_INITIALIZED, &port->flags); | ||
1091 | mutex_unlock(&port->mutex); | ||
1092 | /* Right now the tty_port set is done outside of the close_end helper | ||
1093 | as we don't yet have everyone using refcounts */ | ||
1094 | tty_port_close_end(port, tty); | ||
1095 | tty_port_tty_set(port, NULL); | ||
1096 | } | ||
1097 | |||
1098 | static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
1099 | { | ||
1100 | int c, total = 0; | ||
1101 | struct mxser_port *info = tty->driver_data; | ||
1102 | unsigned long flags; | ||
1103 | |||
1104 | if (!info->port.xmit_buf) | ||
1105 | return 0; | ||
1106 | |||
1107 | while (1) { | ||
1108 | c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, | ||
1109 | SERIAL_XMIT_SIZE - info->xmit_head)); | ||
1110 | if (c <= 0) | ||
1111 | break; | ||
1112 | |||
1113 | memcpy(info->port.xmit_buf + info->xmit_head, buf, c); | ||
1114 | spin_lock_irqsave(&info->slock, flags); | ||
1115 | info->xmit_head = (info->xmit_head + c) & | ||
1116 | (SERIAL_XMIT_SIZE - 1); | ||
1117 | info->xmit_cnt += c; | ||
1118 | spin_unlock_irqrestore(&info->slock, flags); | ||
1119 | |||
1120 | buf += c; | ||
1121 | count -= c; | ||
1122 | total += c; | ||
1123 | } | ||
1124 | |||
1125 | if (info->xmit_cnt && !tty->stopped) { | ||
1126 | if (!tty->hw_stopped || | ||
1127 | (info->type == PORT_16550A) || | ||
1128 | (info->board->chip_flag)) { | ||
1129 | spin_lock_irqsave(&info->slock, flags); | ||
1130 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + | ||
1131 | UART_IER); | ||
1132 | info->IER |= UART_IER_THRI; | ||
1133 | outb(info->IER, info->ioaddr + UART_IER); | ||
1134 | spin_unlock_irqrestore(&info->slock, flags); | ||
1135 | } | ||
1136 | } | ||
1137 | return total; | ||
1138 | } | ||
1139 | |||
1140 | static int mxser_put_char(struct tty_struct *tty, unsigned char ch) | ||
1141 | { | ||
1142 | struct mxser_port *info = tty->driver_data; | ||
1143 | unsigned long flags; | ||
1144 | |||
1145 | if (!info->port.xmit_buf) | ||
1146 | return 0; | ||
1147 | |||
1148 | if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) | ||
1149 | return 0; | ||
1150 | |||
1151 | spin_lock_irqsave(&info->slock, flags); | ||
1152 | info->port.xmit_buf[info->xmit_head++] = ch; | ||
1153 | info->xmit_head &= SERIAL_XMIT_SIZE - 1; | ||
1154 | info->xmit_cnt++; | ||
1155 | spin_unlock_irqrestore(&info->slock, flags); | ||
1156 | if (!tty->stopped) { | ||
1157 | if (!tty->hw_stopped || | ||
1158 | (info->type == PORT_16550A) || | ||
1159 | info->board->chip_flag) { | ||
1160 | spin_lock_irqsave(&info->slock, flags); | ||
1161 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); | ||
1162 | info->IER |= UART_IER_THRI; | ||
1163 | outb(info->IER, info->ioaddr + UART_IER); | ||
1164 | spin_unlock_irqrestore(&info->slock, flags); | ||
1165 | } | ||
1166 | } | ||
1167 | return 1; | ||
1168 | } | ||
1169 | |||
1170 | |||
1171 | static void mxser_flush_chars(struct tty_struct *tty) | ||
1172 | { | ||
1173 | struct mxser_port *info = tty->driver_data; | ||
1174 | unsigned long flags; | ||
1175 | |||
1176 | if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf || | ||
1177 | (tty->hw_stopped && info->type != PORT_16550A && | ||
1178 | !info->board->chip_flag)) | ||
1179 | return; | ||
1180 | |||
1181 | spin_lock_irqsave(&info->slock, flags); | ||
1182 | |||
1183 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); | ||
1184 | info->IER |= UART_IER_THRI; | ||
1185 | outb(info->IER, info->ioaddr + UART_IER); | ||
1186 | |||
1187 | spin_unlock_irqrestore(&info->slock, flags); | ||
1188 | } | ||
1189 | |||
1190 | static int mxser_write_room(struct tty_struct *tty) | ||
1191 | { | ||
1192 | struct mxser_port *info = tty->driver_data; | ||
1193 | int ret; | ||
1194 | |||
1195 | ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; | ||
1196 | return ret < 0 ? 0 : ret; | ||
1197 | } | ||
1198 | |||
1199 | static int mxser_chars_in_buffer(struct tty_struct *tty) | ||
1200 | { | ||
1201 | struct mxser_port *info = tty->driver_data; | ||
1202 | return info->xmit_cnt; | ||
1203 | } | ||
1204 | |||
1205 | /* | ||
1206 | * ------------------------------------------------------------ | ||
1207 | * friends of mxser_ioctl() | ||
1208 | * ------------------------------------------------------------ | ||
1209 | */ | ||
1210 | static int mxser_get_serial_info(struct tty_struct *tty, | ||
1211 | struct serial_struct __user *retinfo) | ||
1212 | { | ||
1213 | struct mxser_port *info = tty->driver_data; | ||
1214 | struct serial_struct tmp = { | ||
1215 | .type = info->type, | ||
1216 | .line = tty->index, | ||
1217 | .port = info->ioaddr, | ||
1218 | .irq = info->board->irq, | ||
1219 | .flags = info->port.flags, | ||
1220 | .baud_base = info->baud_base, | ||
1221 | .close_delay = info->port.close_delay, | ||
1222 | .closing_wait = info->port.closing_wait, | ||
1223 | .custom_divisor = info->custom_divisor, | ||
1224 | .hub6 = 0 | ||
1225 | }; | ||
1226 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
1227 | return -EFAULT; | ||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static int mxser_set_serial_info(struct tty_struct *tty, | ||
1232 | struct serial_struct __user *new_info) | ||
1233 | { | ||
1234 | struct mxser_port *info = tty->driver_data; | ||
1235 | struct tty_port *port = &info->port; | ||
1236 | struct serial_struct new_serial; | ||
1237 | speed_t baud; | ||
1238 | unsigned long sl_flags; | ||
1239 | unsigned int flags; | ||
1240 | int retval = 0; | ||
1241 | |||
1242 | if (!new_info || !info->ioaddr) | ||
1243 | return -ENODEV; | ||
1244 | if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) | ||
1245 | return -EFAULT; | ||
1246 | |||
1247 | if (new_serial.irq != info->board->irq || | ||
1248 | new_serial.port != info->ioaddr) | ||
1249 | return -EINVAL; | ||
1250 | |||
1251 | flags = port->flags & ASYNC_SPD_MASK; | ||
1252 | |||
1253 | if (!capable(CAP_SYS_ADMIN)) { | ||
1254 | if ((new_serial.baud_base != info->baud_base) || | ||
1255 | (new_serial.close_delay != info->port.close_delay) || | ||
1256 | ((new_serial.flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) | ||
1257 | return -EPERM; | ||
1258 | info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | | ||
1259 | (new_serial.flags & ASYNC_USR_MASK)); | ||
1260 | } else { | ||
1261 | /* | ||
1262 | * OK, past this point, all the error checking has been done. | ||
1263 | * At this point, we start making changes..... | ||
1264 | */ | ||
1265 | port->flags = ((port->flags & ~ASYNC_FLAGS) | | ||
1266 | (new_serial.flags & ASYNC_FLAGS)); | ||
1267 | port->close_delay = new_serial.close_delay * HZ / 100; | ||
1268 | port->closing_wait = new_serial.closing_wait * HZ / 100; | ||
1269 | tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
1270 | if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && | ||
1271 | (new_serial.baud_base != info->baud_base || | ||
1272 | new_serial.custom_divisor != | ||
1273 | info->custom_divisor)) { | ||
1274 | if (new_serial.custom_divisor == 0) | ||
1275 | return -EINVAL; | ||
1276 | baud = new_serial.baud_base / new_serial.custom_divisor; | ||
1277 | tty_encode_baud_rate(tty, baud, baud); | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | info->type = new_serial.type; | ||
1282 | |||
1283 | process_txrx_fifo(info); | ||
1284 | |||
1285 | if (test_bit(ASYNCB_INITIALIZED, &port->flags)) { | ||
1286 | if (flags != (port->flags & ASYNC_SPD_MASK)) { | ||
1287 | spin_lock_irqsave(&info->slock, sl_flags); | ||
1288 | mxser_change_speed(tty, NULL); | ||
1289 | spin_unlock_irqrestore(&info->slock, sl_flags); | ||
1290 | } | ||
1291 | } else { | ||
1292 | retval = mxser_activate(port, tty); | ||
1293 | if (retval == 0) | ||
1294 | set_bit(ASYNCB_INITIALIZED, &port->flags); | ||
1295 | } | ||
1296 | return retval; | ||
1297 | } | ||
1298 | |||
1299 | /* | ||
1300 | * mxser_get_lsr_info - get line status register info | ||
1301 | * | ||
1302 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
1303 | * is emptied. On bus types like RS485, the transmitter must | ||
1304 | * release the bus after transmitting. This must be done when | ||
1305 | * the transmit shift register is empty, not be done when the | ||
1306 | * transmit holding register is empty. This functionality | ||
1307 | * allows an RS485 driver to be written in user space. | ||
1308 | */ | ||
1309 | static int mxser_get_lsr_info(struct mxser_port *info, | ||
1310 | unsigned int __user *value) | ||
1311 | { | ||
1312 | unsigned char status; | ||
1313 | unsigned int result; | ||
1314 | unsigned long flags; | ||
1315 | |||
1316 | spin_lock_irqsave(&info->slock, flags); | ||
1317 | status = inb(info->ioaddr + UART_LSR); | ||
1318 | spin_unlock_irqrestore(&info->slock, flags); | ||
1319 | result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); | ||
1320 | return put_user(result, value); | ||
1321 | } | ||
1322 | |||
1323 | static int mxser_tiocmget(struct tty_struct *tty) | ||
1324 | { | ||
1325 | struct mxser_port *info = tty->driver_data; | ||
1326 | unsigned char control, status; | ||
1327 | unsigned long flags; | ||
1328 | |||
1329 | |||
1330 | if (tty->index == MXSER_PORTS) | ||
1331 | return -ENOIOCTLCMD; | ||
1332 | if (test_bit(TTY_IO_ERROR, &tty->flags)) | ||
1333 | return -EIO; | ||
1334 | |||
1335 | control = info->MCR; | ||
1336 | |||
1337 | spin_lock_irqsave(&info->slock, flags); | ||
1338 | status = inb(info->ioaddr + UART_MSR); | ||
1339 | if (status & UART_MSR_ANY_DELTA) | ||
1340 | mxser_check_modem_status(tty, info, status); | ||
1341 | spin_unlock_irqrestore(&info->slock, flags); | ||
1342 | return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | | ||
1343 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | | ||
1344 | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | | ||
1345 | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | | ||
1346 | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | | ||
1347 | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); | ||
1348 | } | ||
1349 | |||
1350 | static int mxser_tiocmset(struct tty_struct *tty, | ||
1351 | unsigned int set, unsigned int clear) | ||
1352 | { | ||
1353 | struct mxser_port *info = tty->driver_data; | ||
1354 | unsigned long flags; | ||
1355 | |||
1356 | |||
1357 | if (tty->index == MXSER_PORTS) | ||
1358 | return -ENOIOCTLCMD; | ||
1359 | if (test_bit(TTY_IO_ERROR, &tty->flags)) | ||
1360 | return -EIO; | ||
1361 | |||
1362 | spin_lock_irqsave(&info->slock, flags); | ||
1363 | |||
1364 | if (set & TIOCM_RTS) | ||
1365 | info->MCR |= UART_MCR_RTS; | ||
1366 | if (set & TIOCM_DTR) | ||
1367 | info->MCR |= UART_MCR_DTR; | ||
1368 | |||
1369 | if (clear & TIOCM_RTS) | ||
1370 | info->MCR &= ~UART_MCR_RTS; | ||
1371 | if (clear & TIOCM_DTR) | ||
1372 | info->MCR &= ~UART_MCR_DTR; | ||
1373 | |||
1374 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
1375 | spin_unlock_irqrestore(&info->slock, flags); | ||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | static int __init mxser_program_mode(int port) | ||
1380 | { | ||
1381 | int id, i, j, n; | ||
1382 | |||
1383 | outb(0, port); | ||
1384 | outb(0, port); | ||
1385 | outb(0, port); | ||
1386 | (void)inb(port); | ||
1387 | (void)inb(port); | ||
1388 | outb(0, port); | ||
1389 | (void)inb(port); | ||
1390 | |||
1391 | id = inb(port + 1) & 0x1F; | ||
1392 | if ((id != C168_ASIC_ID) && | ||
1393 | (id != C104_ASIC_ID) && | ||
1394 | (id != C102_ASIC_ID) && | ||
1395 | (id != CI132_ASIC_ID) && | ||
1396 | (id != CI134_ASIC_ID) && | ||
1397 | (id != CI104J_ASIC_ID)) | ||
1398 | return -1; | ||
1399 | for (i = 0, j = 0; i < 4; i++) { | ||
1400 | n = inb(port + 2); | ||
1401 | if (n == 'M') { | ||
1402 | j = 1; | ||
1403 | } else if ((j == 1) && (n == 1)) { | ||
1404 | j = 2; | ||
1405 | break; | ||
1406 | } else | ||
1407 | j = 0; | ||
1408 | } | ||
1409 | if (j != 2) | ||
1410 | id = -2; | ||
1411 | return id; | ||
1412 | } | ||
1413 | |||
1414 | static void __init mxser_normal_mode(int port) | ||
1415 | { | ||
1416 | int i, n; | ||
1417 | |||
1418 | outb(0xA5, port + 1); | ||
1419 | outb(0x80, port + 3); | ||
1420 | outb(12, port + 0); /* 9600 bps */ | ||
1421 | outb(0, port + 1); | ||
1422 | outb(0x03, port + 3); /* 8 data bits */ | ||
1423 | outb(0x13, port + 4); /* loop back mode */ | ||
1424 | for (i = 0; i < 16; i++) { | ||
1425 | n = inb(port + 5); | ||
1426 | if ((n & 0x61) == 0x60) | ||
1427 | break; | ||
1428 | if ((n & 1) == 1) | ||
1429 | (void)inb(port); | ||
1430 | } | ||
1431 | outb(0x00, port + 4); | ||
1432 | } | ||
1433 | |||
1434 | #define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ | ||
1435 | #define CHIP_DO 0x02 /* Serial Data Output in Eprom */ | ||
1436 | #define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ | ||
1437 | #define CHIP_DI 0x08 /* Serial Data Input in Eprom */ | ||
1438 | #define EN_CCMD 0x000 /* Chip's command register */ | ||
1439 | #define EN0_RSARLO 0x008 /* Remote start address reg 0 */ | ||
1440 | #define EN0_RSARHI 0x009 /* Remote start address reg 1 */ | ||
1441 | #define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ | ||
1442 | #define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ | ||
1443 | #define EN0_DCFG 0x00E /* Data configuration reg WR */ | ||
1444 | #define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ | ||
1445 | #define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ | ||
1446 | #define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ | ||
1447 | static int __init mxser_read_register(int port, unsigned short *regs) | ||
1448 | { | ||
1449 | int i, k, value, id; | ||
1450 | unsigned int j; | ||
1451 | |||
1452 | id = mxser_program_mode(port); | ||
1453 | if (id < 0) | ||
1454 | return id; | ||
1455 | for (i = 0; i < 14; i++) { | ||
1456 | k = (i & 0x3F) | 0x180; | ||
1457 | for (j = 0x100; j > 0; j >>= 1) { | ||
1458 | outb(CHIP_CS, port); | ||
1459 | if (k & j) { | ||
1460 | outb(CHIP_CS | CHIP_DO, port); | ||
1461 | outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ | ||
1462 | } else { | ||
1463 | outb(CHIP_CS, port); | ||
1464 | outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ | ||
1465 | } | ||
1466 | } | ||
1467 | (void)inb(port); | ||
1468 | value = 0; | ||
1469 | for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { | ||
1470 | outb(CHIP_CS, port); | ||
1471 | outb(CHIP_CS | CHIP_SK, port); | ||
1472 | if (inb(port) & CHIP_DI) | ||
1473 | value |= j; | ||
1474 | } | ||
1475 | regs[i] = value; | ||
1476 | outb(0, port); | ||
1477 | } | ||
1478 | mxser_normal_mode(port); | ||
1479 | return id; | ||
1480 | } | ||
1481 | |||
1482 | static int mxser_ioctl_special(unsigned int cmd, void __user *argp) | ||
1483 | { | ||
1484 | struct mxser_port *ip; | ||
1485 | struct tty_port *port; | ||
1486 | struct tty_struct *tty; | ||
1487 | int result, status; | ||
1488 | unsigned int i, j; | ||
1489 | int ret = 0; | ||
1490 | |||
1491 | switch (cmd) { | ||
1492 | case MOXA_GET_MAJOR: | ||
1493 | if (printk_ratelimit()) | ||
1494 | printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl " | ||
1495 | "%x (GET_MAJOR), fix your userspace\n", | ||
1496 | current->comm, cmd); | ||
1497 | return put_user(ttymajor, (int __user *)argp); | ||
1498 | |||
1499 | case MOXA_CHKPORTENABLE: | ||
1500 | result = 0; | ||
1501 | for (i = 0; i < MXSER_BOARDS; i++) | ||
1502 | for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) | ||
1503 | if (mxser_boards[i].ports[j].ioaddr) | ||
1504 | result |= (1 << i); | ||
1505 | return put_user(result, (unsigned long __user *)argp); | ||
1506 | case MOXA_GETDATACOUNT: | ||
1507 | /* The receive side is locked by port->slock but it isn't | ||
1508 | clear that an exact snapshot is worth copying here */ | ||
1509 | if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) | ||
1510 | ret = -EFAULT; | ||
1511 | return ret; | ||
1512 | case MOXA_GETMSTATUS: { | ||
1513 | struct mxser_mstatus ms, __user *msu = argp; | ||
1514 | for (i = 0; i < MXSER_BOARDS; i++) | ||
1515 | for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) { | ||
1516 | ip = &mxser_boards[i].ports[j]; | ||
1517 | port = &ip->port; | ||
1518 | memset(&ms, 0, sizeof(ms)); | ||
1519 | |||
1520 | mutex_lock(&port->mutex); | ||
1521 | if (!ip->ioaddr) | ||
1522 | goto copy; | ||
1523 | |||
1524 | tty = tty_port_tty_get(port); | ||
1525 | |||
1526 | if (!tty || !tty->termios) | ||
1527 | ms.cflag = ip->normal_termios.c_cflag; | ||
1528 | else | ||
1529 | ms.cflag = tty->termios->c_cflag; | ||
1530 | tty_kref_put(tty); | ||
1531 | spin_lock_irq(&ip->slock); | ||
1532 | status = inb(ip->ioaddr + UART_MSR); | ||
1533 | spin_unlock_irq(&ip->slock); | ||
1534 | if (status & UART_MSR_DCD) | ||
1535 | ms.dcd = 1; | ||
1536 | if (status & UART_MSR_DSR) | ||
1537 | ms.dsr = 1; | ||
1538 | if (status & UART_MSR_CTS) | ||
1539 | ms.cts = 1; | ||
1540 | copy: | ||
1541 | mutex_unlock(&port->mutex); | ||
1542 | if (copy_to_user(msu, &ms, sizeof(ms))) | ||
1543 | return -EFAULT; | ||
1544 | msu++; | ||
1545 | } | ||
1546 | return 0; | ||
1547 | } | ||
1548 | case MOXA_ASPP_MON_EXT: { | ||
1549 | struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */ | ||
1550 | unsigned int cflag, iflag, p; | ||
1551 | u8 opmode; | ||
1552 | |||
1553 | me = kzalloc(sizeof(*me), GFP_KERNEL); | ||
1554 | if (!me) | ||
1555 | return -ENOMEM; | ||
1556 | |||
1557 | for (i = 0, p = 0; i < MXSER_BOARDS; i++) { | ||
1558 | for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) { | ||
1559 | if (p >= ARRAY_SIZE(me->rx_cnt)) { | ||
1560 | i = MXSER_BOARDS; | ||
1561 | break; | ||
1562 | } | ||
1563 | ip = &mxser_boards[i].ports[j]; | ||
1564 | port = &ip->port; | ||
1565 | |||
1566 | mutex_lock(&port->mutex); | ||
1567 | if (!ip->ioaddr) { | ||
1568 | mutex_unlock(&port->mutex); | ||
1569 | continue; | ||
1570 | } | ||
1571 | |||
1572 | spin_lock_irq(&ip->slock); | ||
1573 | status = mxser_get_msr(ip->ioaddr, 0, p); | ||
1574 | |||
1575 | if (status & UART_MSR_TERI) | ||
1576 | ip->icount.rng++; | ||
1577 | if (status & UART_MSR_DDSR) | ||
1578 | ip->icount.dsr++; | ||
1579 | if (status & UART_MSR_DDCD) | ||
1580 | ip->icount.dcd++; | ||
1581 | if (status & UART_MSR_DCTS) | ||
1582 | ip->icount.cts++; | ||
1583 | |||
1584 | ip->mon_data.modem_status = status; | ||
1585 | me->rx_cnt[p] = ip->mon_data.rxcnt; | ||
1586 | me->tx_cnt[p] = ip->mon_data.txcnt; | ||
1587 | me->up_rxcnt[p] = ip->mon_data.up_rxcnt; | ||
1588 | me->up_txcnt[p] = ip->mon_data.up_txcnt; | ||
1589 | me->modem_status[p] = | ||
1590 | ip->mon_data.modem_status; | ||
1591 | spin_unlock_irq(&ip->slock); | ||
1592 | |||
1593 | tty = tty_port_tty_get(&ip->port); | ||
1594 | |||
1595 | if (!tty || !tty->termios) { | ||
1596 | cflag = ip->normal_termios.c_cflag; | ||
1597 | iflag = ip->normal_termios.c_iflag; | ||
1598 | me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios); | ||
1599 | } else { | ||
1600 | cflag = tty->termios->c_cflag; | ||
1601 | iflag = tty->termios->c_iflag; | ||
1602 | me->baudrate[p] = tty_get_baud_rate(tty); | ||
1603 | } | ||
1604 | tty_kref_put(tty); | ||
1605 | |||
1606 | me->databits[p] = cflag & CSIZE; | ||
1607 | me->stopbits[p] = cflag & CSTOPB; | ||
1608 | me->parity[p] = cflag & (PARENB | PARODD | | ||
1609 | CMSPAR); | ||
1610 | |||
1611 | if (cflag & CRTSCTS) | ||
1612 | me->flowctrl[p] |= 0x03; | ||
1613 | |||
1614 | if (iflag & (IXON | IXOFF)) | ||
1615 | me->flowctrl[p] |= 0x0C; | ||
1616 | |||
1617 | if (ip->type == PORT_16550A) | ||
1618 | me->fifo[p] = 1; | ||
1619 | |||
1620 | opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); | ||
1621 | opmode &= OP_MODE_MASK; | ||
1622 | me->iftype[p] = opmode; | ||
1623 | mutex_unlock(&port->mutex); | ||
1624 | } | ||
1625 | } | ||
1626 | if (copy_to_user(argp, me, sizeof(*me))) | ||
1627 | ret = -EFAULT; | ||
1628 | kfree(me); | ||
1629 | return ret; | ||
1630 | } | ||
1631 | default: | ||
1632 | return -ENOIOCTLCMD; | ||
1633 | } | ||
1634 | return 0; | ||
1635 | } | ||
1636 | |||
1637 | static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, | ||
1638 | struct async_icount *cprev) | ||
1639 | { | ||
1640 | struct async_icount cnow; | ||
1641 | unsigned long flags; | ||
1642 | int ret; | ||
1643 | |||
1644 | spin_lock_irqsave(&info->slock, flags); | ||
1645 | cnow = info->icount; /* atomic copy */ | ||
1646 | spin_unlock_irqrestore(&info->slock, flags); | ||
1647 | |||
1648 | ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || | ||
1649 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || | ||
1650 | ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || | ||
1651 | ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); | ||
1652 | |||
1653 | *cprev = cnow; | ||
1654 | |||
1655 | return ret; | ||
1656 | } | ||
1657 | |||
1658 | static int mxser_ioctl(struct tty_struct *tty, | ||
1659 | unsigned int cmd, unsigned long arg) | ||
1660 | { | ||
1661 | struct mxser_port *info = tty->driver_data; | ||
1662 | struct tty_port *port = &info->port; | ||
1663 | struct async_icount cnow; | ||
1664 | unsigned long flags; | ||
1665 | void __user *argp = (void __user *)arg; | ||
1666 | int retval; | ||
1667 | |||
1668 | if (tty->index == MXSER_PORTS) | ||
1669 | return mxser_ioctl_special(cmd, argp); | ||
1670 | |||
1671 | if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { | ||
1672 | int p; | ||
1673 | unsigned long opmode; | ||
1674 | static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; | ||
1675 | int shiftbit; | ||
1676 | unsigned char val, mask; | ||
1677 | |||
1678 | p = tty->index % 4; | ||
1679 | if (cmd == MOXA_SET_OP_MODE) { | ||
1680 | if (get_user(opmode, (int __user *) argp)) | ||
1681 | return -EFAULT; | ||
1682 | if (opmode != RS232_MODE && | ||
1683 | opmode != RS485_2WIRE_MODE && | ||
1684 | opmode != RS422_MODE && | ||
1685 | opmode != RS485_4WIRE_MODE) | ||
1686 | return -EFAULT; | ||
1687 | mask = ModeMask[p]; | ||
1688 | shiftbit = p * 2; | ||
1689 | spin_lock_irq(&info->slock); | ||
1690 | val = inb(info->opmode_ioaddr); | ||
1691 | val &= mask; | ||
1692 | val |= (opmode << shiftbit); | ||
1693 | outb(val, info->opmode_ioaddr); | ||
1694 | spin_unlock_irq(&info->slock); | ||
1695 | } else { | ||
1696 | shiftbit = p * 2; | ||
1697 | spin_lock_irq(&info->slock); | ||
1698 | opmode = inb(info->opmode_ioaddr) >> shiftbit; | ||
1699 | spin_unlock_irq(&info->slock); | ||
1700 | opmode &= OP_MODE_MASK; | ||
1701 | if (put_user(opmode, (int __user *)argp)) | ||
1702 | return -EFAULT; | ||
1703 | } | ||
1704 | return 0; | ||
1705 | } | ||
1706 | |||
1707 | if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && | ||
1708 | test_bit(TTY_IO_ERROR, &tty->flags)) | ||
1709 | return -EIO; | ||
1710 | |||
1711 | switch (cmd) { | ||
1712 | case TIOCGSERIAL: | ||
1713 | mutex_lock(&port->mutex); | ||
1714 | retval = mxser_get_serial_info(tty, argp); | ||
1715 | mutex_unlock(&port->mutex); | ||
1716 | return retval; | ||
1717 | case TIOCSSERIAL: | ||
1718 | mutex_lock(&port->mutex); | ||
1719 | retval = mxser_set_serial_info(tty, argp); | ||
1720 | mutex_unlock(&port->mutex); | ||
1721 | return retval; | ||
1722 | case TIOCSERGETLSR: /* Get line status register */ | ||
1723 | return mxser_get_lsr_info(info, argp); | ||
1724 | /* | ||
1725 | * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change | ||
1726 | * - mask passed in arg for lines of interest | ||
1727 | * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) | ||
1728 | * Caller should use TIOCGICOUNT to see which one it was | ||
1729 | */ | ||
1730 | case TIOCMIWAIT: | ||
1731 | spin_lock_irqsave(&info->slock, flags); | ||
1732 | cnow = info->icount; /* note the counters on entry */ | ||
1733 | spin_unlock_irqrestore(&info->slock, flags); | ||
1734 | |||
1735 | return wait_event_interruptible(info->port.delta_msr_wait, | ||
1736 | mxser_cflags_changed(info, arg, &cnow)); | ||
1737 | case MOXA_HighSpeedOn: | ||
1738 | return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); | ||
1739 | case MOXA_SDS_RSTICOUNTER: | ||
1740 | spin_lock_irq(&info->slock); | ||
1741 | info->mon_data.rxcnt = 0; | ||
1742 | info->mon_data.txcnt = 0; | ||
1743 | spin_unlock_irq(&info->slock); | ||
1744 | return 0; | ||
1745 | |||
1746 | case MOXA_ASPP_OQUEUE:{ | ||
1747 | int len, lsr; | ||
1748 | |||
1749 | len = mxser_chars_in_buffer(tty); | ||
1750 | spin_lock_irq(&info->slock); | ||
1751 | lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE; | ||
1752 | spin_unlock_irq(&info->slock); | ||
1753 | len += (lsr ? 0 : 1); | ||
1754 | |||
1755 | return put_user(len, (int __user *)argp); | ||
1756 | } | ||
1757 | case MOXA_ASPP_MON: { | ||
1758 | int mcr, status; | ||
1759 | |||
1760 | spin_lock_irq(&info->slock); | ||
1761 | status = mxser_get_msr(info->ioaddr, 1, tty->index); | ||
1762 | mxser_check_modem_status(tty, info, status); | ||
1763 | |||
1764 | mcr = inb(info->ioaddr + UART_MCR); | ||
1765 | spin_unlock_irq(&info->slock); | ||
1766 | |||
1767 | if (mcr & MOXA_MUST_MCR_XON_FLAG) | ||
1768 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; | ||
1769 | else | ||
1770 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; | ||
1771 | |||
1772 | if (mcr & MOXA_MUST_MCR_TX_XON) | ||
1773 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; | ||
1774 | else | ||
1775 | info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; | ||
1776 | |||
1777 | if (tty->hw_stopped) | ||
1778 | info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; | ||
1779 | else | ||
1780 | info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; | ||
1781 | |||
1782 | if (copy_to_user(argp, &info->mon_data, | ||
1783 | sizeof(struct mxser_mon))) | ||
1784 | return -EFAULT; | ||
1785 | |||
1786 | return 0; | ||
1787 | } | ||
1788 | case MOXA_ASPP_LSTATUS: { | ||
1789 | if (put_user(info->err_shadow, (unsigned char __user *)argp)) | ||
1790 | return -EFAULT; | ||
1791 | |||
1792 | info->err_shadow = 0; | ||
1793 | return 0; | ||
1794 | } | ||
1795 | case MOXA_SET_BAUD_METHOD: { | ||
1796 | int method; | ||
1797 | |||
1798 | if (get_user(method, (int __user *)argp)) | ||
1799 | return -EFAULT; | ||
1800 | mxser_set_baud_method[tty->index] = method; | ||
1801 | return put_user(method, (int __user *)argp); | ||
1802 | } | ||
1803 | default: | ||
1804 | return -ENOIOCTLCMD; | ||
1805 | } | ||
1806 | return 0; | ||
1807 | } | ||
1808 | |||
1809 | /* | ||
1810 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1811 | * Return: write counters to the user passed counter struct | ||
1812 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1813 | * RI where only 0->1 is counted. | ||
1814 | */ | ||
1815 | |||
1816 | static int mxser_get_icount(struct tty_struct *tty, | ||
1817 | struct serial_icounter_struct *icount) | ||
1818 | |||
1819 | { | ||
1820 | struct mxser_port *info = tty->driver_data; | ||
1821 | struct async_icount cnow; | ||
1822 | unsigned long flags; | ||
1823 | |||
1824 | spin_lock_irqsave(&info->slock, flags); | ||
1825 | cnow = info->icount; | ||
1826 | spin_unlock_irqrestore(&info->slock, flags); | ||
1827 | |||
1828 | icount->frame = cnow.frame; | ||
1829 | icount->brk = cnow.brk; | ||
1830 | icount->overrun = cnow.overrun; | ||
1831 | icount->buf_overrun = cnow.buf_overrun; | ||
1832 | icount->parity = cnow.parity; | ||
1833 | icount->rx = cnow.rx; | ||
1834 | icount->tx = cnow.tx; | ||
1835 | icount->cts = cnow.cts; | ||
1836 | icount->dsr = cnow.dsr; | ||
1837 | icount->rng = cnow.rng; | ||
1838 | icount->dcd = cnow.dcd; | ||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | static void mxser_stoprx(struct tty_struct *tty) | ||
1843 | { | ||
1844 | struct mxser_port *info = tty->driver_data; | ||
1845 | |||
1846 | info->ldisc_stop_rx = 1; | ||
1847 | if (I_IXOFF(tty)) { | ||
1848 | if (info->board->chip_flag) { | ||
1849 | info->IER &= ~MOXA_MUST_RECV_ISR; | ||
1850 | outb(info->IER, info->ioaddr + UART_IER); | ||
1851 | } else { | ||
1852 | info->x_char = STOP_CHAR(tty); | ||
1853 | outb(0, info->ioaddr + UART_IER); | ||
1854 | info->IER |= UART_IER_THRI; | ||
1855 | outb(info->IER, info->ioaddr + UART_IER); | ||
1856 | } | ||
1857 | } | ||
1858 | |||
1859 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1860 | info->MCR &= ~UART_MCR_RTS; | ||
1861 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
1862 | } | ||
1863 | } | ||
1864 | |||
1865 | /* | ||
1866 | * This routine is called by the upper-layer tty layer to signal that | ||
1867 | * incoming characters should be throttled. | ||
1868 | */ | ||
1869 | static void mxser_throttle(struct tty_struct *tty) | ||
1870 | { | ||
1871 | mxser_stoprx(tty); | ||
1872 | } | ||
1873 | |||
1874 | static void mxser_unthrottle(struct tty_struct *tty) | ||
1875 | { | ||
1876 | struct mxser_port *info = tty->driver_data; | ||
1877 | |||
1878 | /* startrx */ | ||
1879 | info->ldisc_stop_rx = 0; | ||
1880 | if (I_IXOFF(tty)) { | ||
1881 | if (info->x_char) | ||
1882 | info->x_char = 0; | ||
1883 | else { | ||
1884 | if (info->board->chip_flag) { | ||
1885 | info->IER |= MOXA_MUST_RECV_ISR; | ||
1886 | outb(info->IER, info->ioaddr + UART_IER); | ||
1887 | } else { | ||
1888 | info->x_char = START_CHAR(tty); | ||
1889 | outb(0, info->ioaddr + UART_IER); | ||
1890 | info->IER |= UART_IER_THRI; | ||
1891 | outb(info->IER, info->ioaddr + UART_IER); | ||
1892 | } | ||
1893 | } | ||
1894 | } | ||
1895 | |||
1896 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1897 | info->MCR |= UART_MCR_RTS; | ||
1898 | outb(info->MCR, info->ioaddr + UART_MCR); | ||
1899 | } | ||
1900 | } | ||
1901 | |||
1902 | /* | ||
1903 | * mxser_stop() and mxser_start() | ||
1904 | * | ||
1905 | * This routines are called before setting or resetting tty->stopped. | ||
1906 | * They enable or disable transmitter interrupts, as necessary. | ||
1907 | */ | ||
1908 | static void mxser_stop(struct tty_struct *tty) | ||
1909 | { | ||
1910 | struct mxser_port *info = tty->driver_data; | ||
1911 | unsigned long flags; | ||
1912 | |||
1913 | spin_lock_irqsave(&info->slock, flags); | ||
1914 | if (info->IER & UART_IER_THRI) { | ||
1915 | info->IER &= ~UART_IER_THRI; | ||
1916 | outb(info->IER, info->ioaddr + UART_IER); | ||
1917 | } | ||
1918 | spin_unlock_irqrestore(&info->slock, flags); | ||
1919 | } | ||
1920 | |||
1921 | static void mxser_start(struct tty_struct *tty) | ||
1922 | { | ||
1923 | struct mxser_port *info = tty->driver_data; | ||
1924 | unsigned long flags; | ||
1925 | |||
1926 | spin_lock_irqsave(&info->slock, flags); | ||
1927 | if (info->xmit_cnt && info->port.xmit_buf) { | ||
1928 | outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); | ||
1929 | info->IER |= UART_IER_THRI; | ||
1930 | outb(info->IER, info->ioaddr + UART_IER); | ||
1931 | } | ||
1932 | spin_unlock_irqrestore(&info->slock, flags); | ||
1933 | } | ||
1934 | |||
1935 | static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
1936 | { | ||
1937 | struct mxser_port *info = tty->driver_data; | ||
1938 | unsigned long flags; | ||
1939 | |||
1940 | spin_lock_irqsave(&info->slock, flags); | ||
1941 | mxser_change_speed(tty, old_termios); | ||
1942 | spin_unlock_irqrestore(&info->slock, flags); | ||
1943 | |||
1944 | if ((old_termios->c_cflag & CRTSCTS) && | ||
1945 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
1946 | tty->hw_stopped = 0; | ||
1947 | mxser_start(tty); | ||
1948 | } | ||
1949 | |||
1950 | /* Handle sw stopped */ | ||
1951 | if ((old_termios->c_iflag & IXON) && | ||
1952 | !(tty->termios->c_iflag & IXON)) { | ||
1953 | tty->stopped = 0; | ||
1954 | |||
1955 | if (info->board->chip_flag) { | ||
1956 | spin_lock_irqsave(&info->slock, flags); | ||
1957 | mxser_disable_must_rx_software_flow_control( | ||
1958 | info->ioaddr); | ||
1959 | spin_unlock_irqrestore(&info->slock, flags); | ||
1960 | } | ||
1961 | |||
1962 | mxser_start(tty); | ||
1963 | } | ||
1964 | } | ||
1965 | |||
1966 | /* | ||
1967 | * mxser_wait_until_sent() --- wait until the transmitter is empty | ||
1968 | */ | ||
1969 | static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) | ||
1970 | { | ||
1971 | struct mxser_port *info = tty->driver_data; | ||
1972 | unsigned long orig_jiffies, char_time; | ||
1973 | unsigned long flags; | ||
1974 | int lsr; | ||
1975 | |||
1976 | if (info->type == PORT_UNKNOWN) | ||
1977 | return; | ||
1978 | |||
1979 | if (info->xmit_fifo_size == 0) | ||
1980 | return; /* Just in case.... */ | ||
1981 | |||
1982 | orig_jiffies = jiffies; | ||
1983 | /* | ||
1984 | * Set the check interval to be 1/5 of the estimated time to | ||
1985 | * send a single character, and make it at least 1. The check | ||
1986 | * interval should also be less than the timeout. | ||
1987 | * | ||
1988 | * Note: we have to use pretty tight timings here to satisfy | ||
1989 | * the NIST-PCTS. | ||
1990 | */ | ||
1991 | char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size; | ||
1992 | char_time = char_time / 5; | ||
1993 | if (char_time == 0) | ||
1994 | char_time = 1; | ||
1995 | if (timeout && timeout < char_time) | ||
1996 | char_time = timeout; | ||
1997 | /* | ||
1998 | * If the transmitter hasn't cleared in twice the approximate | ||
1999 | * amount of time to send the entire FIFO, it probably won't | ||
2000 | * ever clear. This assumes the UART isn't doing flow | ||
2001 | * control, which is currently the case. Hence, if it ever | ||
2002 | * takes longer than info->timeout, this is probably due to a | ||
2003 | * UART bug of some kind. So, we clamp the timeout parameter at | ||
2004 | * 2*info->timeout. | ||
2005 | */ | ||
2006 | if (!timeout || timeout > 2 * info->timeout) | ||
2007 | timeout = 2 * info->timeout; | ||
2008 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
2009 | printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", | ||
2010 | timeout, char_time); | ||
2011 | printk("jiff=%lu...", jiffies); | ||
2012 | #endif | ||
2013 | spin_lock_irqsave(&info->slock, flags); | ||
2014 | while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) { | ||
2015 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
2016 | printk("lsr = %d (jiff=%lu)...", lsr, jiffies); | ||
2017 | #endif | ||
2018 | spin_unlock_irqrestore(&info->slock, flags); | ||
2019 | schedule_timeout_interruptible(char_time); | ||
2020 | spin_lock_irqsave(&info->slock, flags); | ||
2021 | if (signal_pending(current)) | ||
2022 | break; | ||
2023 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
2024 | break; | ||
2025 | } | ||
2026 | spin_unlock_irqrestore(&info->slock, flags); | ||
2027 | set_current_state(TASK_RUNNING); | ||
2028 | |||
2029 | #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT | ||
2030 | printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); | ||
2031 | #endif | ||
2032 | } | ||
2033 | |||
2034 | /* | ||
2035 | * This routine is called by tty_hangup() when a hangup is signaled. | ||
2036 | */ | ||
2037 | static void mxser_hangup(struct tty_struct *tty) | ||
2038 | { | ||
2039 | struct mxser_port *info = tty->driver_data; | ||
2040 | |||
2041 | mxser_flush_buffer(tty); | ||
2042 | tty_port_hangup(&info->port); | ||
2043 | } | ||
2044 | |||
2045 | /* | ||
2046 | * mxser_rs_break() --- routine which turns the break handling on or off | ||
2047 | */ | ||
2048 | static int mxser_rs_break(struct tty_struct *tty, int break_state) | ||
2049 | { | ||
2050 | struct mxser_port *info = tty->driver_data; | ||
2051 | unsigned long flags; | ||
2052 | |||
2053 | spin_lock_irqsave(&info->slock, flags); | ||
2054 | if (break_state == -1) | ||
2055 | outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC, | ||
2056 | info->ioaddr + UART_LCR); | ||
2057 | else | ||
2058 | outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, | ||
2059 | info->ioaddr + UART_LCR); | ||
2060 | spin_unlock_irqrestore(&info->slock, flags); | ||
2061 | return 0; | ||
2062 | } | ||
2063 | |||
2064 | static void mxser_receive_chars(struct tty_struct *tty, | ||
2065 | struct mxser_port *port, int *status) | ||
2066 | { | ||
2067 | unsigned char ch, gdl; | ||
2068 | int ignored = 0; | ||
2069 | int cnt = 0; | ||
2070 | int recv_room; | ||
2071 | int max = 256; | ||
2072 | |||
2073 | recv_room = tty->receive_room; | ||
2074 | if (recv_room == 0 && !port->ldisc_stop_rx) | ||
2075 | mxser_stoprx(tty); | ||
2076 | if (port->board->chip_flag != MOXA_OTHER_UART) { | ||
2077 | |||
2078 | if (*status & UART_LSR_SPECIAL) | ||
2079 | goto intr_old; | ||
2080 | if (port->board->chip_flag == MOXA_MUST_MU860_HWID && | ||
2081 | (*status & MOXA_MUST_LSR_RERR)) | ||
2082 | goto intr_old; | ||
2083 | if (*status & MOXA_MUST_LSR_RERR) | ||
2084 | goto intr_old; | ||
2085 | |||
2086 | gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); | ||
2087 | |||
2088 | if (port->board->chip_flag == MOXA_MUST_MU150_HWID) | ||
2089 | gdl &= MOXA_MUST_GDL_MASK; | ||
2090 | if (gdl >= recv_room) { | ||
2091 | if (!port->ldisc_stop_rx) | ||
2092 | mxser_stoprx(tty); | ||
2093 | } | ||
2094 | while (gdl--) { | ||
2095 | ch = inb(port->ioaddr + UART_RX); | ||
2096 | tty_insert_flip_char(tty, ch, 0); | ||
2097 | cnt++; | ||
2098 | } | ||
2099 | goto end_intr; | ||
2100 | } | ||
2101 | intr_old: | ||
2102 | |||
2103 | do { | ||
2104 | if (max-- < 0) | ||
2105 | break; | ||
2106 | |||
2107 | ch = inb(port->ioaddr + UART_RX); | ||
2108 | if (port->board->chip_flag && (*status & UART_LSR_OE)) | ||
2109 | outb(0x23, port->ioaddr + UART_FCR); | ||
2110 | *status &= port->read_status_mask; | ||
2111 | if (*status & port->ignore_status_mask) { | ||
2112 | if (++ignored > 100) | ||
2113 | break; | ||
2114 | } else { | ||
2115 | char flag = 0; | ||
2116 | if (*status & UART_LSR_SPECIAL) { | ||
2117 | if (*status & UART_LSR_BI) { | ||
2118 | flag = TTY_BREAK; | ||
2119 | port->icount.brk++; | ||
2120 | |||
2121 | if (port->port.flags & ASYNC_SAK) | ||
2122 | do_SAK(tty); | ||
2123 | } else if (*status & UART_LSR_PE) { | ||
2124 | flag = TTY_PARITY; | ||
2125 | port->icount.parity++; | ||
2126 | } else if (*status & UART_LSR_FE) { | ||
2127 | flag = TTY_FRAME; | ||
2128 | port->icount.frame++; | ||
2129 | } else if (*status & UART_LSR_OE) { | ||
2130 | flag = TTY_OVERRUN; | ||
2131 | port->icount.overrun++; | ||
2132 | } else | ||
2133 | flag = TTY_BREAK; | ||
2134 | } | ||
2135 | tty_insert_flip_char(tty, ch, flag); | ||
2136 | cnt++; | ||
2137 | if (cnt >= recv_room) { | ||
2138 | if (!port->ldisc_stop_rx) | ||
2139 | mxser_stoprx(tty); | ||
2140 | break; | ||
2141 | } | ||
2142 | |||
2143 | } | ||
2144 | |||
2145 | if (port->board->chip_flag) | ||
2146 | break; | ||
2147 | |||
2148 | *status = inb(port->ioaddr + UART_LSR); | ||
2149 | } while (*status & UART_LSR_DR); | ||
2150 | |||
2151 | end_intr: | ||
2152 | mxvar_log.rxcnt[tty->index] += cnt; | ||
2153 | port->mon_data.rxcnt += cnt; | ||
2154 | port->mon_data.up_rxcnt += cnt; | ||
2155 | |||
2156 | /* | ||
2157 | * We are called from an interrupt context with &port->slock | ||
2158 | * being held. Drop it temporarily in order to prevent | ||
2159 | * recursive locking. | ||
2160 | */ | ||
2161 | spin_unlock(&port->slock); | ||
2162 | tty_flip_buffer_push(tty); | ||
2163 | spin_lock(&port->slock); | ||
2164 | } | ||
2165 | |||
2166 | static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) | ||
2167 | { | ||
2168 | int count, cnt; | ||
2169 | |||
2170 | if (port->x_char) { | ||
2171 | outb(port->x_char, port->ioaddr + UART_TX); | ||
2172 | port->x_char = 0; | ||
2173 | mxvar_log.txcnt[tty->index]++; | ||
2174 | port->mon_data.txcnt++; | ||
2175 | port->mon_data.up_txcnt++; | ||
2176 | port->icount.tx++; | ||
2177 | return; | ||
2178 | } | ||
2179 | |||
2180 | if (port->port.xmit_buf == NULL) | ||
2181 | return; | ||
2182 | |||
2183 | if (port->xmit_cnt <= 0 || tty->stopped || | ||
2184 | (tty->hw_stopped && | ||
2185 | (port->type != PORT_16550A) && | ||
2186 | (!port->board->chip_flag))) { | ||
2187 | port->IER &= ~UART_IER_THRI; | ||
2188 | outb(port->IER, port->ioaddr + UART_IER); | ||
2189 | return; | ||
2190 | } | ||
2191 | |||
2192 | cnt = port->xmit_cnt; | ||
2193 | count = port->xmit_fifo_size; | ||
2194 | do { | ||
2195 | outb(port->port.xmit_buf[port->xmit_tail++], | ||
2196 | port->ioaddr + UART_TX); | ||
2197 | port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); | ||
2198 | if (--port->xmit_cnt <= 0) | ||
2199 | break; | ||
2200 | } while (--count > 0); | ||
2201 | mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); | ||
2202 | |||
2203 | port->mon_data.txcnt += (cnt - port->xmit_cnt); | ||
2204 | port->mon_data.up_txcnt += (cnt - port->xmit_cnt); | ||
2205 | port->icount.tx += (cnt - port->xmit_cnt); | ||
2206 | |||
2207 | if (port->xmit_cnt < WAKEUP_CHARS) | ||
2208 | tty_wakeup(tty); | ||
2209 | |||
2210 | if (port->xmit_cnt <= 0) { | ||
2211 | port->IER &= ~UART_IER_THRI; | ||
2212 | outb(port->IER, port->ioaddr + UART_IER); | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | /* | ||
2217 | * This is the serial driver's generic interrupt routine | ||
2218 | */ | ||
2219 | static irqreturn_t mxser_interrupt(int irq, void *dev_id) | ||
2220 | { | ||
2221 | int status, iir, i; | ||
2222 | struct mxser_board *brd = NULL; | ||
2223 | struct mxser_port *port; | ||
2224 | int max, irqbits, bits, msr; | ||
2225 | unsigned int int_cnt, pass_counter = 0; | ||
2226 | int handled = IRQ_NONE; | ||
2227 | struct tty_struct *tty; | ||
2228 | |||
2229 | for (i = 0; i < MXSER_BOARDS; i++) | ||
2230 | if (dev_id == &mxser_boards[i]) { | ||
2231 | brd = dev_id; | ||
2232 | break; | ||
2233 | } | ||
2234 | |||
2235 | if (i == MXSER_BOARDS) | ||
2236 | goto irq_stop; | ||
2237 | if (brd == NULL) | ||
2238 | goto irq_stop; | ||
2239 | max = brd->info->nports; | ||
2240 | while (pass_counter++ < MXSER_ISR_PASS_LIMIT) { | ||
2241 | irqbits = inb(brd->vector) & brd->vector_mask; | ||
2242 | if (irqbits == brd->vector_mask) | ||
2243 | break; | ||
2244 | |||
2245 | handled = IRQ_HANDLED; | ||
2246 | for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { | ||
2247 | if (irqbits == brd->vector_mask) | ||
2248 | break; | ||
2249 | if (bits & irqbits) | ||
2250 | continue; | ||
2251 | port = &brd->ports[i]; | ||
2252 | |||
2253 | int_cnt = 0; | ||
2254 | spin_lock(&port->slock); | ||
2255 | do { | ||
2256 | iir = inb(port->ioaddr + UART_IIR); | ||
2257 | if (iir & UART_IIR_NO_INT) | ||
2258 | break; | ||
2259 | iir &= MOXA_MUST_IIR_MASK; | ||
2260 | tty = tty_port_tty_get(&port->port); | ||
2261 | if (!tty || | ||
2262 | (port->port.flags & ASYNC_CLOSING) || | ||
2263 | !(port->port.flags & | ||
2264 | ASYNC_INITIALIZED)) { | ||
2265 | status = inb(port->ioaddr + UART_LSR); | ||
2266 | outb(0x27, port->ioaddr + UART_FCR); | ||
2267 | inb(port->ioaddr + UART_MSR); | ||
2268 | tty_kref_put(tty); | ||
2269 | break; | ||
2270 | } | ||
2271 | |||
2272 | status = inb(port->ioaddr + UART_LSR); | ||
2273 | |||
2274 | if (status & UART_LSR_PE) | ||
2275 | port->err_shadow |= NPPI_NOTIFY_PARITY; | ||
2276 | if (status & UART_LSR_FE) | ||
2277 | port->err_shadow |= NPPI_NOTIFY_FRAMING; | ||
2278 | if (status & UART_LSR_OE) | ||
2279 | port->err_shadow |= | ||
2280 | NPPI_NOTIFY_HW_OVERRUN; | ||
2281 | if (status & UART_LSR_BI) | ||
2282 | port->err_shadow |= NPPI_NOTIFY_BREAK; | ||
2283 | |||
2284 | if (port->board->chip_flag) { | ||
2285 | if (iir == MOXA_MUST_IIR_GDA || | ||
2286 | iir == MOXA_MUST_IIR_RDA || | ||
2287 | iir == MOXA_MUST_IIR_RTO || | ||
2288 | iir == MOXA_MUST_IIR_LSR) | ||
2289 | mxser_receive_chars(tty, port, | ||
2290 | &status); | ||
2291 | |||
2292 | } else { | ||
2293 | status &= port->read_status_mask; | ||
2294 | if (status & UART_LSR_DR) | ||
2295 | mxser_receive_chars(tty, port, | ||
2296 | &status); | ||
2297 | } | ||
2298 | msr = inb(port->ioaddr + UART_MSR); | ||
2299 | if (msr & UART_MSR_ANY_DELTA) | ||
2300 | mxser_check_modem_status(tty, port, msr); | ||
2301 | |||
2302 | if (port->board->chip_flag) { | ||
2303 | if (iir == 0x02 && (status & | ||
2304 | UART_LSR_THRE)) | ||
2305 | mxser_transmit_chars(tty, port); | ||
2306 | } else { | ||
2307 | if (status & UART_LSR_THRE) | ||
2308 | mxser_transmit_chars(tty, port); | ||
2309 | } | ||
2310 | tty_kref_put(tty); | ||
2311 | } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); | ||
2312 | spin_unlock(&port->slock); | ||
2313 | } | ||
2314 | } | ||
2315 | |||
2316 | irq_stop: | ||
2317 | return handled; | ||
2318 | } | ||
2319 | |||
2320 | static const struct tty_operations mxser_ops = { | ||
2321 | .open = mxser_open, | ||
2322 | .close = mxser_close, | ||
2323 | .write = mxser_write, | ||
2324 | .put_char = mxser_put_char, | ||
2325 | .flush_chars = mxser_flush_chars, | ||
2326 | .write_room = mxser_write_room, | ||
2327 | .chars_in_buffer = mxser_chars_in_buffer, | ||
2328 | .flush_buffer = mxser_flush_buffer, | ||
2329 | .ioctl = mxser_ioctl, | ||
2330 | .throttle = mxser_throttle, | ||
2331 | .unthrottle = mxser_unthrottle, | ||
2332 | .set_termios = mxser_set_termios, | ||
2333 | .stop = mxser_stop, | ||
2334 | .start = mxser_start, | ||
2335 | .hangup = mxser_hangup, | ||
2336 | .break_ctl = mxser_rs_break, | ||
2337 | .wait_until_sent = mxser_wait_until_sent, | ||
2338 | .tiocmget = mxser_tiocmget, | ||
2339 | .tiocmset = mxser_tiocmset, | ||
2340 | .get_icount = mxser_get_icount, | ||
2341 | }; | ||
2342 | |||
2343 | struct tty_port_operations mxser_port_ops = { | ||
2344 | .carrier_raised = mxser_carrier_raised, | ||
2345 | .dtr_rts = mxser_dtr_rts, | ||
2346 | .activate = mxser_activate, | ||
2347 | .shutdown = mxser_shutdown_port, | ||
2348 | }; | ||
2349 | |||
2350 | /* | ||
2351 | * The MOXA Smartio/Industio serial driver boot-time initialization code! | ||
2352 | */ | ||
2353 | |||
2354 | static void mxser_release_ISA_res(struct mxser_board *brd) | ||
2355 | { | ||
2356 | free_irq(brd->irq, brd); | ||
2357 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); | ||
2358 | release_region(brd->vector, 1); | ||
2359 | } | ||
2360 | |||
2361 | static int __devinit mxser_initbrd(struct mxser_board *brd, | ||
2362 | struct pci_dev *pdev) | ||
2363 | { | ||
2364 | struct mxser_port *info; | ||
2365 | unsigned int i; | ||
2366 | int retval; | ||
2367 | |||
2368 | printk(KERN_INFO "mxser: max. baud rate = %d bps\n", | ||
2369 | brd->ports[0].max_baud); | ||
2370 | |||
2371 | for (i = 0; i < brd->info->nports; i++) { | ||
2372 | info = &brd->ports[i]; | ||
2373 | tty_port_init(&info->port); | ||
2374 | info->port.ops = &mxser_port_ops; | ||
2375 | info->board = brd; | ||
2376 | info->stop_rx = 0; | ||
2377 | info->ldisc_stop_rx = 0; | ||
2378 | |||
2379 | /* Enhance mode enabled here */ | ||
2380 | if (brd->chip_flag != MOXA_OTHER_UART) | ||
2381 | mxser_enable_must_enchance_mode(info->ioaddr); | ||
2382 | |||
2383 | info->port.flags = ASYNC_SHARE_IRQ; | ||
2384 | info->type = brd->uart_type; | ||
2385 | |||
2386 | process_txrx_fifo(info); | ||
2387 | |||
2388 | info->custom_divisor = info->baud_base * 16; | ||
2389 | info->port.close_delay = 5 * HZ / 10; | ||
2390 | info->port.closing_wait = 30 * HZ; | ||
2391 | info->normal_termios = mxvar_sdriver->init_termios; | ||
2392 | memset(&info->mon_data, 0, sizeof(struct mxser_mon)); | ||
2393 | info->err_shadow = 0; | ||
2394 | spin_lock_init(&info->slock); | ||
2395 | |||
2396 | /* before set INT ISR, disable all int */ | ||
2397 | outb(inb(info->ioaddr + UART_IER) & 0xf0, | ||
2398 | info->ioaddr + UART_IER); | ||
2399 | } | ||
2400 | |||
2401 | retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", | ||
2402 | brd); | ||
2403 | if (retval) | ||
2404 | printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " | ||
2405 | "conflict with another device.\n", | ||
2406 | brd->info->name, brd->irq); | ||
2407 | |||
2408 | return retval; | ||
2409 | } | ||
2410 | |||
2411 | static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) | ||
2412 | { | ||
2413 | int id, i, bits; | ||
2414 | unsigned short regs[16], irq; | ||
2415 | unsigned char scratch, scratch2; | ||
2416 | |||
2417 | brd->chip_flag = MOXA_OTHER_UART; | ||
2418 | |||
2419 | id = mxser_read_register(cap, regs); | ||
2420 | switch (id) { | ||
2421 | case C168_ASIC_ID: | ||
2422 | brd->info = &mxser_cards[0]; | ||
2423 | break; | ||
2424 | case C104_ASIC_ID: | ||
2425 | brd->info = &mxser_cards[1]; | ||
2426 | break; | ||
2427 | case CI104J_ASIC_ID: | ||
2428 | brd->info = &mxser_cards[2]; | ||
2429 | break; | ||
2430 | case C102_ASIC_ID: | ||
2431 | brd->info = &mxser_cards[5]; | ||
2432 | break; | ||
2433 | case CI132_ASIC_ID: | ||
2434 | brd->info = &mxser_cards[6]; | ||
2435 | break; | ||
2436 | case CI134_ASIC_ID: | ||
2437 | brd->info = &mxser_cards[7]; | ||
2438 | break; | ||
2439 | default: | ||
2440 | return 0; | ||
2441 | } | ||
2442 | |||
2443 | irq = 0; | ||
2444 | /* some ISA cards have 2 ports, but we want to see them as 4-port (why?) | ||
2445 | Flag-hack checks if configuration should be read as 2-port here. */ | ||
2446 | if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) { | ||
2447 | irq = regs[9] & 0xF000; | ||
2448 | irq = irq | (irq >> 4); | ||
2449 | if (irq != (regs[9] & 0xFF00)) | ||
2450 | goto err_irqconflict; | ||
2451 | } else if (brd->info->nports == 4) { | ||
2452 | irq = regs[9] & 0xF000; | ||
2453 | irq = irq | (irq >> 4); | ||
2454 | irq = irq | (irq >> 8); | ||
2455 | if (irq != regs[9]) | ||
2456 | goto err_irqconflict; | ||
2457 | } else if (brd->info->nports == 8) { | ||
2458 | irq = regs[9] & 0xF000; | ||
2459 | irq = irq | (irq >> 4); | ||
2460 | irq = irq | (irq >> 8); | ||
2461 | if ((irq != regs[9]) || (irq != regs[10])) | ||
2462 | goto err_irqconflict; | ||
2463 | } | ||
2464 | |||
2465 | if (!irq) { | ||
2466 | printk(KERN_ERR "mxser: interrupt number unset\n"); | ||
2467 | return -EIO; | ||
2468 | } | ||
2469 | brd->irq = ((int)(irq & 0xF000) >> 12); | ||
2470 | for (i = 0; i < 8; i++) | ||
2471 | brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8; | ||
2472 | if ((regs[12] & 0x80) == 0) { | ||
2473 | printk(KERN_ERR "mxser: invalid interrupt vector\n"); | ||
2474 | return -EIO; | ||
2475 | } | ||
2476 | brd->vector = (int)regs[11]; /* interrupt vector */ | ||
2477 | if (id == 1) | ||
2478 | brd->vector_mask = 0x00FF; | ||
2479 | else | ||
2480 | brd->vector_mask = 0x000F; | ||
2481 | for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { | ||
2482 | if (regs[12] & bits) { | ||
2483 | brd->ports[i].baud_base = 921600; | ||
2484 | brd->ports[i].max_baud = 921600; | ||
2485 | } else { | ||
2486 | brd->ports[i].baud_base = 115200; | ||
2487 | brd->ports[i].max_baud = 115200; | ||
2488 | } | ||
2489 | } | ||
2490 | scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); | ||
2491 | outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); | ||
2492 | outb(0, cap + UART_EFR); /* EFR is the same as FCR */ | ||
2493 | outb(scratch2, cap + UART_LCR); | ||
2494 | outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); | ||
2495 | scratch = inb(cap + UART_IIR); | ||
2496 | |||
2497 | if (scratch & 0xC0) | ||
2498 | brd->uart_type = PORT_16550A; | ||
2499 | else | ||
2500 | brd->uart_type = PORT_16450; | ||
2501 | if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports, | ||
2502 | "mxser(IO)")) { | ||
2503 | printk(KERN_ERR "mxser: can't request ports I/O region: " | ||
2504 | "0x%.8lx-0x%.8lx\n", | ||
2505 | brd->ports[0].ioaddr, brd->ports[0].ioaddr + | ||
2506 | 8 * brd->info->nports - 1); | ||
2507 | return -EIO; | ||
2508 | } | ||
2509 | if (!request_region(brd->vector, 1, "mxser(vector)")) { | ||
2510 | release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); | ||
2511 | printk(KERN_ERR "mxser: can't request interrupt vector region: " | ||
2512 | "0x%.8lx-0x%.8lx\n", | ||
2513 | brd->ports[0].ioaddr, brd->ports[0].ioaddr + | ||
2514 | 8 * brd->info->nports - 1); | ||
2515 | return -EIO; | ||
2516 | } | ||
2517 | return brd->info->nports; | ||
2518 | |||
2519 | err_irqconflict: | ||
2520 | printk(KERN_ERR "mxser: invalid interrupt number\n"); | ||
2521 | return -EIO; | ||
2522 | } | ||
2523 | |||
2524 | static int __devinit mxser_probe(struct pci_dev *pdev, | ||
2525 | const struct pci_device_id *ent) | ||
2526 | { | ||
2527 | #ifdef CONFIG_PCI | ||
2528 | struct mxser_board *brd; | ||
2529 | unsigned int i, j; | ||
2530 | unsigned long ioaddress; | ||
2531 | int retval = -EINVAL; | ||
2532 | |||
2533 | for (i = 0; i < MXSER_BOARDS; i++) | ||
2534 | if (mxser_boards[i].info == NULL) | ||
2535 | break; | ||
2536 | |||
2537 | if (i >= MXSER_BOARDS) { | ||
2538 | dev_err(&pdev->dev, "too many boards found (maximum %d), board " | ||
2539 | "not configured\n", MXSER_BOARDS); | ||
2540 | goto err; | ||
2541 | } | ||
2542 | |||
2543 | brd = &mxser_boards[i]; | ||
2544 | brd->idx = i * MXSER_PORTS_PER_BOARD; | ||
2545 | dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)\n", | ||
2546 | mxser_cards[ent->driver_data].name, | ||
2547 | pdev->bus->number, PCI_SLOT(pdev->devfn)); | ||
2548 | |||
2549 | retval = pci_enable_device(pdev); | ||
2550 | if (retval) { | ||
2551 | dev_err(&pdev->dev, "PCI enable failed\n"); | ||
2552 | goto err; | ||
2553 | } | ||
2554 | |||
2555 | /* io address */ | ||
2556 | ioaddress = pci_resource_start(pdev, 2); | ||
2557 | retval = pci_request_region(pdev, 2, "mxser(IO)"); | ||
2558 | if (retval) | ||
2559 | goto err_dis; | ||
2560 | |||
2561 | brd->info = &mxser_cards[ent->driver_data]; | ||
2562 | for (i = 0; i < brd->info->nports; i++) | ||
2563 | brd->ports[i].ioaddr = ioaddress + 8 * i; | ||
2564 | |||
2565 | /* vector */ | ||
2566 | ioaddress = pci_resource_start(pdev, 3); | ||
2567 | retval = pci_request_region(pdev, 3, "mxser(vector)"); | ||
2568 | if (retval) | ||
2569 | goto err_zero; | ||
2570 | brd->vector = ioaddress; | ||
2571 | |||
2572 | /* irq */ | ||
2573 | brd->irq = pdev->irq; | ||
2574 | |||
2575 | brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr); | ||
2576 | brd->uart_type = PORT_16550A; | ||
2577 | brd->vector_mask = 0; | ||
2578 | |||
2579 | for (i = 0; i < brd->info->nports; i++) { | ||
2580 | for (j = 0; j < UART_INFO_NUM; j++) { | ||
2581 | if (Gpci_uart_info[j].type == brd->chip_flag) { | ||
2582 | brd->ports[i].max_baud = | ||
2583 | Gpci_uart_info[j].max_baud; | ||
2584 | |||
2585 | /* exception....CP-102 */ | ||
2586 | if (brd->info->flags & MXSER_HIGHBAUD) | ||
2587 | brd->ports[i].max_baud = 921600; | ||
2588 | break; | ||
2589 | } | ||
2590 | } | ||
2591 | } | ||
2592 | |||
2593 | if (brd->chip_flag == MOXA_MUST_MU860_HWID) { | ||
2594 | for (i = 0; i < brd->info->nports; i++) { | ||
2595 | if (i < 4) | ||
2596 | brd->ports[i].opmode_ioaddr = ioaddress + 4; | ||
2597 | else | ||
2598 | brd->ports[i].opmode_ioaddr = ioaddress + 0x0c; | ||
2599 | } | ||
2600 | outb(0, ioaddress + 4); /* default set to RS232 mode */ | ||
2601 | outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ | ||
2602 | } | ||
2603 | |||
2604 | for (i = 0; i < brd->info->nports; i++) { | ||
2605 | brd->vector_mask |= (1 << i); | ||
2606 | brd->ports[i].baud_base = 921600; | ||
2607 | } | ||
2608 | |||
2609 | /* mxser_initbrd will hook ISR. */ | ||
2610 | retval = mxser_initbrd(brd, pdev); | ||
2611 | if (retval) | ||
2612 | goto err_rel3; | ||
2613 | |||
2614 | for (i = 0; i < brd->info->nports; i++) | ||
2615 | tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev); | ||
2616 | |||
2617 | pci_set_drvdata(pdev, brd); | ||
2618 | |||
2619 | return 0; | ||
2620 | err_rel3: | ||
2621 | pci_release_region(pdev, 3); | ||
2622 | err_zero: | ||
2623 | brd->info = NULL; | ||
2624 | pci_release_region(pdev, 2); | ||
2625 | err_dis: | ||
2626 | pci_disable_device(pdev); | ||
2627 | err: | ||
2628 | return retval; | ||
2629 | #else | ||
2630 | return -ENODEV; | ||
2631 | #endif | ||
2632 | } | ||
2633 | |||
2634 | static void __devexit mxser_remove(struct pci_dev *pdev) | ||
2635 | { | ||
2636 | #ifdef CONFIG_PCI | ||
2637 | struct mxser_board *brd = pci_get_drvdata(pdev); | ||
2638 | unsigned int i; | ||
2639 | |||
2640 | for (i = 0; i < brd->info->nports; i++) | ||
2641 | tty_unregister_device(mxvar_sdriver, brd->idx + i); | ||
2642 | |||
2643 | free_irq(pdev->irq, brd); | ||
2644 | pci_release_region(pdev, 2); | ||
2645 | pci_release_region(pdev, 3); | ||
2646 | pci_disable_device(pdev); | ||
2647 | brd->info = NULL; | ||
2648 | #endif | ||
2649 | } | ||
2650 | |||
2651 | static struct pci_driver mxser_driver = { | ||
2652 | .name = "mxser", | ||
2653 | .id_table = mxser_pcibrds, | ||
2654 | .probe = mxser_probe, | ||
2655 | .remove = __devexit_p(mxser_remove) | ||
2656 | }; | ||
2657 | |||
2658 | static int __init mxser_module_init(void) | ||
2659 | { | ||
2660 | struct mxser_board *brd; | ||
2661 | unsigned int b, i, m; | ||
2662 | int retval; | ||
2663 | |||
2664 | mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); | ||
2665 | if (!mxvar_sdriver) | ||
2666 | return -ENOMEM; | ||
2667 | |||
2668 | printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", | ||
2669 | MXSER_VERSION); | ||
2670 | |||
2671 | /* Initialize the tty_driver structure */ | ||
2672 | mxvar_sdriver->owner = THIS_MODULE; | ||
2673 | mxvar_sdriver->magic = TTY_DRIVER_MAGIC; | ||
2674 | mxvar_sdriver->name = "ttyMI"; | ||
2675 | mxvar_sdriver->major = ttymajor; | ||
2676 | mxvar_sdriver->minor_start = 0; | ||
2677 | mxvar_sdriver->num = MXSER_PORTS + 1; | ||
2678 | mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL; | ||
2679 | mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; | ||
2680 | mxvar_sdriver->init_termios = tty_std_termios; | ||
2681 | mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; | ||
2682 | mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV; | ||
2683 | tty_set_operations(mxvar_sdriver, &mxser_ops); | ||
2684 | |||
2685 | retval = tty_register_driver(mxvar_sdriver); | ||
2686 | if (retval) { | ||
2687 | printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family " | ||
2688 | "tty driver !\n"); | ||
2689 | goto err_put; | ||
2690 | } | ||
2691 | |||
2692 | /* Start finding ISA boards here */ | ||
2693 | for (m = 0, b = 0; b < MXSER_BOARDS; b++) { | ||
2694 | if (!ioaddr[b]) | ||
2695 | continue; | ||
2696 | |||
2697 | brd = &mxser_boards[m]; | ||
2698 | retval = mxser_get_ISA_conf(ioaddr[b], brd); | ||
2699 | if (retval <= 0) { | ||
2700 | brd->info = NULL; | ||
2701 | continue; | ||
2702 | } | ||
2703 | |||
2704 | printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n", | ||
2705 | brd->info->name, ioaddr[b]); | ||
2706 | |||
2707 | /* mxser_initbrd will hook ISR. */ | ||
2708 | if (mxser_initbrd(brd, NULL) < 0) { | ||
2709 | brd->info = NULL; | ||
2710 | continue; | ||
2711 | } | ||
2712 | |||
2713 | brd->idx = m * MXSER_PORTS_PER_BOARD; | ||
2714 | for (i = 0; i < brd->info->nports; i++) | ||
2715 | tty_register_device(mxvar_sdriver, brd->idx + i, NULL); | ||
2716 | |||
2717 | m++; | ||
2718 | } | ||
2719 | |||
2720 | retval = pci_register_driver(&mxser_driver); | ||
2721 | if (retval) { | ||
2722 | printk(KERN_ERR "mxser: can't register pci driver\n"); | ||
2723 | if (!m) { | ||
2724 | retval = -ENODEV; | ||
2725 | goto err_unr; | ||
2726 | } /* else: we have some ISA cards under control */ | ||
2727 | } | ||
2728 | |||
2729 | return 0; | ||
2730 | err_unr: | ||
2731 | tty_unregister_driver(mxvar_sdriver); | ||
2732 | err_put: | ||
2733 | put_tty_driver(mxvar_sdriver); | ||
2734 | return retval; | ||
2735 | } | ||
2736 | |||
2737 | static void __exit mxser_module_exit(void) | ||
2738 | { | ||
2739 | unsigned int i, j; | ||
2740 | |||
2741 | pci_unregister_driver(&mxser_driver); | ||
2742 | |||
2743 | for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */ | ||
2744 | if (mxser_boards[i].info != NULL) | ||
2745 | for (j = 0; j < mxser_boards[i].info->nports; j++) | ||
2746 | tty_unregister_device(mxvar_sdriver, | ||
2747 | mxser_boards[i].idx + j); | ||
2748 | tty_unregister_driver(mxvar_sdriver); | ||
2749 | put_tty_driver(mxvar_sdriver); | ||
2750 | |||
2751 | for (i = 0; i < MXSER_BOARDS; i++) | ||
2752 | if (mxser_boards[i].info != NULL) | ||
2753 | mxser_release_ISA_res(&mxser_boards[i]); | ||
2754 | } | ||
2755 | |||
2756 | module_init(mxser_module_init); | ||
2757 | module_exit(mxser_module_exit); | ||
diff --git a/drivers/tty/mxser.h b/drivers/tty/mxser.h new file mode 100644 index 000000000000..41878a69203d --- /dev/null +++ b/drivers/tty/mxser.h | |||
@@ -0,0 +1,150 @@ | |||
1 | #ifndef _MXSER_H | ||
2 | #define _MXSER_H | ||
3 | |||
4 | /* | ||
5 | * Semi-public control interfaces | ||
6 | */ | ||
7 | |||
8 | /* | ||
9 | * MOXA ioctls | ||
10 | */ | ||
11 | |||
12 | #define MOXA 0x400 | ||
13 | #define MOXA_GETDATACOUNT (MOXA + 23) | ||
14 | #define MOXA_DIAGNOSE (MOXA + 50) | ||
15 | #define MOXA_CHKPORTENABLE (MOXA + 60) | ||
16 | #define MOXA_HighSpeedOn (MOXA + 61) | ||
17 | #define MOXA_GET_MAJOR (MOXA + 63) | ||
18 | #define MOXA_GETMSTATUS (MOXA + 65) | ||
19 | #define MOXA_SET_OP_MODE (MOXA + 66) | ||
20 | #define MOXA_GET_OP_MODE (MOXA + 67) | ||
21 | |||
22 | #define RS232_MODE 0 | ||
23 | #define RS485_2WIRE_MODE 1 | ||
24 | #define RS422_MODE 2 | ||
25 | #define RS485_4WIRE_MODE 3 | ||
26 | #define OP_MODE_MASK 3 | ||
27 | |||
28 | #define MOXA_SDS_RSTICOUNTER (MOXA + 69) | ||
29 | #define MOXA_ASPP_OQUEUE (MOXA + 70) | ||
30 | #define MOXA_ASPP_MON (MOXA + 73) | ||
31 | #define MOXA_ASPP_LSTATUS (MOXA + 74) | ||
32 | #define MOXA_ASPP_MON_EXT (MOXA + 75) | ||
33 | #define MOXA_SET_BAUD_METHOD (MOXA + 76) | ||
34 | |||
35 | /* --------------------------------------------------- */ | ||
36 | |||
37 | #define NPPI_NOTIFY_PARITY 0x01 | ||
38 | #define NPPI_NOTIFY_FRAMING 0x02 | ||
39 | #define NPPI_NOTIFY_HW_OVERRUN 0x04 | ||
40 | #define NPPI_NOTIFY_SW_OVERRUN 0x08 | ||
41 | #define NPPI_NOTIFY_BREAK 0x10 | ||
42 | |||
43 | #define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */ | ||
44 | #define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */ | ||
45 | #define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */ | ||
46 | #define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */ | ||
47 | |||
48 | /* follow just for Moxa Must chip define. */ | ||
49 | /* */ | ||
50 | /* when LCR register (offset 0x03) write following value, */ | ||
51 | /* the Must chip will enter enchance mode. And write value */ | ||
52 | /* on EFR (offset 0x02) bit 6,7 to change bank. */ | ||
53 | #define MOXA_MUST_ENTER_ENCHANCE 0xBF | ||
54 | |||
55 | /* when enhance mode enable, access on general bank register */ | ||
56 | #define MOXA_MUST_GDL_REGISTER 0x07 | ||
57 | #define MOXA_MUST_GDL_MASK 0x7F | ||
58 | #define MOXA_MUST_GDL_HAS_BAD_DATA 0x80 | ||
59 | |||
60 | #define MOXA_MUST_LSR_RERR 0x80 /* error in receive FIFO */ | ||
61 | /* enchance register bank select and enchance mode setting register */ | ||
62 | /* when LCR register equal to 0xBF */ | ||
63 | #define MOXA_MUST_EFR_REGISTER 0x02 | ||
64 | /* enchance mode enable */ | ||
65 | #define MOXA_MUST_EFR_EFRB_ENABLE 0x10 | ||
66 | /* enchance reister bank set 0, 1, 2 */ | ||
67 | #define MOXA_MUST_EFR_BANK0 0x00 | ||
68 | #define MOXA_MUST_EFR_BANK1 0x40 | ||
69 | #define MOXA_MUST_EFR_BANK2 0x80 | ||
70 | #define MOXA_MUST_EFR_BANK3 0xC0 | ||
71 | #define MOXA_MUST_EFR_BANK_MASK 0xC0 | ||
72 | |||
73 | /* set XON1 value register, when LCR=0xBF and change to bank0 */ | ||
74 | #define MOXA_MUST_XON1_REGISTER 0x04 | ||
75 | |||
76 | /* set XON2 value register, when LCR=0xBF and change to bank0 */ | ||
77 | #define MOXA_MUST_XON2_REGISTER 0x05 | ||
78 | |||
79 | /* set XOFF1 value register, when LCR=0xBF and change to bank0 */ | ||
80 | #define MOXA_MUST_XOFF1_REGISTER 0x06 | ||
81 | |||
82 | /* set XOFF2 value register, when LCR=0xBF and change to bank0 */ | ||
83 | #define MOXA_MUST_XOFF2_REGISTER 0x07 | ||
84 | |||
85 | #define MOXA_MUST_RBRTL_REGISTER 0x04 | ||
86 | #define MOXA_MUST_RBRTH_REGISTER 0x05 | ||
87 | #define MOXA_MUST_RBRTI_REGISTER 0x06 | ||
88 | #define MOXA_MUST_THRTL_REGISTER 0x07 | ||
89 | #define MOXA_MUST_ENUM_REGISTER 0x04 | ||
90 | #define MOXA_MUST_HWID_REGISTER 0x05 | ||
91 | #define MOXA_MUST_ECR_REGISTER 0x06 | ||
92 | #define MOXA_MUST_CSR_REGISTER 0x07 | ||
93 | |||
94 | /* good data mode enable */ | ||
95 | #define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 | ||
96 | /* only good data put into RxFIFO */ | ||
97 | #define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 | ||
98 | |||
99 | /* enable CTS interrupt */ | ||
100 | #define MOXA_MUST_IER_ECTSI 0x80 | ||
101 | /* enable RTS interrupt */ | ||
102 | #define MOXA_MUST_IER_ERTSI 0x40 | ||
103 | /* enable Xon/Xoff interrupt */ | ||
104 | #define MOXA_MUST_IER_XINT 0x20 | ||
105 | /* enable GDA interrupt */ | ||
106 | #define MOXA_MUST_IER_EGDAI 0x10 | ||
107 | |||
108 | #define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI) | ||
109 | |||
110 | /* GDA interrupt pending */ | ||
111 | #define MOXA_MUST_IIR_GDA 0x1C | ||
112 | #define MOXA_MUST_IIR_RDA 0x04 | ||
113 | #define MOXA_MUST_IIR_RTO 0x0C | ||
114 | #define MOXA_MUST_IIR_LSR 0x06 | ||
115 | |||
116 | /* recieved Xon/Xoff or specical interrupt pending */ | ||
117 | #define MOXA_MUST_IIR_XSC 0x10 | ||
118 | |||
119 | /* RTS/CTS change state interrupt pending */ | ||
120 | #define MOXA_MUST_IIR_RTSCTS 0x20 | ||
121 | #define MOXA_MUST_IIR_MASK 0x3E | ||
122 | |||
123 | #define MOXA_MUST_MCR_XON_FLAG 0x40 | ||
124 | #define MOXA_MUST_MCR_XON_ANY 0x80 | ||
125 | #define MOXA_MUST_MCR_TX_XON 0x08 | ||
126 | |||
127 | /* software flow control on chip mask value */ | ||
128 | #define MOXA_MUST_EFR_SF_MASK 0x0F | ||
129 | /* send Xon1/Xoff1 */ | ||
130 | #define MOXA_MUST_EFR_SF_TX1 0x08 | ||
131 | /* send Xon2/Xoff2 */ | ||
132 | #define MOXA_MUST_EFR_SF_TX2 0x04 | ||
133 | /* send Xon1,Xon2/Xoff1,Xoff2 */ | ||
134 | #define MOXA_MUST_EFR_SF_TX12 0x0C | ||
135 | /* don't send Xon/Xoff */ | ||
136 | #define MOXA_MUST_EFR_SF_TX_NO 0x00 | ||
137 | /* Tx software flow control mask */ | ||
138 | #define MOXA_MUST_EFR_SF_TX_MASK 0x0C | ||
139 | /* don't receive Xon/Xoff */ | ||
140 | #define MOXA_MUST_EFR_SF_RX_NO 0x00 | ||
141 | /* receive Xon1/Xoff1 */ | ||
142 | #define MOXA_MUST_EFR_SF_RX1 0x02 | ||
143 | /* receive Xon2/Xoff2 */ | ||
144 | #define MOXA_MUST_EFR_SF_RX2 0x01 | ||
145 | /* receive Xon1,Xon2/Xoff1,Xoff2 */ | ||
146 | #define MOXA_MUST_EFR_SF_RX12 0x03 | ||
147 | /* Rx software flow control mask */ | ||
148 | #define MOXA_MUST_EFR_SF_RX_MASK 0x03 | ||
149 | |||
150 | #endif | ||
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index aa2e5d3eb01a..176f63256b37 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
@@ -1250,8 +1250,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, | |||
1250 | 1250 | ||
1251 | static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) | 1251 | static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) |
1252 | { | 1252 | { |
1253 | struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, | 1253 | struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, gsm->ftype); |
1254 | gsm->ftype|PF); | ||
1255 | if (msg == NULL) | 1254 | if (msg == NULL) |
1256 | return; | 1255 | return; |
1257 | msg->data[0] = (ctrl->cmd << 1) | 2 | EA; /* command */ | 1256 | msg->data[0] = (ctrl->cmd << 1) | 2 | EA; /* command */ |
@@ -2649,13 +2648,13 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout) | |||
2649 | to do here */ | 2648 | to do here */ |
2650 | } | 2649 | } |
2651 | 2650 | ||
2652 | static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp) | 2651 | static int gsmtty_tiocmget(struct tty_struct *tty) |
2653 | { | 2652 | { |
2654 | struct gsm_dlci *dlci = tty->driver_data; | 2653 | struct gsm_dlci *dlci = tty->driver_data; |
2655 | return dlci->modem_rx; | 2654 | return dlci->modem_rx; |
2656 | } | 2655 | } |
2657 | 2656 | ||
2658 | static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp, | 2657 | static int gsmtty_tiocmset(struct tty_struct *tty, |
2659 | unsigned int set, unsigned int clear) | 2658 | unsigned int set, unsigned int clear) |
2660 | { | 2659 | { |
2661 | struct gsm_dlci *dlci = tty->driver_data; | 2660 | struct gsm_dlci *dlci = tty->driver_data; |
@@ -2672,7 +2671,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp, | |||
2672 | } | 2671 | } |
2673 | 2672 | ||
2674 | 2673 | ||
2675 | static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp, | 2674 | static int gsmtty_ioctl(struct tty_struct *tty, |
2676 | unsigned int cmd, unsigned long arg) | 2675 | unsigned int cmd, unsigned long arg) |
2677 | { | 2676 | { |
2678 | return -ENOIOCTLCMD; | 2677 | return -ENOIOCTLCMD; |
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 52fc0c9a6364..cea56033b34c 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c | |||
@@ -97,7 +97,6 @@ | |||
97 | #include <linux/slab.h> | 97 | #include <linux/slab.h> |
98 | #include <linux/tty.h> | 98 | #include <linux/tty.h> |
99 | #include <linux/errno.h> | 99 | #include <linux/errno.h> |
100 | #include <linux/smp_lock.h> | ||
101 | #include <linux/string.h> /* used in new tty drivers */ | 100 | #include <linux/string.h> /* used in new tty drivers */ |
102 | #include <linux/signal.h> /* used in new tty drivers */ | 101 | #include <linux/signal.h> /* used in new tty drivers */ |
103 | #include <linux/if.h> | 102 | #include <linux/if.h> |
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 88dda0c45ee0..5c6c31459a2f 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c | |||
@@ -57,7 +57,6 @@ | |||
57 | #include <linux/ioport.h> | 57 | #include <linux/ioport.h> |
58 | #include <linux/in.h> | 58 | #include <linux/in.h> |
59 | #include <linux/slab.h> | 59 | #include <linux/slab.h> |
60 | #include <linux/smp_lock.h> | ||
61 | #include <linux/tty.h> | 60 | #include <linux/tty.h> |
62 | #include <linux/errno.h> | 61 | #include <linux/errno.h> |
63 | #include <linux/string.h> /* used in new tty drivers */ | 62 | #include <linux/string.h> /* used in new tty drivers */ |
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c new file mode 100644 index 000000000000..f4f11164efe5 --- /dev/null +++ b/drivers/tty/nozomi.c | |||
@@ -0,0 +1,1991 @@ | |||
1 | /* | ||
2 | * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter | ||
3 | * | ||
4 | * Written by: Ulf Jakobsson, | ||
5 | * Jan Ã…kerfeldt, | ||
6 | * Stefan Thomasson, | ||
7 | * | ||
8 | * Maintained by: Paul Hardwick (p.hardwick@option.com) | ||
9 | * | ||
10 | * Patches: | ||
11 | * Locking code changes for Vodafone by Sphere Systems Ltd, | ||
12 | * Andrew Bird (ajb@spheresystems.co.uk ) | ||
13 | * & Phil Sanderson | ||
14 | * | ||
15 | * Source has been ported from an implementation made by Filip Aben @ Option | ||
16 | * | ||
17 | * -------------------------------------------------------------------------- | ||
18 | * | ||
19 | * Copyright (c) 2005,2006 Option Wireless Sweden AB | ||
20 | * Copyright (c) 2006 Sphere Systems Ltd | ||
21 | * Copyright (c) 2006 Option Wireless n/v | ||
22 | * All rights Reserved. | ||
23 | * | ||
24 | * This program is free software; you can redistribute it and/or modify | ||
25 | * it under the terms of the GNU General Public License as published by | ||
26 | * the Free Software Foundation; either version 2 of the License, or | ||
27 | * (at your option) any later version. | ||
28 | * | ||
29 | * This program is distributed in the hope that it will be useful, | ||
30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
32 | * GNU General Public License for more details. | ||
33 | * | ||
34 | * You should have received a copy of the GNU General Public License | ||
35 | * along with this program; if not, write to the Free Software | ||
36 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
37 | * | ||
38 | * -------------------------------------------------------------------------- | ||
39 | */ | ||
40 | |||
41 | /* Enable this to have a lot of debug printouts */ | ||
42 | #define DEBUG | ||
43 | |||
44 | #include <linux/kernel.h> | ||
45 | #include <linux/module.h> | ||
46 | #include <linux/pci.h> | ||
47 | #include <linux/ioport.h> | ||
48 | #include <linux/tty.h> | ||
49 | #include <linux/tty_driver.h> | ||
50 | #include <linux/tty_flip.h> | ||
51 | #include <linux/sched.h> | ||
52 | #include <linux/serial.h> | ||
53 | #include <linux/interrupt.h> | ||
54 | #include <linux/kmod.h> | ||
55 | #include <linux/init.h> | ||
56 | #include <linux/kfifo.h> | ||
57 | #include <linux/uaccess.h> | ||
58 | #include <linux/slab.h> | ||
59 | #include <asm/byteorder.h> | ||
60 | |||
61 | #include <linux/delay.h> | ||
62 | |||
63 | |||
64 | #define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ | ||
65 | __DATE__ " " __TIME__ ")" | ||
66 | |||
67 | /* Macros definitions */ | ||
68 | |||
69 | /* Default debug printout level */ | ||
70 | #define NOZOMI_DEBUG_LEVEL 0x00 | ||
71 | |||
72 | #define P_BUF_SIZE 128 | ||
73 | #define NFO(_err_flag_, args...) \ | ||
74 | do { \ | ||
75 | char tmp[P_BUF_SIZE]; \ | ||
76 | snprintf(tmp, sizeof(tmp), ##args); \ | ||
77 | printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ | ||
78 | __func__, tmp); \ | ||
79 | } while (0) | ||
80 | |||
81 | #define DBG1(args...) D_(0x01, ##args) | ||
82 | #define DBG2(args...) D_(0x02, ##args) | ||
83 | #define DBG3(args...) D_(0x04, ##args) | ||
84 | #define DBG4(args...) D_(0x08, ##args) | ||
85 | #define DBG5(args...) D_(0x10, ##args) | ||
86 | #define DBG6(args...) D_(0x20, ##args) | ||
87 | #define DBG7(args...) D_(0x40, ##args) | ||
88 | #define DBG8(args...) D_(0x80, ##args) | ||
89 | |||
90 | #ifdef DEBUG | ||
91 | /* Do we need this settable at runtime? */ | ||
92 | static int debug = NOZOMI_DEBUG_LEVEL; | ||
93 | |||
94 | #define D(lvl, args...) do \ | ||
95 | {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ | ||
96 | while (0) | ||
97 | #define D_(lvl, args...) D(lvl, ##args) | ||
98 | |||
99 | /* These printouts are always printed */ | ||
100 | |||
101 | #else | ||
102 | static int debug; | ||
103 | #define D_(lvl, args...) | ||
104 | #endif | ||
105 | |||
106 | /* TODO: rewrite to optimize macros... */ | ||
107 | |||
108 | #define TMP_BUF_MAX 256 | ||
109 | |||
110 | #define DUMP(buf__,len__) \ | ||
111 | do { \ | ||
112 | char tbuf[TMP_BUF_MAX] = {0};\ | ||
113 | if (len__ > 1) {\ | ||
114 | snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ | ||
115 | if (tbuf[len__-2] == '\r') {\ | ||
116 | tbuf[len__-2] = 'r';\ | ||
117 | } \ | ||
118 | DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ | ||
119 | } else {\ | ||
120 | DBG1("SENDING: '%s' (%d)", tbuf, len__);\ | ||
121 | } \ | ||
122 | } while (0) | ||
123 | |||
124 | /* Defines */ | ||
125 | #define NOZOMI_NAME "nozomi" | ||
126 | #define NOZOMI_NAME_TTY "nozomi_tty" | ||
127 | #define DRIVER_DESC "Nozomi driver" | ||
128 | |||
129 | #define NTTY_TTY_MAXMINORS 256 | ||
130 | #define NTTY_FIFO_BUFFER_SIZE 8192 | ||
131 | |||
132 | /* Must be power of 2 */ | ||
133 | #define FIFO_BUFFER_SIZE_UL 8192 | ||
134 | |||
135 | /* Size of tmp send buffer to card */ | ||
136 | #define SEND_BUF_MAX 1024 | ||
137 | #define RECEIVE_BUF_MAX 4 | ||
138 | |||
139 | |||
140 | #define R_IIR 0x0000 /* Interrupt Identity Register */ | ||
141 | #define R_FCR 0x0000 /* Flow Control Register */ | ||
142 | #define R_IER 0x0004 /* Interrupt Enable Register */ | ||
143 | |||
144 | #define CONFIG_MAGIC 0xEFEFFEFE | ||
145 | #define TOGGLE_VALID 0x0000 | ||
146 | |||
147 | /* Definition of interrupt tokens */ | ||
148 | #define MDM_DL1 0x0001 | ||
149 | #define MDM_UL1 0x0002 | ||
150 | #define MDM_DL2 0x0004 | ||
151 | #define MDM_UL2 0x0008 | ||
152 | #define DIAG_DL1 0x0010 | ||
153 | #define DIAG_DL2 0x0020 | ||
154 | #define DIAG_UL 0x0040 | ||
155 | #define APP1_DL 0x0080 | ||
156 | #define APP1_UL 0x0100 | ||
157 | #define APP2_DL 0x0200 | ||
158 | #define APP2_UL 0x0400 | ||
159 | #define CTRL_DL 0x0800 | ||
160 | #define CTRL_UL 0x1000 | ||
161 | #define RESET 0x8000 | ||
162 | |||
163 | #define MDM_DL (MDM_DL1 | MDM_DL2) | ||
164 | #define MDM_UL (MDM_UL1 | MDM_UL2) | ||
165 | #define DIAG_DL (DIAG_DL1 | DIAG_DL2) | ||
166 | |||
167 | /* modem signal definition */ | ||
168 | #define CTRL_DSR 0x0001 | ||
169 | #define CTRL_DCD 0x0002 | ||
170 | #define CTRL_RI 0x0004 | ||
171 | #define CTRL_CTS 0x0008 | ||
172 | |||
173 | #define CTRL_DTR 0x0001 | ||
174 | #define CTRL_RTS 0x0002 | ||
175 | |||
176 | #define MAX_PORT 4 | ||
177 | #define NOZOMI_MAX_PORTS 5 | ||
178 | #define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) | ||
179 | |||
180 | /* Type definitions */ | ||
181 | |||
182 | /* | ||
183 | * There are two types of nozomi cards, | ||
184 | * one with 2048 memory and with 8192 memory | ||
185 | */ | ||
186 | enum card_type { | ||
187 | F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ | ||
188 | F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ | ||
189 | }; | ||
190 | |||
191 | /* Initialization states a card can be in */ | ||
192 | enum card_state { | ||
193 | NOZOMI_STATE_UKNOWN = 0, | ||
194 | NOZOMI_STATE_ENABLED = 1, /* pci device enabled */ | ||
195 | NOZOMI_STATE_ALLOCATED = 2, /* config setup done */ | ||
196 | NOZOMI_STATE_READY = 3, /* flowcontrols received */ | ||
197 | }; | ||
198 | |||
199 | /* Two different toggle channels exist */ | ||
200 | enum channel_type { | ||
201 | CH_A = 0, | ||
202 | CH_B = 1, | ||
203 | }; | ||
204 | |||
205 | /* Port definition for the card regarding flow control */ | ||
206 | enum ctrl_port_type { | ||
207 | CTRL_CMD = 0, | ||
208 | CTRL_MDM = 1, | ||
209 | CTRL_DIAG = 2, | ||
210 | CTRL_APP1 = 3, | ||
211 | CTRL_APP2 = 4, | ||
212 | CTRL_ERROR = -1, | ||
213 | }; | ||
214 | |||
215 | /* Ports that the nozomi has */ | ||
216 | enum port_type { | ||
217 | PORT_MDM = 0, | ||
218 | PORT_DIAG = 1, | ||
219 | PORT_APP1 = 2, | ||
220 | PORT_APP2 = 3, | ||
221 | PORT_CTRL = 4, | ||
222 | PORT_ERROR = -1, | ||
223 | }; | ||
224 | |||
225 | #ifdef __BIG_ENDIAN | ||
226 | /* Big endian */ | ||
227 | |||
228 | struct toggles { | ||
229 | unsigned int enabled:5; /* | ||
230 | * Toggle fields are valid if enabled is 0, | ||
231 | * else A-channels must always be used. | ||
232 | */ | ||
233 | unsigned int diag_dl:1; | ||
234 | unsigned int mdm_dl:1; | ||
235 | unsigned int mdm_ul:1; | ||
236 | } __attribute__ ((packed)); | ||
237 | |||
238 | /* Configuration table to read at startup of card */ | ||
239 | /* Is for now only needed during initialization phase */ | ||
240 | struct config_table { | ||
241 | u32 signature; | ||
242 | u16 product_information; | ||
243 | u16 version; | ||
244 | u8 pad3[3]; | ||
245 | struct toggles toggle; | ||
246 | u8 pad1[4]; | ||
247 | u16 dl_mdm_len1; /* | ||
248 | * If this is 64, it can hold | ||
249 | * 60 bytes + 4 that is length field | ||
250 | */ | ||
251 | u16 dl_start; | ||
252 | |||
253 | u16 dl_diag_len1; | ||
254 | u16 dl_mdm_len2; /* | ||
255 | * If this is 64, it can hold | ||
256 | * 60 bytes + 4 that is length field | ||
257 | */ | ||
258 | u16 dl_app1_len; | ||
259 | |||
260 | u16 dl_diag_len2; | ||
261 | u16 dl_ctrl_len; | ||
262 | u16 dl_app2_len; | ||
263 | u8 pad2[16]; | ||
264 | u16 ul_mdm_len1; | ||
265 | u16 ul_start; | ||
266 | u16 ul_diag_len; | ||
267 | u16 ul_mdm_len2; | ||
268 | u16 ul_app1_len; | ||
269 | u16 ul_app2_len; | ||
270 | u16 ul_ctrl_len; | ||
271 | } __attribute__ ((packed)); | ||
272 | |||
273 | /* This stores all control downlink flags */ | ||
274 | struct ctrl_dl { | ||
275 | u8 port; | ||
276 | unsigned int reserved:4; | ||
277 | unsigned int CTS:1; | ||
278 | unsigned int RI:1; | ||
279 | unsigned int DCD:1; | ||
280 | unsigned int DSR:1; | ||
281 | } __attribute__ ((packed)); | ||
282 | |||
283 | /* This stores all control uplink flags */ | ||
284 | struct ctrl_ul { | ||
285 | u8 port; | ||
286 | unsigned int reserved:6; | ||
287 | unsigned int RTS:1; | ||
288 | unsigned int DTR:1; | ||
289 | } __attribute__ ((packed)); | ||
290 | |||
291 | #else | ||
292 | /* Little endian */ | ||
293 | |||
294 | /* This represents the toggle information */ | ||
295 | struct toggles { | ||
296 | unsigned int mdm_ul:1; | ||
297 | unsigned int mdm_dl:1; | ||
298 | unsigned int diag_dl:1; | ||
299 | unsigned int enabled:5; /* | ||
300 | * Toggle fields are valid if enabled is 0, | ||
301 | * else A-channels must always be used. | ||
302 | */ | ||
303 | } __attribute__ ((packed)); | ||
304 | |||
305 | /* Configuration table to read at startup of card */ | ||
306 | struct config_table { | ||
307 | u32 signature; | ||
308 | u16 version; | ||
309 | u16 product_information; | ||
310 | struct toggles toggle; | ||
311 | u8 pad1[7]; | ||
312 | u16 dl_start; | ||
313 | u16 dl_mdm_len1; /* | ||
314 | * If this is 64, it can hold | ||
315 | * 60 bytes + 4 that is length field | ||
316 | */ | ||
317 | u16 dl_mdm_len2; | ||
318 | u16 dl_diag_len1; | ||
319 | u16 dl_diag_len2; | ||
320 | u16 dl_app1_len; | ||
321 | u16 dl_app2_len; | ||
322 | u16 dl_ctrl_len; | ||
323 | u8 pad2[16]; | ||
324 | u16 ul_start; | ||
325 | u16 ul_mdm_len2; | ||
326 | u16 ul_mdm_len1; | ||
327 | u16 ul_diag_len; | ||
328 | u16 ul_app1_len; | ||
329 | u16 ul_app2_len; | ||
330 | u16 ul_ctrl_len; | ||
331 | } __attribute__ ((packed)); | ||
332 | |||
333 | /* This stores all control downlink flags */ | ||
334 | struct ctrl_dl { | ||
335 | unsigned int DSR:1; | ||
336 | unsigned int DCD:1; | ||
337 | unsigned int RI:1; | ||
338 | unsigned int CTS:1; | ||
339 | unsigned int reserverd:4; | ||
340 | u8 port; | ||
341 | } __attribute__ ((packed)); | ||
342 | |||
343 | /* This stores all control uplink flags */ | ||
344 | struct ctrl_ul { | ||
345 | unsigned int DTR:1; | ||
346 | unsigned int RTS:1; | ||
347 | unsigned int reserved:6; | ||
348 | u8 port; | ||
349 | } __attribute__ ((packed)); | ||
350 | #endif | ||
351 | |||
352 | /* This holds all information that is needed regarding a port */ | ||
353 | struct port { | ||
354 | struct tty_port port; | ||
355 | u8 update_flow_control; | ||
356 | struct ctrl_ul ctrl_ul; | ||
357 | struct ctrl_dl ctrl_dl; | ||
358 | struct kfifo fifo_ul; | ||
359 | void __iomem *dl_addr[2]; | ||
360 | u32 dl_size[2]; | ||
361 | u8 toggle_dl; | ||
362 | void __iomem *ul_addr[2]; | ||
363 | u32 ul_size[2]; | ||
364 | u8 toggle_ul; | ||
365 | u16 token_dl; | ||
366 | |||
367 | /* mutex to ensure one access patch to this port */ | ||
368 | struct mutex tty_sem; | ||
369 | wait_queue_head_t tty_wait; | ||
370 | struct async_icount tty_icount; | ||
371 | |||
372 | struct nozomi *dc; | ||
373 | }; | ||
374 | |||
375 | /* Private data one for each card in the system */ | ||
376 | struct nozomi { | ||
377 | void __iomem *base_addr; | ||
378 | unsigned long flip; | ||
379 | |||
380 | /* Pointers to registers */ | ||
381 | void __iomem *reg_iir; | ||
382 | void __iomem *reg_fcr; | ||
383 | void __iomem *reg_ier; | ||
384 | |||
385 | u16 last_ier; | ||
386 | enum card_type card_type; | ||
387 | struct config_table config_table; /* Configuration table */ | ||
388 | struct pci_dev *pdev; | ||
389 | struct port port[NOZOMI_MAX_PORTS]; | ||
390 | u8 *send_buf; | ||
391 | |||
392 | spinlock_t spin_mutex; /* secures access to registers and tty */ | ||
393 | |||
394 | unsigned int index_start; | ||
395 | enum card_state state; | ||
396 | u32 open_ttys; | ||
397 | }; | ||
398 | |||
399 | /* This is a data packet that is read or written to/from card */ | ||
400 | struct buffer { | ||
401 | u32 size; /* size is the length of the data buffer */ | ||
402 | u8 *data; | ||
403 | } __attribute__ ((packed)); | ||
404 | |||
405 | /* Global variables */ | ||
406 | static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { | ||
407 | {PCI_DEVICE(0x1931, 0x000c)}, /* Nozomi HSDPA */ | ||
408 | {}, | ||
409 | }; | ||
410 | |||
411 | MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); | ||
412 | |||
413 | static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; | ||
414 | static struct tty_driver *ntty_driver; | ||
415 | |||
416 | static const struct tty_port_operations noz_tty_port_ops; | ||
417 | |||
418 | /* | ||
419 | * find card by tty_index | ||
420 | */ | ||
421 | static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) | ||
422 | { | ||
423 | return tty ? ndevs[tty->index / MAX_PORT] : NULL; | ||
424 | } | ||
425 | |||
426 | static inline struct port *get_port_by_tty(const struct tty_struct *tty) | ||
427 | { | ||
428 | struct nozomi *ndev = get_dc_by_tty(tty); | ||
429 | return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * TODO: | ||
434 | * -Optimize | ||
435 | * -Rewrite cleaner | ||
436 | */ | ||
437 | |||
438 | static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, | ||
439 | u32 size_bytes) | ||
440 | { | ||
441 | u32 i = 0; | ||
442 | const u32 __iomem *ptr = mem_addr_start; | ||
443 | u16 *buf16; | ||
444 | |||
445 | if (unlikely(!ptr || !buf)) | ||
446 | goto out; | ||
447 | |||
448 | /* shortcut for extremely often used cases */ | ||
449 | switch (size_bytes) { | ||
450 | case 2: /* 2 bytes */ | ||
451 | buf16 = (u16 *) buf; | ||
452 | *buf16 = __le16_to_cpu(readw(ptr)); | ||
453 | goto out; | ||
454 | break; | ||
455 | case 4: /* 4 bytes */ | ||
456 | *(buf) = __le32_to_cpu(readl(ptr)); | ||
457 | goto out; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | while (i < size_bytes) { | ||
462 | if (size_bytes - i == 2) { | ||
463 | /* Handle 2 bytes in the end */ | ||
464 | buf16 = (u16 *) buf; | ||
465 | *(buf16) = __le16_to_cpu(readw(ptr)); | ||
466 | i += 2; | ||
467 | } else { | ||
468 | /* Read 4 bytes */ | ||
469 | *(buf) = __le32_to_cpu(readl(ptr)); | ||
470 | i += 4; | ||
471 | } | ||
472 | buf++; | ||
473 | ptr++; | ||
474 | } | ||
475 | out: | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | /* | ||
480 | * TODO: | ||
481 | * -Optimize | ||
482 | * -Rewrite cleaner | ||
483 | */ | ||
484 | static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, | ||
485 | u32 size_bytes) | ||
486 | { | ||
487 | u32 i = 0; | ||
488 | u32 __iomem *ptr = mem_addr_start; | ||
489 | const u16 *buf16; | ||
490 | |||
491 | if (unlikely(!ptr || !buf)) | ||
492 | return 0; | ||
493 | |||
494 | /* shortcut for extremely often used cases */ | ||
495 | switch (size_bytes) { | ||
496 | case 2: /* 2 bytes */ | ||
497 | buf16 = (const u16 *)buf; | ||
498 | writew(__cpu_to_le16(*buf16), ptr); | ||
499 | return 2; | ||
500 | break; | ||
501 | case 1: /* | ||
502 | * also needs to write 4 bytes in this case | ||
503 | * so falling through.. | ||
504 | */ | ||
505 | case 4: /* 4 bytes */ | ||
506 | writel(__cpu_to_le32(*buf), ptr); | ||
507 | return 4; | ||
508 | break; | ||
509 | } | ||
510 | |||
511 | while (i < size_bytes) { | ||
512 | if (size_bytes - i == 2) { | ||
513 | /* 2 bytes */ | ||
514 | buf16 = (const u16 *)buf; | ||
515 | writew(__cpu_to_le16(*buf16), ptr); | ||
516 | i += 2; | ||
517 | } else { | ||
518 | /* 4 bytes */ | ||
519 | writel(__cpu_to_le32(*buf), ptr); | ||
520 | i += 4; | ||
521 | } | ||
522 | buf++; | ||
523 | ptr++; | ||
524 | } | ||
525 | return i; | ||
526 | } | ||
527 | |||
528 | /* Setup pointers to different channels and also setup buffer sizes. */ | ||
529 | static void setup_memory(struct nozomi *dc) | ||
530 | { | ||
531 | void __iomem *offset = dc->base_addr + dc->config_table.dl_start; | ||
532 | /* The length reported is including the length field of 4 bytes, | ||
533 | * hence subtract with 4. | ||
534 | */ | ||
535 | const u16 buff_offset = 4; | ||
536 | |||
537 | /* Modem port dl configuration */ | ||
538 | dc->port[PORT_MDM].dl_addr[CH_A] = offset; | ||
539 | dc->port[PORT_MDM].dl_addr[CH_B] = | ||
540 | (offset += dc->config_table.dl_mdm_len1); | ||
541 | dc->port[PORT_MDM].dl_size[CH_A] = | ||
542 | dc->config_table.dl_mdm_len1 - buff_offset; | ||
543 | dc->port[PORT_MDM].dl_size[CH_B] = | ||
544 | dc->config_table.dl_mdm_len2 - buff_offset; | ||
545 | |||
546 | /* Diag port dl configuration */ | ||
547 | dc->port[PORT_DIAG].dl_addr[CH_A] = | ||
548 | (offset += dc->config_table.dl_mdm_len2); | ||
549 | dc->port[PORT_DIAG].dl_size[CH_A] = | ||
550 | dc->config_table.dl_diag_len1 - buff_offset; | ||
551 | dc->port[PORT_DIAG].dl_addr[CH_B] = | ||
552 | (offset += dc->config_table.dl_diag_len1); | ||
553 | dc->port[PORT_DIAG].dl_size[CH_B] = | ||
554 | dc->config_table.dl_diag_len2 - buff_offset; | ||
555 | |||
556 | /* App1 port dl configuration */ | ||
557 | dc->port[PORT_APP1].dl_addr[CH_A] = | ||
558 | (offset += dc->config_table.dl_diag_len2); | ||
559 | dc->port[PORT_APP1].dl_size[CH_A] = | ||
560 | dc->config_table.dl_app1_len - buff_offset; | ||
561 | |||
562 | /* App2 port dl configuration */ | ||
563 | dc->port[PORT_APP2].dl_addr[CH_A] = | ||
564 | (offset += dc->config_table.dl_app1_len); | ||
565 | dc->port[PORT_APP2].dl_size[CH_A] = | ||
566 | dc->config_table.dl_app2_len - buff_offset; | ||
567 | |||
568 | /* Ctrl dl configuration */ | ||
569 | dc->port[PORT_CTRL].dl_addr[CH_A] = | ||
570 | (offset += dc->config_table.dl_app2_len); | ||
571 | dc->port[PORT_CTRL].dl_size[CH_A] = | ||
572 | dc->config_table.dl_ctrl_len - buff_offset; | ||
573 | |||
574 | offset = dc->base_addr + dc->config_table.ul_start; | ||
575 | |||
576 | /* Modem Port ul configuration */ | ||
577 | dc->port[PORT_MDM].ul_addr[CH_A] = offset; | ||
578 | dc->port[PORT_MDM].ul_size[CH_A] = | ||
579 | dc->config_table.ul_mdm_len1 - buff_offset; | ||
580 | dc->port[PORT_MDM].ul_addr[CH_B] = | ||
581 | (offset += dc->config_table.ul_mdm_len1); | ||
582 | dc->port[PORT_MDM].ul_size[CH_B] = | ||
583 | dc->config_table.ul_mdm_len2 - buff_offset; | ||
584 | |||
585 | /* Diag port ul configuration */ | ||
586 | dc->port[PORT_DIAG].ul_addr[CH_A] = | ||
587 | (offset += dc->config_table.ul_mdm_len2); | ||
588 | dc->port[PORT_DIAG].ul_size[CH_A] = | ||
589 | dc->config_table.ul_diag_len - buff_offset; | ||
590 | |||
591 | /* App1 port ul configuration */ | ||
592 | dc->port[PORT_APP1].ul_addr[CH_A] = | ||
593 | (offset += dc->config_table.ul_diag_len); | ||
594 | dc->port[PORT_APP1].ul_size[CH_A] = | ||
595 | dc->config_table.ul_app1_len - buff_offset; | ||
596 | |||
597 | /* App2 port ul configuration */ | ||
598 | dc->port[PORT_APP2].ul_addr[CH_A] = | ||
599 | (offset += dc->config_table.ul_app1_len); | ||
600 | dc->port[PORT_APP2].ul_size[CH_A] = | ||
601 | dc->config_table.ul_app2_len - buff_offset; | ||
602 | |||
603 | /* Ctrl ul configuration */ | ||
604 | dc->port[PORT_CTRL].ul_addr[CH_A] = | ||
605 | (offset += dc->config_table.ul_app2_len); | ||
606 | dc->port[PORT_CTRL].ul_size[CH_A] = | ||
607 | dc->config_table.ul_ctrl_len - buff_offset; | ||
608 | } | ||
609 | |||
610 | /* Dump config table under initalization phase */ | ||
611 | #ifdef DEBUG | ||
612 | static void dump_table(const struct nozomi *dc) | ||
613 | { | ||
614 | DBG3("signature: 0x%08X", dc->config_table.signature); | ||
615 | DBG3("version: 0x%04X", dc->config_table.version); | ||
616 | DBG3("product_information: 0x%04X", \ | ||
617 | dc->config_table.product_information); | ||
618 | DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); | ||
619 | DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); | ||
620 | DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); | ||
621 | DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); | ||
622 | |||
623 | DBG3("dl_start: 0x%04X", dc->config_table.dl_start); | ||
624 | DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, | ||
625 | dc->config_table.dl_mdm_len1); | ||
626 | DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, | ||
627 | dc->config_table.dl_mdm_len2); | ||
628 | DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, | ||
629 | dc->config_table.dl_diag_len1); | ||
630 | DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, | ||
631 | dc->config_table.dl_diag_len2); | ||
632 | DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, | ||
633 | dc->config_table.dl_app1_len); | ||
634 | DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, | ||
635 | dc->config_table.dl_app2_len); | ||
636 | DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, | ||
637 | dc->config_table.dl_ctrl_len); | ||
638 | DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, | ||
639 | dc->config_table.ul_start); | ||
640 | DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, | ||
641 | dc->config_table.ul_mdm_len1); | ||
642 | DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, | ||
643 | dc->config_table.ul_mdm_len2); | ||
644 | DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, | ||
645 | dc->config_table.ul_diag_len); | ||
646 | DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, | ||
647 | dc->config_table.ul_app1_len); | ||
648 | DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, | ||
649 | dc->config_table.ul_app2_len); | ||
650 | DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, | ||
651 | dc->config_table.ul_ctrl_len); | ||
652 | } | ||
653 | #else | ||
654 | static inline void dump_table(const struct nozomi *dc) { } | ||
655 | #endif | ||
656 | |||
657 | /* | ||
658 | * Read configuration table from card under intalization phase | ||
659 | * Returns 1 if ok, else 0 | ||
660 | */ | ||
661 | static int nozomi_read_config_table(struct nozomi *dc) | ||
662 | { | ||
663 | read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, | ||
664 | sizeof(struct config_table)); | ||
665 | |||
666 | if (dc->config_table.signature != CONFIG_MAGIC) { | ||
667 | dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", | ||
668 | dc->config_table.signature, CONFIG_MAGIC); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | if ((dc->config_table.version == 0) | ||
673 | || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { | ||
674 | int i; | ||
675 | DBG1("Second phase, configuring card"); | ||
676 | |||
677 | setup_memory(dc); | ||
678 | |||
679 | dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; | ||
680 | dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; | ||
681 | dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; | ||
682 | DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", | ||
683 | dc->port[PORT_MDM].toggle_ul, | ||
684 | dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); | ||
685 | |||
686 | dump_table(dc); | ||
687 | |||
688 | for (i = PORT_MDM; i < MAX_PORT; i++) { | ||
689 | memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); | ||
690 | memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); | ||
691 | } | ||
692 | |||
693 | /* Enable control channel */ | ||
694 | dc->last_ier = dc->last_ier | CTRL_DL; | ||
695 | writew(dc->last_ier, dc->reg_ier); | ||
696 | |||
697 | dc->state = NOZOMI_STATE_ALLOCATED; | ||
698 | dev_info(&dc->pdev->dev, "Initialization OK!\n"); | ||
699 | return 1; | ||
700 | } | ||
701 | |||
702 | if ((dc->config_table.version > 0) | ||
703 | && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { | ||
704 | u32 offset = 0; | ||
705 | DBG1("First phase: pushing upload buffers, clearing download"); | ||
706 | |||
707 | dev_info(&dc->pdev->dev, "Version of card: %d\n", | ||
708 | dc->config_table.version); | ||
709 | |||
710 | /* Here we should disable all I/O over F32. */ | ||
711 | setup_memory(dc); | ||
712 | |||
713 | /* | ||
714 | * We should send ALL channel pair tokens back along | ||
715 | * with reset token | ||
716 | */ | ||
717 | |||
718 | /* push upload modem buffers */ | ||
719 | write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], | ||
720 | (u32 *) &offset, 4); | ||
721 | write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], | ||
722 | (u32 *) &offset, 4); | ||
723 | |||
724 | writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); | ||
725 | |||
726 | DBG1("First phase done"); | ||
727 | } | ||
728 | |||
729 | return 1; | ||
730 | } | ||
731 | |||
732 | /* Enable uplink interrupts */ | ||
733 | static void enable_transmit_ul(enum port_type port, struct nozomi *dc) | ||
734 | { | ||
735 | static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; | ||
736 | |||
737 | if (port < NOZOMI_MAX_PORTS) { | ||
738 | dc->last_ier |= mask[port]; | ||
739 | writew(dc->last_ier, dc->reg_ier); | ||
740 | } else { | ||
741 | dev_err(&dc->pdev->dev, "Called with wrong port?\n"); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | /* Disable uplink interrupts */ | ||
746 | static void disable_transmit_ul(enum port_type port, struct nozomi *dc) | ||
747 | { | ||
748 | static const u16 mask[] = | ||
749 | {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; | ||
750 | |||
751 | if (port < NOZOMI_MAX_PORTS) { | ||
752 | dc->last_ier &= mask[port]; | ||
753 | writew(dc->last_ier, dc->reg_ier); | ||
754 | } else { | ||
755 | dev_err(&dc->pdev->dev, "Called with wrong port?\n"); | ||
756 | } | ||
757 | } | ||
758 | |||
759 | /* Enable downlink interrupts */ | ||
760 | static void enable_transmit_dl(enum port_type port, struct nozomi *dc) | ||
761 | { | ||
762 | static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; | ||
763 | |||
764 | if (port < NOZOMI_MAX_PORTS) { | ||
765 | dc->last_ier |= mask[port]; | ||
766 | writew(dc->last_ier, dc->reg_ier); | ||
767 | } else { | ||
768 | dev_err(&dc->pdev->dev, "Called with wrong port?\n"); | ||
769 | } | ||
770 | } | ||
771 | |||
772 | /* Disable downlink interrupts */ | ||
773 | static void disable_transmit_dl(enum port_type port, struct nozomi *dc) | ||
774 | { | ||
775 | static const u16 mask[] = | ||
776 | {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; | ||
777 | |||
778 | if (port < NOZOMI_MAX_PORTS) { | ||
779 | dc->last_ier &= mask[port]; | ||
780 | writew(dc->last_ier, dc->reg_ier); | ||
781 | } else { | ||
782 | dev_err(&dc->pdev->dev, "Called with wrong port?\n"); | ||
783 | } | ||
784 | } | ||
785 | |||
786 | /* | ||
787 | * Return 1 - send buffer to card and ack. | ||
788 | * Return 0 - don't ack, don't send buffer to card. | ||
789 | */ | ||
790 | static int send_data(enum port_type index, struct nozomi *dc) | ||
791 | { | ||
792 | u32 size = 0; | ||
793 | struct port *port = &dc->port[index]; | ||
794 | const u8 toggle = port->toggle_ul; | ||
795 | void __iomem *addr = port->ul_addr[toggle]; | ||
796 | const u32 ul_size = port->ul_size[toggle]; | ||
797 | struct tty_struct *tty = tty_port_tty_get(&port->port); | ||
798 | |||
799 | /* Get data from tty and place in buf for now */ | ||
800 | size = kfifo_out(&port->fifo_ul, dc->send_buf, | ||
801 | ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); | ||
802 | |||
803 | if (size == 0) { | ||
804 | DBG4("No more data to send, disable link:"); | ||
805 | tty_kref_put(tty); | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | /* DUMP(buf, size); */ | ||
810 | |||
811 | /* Write length + data */ | ||
812 | write_mem32(addr, (u32 *) &size, 4); | ||
813 | write_mem32(addr + 4, (u32 *) dc->send_buf, size); | ||
814 | |||
815 | if (tty) | ||
816 | tty_wakeup(tty); | ||
817 | |||
818 | tty_kref_put(tty); | ||
819 | return 1; | ||
820 | } | ||
821 | |||
822 | /* If all data has been read, return 1, else 0 */ | ||
823 | static int receive_data(enum port_type index, struct nozomi *dc) | ||
824 | { | ||
825 | u8 buf[RECEIVE_BUF_MAX] = { 0 }; | ||
826 | int size; | ||
827 | u32 offset = 4; | ||
828 | struct port *port = &dc->port[index]; | ||
829 | void __iomem *addr = port->dl_addr[port->toggle_dl]; | ||
830 | struct tty_struct *tty = tty_port_tty_get(&port->port); | ||
831 | int i, ret; | ||
832 | |||
833 | if (unlikely(!tty)) { | ||
834 | DBG1("tty not open for port: %d?", index); | ||
835 | return 1; | ||
836 | } | ||
837 | |||
838 | read_mem32((u32 *) &size, addr, 4); | ||
839 | /* DBG1( "%d bytes port: %d", size, index); */ | ||
840 | |||
841 | if (test_bit(TTY_THROTTLED, &tty->flags)) { | ||
842 | DBG1("No room in tty, don't read data, don't ack interrupt, " | ||
843 | "disable interrupt"); | ||
844 | |||
845 | /* disable interrupt in downlink... */ | ||
846 | disable_transmit_dl(index, dc); | ||
847 | ret = 0; | ||
848 | goto put; | ||
849 | } | ||
850 | |||
851 | if (unlikely(size == 0)) { | ||
852 | dev_err(&dc->pdev->dev, "size == 0?\n"); | ||
853 | ret = 1; | ||
854 | goto put; | ||
855 | } | ||
856 | |||
857 | while (size > 0) { | ||
858 | read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); | ||
859 | |||
860 | if (size == 1) { | ||
861 | tty_insert_flip_char(tty, buf[0], TTY_NORMAL); | ||
862 | size = 0; | ||
863 | } else if (size < RECEIVE_BUF_MAX) { | ||
864 | size -= tty_insert_flip_string(tty, (char *) buf, size); | ||
865 | } else { | ||
866 | i = tty_insert_flip_string(tty, \ | ||
867 | (char *) buf, RECEIVE_BUF_MAX); | ||
868 | size -= i; | ||
869 | offset += i; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | set_bit(index, &dc->flip); | ||
874 | ret = 1; | ||
875 | put: | ||
876 | tty_kref_put(tty); | ||
877 | return ret; | ||
878 | } | ||
879 | |||
880 | /* Debug for interrupts */ | ||
881 | #ifdef DEBUG | ||
882 | static char *interrupt2str(u16 interrupt) | ||
883 | { | ||
884 | static char buf[TMP_BUF_MAX]; | ||
885 | char *p = buf; | ||
886 | |||
887 | interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; | ||
888 | interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
889 | "MDM_DL2 ") : NULL; | ||
890 | |||
891 | interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
892 | "MDM_UL1 ") : NULL; | ||
893 | interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
894 | "MDM_UL2 ") : NULL; | ||
895 | |||
896 | interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
897 | "DIAG_DL1 ") : NULL; | ||
898 | interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
899 | "DIAG_DL2 ") : NULL; | ||
900 | |||
901 | interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
902 | "DIAG_UL ") : NULL; | ||
903 | |||
904 | interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
905 | "APP1_DL ") : NULL; | ||
906 | interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
907 | "APP2_DL ") : NULL; | ||
908 | |||
909 | interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
910 | "APP1_UL ") : NULL; | ||
911 | interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
912 | "APP2_UL ") : NULL; | ||
913 | |||
914 | interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
915 | "CTRL_DL ") : NULL; | ||
916 | interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
917 | "CTRL_UL ") : NULL; | ||
918 | |||
919 | interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), | ||
920 | "RESET ") : NULL; | ||
921 | |||
922 | return buf; | ||
923 | } | ||
924 | #endif | ||
925 | |||
926 | /* | ||
927 | * Receive flow control | ||
928 | * Return 1 - If ok, else 0 | ||
929 | */ | ||
930 | static int receive_flow_control(struct nozomi *dc) | ||
931 | { | ||
932 | enum port_type port = PORT_MDM; | ||
933 | struct ctrl_dl ctrl_dl; | ||
934 | struct ctrl_dl old_ctrl; | ||
935 | u16 enable_ier = 0; | ||
936 | |||
937 | read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); | ||
938 | |||
939 | switch (ctrl_dl.port) { | ||
940 | case CTRL_CMD: | ||
941 | DBG1("The Base Band sends this value as a response to a " | ||
942 | "request for IMSI detach sent over the control " | ||
943 | "channel uplink (see section 7.6.1)."); | ||
944 | break; | ||
945 | case CTRL_MDM: | ||
946 | port = PORT_MDM; | ||
947 | enable_ier = MDM_DL; | ||
948 | break; | ||
949 | case CTRL_DIAG: | ||
950 | port = PORT_DIAG; | ||
951 | enable_ier = DIAG_DL; | ||
952 | break; | ||
953 | case CTRL_APP1: | ||
954 | port = PORT_APP1; | ||
955 | enable_ier = APP1_DL; | ||
956 | break; | ||
957 | case CTRL_APP2: | ||
958 | port = PORT_APP2; | ||
959 | enable_ier = APP2_DL; | ||
960 | if (dc->state == NOZOMI_STATE_ALLOCATED) { | ||
961 | /* | ||
962 | * After card initialization the flow control | ||
963 | * received for APP2 is always the last | ||
964 | */ | ||
965 | dc->state = NOZOMI_STATE_READY; | ||
966 | dev_info(&dc->pdev->dev, "Device READY!\n"); | ||
967 | } | ||
968 | break; | ||
969 | default: | ||
970 | dev_err(&dc->pdev->dev, | ||
971 | "ERROR: flow control received for non-existing port\n"); | ||
972 | return 0; | ||
973 | }; | ||
974 | |||
975 | DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), | ||
976 | *((u16 *)&ctrl_dl)); | ||
977 | |||
978 | old_ctrl = dc->port[port].ctrl_dl; | ||
979 | dc->port[port].ctrl_dl = ctrl_dl; | ||
980 | |||
981 | if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { | ||
982 | DBG1("Disable interrupt (0x%04X) on port: %d", | ||
983 | enable_ier, port); | ||
984 | disable_transmit_ul(port, dc); | ||
985 | |||
986 | } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { | ||
987 | |||
988 | if (kfifo_len(&dc->port[port].fifo_ul)) { | ||
989 | DBG1("Enable interrupt (0x%04X) on port: %d", | ||
990 | enable_ier, port); | ||
991 | DBG1("Data in buffer [%d], enable transmit! ", | ||
992 | kfifo_len(&dc->port[port].fifo_ul)); | ||
993 | enable_transmit_ul(port, dc); | ||
994 | } else { | ||
995 | DBG1("No data in buffer..."); | ||
996 | } | ||
997 | } | ||
998 | |||
999 | if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { | ||
1000 | DBG1(" No change in mctrl"); | ||
1001 | return 1; | ||
1002 | } | ||
1003 | /* Update statistics */ | ||
1004 | if (old_ctrl.CTS != ctrl_dl.CTS) | ||
1005 | dc->port[port].tty_icount.cts++; | ||
1006 | if (old_ctrl.DSR != ctrl_dl.DSR) | ||
1007 | dc->port[port].tty_icount.dsr++; | ||
1008 | if (old_ctrl.RI != ctrl_dl.RI) | ||
1009 | dc->port[port].tty_icount.rng++; | ||
1010 | if (old_ctrl.DCD != ctrl_dl.DCD) | ||
1011 | dc->port[port].tty_icount.dcd++; | ||
1012 | |||
1013 | wake_up_interruptible(&dc->port[port].tty_wait); | ||
1014 | |||
1015 | DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", | ||
1016 | port, | ||
1017 | dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, | ||
1018 | dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); | ||
1019 | |||
1020 | return 1; | ||
1021 | } | ||
1022 | |||
1023 | static enum ctrl_port_type port2ctrl(enum port_type port, | ||
1024 | const struct nozomi *dc) | ||
1025 | { | ||
1026 | switch (port) { | ||
1027 | case PORT_MDM: | ||
1028 | return CTRL_MDM; | ||
1029 | case PORT_DIAG: | ||
1030 | return CTRL_DIAG; | ||
1031 | case PORT_APP1: | ||
1032 | return CTRL_APP1; | ||
1033 | case PORT_APP2: | ||
1034 | return CTRL_APP2; | ||
1035 | default: | ||
1036 | dev_err(&dc->pdev->dev, | ||
1037 | "ERROR: send flow control " \ | ||
1038 | "received for non-existing port\n"); | ||
1039 | }; | ||
1040 | return CTRL_ERROR; | ||
1041 | } | ||
1042 | |||
1043 | /* | ||
1044 | * Send flow control, can only update one channel at a time | ||
1045 | * Return 0 - If we have updated all flow control | ||
1046 | * Return 1 - If we need to update more flow control, ack current enable more | ||
1047 | */ | ||
1048 | static int send_flow_control(struct nozomi *dc) | ||
1049 | { | ||
1050 | u32 i, more_flow_control_to_be_updated = 0; | ||
1051 | u16 *ctrl; | ||
1052 | |||
1053 | for (i = PORT_MDM; i < MAX_PORT; i++) { | ||
1054 | if (dc->port[i].update_flow_control) { | ||
1055 | if (more_flow_control_to_be_updated) { | ||
1056 | /* We have more flow control to be updated */ | ||
1057 | return 1; | ||
1058 | } | ||
1059 | dc->port[i].ctrl_ul.port = port2ctrl(i, dc); | ||
1060 | ctrl = (u16 *)&dc->port[i].ctrl_ul; | ||
1061 | write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ | ||
1062 | (u32 *) ctrl, 2); | ||
1063 | dc->port[i].update_flow_control = 0; | ||
1064 | more_flow_control_to_be_updated = 1; | ||
1065 | } | ||
1066 | } | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | /* | ||
1071 | * Handle downlink data, ports that are handled are modem and diagnostics | ||
1072 | * Return 1 - ok | ||
1073 | * Return 0 - toggle fields are out of sync | ||
1074 | */ | ||
1075 | static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, | ||
1076 | u16 read_iir, u16 mask1, u16 mask2) | ||
1077 | { | ||
1078 | if (*toggle == 0 && read_iir & mask1) { | ||
1079 | if (receive_data(port, dc)) { | ||
1080 | writew(mask1, dc->reg_fcr); | ||
1081 | *toggle = !(*toggle); | ||
1082 | } | ||
1083 | |||
1084 | if (read_iir & mask2) { | ||
1085 | if (receive_data(port, dc)) { | ||
1086 | writew(mask2, dc->reg_fcr); | ||
1087 | *toggle = !(*toggle); | ||
1088 | } | ||
1089 | } | ||
1090 | } else if (*toggle == 1 && read_iir & mask2) { | ||
1091 | if (receive_data(port, dc)) { | ||
1092 | writew(mask2, dc->reg_fcr); | ||
1093 | *toggle = !(*toggle); | ||
1094 | } | ||
1095 | |||
1096 | if (read_iir & mask1) { | ||
1097 | if (receive_data(port, dc)) { | ||
1098 | writew(mask1, dc->reg_fcr); | ||
1099 | *toggle = !(*toggle); | ||
1100 | } | ||
1101 | } | ||
1102 | } else { | ||
1103 | dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", | ||
1104 | *toggle); | ||
1105 | return 0; | ||
1106 | } | ||
1107 | return 1; | ||
1108 | } | ||
1109 | |||
1110 | /* | ||
1111 | * Handle uplink data, this is currently for the modem port | ||
1112 | * Return 1 - ok | ||
1113 | * Return 0 - toggle field are out of sync | ||
1114 | */ | ||
1115 | static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) | ||
1116 | { | ||
1117 | u8 *toggle = &(dc->port[port].toggle_ul); | ||
1118 | |||
1119 | if (*toggle == 0 && read_iir & MDM_UL1) { | ||
1120 | dc->last_ier &= ~MDM_UL; | ||
1121 | writew(dc->last_ier, dc->reg_ier); | ||
1122 | if (send_data(port, dc)) { | ||
1123 | writew(MDM_UL1, dc->reg_fcr); | ||
1124 | dc->last_ier = dc->last_ier | MDM_UL; | ||
1125 | writew(dc->last_ier, dc->reg_ier); | ||
1126 | *toggle = !*toggle; | ||
1127 | } | ||
1128 | |||
1129 | if (read_iir & MDM_UL2) { | ||
1130 | dc->last_ier &= ~MDM_UL; | ||
1131 | writew(dc->last_ier, dc->reg_ier); | ||
1132 | if (send_data(port, dc)) { | ||
1133 | writew(MDM_UL2, dc->reg_fcr); | ||
1134 | dc->last_ier = dc->last_ier | MDM_UL; | ||
1135 | writew(dc->last_ier, dc->reg_ier); | ||
1136 | *toggle = !*toggle; | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | } else if (*toggle == 1 && read_iir & MDM_UL2) { | ||
1141 | dc->last_ier &= ~MDM_UL; | ||
1142 | writew(dc->last_ier, dc->reg_ier); | ||
1143 | if (send_data(port, dc)) { | ||
1144 | writew(MDM_UL2, dc->reg_fcr); | ||
1145 | dc->last_ier = dc->last_ier | MDM_UL; | ||
1146 | writew(dc->last_ier, dc->reg_ier); | ||
1147 | *toggle = !*toggle; | ||
1148 | } | ||
1149 | |||
1150 | if (read_iir & MDM_UL1) { | ||
1151 | dc->last_ier &= ~MDM_UL; | ||
1152 | writew(dc->last_ier, dc->reg_ier); | ||
1153 | if (send_data(port, dc)) { | ||
1154 | writew(MDM_UL1, dc->reg_fcr); | ||
1155 | dc->last_ier = dc->last_ier | MDM_UL; | ||
1156 | writew(dc->last_ier, dc->reg_ier); | ||
1157 | *toggle = !*toggle; | ||
1158 | } | ||
1159 | } | ||
1160 | } else { | ||
1161 | writew(read_iir & MDM_UL, dc->reg_fcr); | ||
1162 | dev_err(&dc->pdev->dev, "port out of sync!\n"); | ||
1163 | return 0; | ||
1164 | } | ||
1165 | return 1; | ||
1166 | } | ||
1167 | |||
1168 | static irqreturn_t interrupt_handler(int irq, void *dev_id) | ||
1169 | { | ||
1170 | struct nozomi *dc = dev_id; | ||
1171 | unsigned int a; | ||
1172 | u16 read_iir; | ||
1173 | |||
1174 | if (!dc) | ||
1175 | return IRQ_NONE; | ||
1176 | |||
1177 | spin_lock(&dc->spin_mutex); | ||
1178 | read_iir = readw(dc->reg_iir); | ||
1179 | |||
1180 | /* Card removed */ | ||
1181 | if (read_iir == (u16)-1) | ||
1182 | goto none; | ||
1183 | /* | ||
1184 | * Just handle interrupt enabled in IER | ||
1185 | * (by masking with dc->last_ier) | ||
1186 | */ | ||
1187 | read_iir &= dc->last_ier; | ||
1188 | |||
1189 | if (read_iir == 0) | ||
1190 | goto none; | ||
1191 | |||
1192 | |||
1193 | DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, | ||
1194 | dc->last_ier); | ||
1195 | |||
1196 | if (read_iir & RESET) { | ||
1197 | if (unlikely(!nozomi_read_config_table(dc))) { | ||
1198 | dc->last_ier = 0x0; | ||
1199 | writew(dc->last_ier, dc->reg_ier); | ||
1200 | dev_err(&dc->pdev->dev, "Could not read status from " | ||
1201 | "card, we should disable interface\n"); | ||
1202 | } else { | ||
1203 | writew(RESET, dc->reg_fcr); | ||
1204 | } | ||
1205 | /* No more useful info if this was the reset interrupt. */ | ||
1206 | goto exit_handler; | ||
1207 | } | ||
1208 | if (read_iir & CTRL_UL) { | ||
1209 | DBG1("CTRL_UL"); | ||
1210 | dc->last_ier &= ~CTRL_UL; | ||
1211 | writew(dc->last_ier, dc->reg_ier); | ||
1212 | if (send_flow_control(dc)) { | ||
1213 | writew(CTRL_UL, dc->reg_fcr); | ||
1214 | dc->last_ier = dc->last_ier | CTRL_UL; | ||
1215 | writew(dc->last_ier, dc->reg_ier); | ||
1216 | } | ||
1217 | } | ||
1218 | if (read_iir & CTRL_DL) { | ||
1219 | receive_flow_control(dc); | ||
1220 | writew(CTRL_DL, dc->reg_fcr); | ||
1221 | } | ||
1222 | if (read_iir & MDM_DL) { | ||
1223 | if (!handle_data_dl(dc, PORT_MDM, | ||
1224 | &(dc->port[PORT_MDM].toggle_dl), read_iir, | ||
1225 | MDM_DL1, MDM_DL2)) { | ||
1226 | dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); | ||
1227 | goto exit_handler; | ||
1228 | } | ||
1229 | } | ||
1230 | if (read_iir & MDM_UL) { | ||
1231 | if (!handle_data_ul(dc, PORT_MDM, read_iir)) { | ||
1232 | dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); | ||
1233 | goto exit_handler; | ||
1234 | } | ||
1235 | } | ||
1236 | if (read_iir & DIAG_DL) { | ||
1237 | if (!handle_data_dl(dc, PORT_DIAG, | ||
1238 | &(dc->port[PORT_DIAG].toggle_dl), read_iir, | ||
1239 | DIAG_DL1, DIAG_DL2)) { | ||
1240 | dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); | ||
1241 | goto exit_handler; | ||
1242 | } | ||
1243 | } | ||
1244 | if (read_iir & DIAG_UL) { | ||
1245 | dc->last_ier &= ~DIAG_UL; | ||
1246 | writew(dc->last_ier, dc->reg_ier); | ||
1247 | if (send_data(PORT_DIAG, dc)) { | ||
1248 | writew(DIAG_UL, dc->reg_fcr); | ||
1249 | dc->last_ier = dc->last_ier | DIAG_UL; | ||
1250 | writew(dc->last_ier, dc->reg_ier); | ||
1251 | } | ||
1252 | } | ||
1253 | if (read_iir & APP1_DL) { | ||
1254 | if (receive_data(PORT_APP1, dc)) | ||
1255 | writew(APP1_DL, dc->reg_fcr); | ||
1256 | } | ||
1257 | if (read_iir & APP1_UL) { | ||
1258 | dc->last_ier &= ~APP1_UL; | ||
1259 | writew(dc->last_ier, dc->reg_ier); | ||
1260 | if (send_data(PORT_APP1, dc)) { | ||
1261 | writew(APP1_UL, dc->reg_fcr); | ||
1262 | dc->last_ier = dc->last_ier | APP1_UL; | ||
1263 | writew(dc->last_ier, dc->reg_ier); | ||
1264 | } | ||
1265 | } | ||
1266 | if (read_iir & APP2_DL) { | ||
1267 | if (receive_data(PORT_APP2, dc)) | ||
1268 | writew(APP2_DL, dc->reg_fcr); | ||
1269 | } | ||
1270 | if (read_iir & APP2_UL) { | ||
1271 | dc->last_ier &= ~APP2_UL; | ||
1272 | writew(dc->last_ier, dc->reg_ier); | ||
1273 | if (send_data(PORT_APP2, dc)) { | ||
1274 | writew(APP2_UL, dc->reg_fcr); | ||
1275 | dc->last_ier = dc->last_ier | APP2_UL; | ||
1276 | writew(dc->last_ier, dc->reg_ier); | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | exit_handler: | ||
1281 | spin_unlock(&dc->spin_mutex); | ||
1282 | for (a = 0; a < NOZOMI_MAX_PORTS; a++) { | ||
1283 | struct tty_struct *tty; | ||
1284 | if (test_and_clear_bit(a, &dc->flip)) { | ||
1285 | tty = tty_port_tty_get(&dc->port[a].port); | ||
1286 | if (tty) | ||
1287 | tty_flip_buffer_push(tty); | ||
1288 | tty_kref_put(tty); | ||
1289 | } | ||
1290 | } | ||
1291 | return IRQ_HANDLED; | ||
1292 | none: | ||
1293 | spin_unlock(&dc->spin_mutex); | ||
1294 | return IRQ_NONE; | ||
1295 | } | ||
1296 | |||
1297 | static void nozomi_get_card_type(struct nozomi *dc) | ||
1298 | { | ||
1299 | int i; | ||
1300 | u32 size = 0; | ||
1301 | |||
1302 | for (i = 0; i < 6; i++) | ||
1303 | size += pci_resource_len(dc->pdev, i); | ||
1304 | |||
1305 | /* Assume card type F32_8 if no match */ | ||
1306 | dc->card_type = size == 2048 ? F32_2 : F32_8; | ||
1307 | |||
1308 | dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); | ||
1309 | } | ||
1310 | |||
1311 | static void nozomi_setup_private_data(struct nozomi *dc) | ||
1312 | { | ||
1313 | void __iomem *offset = dc->base_addr + dc->card_type / 2; | ||
1314 | unsigned int i; | ||
1315 | |||
1316 | dc->reg_fcr = (void __iomem *)(offset + R_FCR); | ||
1317 | dc->reg_iir = (void __iomem *)(offset + R_IIR); | ||
1318 | dc->reg_ier = (void __iomem *)(offset + R_IER); | ||
1319 | dc->last_ier = 0; | ||
1320 | dc->flip = 0; | ||
1321 | |||
1322 | dc->port[PORT_MDM].token_dl = MDM_DL; | ||
1323 | dc->port[PORT_DIAG].token_dl = DIAG_DL; | ||
1324 | dc->port[PORT_APP1].token_dl = APP1_DL; | ||
1325 | dc->port[PORT_APP2].token_dl = APP2_DL; | ||
1326 | |||
1327 | for (i = 0; i < MAX_PORT; i++) | ||
1328 | init_waitqueue_head(&dc->port[i].tty_wait); | ||
1329 | } | ||
1330 | |||
1331 | static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, | ||
1332 | char *buf) | ||
1333 | { | ||
1334 | const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); | ||
1335 | |||
1336 | return sprintf(buf, "%d\n", dc->card_type); | ||
1337 | } | ||
1338 | static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); | ||
1339 | |||
1340 | static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, | ||
1341 | char *buf) | ||
1342 | { | ||
1343 | const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); | ||
1344 | |||
1345 | return sprintf(buf, "%u\n", dc->open_ttys); | ||
1346 | } | ||
1347 | static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); | ||
1348 | |||
1349 | static void make_sysfs_files(struct nozomi *dc) | ||
1350 | { | ||
1351 | if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) | ||
1352 | dev_err(&dc->pdev->dev, | ||
1353 | "Could not create sysfs file for card_type\n"); | ||
1354 | if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) | ||
1355 | dev_err(&dc->pdev->dev, | ||
1356 | "Could not create sysfs file for open_ttys\n"); | ||
1357 | } | ||
1358 | |||
1359 | static void remove_sysfs_files(struct nozomi *dc) | ||
1360 | { | ||
1361 | device_remove_file(&dc->pdev->dev, &dev_attr_card_type); | ||
1362 | device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); | ||
1363 | } | ||
1364 | |||
1365 | /* Allocate memory for one device */ | ||
1366 | static int __devinit nozomi_card_init(struct pci_dev *pdev, | ||
1367 | const struct pci_device_id *ent) | ||
1368 | { | ||
1369 | resource_size_t start; | ||
1370 | int ret; | ||
1371 | struct nozomi *dc = NULL; | ||
1372 | int ndev_idx; | ||
1373 | int i; | ||
1374 | |||
1375 | dev_dbg(&pdev->dev, "Init, new card found\n"); | ||
1376 | |||
1377 | for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) | ||
1378 | if (!ndevs[ndev_idx]) | ||
1379 | break; | ||
1380 | |||
1381 | if (ndev_idx >= ARRAY_SIZE(ndevs)) { | ||
1382 | dev_err(&pdev->dev, "no free tty range for this card left\n"); | ||
1383 | ret = -EIO; | ||
1384 | goto err; | ||
1385 | } | ||
1386 | |||
1387 | dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); | ||
1388 | if (unlikely(!dc)) { | ||
1389 | dev_err(&pdev->dev, "Could not allocate memory\n"); | ||
1390 | ret = -ENOMEM; | ||
1391 | goto err_free; | ||
1392 | } | ||
1393 | |||
1394 | dc->pdev = pdev; | ||
1395 | |||
1396 | ret = pci_enable_device(dc->pdev); | ||
1397 | if (ret) { | ||
1398 | dev_err(&pdev->dev, "Failed to enable PCI Device\n"); | ||
1399 | goto err_free; | ||
1400 | } | ||
1401 | |||
1402 | ret = pci_request_regions(dc->pdev, NOZOMI_NAME); | ||
1403 | if (ret) { | ||
1404 | dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", | ||
1405 | (int) /* nozomi_private.io_addr */ 0); | ||
1406 | goto err_disable_device; | ||
1407 | } | ||
1408 | |||
1409 | start = pci_resource_start(dc->pdev, 0); | ||
1410 | if (start == 0) { | ||
1411 | dev_err(&pdev->dev, "No I/O address for card detected\n"); | ||
1412 | ret = -ENODEV; | ||
1413 | goto err_rel_regs; | ||
1414 | } | ||
1415 | |||
1416 | /* Find out what card type it is */ | ||
1417 | nozomi_get_card_type(dc); | ||
1418 | |||
1419 | dc->base_addr = ioremap_nocache(start, dc->card_type); | ||
1420 | if (!dc->base_addr) { | ||
1421 | dev_err(&pdev->dev, "Unable to map card MMIO\n"); | ||
1422 | ret = -ENODEV; | ||
1423 | goto err_rel_regs; | ||
1424 | } | ||
1425 | |||
1426 | dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); | ||
1427 | if (!dc->send_buf) { | ||
1428 | dev_err(&pdev->dev, "Could not allocate send buffer?\n"); | ||
1429 | ret = -ENOMEM; | ||
1430 | goto err_free_sbuf; | ||
1431 | } | ||
1432 | |||
1433 | for (i = PORT_MDM; i < MAX_PORT; i++) { | ||
1434 | if (kfifo_alloc(&dc->port[i].fifo_ul, | ||
1435 | FIFO_BUFFER_SIZE_UL, GFP_ATOMIC)) { | ||
1436 | dev_err(&pdev->dev, | ||
1437 | "Could not allocate kfifo buffer\n"); | ||
1438 | ret = -ENOMEM; | ||
1439 | goto err_free_kfifo; | ||
1440 | } | ||
1441 | } | ||
1442 | |||
1443 | spin_lock_init(&dc->spin_mutex); | ||
1444 | |||
1445 | nozomi_setup_private_data(dc); | ||
1446 | |||
1447 | /* Disable all interrupts */ | ||
1448 | dc->last_ier = 0; | ||
1449 | writew(dc->last_ier, dc->reg_ier); | ||
1450 | |||
1451 | ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, | ||
1452 | NOZOMI_NAME, dc); | ||
1453 | if (unlikely(ret)) { | ||
1454 | dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); | ||
1455 | goto err_free_kfifo; | ||
1456 | } | ||
1457 | |||
1458 | DBG1("base_addr: %p", dc->base_addr); | ||
1459 | |||
1460 | make_sysfs_files(dc); | ||
1461 | |||
1462 | dc->index_start = ndev_idx * MAX_PORT; | ||
1463 | ndevs[ndev_idx] = dc; | ||
1464 | |||
1465 | pci_set_drvdata(pdev, dc); | ||
1466 | |||
1467 | /* Enable RESET interrupt */ | ||
1468 | dc->last_ier = RESET; | ||
1469 | iowrite16(dc->last_ier, dc->reg_ier); | ||
1470 | |||
1471 | dc->state = NOZOMI_STATE_ENABLED; | ||
1472 | |||
1473 | for (i = 0; i < MAX_PORT; i++) { | ||
1474 | struct device *tty_dev; | ||
1475 | struct port *port = &dc->port[i]; | ||
1476 | port->dc = dc; | ||
1477 | mutex_init(&port->tty_sem); | ||
1478 | tty_port_init(&port->port); | ||
1479 | port->port.ops = &noz_tty_port_ops; | ||
1480 | tty_dev = tty_register_device(ntty_driver, dc->index_start + i, | ||
1481 | &pdev->dev); | ||
1482 | |||
1483 | if (IS_ERR(tty_dev)) { | ||
1484 | ret = PTR_ERR(tty_dev); | ||
1485 | dev_err(&pdev->dev, "Could not allocate tty?\n"); | ||
1486 | goto err_free_tty; | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | return 0; | ||
1491 | |||
1492 | err_free_tty: | ||
1493 | for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) | ||
1494 | tty_unregister_device(ntty_driver, i); | ||
1495 | err_free_kfifo: | ||
1496 | for (i = 0; i < MAX_PORT; i++) | ||
1497 | kfifo_free(&dc->port[i].fifo_ul); | ||
1498 | err_free_sbuf: | ||
1499 | kfree(dc->send_buf); | ||
1500 | iounmap(dc->base_addr); | ||
1501 | err_rel_regs: | ||
1502 | pci_release_regions(pdev); | ||
1503 | err_disable_device: | ||
1504 | pci_disable_device(pdev); | ||
1505 | err_free: | ||
1506 | kfree(dc); | ||
1507 | err: | ||
1508 | return ret; | ||
1509 | } | ||
1510 | |||
1511 | static void __devexit tty_exit(struct nozomi *dc) | ||
1512 | { | ||
1513 | unsigned int i; | ||
1514 | |||
1515 | DBG1(" "); | ||
1516 | |||
1517 | for (i = 0; i < MAX_PORT; ++i) { | ||
1518 | struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port); | ||
1519 | if (tty && list_empty(&tty->hangup_work.entry)) | ||
1520 | tty_hangup(tty); | ||
1521 | tty_kref_put(tty); | ||
1522 | } | ||
1523 | /* Racy below - surely should wait for scheduled work to be done or | ||
1524 | complete off a hangup method ? */ | ||
1525 | while (dc->open_ttys) | ||
1526 | msleep(1); | ||
1527 | for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) | ||
1528 | tty_unregister_device(ntty_driver, i); | ||
1529 | } | ||
1530 | |||
1531 | /* Deallocate memory for one device */ | ||
1532 | static void __devexit nozomi_card_exit(struct pci_dev *pdev) | ||
1533 | { | ||
1534 | int i; | ||
1535 | struct ctrl_ul ctrl; | ||
1536 | struct nozomi *dc = pci_get_drvdata(pdev); | ||
1537 | |||
1538 | /* Disable all interrupts */ | ||
1539 | dc->last_ier = 0; | ||
1540 | writew(dc->last_ier, dc->reg_ier); | ||
1541 | |||
1542 | tty_exit(dc); | ||
1543 | |||
1544 | /* Send 0x0001, command card to resend the reset token. */ | ||
1545 | /* This is to get the reset when the module is reloaded. */ | ||
1546 | ctrl.port = 0x00; | ||
1547 | ctrl.reserved = 0; | ||
1548 | ctrl.RTS = 0; | ||
1549 | ctrl.DTR = 1; | ||
1550 | DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); | ||
1551 | |||
1552 | /* Setup dc->reg addresses to we can use defines here */ | ||
1553 | write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); | ||
1554 | writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ | ||
1555 | |||
1556 | remove_sysfs_files(dc); | ||
1557 | |||
1558 | free_irq(pdev->irq, dc); | ||
1559 | |||
1560 | for (i = 0; i < MAX_PORT; i++) | ||
1561 | kfifo_free(&dc->port[i].fifo_ul); | ||
1562 | |||
1563 | kfree(dc->send_buf); | ||
1564 | |||
1565 | iounmap(dc->base_addr); | ||
1566 | |||
1567 | pci_release_regions(pdev); | ||
1568 | |||
1569 | pci_disable_device(pdev); | ||
1570 | |||
1571 | ndevs[dc->index_start / MAX_PORT] = NULL; | ||
1572 | |||
1573 | kfree(dc); | ||
1574 | } | ||
1575 | |||
1576 | static void set_rts(const struct tty_struct *tty, int rts) | ||
1577 | { | ||
1578 | struct port *port = get_port_by_tty(tty); | ||
1579 | |||
1580 | port->ctrl_ul.RTS = rts; | ||
1581 | port->update_flow_control = 1; | ||
1582 | enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); | ||
1583 | } | ||
1584 | |||
1585 | static void set_dtr(const struct tty_struct *tty, int dtr) | ||
1586 | { | ||
1587 | struct port *port = get_port_by_tty(tty); | ||
1588 | |||
1589 | DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); | ||
1590 | |||
1591 | port->ctrl_ul.DTR = dtr; | ||
1592 | port->update_flow_control = 1; | ||
1593 | enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); | ||
1594 | } | ||
1595 | |||
1596 | /* | ||
1597 | * ---------------------------------------------------------------------------- | ||
1598 | * TTY code | ||
1599 | * ---------------------------------------------------------------------------- | ||
1600 | */ | ||
1601 | |||
1602 | static int ntty_install(struct tty_driver *driver, struct tty_struct *tty) | ||
1603 | { | ||
1604 | struct port *port = get_port_by_tty(tty); | ||
1605 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1606 | int ret; | ||
1607 | if (!port || !dc || dc->state != NOZOMI_STATE_READY) | ||
1608 | return -ENODEV; | ||
1609 | ret = tty_init_termios(tty); | ||
1610 | if (ret == 0) { | ||
1611 | tty_driver_kref_get(driver); | ||
1612 | tty->count++; | ||
1613 | tty->driver_data = port; | ||
1614 | driver->ttys[tty->index] = tty; | ||
1615 | } | ||
1616 | return ret; | ||
1617 | } | ||
1618 | |||
1619 | static void ntty_cleanup(struct tty_struct *tty) | ||
1620 | { | ||
1621 | tty->driver_data = NULL; | ||
1622 | } | ||
1623 | |||
1624 | static int ntty_activate(struct tty_port *tport, struct tty_struct *tty) | ||
1625 | { | ||
1626 | struct port *port = container_of(tport, struct port, port); | ||
1627 | struct nozomi *dc = port->dc; | ||
1628 | unsigned long flags; | ||
1629 | |||
1630 | DBG1("open: %d", port->token_dl); | ||
1631 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1632 | dc->last_ier = dc->last_ier | port->token_dl; | ||
1633 | writew(dc->last_ier, dc->reg_ier); | ||
1634 | dc->open_ttys++; | ||
1635 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1636 | printk("noz: activated %d: %p\n", tty->index, tport); | ||
1637 | return 0; | ||
1638 | } | ||
1639 | |||
1640 | static int ntty_open(struct tty_struct *tty, struct file *filp) | ||
1641 | { | ||
1642 | struct port *port = tty->driver_data; | ||
1643 | return tty_port_open(&port->port, tty, filp); | ||
1644 | } | ||
1645 | |||
1646 | static void ntty_shutdown(struct tty_port *tport) | ||
1647 | { | ||
1648 | struct port *port = container_of(tport, struct port, port); | ||
1649 | struct nozomi *dc = port->dc; | ||
1650 | unsigned long flags; | ||
1651 | |||
1652 | DBG1("close: %d", port->token_dl); | ||
1653 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1654 | dc->last_ier &= ~(port->token_dl); | ||
1655 | writew(dc->last_ier, dc->reg_ier); | ||
1656 | dc->open_ttys--; | ||
1657 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1658 | printk("noz: shutdown %p\n", tport); | ||
1659 | } | ||
1660 | |||
1661 | static void ntty_close(struct tty_struct *tty, struct file *filp) | ||
1662 | { | ||
1663 | struct port *port = tty->driver_data; | ||
1664 | if (port) | ||
1665 | tty_port_close(&port->port, tty, filp); | ||
1666 | } | ||
1667 | |||
1668 | static void ntty_hangup(struct tty_struct *tty) | ||
1669 | { | ||
1670 | struct port *port = tty->driver_data; | ||
1671 | tty_port_hangup(&port->port); | ||
1672 | } | ||
1673 | |||
1674 | /* | ||
1675 | * called when the userspace process writes to the tty (/dev/noz*). | ||
1676 | * Data is inserted into a fifo, which is then read and transfered to the modem. | ||
1677 | */ | ||
1678 | static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, | ||
1679 | int count) | ||
1680 | { | ||
1681 | int rval = -EINVAL; | ||
1682 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1683 | struct port *port = tty->driver_data; | ||
1684 | unsigned long flags; | ||
1685 | |||
1686 | /* DBG1( "WRITEx: %d, index = %d", count, index); */ | ||
1687 | |||
1688 | if (!dc || !port) | ||
1689 | return -ENODEV; | ||
1690 | |||
1691 | mutex_lock(&port->tty_sem); | ||
1692 | |||
1693 | if (unlikely(!port->port.count)) { | ||
1694 | DBG1(" "); | ||
1695 | goto exit; | ||
1696 | } | ||
1697 | |||
1698 | rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count); | ||
1699 | |||
1700 | /* notify card */ | ||
1701 | if (unlikely(dc == NULL)) { | ||
1702 | DBG1("No device context?"); | ||
1703 | goto exit; | ||
1704 | } | ||
1705 | |||
1706 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1707 | /* CTS is only valid on the modem channel */ | ||
1708 | if (port == &(dc->port[PORT_MDM])) { | ||
1709 | if (port->ctrl_dl.CTS) { | ||
1710 | DBG4("Enable interrupt"); | ||
1711 | enable_transmit_ul(tty->index % MAX_PORT, dc); | ||
1712 | } else { | ||
1713 | dev_err(&dc->pdev->dev, | ||
1714 | "CTS not active on modem port?\n"); | ||
1715 | } | ||
1716 | } else { | ||
1717 | enable_transmit_ul(tty->index % MAX_PORT, dc); | ||
1718 | } | ||
1719 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1720 | |||
1721 | exit: | ||
1722 | mutex_unlock(&port->tty_sem); | ||
1723 | return rval; | ||
1724 | } | ||
1725 | |||
1726 | /* | ||
1727 | * Calculate how much is left in device | ||
1728 | * This method is called by the upper tty layer. | ||
1729 | * #according to sources N_TTY.c it expects a value >= 0 and | ||
1730 | * does not check for negative values. | ||
1731 | * | ||
1732 | * If the port is unplugged report lots of room and let the bits | ||
1733 | * dribble away so we don't block anything. | ||
1734 | */ | ||
1735 | static int ntty_write_room(struct tty_struct *tty) | ||
1736 | { | ||
1737 | struct port *port = tty->driver_data; | ||
1738 | int room = 4096; | ||
1739 | const struct nozomi *dc = get_dc_by_tty(tty); | ||
1740 | |||
1741 | if (dc) { | ||
1742 | mutex_lock(&port->tty_sem); | ||
1743 | if (port->port.count) | ||
1744 | room = kfifo_avail(&port->fifo_ul); | ||
1745 | mutex_unlock(&port->tty_sem); | ||
1746 | } | ||
1747 | return room; | ||
1748 | } | ||
1749 | |||
1750 | /* Gets io control parameters */ | ||
1751 | static int ntty_tiocmget(struct tty_struct *tty) | ||
1752 | { | ||
1753 | const struct port *port = tty->driver_data; | ||
1754 | const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; | ||
1755 | const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; | ||
1756 | |||
1757 | /* Note: these could change under us but it is not clear this | ||
1758 | matters if so */ | ||
1759 | return (ctrl_ul->RTS ? TIOCM_RTS : 0) | | ||
1760 | (ctrl_ul->DTR ? TIOCM_DTR : 0) | | ||
1761 | (ctrl_dl->DCD ? TIOCM_CAR : 0) | | ||
1762 | (ctrl_dl->RI ? TIOCM_RNG : 0) | | ||
1763 | (ctrl_dl->DSR ? TIOCM_DSR : 0) | | ||
1764 | (ctrl_dl->CTS ? TIOCM_CTS : 0); | ||
1765 | } | ||
1766 | |||
1767 | /* Sets io controls parameters */ | ||
1768 | static int ntty_tiocmset(struct tty_struct *tty, | ||
1769 | unsigned int set, unsigned int clear) | ||
1770 | { | ||
1771 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1772 | unsigned long flags; | ||
1773 | |||
1774 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1775 | if (set & TIOCM_RTS) | ||
1776 | set_rts(tty, 1); | ||
1777 | else if (clear & TIOCM_RTS) | ||
1778 | set_rts(tty, 0); | ||
1779 | |||
1780 | if (set & TIOCM_DTR) | ||
1781 | set_dtr(tty, 1); | ||
1782 | else if (clear & TIOCM_DTR) | ||
1783 | set_dtr(tty, 0); | ||
1784 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1785 | |||
1786 | return 0; | ||
1787 | } | ||
1788 | |||
1789 | static int ntty_cflags_changed(struct port *port, unsigned long flags, | ||
1790 | struct async_icount *cprev) | ||
1791 | { | ||
1792 | const struct async_icount cnow = port->tty_icount; | ||
1793 | int ret; | ||
1794 | |||
1795 | ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || | ||
1796 | ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || | ||
1797 | ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || | ||
1798 | ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); | ||
1799 | |||
1800 | *cprev = cnow; | ||
1801 | |||
1802 | return ret; | ||
1803 | } | ||
1804 | |||
1805 | static int ntty_tiocgicount(struct tty_struct *tty, | ||
1806 | struct serial_icounter_struct *icount) | ||
1807 | { | ||
1808 | struct port *port = tty->driver_data; | ||
1809 | const struct async_icount cnow = port->tty_icount; | ||
1810 | |||
1811 | icount->cts = cnow.cts; | ||
1812 | icount->dsr = cnow.dsr; | ||
1813 | icount->rng = cnow.rng; | ||
1814 | icount->dcd = cnow.dcd; | ||
1815 | icount->rx = cnow.rx; | ||
1816 | icount->tx = cnow.tx; | ||
1817 | icount->frame = cnow.frame; | ||
1818 | icount->overrun = cnow.overrun; | ||
1819 | icount->parity = cnow.parity; | ||
1820 | icount->brk = cnow.brk; | ||
1821 | icount->buf_overrun = cnow.buf_overrun; | ||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1825 | static int ntty_ioctl(struct tty_struct *tty, | ||
1826 | unsigned int cmd, unsigned long arg) | ||
1827 | { | ||
1828 | struct port *port = tty->driver_data; | ||
1829 | int rval = -ENOIOCTLCMD; | ||
1830 | |||
1831 | DBG1("******** IOCTL, cmd: %d", cmd); | ||
1832 | |||
1833 | switch (cmd) { | ||
1834 | case TIOCMIWAIT: { | ||
1835 | struct async_icount cprev = port->tty_icount; | ||
1836 | |||
1837 | rval = wait_event_interruptible(port->tty_wait, | ||
1838 | ntty_cflags_changed(port, arg, &cprev)); | ||
1839 | break; | ||
1840 | } | ||
1841 | default: | ||
1842 | DBG1("ERR: 0x%08X, %d", cmd, cmd); | ||
1843 | break; | ||
1844 | }; | ||
1845 | |||
1846 | return rval; | ||
1847 | } | ||
1848 | |||
1849 | /* | ||
1850 | * Called by the upper tty layer when tty buffers are ready | ||
1851 | * to receive data again after a call to throttle. | ||
1852 | */ | ||
1853 | static void ntty_unthrottle(struct tty_struct *tty) | ||
1854 | { | ||
1855 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1856 | unsigned long flags; | ||
1857 | |||
1858 | DBG1("UNTHROTTLE"); | ||
1859 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1860 | enable_transmit_dl(tty->index % MAX_PORT, dc); | ||
1861 | set_rts(tty, 1); | ||
1862 | |||
1863 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1864 | } | ||
1865 | |||
1866 | /* | ||
1867 | * Called by the upper tty layer when the tty buffers are almost full. | ||
1868 | * The driver should stop send more data. | ||
1869 | */ | ||
1870 | static void ntty_throttle(struct tty_struct *tty) | ||
1871 | { | ||
1872 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1873 | unsigned long flags; | ||
1874 | |||
1875 | DBG1("THROTTLE"); | ||
1876 | spin_lock_irqsave(&dc->spin_mutex, flags); | ||
1877 | set_rts(tty, 0); | ||
1878 | spin_unlock_irqrestore(&dc->spin_mutex, flags); | ||
1879 | } | ||
1880 | |||
1881 | /* Returns number of chars in buffer, called by tty layer */ | ||
1882 | static s32 ntty_chars_in_buffer(struct tty_struct *tty) | ||
1883 | { | ||
1884 | struct port *port = tty->driver_data; | ||
1885 | struct nozomi *dc = get_dc_by_tty(tty); | ||
1886 | s32 rval = 0; | ||
1887 | |||
1888 | if (unlikely(!dc || !port)) { | ||
1889 | goto exit_in_buffer; | ||
1890 | } | ||
1891 | |||
1892 | if (unlikely(!port->port.count)) { | ||
1893 | dev_err(&dc->pdev->dev, "No tty open?\n"); | ||
1894 | goto exit_in_buffer; | ||
1895 | } | ||
1896 | |||
1897 | rval = kfifo_len(&port->fifo_ul); | ||
1898 | |||
1899 | exit_in_buffer: | ||
1900 | return rval; | ||
1901 | } | ||
1902 | |||
1903 | static const struct tty_port_operations noz_tty_port_ops = { | ||
1904 | .activate = ntty_activate, | ||
1905 | .shutdown = ntty_shutdown, | ||
1906 | }; | ||
1907 | |||
1908 | static const struct tty_operations tty_ops = { | ||
1909 | .ioctl = ntty_ioctl, | ||
1910 | .open = ntty_open, | ||
1911 | .close = ntty_close, | ||
1912 | .hangup = ntty_hangup, | ||
1913 | .write = ntty_write, | ||
1914 | .write_room = ntty_write_room, | ||
1915 | .unthrottle = ntty_unthrottle, | ||
1916 | .throttle = ntty_throttle, | ||
1917 | .chars_in_buffer = ntty_chars_in_buffer, | ||
1918 | .tiocmget = ntty_tiocmget, | ||
1919 | .tiocmset = ntty_tiocmset, | ||
1920 | .get_icount = ntty_tiocgicount, | ||
1921 | .install = ntty_install, | ||
1922 | .cleanup = ntty_cleanup, | ||
1923 | }; | ||
1924 | |||
1925 | /* Module initialization */ | ||
1926 | static struct pci_driver nozomi_driver = { | ||
1927 | .name = NOZOMI_NAME, | ||
1928 | .id_table = nozomi_pci_tbl, | ||
1929 | .probe = nozomi_card_init, | ||
1930 | .remove = __devexit_p(nozomi_card_exit), | ||
1931 | }; | ||
1932 | |||
1933 | static __init int nozomi_init(void) | ||
1934 | { | ||
1935 | int ret; | ||
1936 | |||
1937 | printk(KERN_INFO "Initializing %s\n", VERSION_STRING); | ||
1938 | |||
1939 | ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); | ||
1940 | if (!ntty_driver) | ||
1941 | return -ENOMEM; | ||
1942 | |||
1943 | ntty_driver->owner = THIS_MODULE; | ||
1944 | ntty_driver->driver_name = NOZOMI_NAME_TTY; | ||
1945 | ntty_driver->name = "noz"; | ||
1946 | ntty_driver->major = 0; | ||
1947 | ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
1948 | ntty_driver->subtype = SERIAL_TYPE_NORMAL; | ||
1949 | ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
1950 | ntty_driver->init_termios = tty_std_termios; | ||
1951 | ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ | ||
1952 | HUPCL | CLOCAL; | ||
1953 | ntty_driver->init_termios.c_ispeed = 115200; | ||
1954 | ntty_driver->init_termios.c_ospeed = 115200; | ||
1955 | tty_set_operations(ntty_driver, &tty_ops); | ||
1956 | |||
1957 | ret = tty_register_driver(ntty_driver); | ||
1958 | if (ret) { | ||
1959 | printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); | ||
1960 | goto free_tty; | ||
1961 | } | ||
1962 | |||
1963 | ret = pci_register_driver(&nozomi_driver); | ||
1964 | if (ret) { | ||
1965 | printk(KERN_ERR "Nozomi: can't register pci driver\n"); | ||
1966 | goto unr_tty; | ||
1967 | } | ||
1968 | |||
1969 | return 0; | ||
1970 | unr_tty: | ||
1971 | tty_unregister_driver(ntty_driver); | ||
1972 | free_tty: | ||
1973 | put_tty_driver(ntty_driver); | ||
1974 | return ret; | ||
1975 | } | ||
1976 | |||
1977 | static __exit void nozomi_exit(void) | ||
1978 | { | ||
1979 | printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); | ||
1980 | pci_unregister_driver(&nozomi_driver); | ||
1981 | tty_unregister_driver(ntty_driver); | ||
1982 | put_tty_driver(ntty_driver); | ||
1983 | } | ||
1984 | |||
1985 | module_init(nozomi_init); | ||
1986 | module_exit(nozomi_exit); | ||
1987 | |||
1988 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
1989 | |||
1990 | MODULE_LICENSE("Dual BSD/GPL"); | ||
1991 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 923a48585501..210774726add 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/major.h> | 23 | #include <linux/major.h> |
24 | #include <linux/mm.h> | 24 | #include <linux/mm.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/smp_lock.h> | ||
27 | #include <linux/sysctl.h> | 26 | #include <linux/sysctl.h> |
28 | #include <linux/device.h> | 27 | #include <linux/device.h> |
29 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
@@ -334,7 +333,7 @@ free_mem_out: | |||
334 | return -ENOMEM; | 333 | return -ENOMEM; |
335 | } | 334 | } |
336 | 335 | ||
337 | static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, | 336 | static int pty_bsd_ioctl(struct tty_struct *tty, |
338 | unsigned int cmd, unsigned long arg) | 337 | unsigned int cmd, unsigned long arg) |
339 | { | 338 | { |
340 | switch (cmd) { | 339 | switch (cmd) { |
@@ -489,7 +488,7 @@ static struct ctl_table pty_root_table[] = { | |||
489 | }; | 488 | }; |
490 | 489 | ||
491 | 490 | ||
492 | static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, | 491 | static int pty_unix98_ioctl(struct tty_struct *tty, |
493 | unsigned int cmd, unsigned long arg) | 492 | unsigned int cmd, unsigned long arg) |
494 | { | 493 | { |
495 | switch (cmd) { | 494 | switch (cmd) { |
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c new file mode 100644 index 000000000000..3780da8ad12d --- /dev/null +++ b/drivers/tty/rocket.c | |||
@@ -0,0 +1,3199 @@ | |||
1 | /* | ||
2 | * RocketPort device driver for Linux | ||
3 | * | ||
4 | * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. | ||
5 | * | ||
6 | * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of the | ||
11 | * License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Kernel Synchronization: | ||
25 | * | ||
26 | * This driver has 2 kernel control paths - exception handlers (calls into the driver | ||
27 | * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts | ||
28 | * are not used. | ||
29 | * | ||
30 | * Critical data: | ||
31 | * - rp_table[], accessed through passed "info" pointers, is a global (static) array of | ||
32 | * serial port state information and the xmit_buf circular buffer. Protected by | ||
33 | * a per port spinlock. | ||
34 | * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there | ||
35 | * is data to be transmitted. Protected by atomic bit operations. | ||
36 | * - rp_num_ports, int indicating number of open ports, protected by atomic operations. | ||
37 | * | ||
38 | * rp_write() and rp_write_char() functions use a per port semaphore to protect against | ||
39 | * simultaneous access to the same port by more than one process. | ||
40 | */ | ||
41 | |||
42 | /****** Defines ******/ | ||
43 | #define ROCKET_PARANOIA_CHECK | ||
44 | #define ROCKET_DISABLE_SIMUSAGE | ||
45 | |||
46 | #undef ROCKET_SOFT_FLOW | ||
47 | #undef ROCKET_DEBUG_OPEN | ||
48 | #undef ROCKET_DEBUG_INTR | ||
49 | #undef ROCKET_DEBUG_WRITE | ||
50 | #undef ROCKET_DEBUG_FLOW | ||
51 | #undef ROCKET_DEBUG_THROTTLE | ||
52 | #undef ROCKET_DEBUG_WAIT_UNTIL_SENT | ||
53 | #undef ROCKET_DEBUG_RECEIVE | ||
54 | #undef ROCKET_DEBUG_HANGUP | ||
55 | #undef REV_PCI_ORDER | ||
56 | #undef ROCKET_DEBUG_IO | ||
57 | |||
58 | #define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */ | ||
59 | |||
60 | /****** Kernel includes ******/ | ||
61 | |||
62 | #include <linux/module.h> | ||
63 | #include <linux/errno.h> | ||
64 | #include <linux/major.h> | ||
65 | #include <linux/kernel.h> | ||
66 | #include <linux/signal.h> | ||
67 | #include <linux/slab.h> | ||
68 | #include <linux/mm.h> | ||
69 | #include <linux/sched.h> | ||
70 | #include <linux/timer.h> | ||
71 | #include <linux/interrupt.h> | ||
72 | #include <linux/tty.h> | ||
73 | #include <linux/tty_driver.h> | ||
74 | #include <linux/tty_flip.h> | ||
75 | #include <linux/serial.h> | ||
76 | #include <linux/string.h> | ||
77 | #include <linux/fcntl.h> | ||
78 | #include <linux/ptrace.h> | ||
79 | #include <linux/mutex.h> | ||
80 | #include <linux/ioport.h> | ||
81 | #include <linux/delay.h> | ||
82 | #include <linux/completion.h> | ||
83 | #include <linux/wait.h> | ||
84 | #include <linux/pci.h> | ||
85 | #include <linux/uaccess.h> | ||
86 | #include <asm/atomic.h> | ||
87 | #include <asm/unaligned.h> | ||
88 | #include <linux/bitops.h> | ||
89 | #include <linux/spinlock.h> | ||
90 | #include <linux/init.h> | ||
91 | |||
92 | /****** RocketPort includes ******/ | ||
93 | |||
94 | #include "rocket_int.h" | ||
95 | #include "rocket.h" | ||
96 | |||
97 | #define ROCKET_VERSION "2.09" | ||
98 | #define ROCKET_DATE "12-June-2003" | ||
99 | |||
100 | /****** RocketPort Local Variables ******/ | ||
101 | |||
102 | static void rp_do_poll(unsigned long dummy); | ||
103 | |||
104 | static struct tty_driver *rocket_driver; | ||
105 | |||
106 | static struct rocket_version driver_version = { | ||
107 | ROCKET_VERSION, ROCKET_DATE | ||
108 | }; | ||
109 | |||
110 | static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ | ||
111 | static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ | ||
112 | /* eg. Bit 0 indicates port 0 has xmit data, ... */ | ||
113 | static atomic_t rp_num_ports_open; /* Number of serial ports open */ | ||
114 | static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0); | ||
115 | |||
116 | static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ | ||
117 | static unsigned long board2; | ||
118 | static unsigned long board3; | ||
119 | static unsigned long board4; | ||
120 | static unsigned long controller; | ||
121 | static int support_low_speed; | ||
122 | static unsigned long modem1; | ||
123 | static unsigned long modem2; | ||
124 | static unsigned long modem3; | ||
125 | static unsigned long modem4; | ||
126 | static unsigned long pc104_1[8]; | ||
127 | static unsigned long pc104_2[8]; | ||
128 | static unsigned long pc104_3[8]; | ||
129 | static unsigned long pc104_4[8]; | ||
130 | static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; | ||
131 | |||
132 | static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ | ||
133 | static unsigned long rcktpt_io_addr[NUM_BOARDS]; | ||
134 | static int rcktpt_type[NUM_BOARDS]; | ||
135 | static int is_PCI[NUM_BOARDS]; | ||
136 | static rocketModel_t rocketModel[NUM_BOARDS]; | ||
137 | static int max_board; | ||
138 | static const struct tty_port_operations rocket_port_ops; | ||
139 | |||
140 | /* | ||
141 | * The following arrays define the interrupt bits corresponding to each AIOP. | ||
142 | * These bits are different between the ISA and regular PCI boards and the | ||
143 | * Universal PCI boards. | ||
144 | */ | ||
145 | |||
146 | static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { | ||
147 | AIOP_INTR_BIT_0, | ||
148 | AIOP_INTR_BIT_1, | ||
149 | AIOP_INTR_BIT_2, | ||
150 | AIOP_INTR_BIT_3 | ||
151 | }; | ||
152 | |||
153 | static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { | ||
154 | UPCI_AIOP_INTR_BIT_0, | ||
155 | UPCI_AIOP_INTR_BIT_1, | ||
156 | UPCI_AIOP_INTR_BIT_2, | ||
157 | UPCI_AIOP_INTR_BIT_3 | ||
158 | }; | ||
159 | |||
160 | static Byte_t RData[RDATASIZE] = { | ||
161 | 0x00, 0x09, 0xf6, 0x82, | ||
162 | 0x02, 0x09, 0x86, 0xfb, | ||
163 | 0x04, 0x09, 0x00, 0x0a, | ||
164 | 0x06, 0x09, 0x01, 0x0a, | ||
165 | 0x08, 0x09, 0x8a, 0x13, | ||
166 | 0x0a, 0x09, 0xc5, 0x11, | ||
167 | 0x0c, 0x09, 0x86, 0x85, | ||
168 | 0x0e, 0x09, 0x20, 0x0a, | ||
169 | 0x10, 0x09, 0x21, 0x0a, | ||
170 | 0x12, 0x09, 0x41, 0xff, | ||
171 | 0x14, 0x09, 0x82, 0x00, | ||
172 | 0x16, 0x09, 0x82, 0x7b, | ||
173 | 0x18, 0x09, 0x8a, 0x7d, | ||
174 | 0x1a, 0x09, 0x88, 0x81, | ||
175 | 0x1c, 0x09, 0x86, 0x7a, | ||
176 | 0x1e, 0x09, 0x84, 0x81, | ||
177 | 0x20, 0x09, 0x82, 0x7c, | ||
178 | 0x22, 0x09, 0x0a, 0x0a | ||
179 | }; | ||
180 | |||
181 | static Byte_t RRegData[RREGDATASIZE] = { | ||
182 | 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ | ||
183 | 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ | ||
184 | 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ | ||
185 | 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ | ||
186 | 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ | ||
187 | 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ | ||
188 | 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ | ||
189 | 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ | ||
190 | 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ | ||
191 | 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ | ||
192 | 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ | ||
193 | 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ | ||
194 | 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ | ||
195 | }; | ||
196 | |||
197 | static CONTROLLER_T sController[CTL_SIZE] = { | ||
198 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
199 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
200 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
201 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
202 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
203 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, | ||
204 | {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, | ||
205 | {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} | ||
206 | }; | ||
207 | |||
208 | static Byte_t sBitMapClrTbl[8] = { | ||
209 | 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f | ||
210 | }; | ||
211 | |||
212 | static Byte_t sBitMapSetTbl[8] = { | ||
213 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 | ||
214 | }; | ||
215 | |||
216 | static int sClockPrescale = 0x14; | ||
217 | |||
218 | /* | ||
219 | * Line number is the ttySIx number (x), the Minor number. We | ||
220 | * assign them sequentially, starting at zero. The following | ||
221 | * array keeps track of the line number assigned to a given board/aiop/channel. | ||
222 | */ | ||
223 | static unsigned char lineNumbers[MAX_RP_PORTS]; | ||
224 | static unsigned long nextLineNumber; | ||
225 | |||
226 | /***** RocketPort Static Prototypes *********/ | ||
227 | static int __init init_ISA(int i); | ||
228 | static void rp_wait_until_sent(struct tty_struct *tty, int timeout); | ||
229 | static void rp_flush_buffer(struct tty_struct *tty); | ||
230 | static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); | ||
231 | static unsigned char GetLineNumber(int ctrl, int aiop, int ch); | ||
232 | static unsigned char SetLineNumber(int ctrl, int aiop, int ch); | ||
233 | static void rp_start(struct tty_struct *tty); | ||
234 | static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | ||
235 | int ChanNum); | ||
236 | static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); | ||
237 | static void sFlushRxFIFO(CHANNEL_T * ChP); | ||
238 | static void sFlushTxFIFO(CHANNEL_T * ChP); | ||
239 | static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
240 | static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); | ||
241 | static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
242 | static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); | ||
243 | static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); | ||
244 | static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, | ||
245 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
246 | WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, | ||
247 | int PeriodicOnly, int altChanRingIndicator, | ||
248 | int UPCIRingInd); | ||
249 | static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, | ||
250 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
251 | int IRQNum, Byte_t Frequency, int PeriodicOnly); | ||
252 | static int sReadAiopID(ByteIO_t io); | ||
253 | static int sReadAiopNumChan(WordIO_t io); | ||
254 | |||
255 | MODULE_AUTHOR("Theodore Ts'o"); | ||
256 | MODULE_DESCRIPTION("Comtrol RocketPort driver"); | ||
257 | module_param(board1, ulong, 0); | ||
258 | MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); | ||
259 | module_param(board2, ulong, 0); | ||
260 | MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); | ||
261 | module_param(board3, ulong, 0); | ||
262 | MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); | ||
263 | module_param(board4, ulong, 0); | ||
264 | MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); | ||
265 | module_param(controller, ulong, 0); | ||
266 | MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); | ||
267 | module_param(support_low_speed, bool, 0); | ||
268 | MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); | ||
269 | module_param(modem1, ulong, 0); | ||
270 | MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); | ||
271 | module_param(modem2, ulong, 0); | ||
272 | MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); | ||
273 | module_param(modem3, ulong, 0); | ||
274 | MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); | ||
275 | module_param(modem4, ulong, 0); | ||
276 | MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); | ||
277 | module_param_array(pc104_1, ulong, NULL, 0); | ||
278 | MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); | ||
279 | module_param_array(pc104_2, ulong, NULL, 0); | ||
280 | MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); | ||
281 | module_param_array(pc104_3, ulong, NULL, 0); | ||
282 | MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); | ||
283 | module_param_array(pc104_4, ulong, NULL, 0); | ||
284 | MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); | ||
285 | |||
286 | static int rp_init(void); | ||
287 | static void rp_cleanup_module(void); | ||
288 | |||
289 | module_init(rp_init); | ||
290 | module_exit(rp_cleanup_module); | ||
291 | |||
292 | |||
293 | MODULE_LICENSE("Dual BSD/GPL"); | ||
294 | |||
295 | /*************************************************************************/ | ||
296 | /* Module code starts here */ | ||
297 | |||
298 | static inline int rocket_paranoia_check(struct r_port *info, | ||
299 | const char *routine) | ||
300 | { | ||
301 | #ifdef ROCKET_PARANOIA_CHECK | ||
302 | if (!info) | ||
303 | return 1; | ||
304 | if (info->magic != RPORT_MAGIC) { | ||
305 | printk(KERN_WARNING "Warning: bad magic number for rocketport " | ||
306 | "struct in %s\n", routine); | ||
307 | return 1; | ||
308 | } | ||
309 | #endif | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | |||
314 | /* Serial port receive data function. Called (from timer poll) when an AIOPIC signals | ||
315 | * that receive data is present on a serial port. Pulls data from FIFO, moves it into the | ||
316 | * tty layer. | ||
317 | */ | ||
318 | static void rp_do_receive(struct r_port *info, | ||
319 | struct tty_struct *tty, | ||
320 | CHANNEL_t * cp, unsigned int ChanStatus) | ||
321 | { | ||
322 | unsigned int CharNStat; | ||
323 | int ToRecv, wRecv, space; | ||
324 | unsigned char *cbuf; | ||
325 | |||
326 | ToRecv = sGetRxCnt(cp); | ||
327 | #ifdef ROCKET_DEBUG_INTR | ||
328 | printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv); | ||
329 | #endif | ||
330 | if (ToRecv == 0) | ||
331 | return; | ||
332 | |||
333 | /* | ||
334 | * if status indicates there are errored characters in the | ||
335 | * FIFO, then enter status mode (a word in FIFO holds | ||
336 | * character and status). | ||
337 | */ | ||
338 | if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { | ||
339 | if (!(ChanStatus & STATMODE)) { | ||
340 | #ifdef ROCKET_DEBUG_RECEIVE | ||
341 | printk(KERN_INFO "Entering STATMODE...\n"); | ||
342 | #endif | ||
343 | ChanStatus |= STATMODE; | ||
344 | sEnRxStatusMode(cp); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * if we previously entered status mode, then read down the | ||
350 | * FIFO one word at a time, pulling apart the character and | ||
351 | * the status. Update error counters depending on status | ||
352 | */ | ||
353 | if (ChanStatus & STATMODE) { | ||
354 | #ifdef ROCKET_DEBUG_RECEIVE | ||
355 | printk(KERN_INFO "Ignore %x, read %x...\n", | ||
356 | info->ignore_status_mask, info->read_status_mask); | ||
357 | #endif | ||
358 | while (ToRecv) { | ||
359 | char flag; | ||
360 | |||
361 | CharNStat = sInW(sGetTxRxDataIO(cp)); | ||
362 | #ifdef ROCKET_DEBUG_RECEIVE | ||
363 | printk(KERN_INFO "%x...\n", CharNStat); | ||
364 | #endif | ||
365 | if (CharNStat & STMBREAKH) | ||
366 | CharNStat &= ~(STMFRAMEH | STMPARITYH); | ||
367 | if (CharNStat & info->ignore_status_mask) { | ||
368 | ToRecv--; | ||
369 | continue; | ||
370 | } | ||
371 | CharNStat &= info->read_status_mask; | ||
372 | if (CharNStat & STMBREAKH) | ||
373 | flag = TTY_BREAK; | ||
374 | else if (CharNStat & STMPARITYH) | ||
375 | flag = TTY_PARITY; | ||
376 | else if (CharNStat & STMFRAMEH) | ||
377 | flag = TTY_FRAME; | ||
378 | else if (CharNStat & STMRCVROVRH) | ||
379 | flag = TTY_OVERRUN; | ||
380 | else | ||
381 | flag = TTY_NORMAL; | ||
382 | tty_insert_flip_char(tty, CharNStat & 0xff, flag); | ||
383 | ToRecv--; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * after we've emptied the FIFO in status mode, turn | ||
388 | * status mode back off | ||
389 | */ | ||
390 | if (sGetRxCnt(cp) == 0) { | ||
391 | #ifdef ROCKET_DEBUG_RECEIVE | ||
392 | printk(KERN_INFO "Status mode off.\n"); | ||
393 | #endif | ||
394 | sDisRxStatusMode(cp); | ||
395 | } | ||
396 | } else { | ||
397 | /* | ||
398 | * we aren't in status mode, so read down the FIFO two | ||
399 | * characters at time by doing repeated word IO | ||
400 | * transfer. | ||
401 | */ | ||
402 | space = tty_prepare_flip_string(tty, &cbuf, ToRecv); | ||
403 | if (space < ToRecv) { | ||
404 | #ifdef ROCKET_DEBUG_RECEIVE | ||
405 | printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space); | ||
406 | #endif | ||
407 | if (space <= 0) | ||
408 | return; | ||
409 | ToRecv = space; | ||
410 | } | ||
411 | wRecv = ToRecv >> 1; | ||
412 | if (wRecv) | ||
413 | sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); | ||
414 | if (ToRecv & 1) | ||
415 | cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); | ||
416 | } | ||
417 | /* Push the data up to the tty layer */ | ||
418 | tty_flip_buffer_push(tty); | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Serial port transmit data function. Called from the timer polling loop as a | ||
423 | * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready | ||
424 | * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is | ||
425 | * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. | ||
426 | */ | ||
427 | static void rp_do_transmit(struct r_port *info) | ||
428 | { | ||
429 | int c; | ||
430 | CHANNEL_t *cp = &info->channel; | ||
431 | struct tty_struct *tty; | ||
432 | unsigned long flags; | ||
433 | |||
434 | #ifdef ROCKET_DEBUG_INTR | ||
435 | printk(KERN_DEBUG "%s\n", __func__); | ||
436 | #endif | ||
437 | if (!info) | ||
438 | return; | ||
439 | tty = tty_port_tty_get(&info->port); | ||
440 | |||
441 | if (tty == NULL) { | ||
442 | printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__); | ||
443 | clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
444 | return; | ||
445 | } | ||
446 | |||
447 | spin_lock_irqsave(&info->slock, flags); | ||
448 | info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); | ||
449 | |||
450 | /* Loop sending data to FIFO until done or FIFO full */ | ||
451 | while (1) { | ||
452 | if (tty->stopped || tty->hw_stopped) | ||
453 | break; | ||
454 | c = min(info->xmit_fifo_room, info->xmit_cnt); | ||
455 | c = min(c, XMIT_BUF_SIZE - info->xmit_tail); | ||
456 | if (c <= 0 || info->xmit_fifo_room <= 0) | ||
457 | break; | ||
458 | sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); | ||
459 | if (c & 1) | ||
460 | sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); | ||
461 | info->xmit_tail += c; | ||
462 | info->xmit_tail &= XMIT_BUF_SIZE - 1; | ||
463 | info->xmit_cnt -= c; | ||
464 | info->xmit_fifo_room -= c; | ||
465 | #ifdef ROCKET_DEBUG_INTR | ||
466 | printk(KERN_INFO "tx %d chars...\n", c); | ||
467 | #endif | ||
468 | } | ||
469 | |||
470 | if (info->xmit_cnt == 0) | ||
471 | clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
472 | |||
473 | if (info->xmit_cnt < WAKEUP_CHARS) { | ||
474 | tty_wakeup(tty); | ||
475 | #ifdef ROCKETPORT_HAVE_POLL_WAIT | ||
476 | wake_up_interruptible(&tty->poll_wait); | ||
477 | #endif | ||
478 | } | ||
479 | |||
480 | spin_unlock_irqrestore(&info->slock, flags); | ||
481 | tty_kref_put(tty); | ||
482 | |||
483 | #ifdef ROCKET_DEBUG_INTR | ||
484 | printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head, | ||
485 | info->xmit_tail, info->xmit_fifo_room); | ||
486 | #endif | ||
487 | } | ||
488 | |||
489 | /* | ||
490 | * Called when a serial port signals it has read data in it's RX FIFO. | ||
491 | * It checks what interrupts are pending and services them, including | ||
492 | * receiving serial data. | ||
493 | */ | ||
494 | static void rp_handle_port(struct r_port *info) | ||
495 | { | ||
496 | CHANNEL_t *cp; | ||
497 | struct tty_struct *tty; | ||
498 | unsigned int IntMask, ChanStatus; | ||
499 | |||
500 | if (!info) | ||
501 | return; | ||
502 | |||
503 | if ((info->port.flags & ASYNC_INITIALIZED) == 0) { | ||
504 | printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " | ||
505 | "info->flags & NOT_INIT\n"); | ||
506 | return; | ||
507 | } | ||
508 | tty = tty_port_tty_get(&info->port); | ||
509 | if (!tty) { | ||
510 | printk(KERN_WARNING "rp: WARNING: rp_handle_port called with " | ||
511 | "tty==NULL\n"); | ||
512 | return; | ||
513 | } | ||
514 | cp = &info->channel; | ||
515 | |||
516 | IntMask = sGetChanIntID(cp) & info->intmask; | ||
517 | #ifdef ROCKET_DEBUG_INTR | ||
518 | printk(KERN_INFO "rp_interrupt %02x...\n", IntMask); | ||
519 | #endif | ||
520 | ChanStatus = sGetChanStatus(cp); | ||
521 | if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ | ||
522 | rp_do_receive(info, tty, cp, ChanStatus); | ||
523 | } | ||
524 | if (IntMask & DELTA_CD) { /* CD change */ | ||
525 | #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) | ||
526 | printk(KERN_INFO "ttyR%d CD now %s...\n", info->line, | ||
527 | (ChanStatus & CD_ACT) ? "on" : "off"); | ||
528 | #endif | ||
529 | if (!(ChanStatus & CD_ACT) && info->cd_status) { | ||
530 | #ifdef ROCKET_DEBUG_HANGUP | ||
531 | printk(KERN_INFO "CD drop, calling hangup.\n"); | ||
532 | #endif | ||
533 | tty_hangup(tty); | ||
534 | } | ||
535 | info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0; | ||
536 | wake_up_interruptible(&info->port.open_wait); | ||
537 | } | ||
538 | #ifdef ROCKET_DEBUG_INTR | ||
539 | if (IntMask & DELTA_CTS) { /* CTS change */ | ||
540 | printk(KERN_INFO "CTS change...\n"); | ||
541 | } | ||
542 | if (IntMask & DELTA_DSR) { /* DSR change */ | ||
543 | printk(KERN_INFO "DSR change...\n"); | ||
544 | } | ||
545 | #endif | ||
546 | tty_kref_put(tty); | ||
547 | } | ||
548 | |||
549 | /* | ||
550 | * The top level polling routine. Repeats every 1/100 HZ (10ms). | ||
551 | */ | ||
552 | static void rp_do_poll(unsigned long dummy) | ||
553 | { | ||
554 | CONTROLLER_t *ctlp; | ||
555 | int ctrl, aiop, ch, line; | ||
556 | unsigned int xmitmask, i; | ||
557 | unsigned int CtlMask; | ||
558 | unsigned char AiopMask; | ||
559 | Word_t bit; | ||
560 | |||
561 | /* Walk through all the boards (ctrl's) */ | ||
562 | for (ctrl = 0; ctrl < max_board; ctrl++) { | ||
563 | if (rcktpt_io_addr[ctrl] <= 0) | ||
564 | continue; | ||
565 | |||
566 | /* Get a ptr to the board's control struct */ | ||
567 | ctlp = sCtlNumToCtlPtr(ctrl); | ||
568 | |||
569 | /* Get the interrupt status from the board */ | ||
570 | #ifdef CONFIG_PCI | ||
571 | if (ctlp->BusType == isPCI) | ||
572 | CtlMask = sPCIGetControllerIntStatus(ctlp); | ||
573 | else | ||
574 | #endif | ||
575 | CtlMask = sGetControllerIntStatus(ctlp); | ||
576 | |||
577 | /* Check if any AIOP read bits are set */ | ||
578 | for (aiop = 0; CtlMask; aiop++) { | ||
579 | bit = ctlp->AiopIntrBits[aiop]; | ||
580 | if (CtlMask & bit) { | ||
581 | CtlMask &= ~bit; | ||
582 | AiopMask = sGetAiopIntStatus(ctlp, aiop); | ||
583 | |||
584 | /* Check if any port read bits are set */ | ||
585 | for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { | ||
586 | if (AiopMask & 1) { | ||
587 | |||
588 | /* Get the line number (/dev/ttyRx number). */ | ||
589 | /* Read the data from the port. */ | ||
590 | line = GetLineNumber(ctrl, aiop, ch); | ||
591 | rp_handle_port(rp_table[line]); | ||
592 | } | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | |||
597 | xmitmask = xmit_flags[ctrl]; | ||
598 | |||
599 | /* | ||
600 | * xmit_flags contains bit-significant flags, indicating there is data | ||
601 | * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port | ||
602 | * 1, ... (32 total possible). The variable i has the aiop and ch | ||
603 | * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). | ||
604 | */ | ||
605 | if (xmitmask) { | ||
606 | for (i = 0; i < rocketModel[ctrl].numPorts; i++) { | ||
607 | if (xmitmask & (1 << i)) { | ||
608 | aiop = (i & 0x18) >> 3; | ||
609 | ch = i & 0x07; | ||
610 | line = GetLineNumber(ctrl, aiop, ch); | ||
611 | rp_do_transmit(rp_table[line]); | ||
612 | } | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | * Reset the timer so we get called at the next clock tick (10ms). | ||
619 | */ | ||
620 | if (atomic_read(&rp_num_ports_open)) | ||
621 | mod_timer(&rocket_timer, jiffies + POLL_PERIOD); | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * Initializes the r_port structure for a port, as well as enabling the port on | ||
626 | * the board. | ||
627 | * Inputs: board, aiop, chan numbers | ||
628 | */ | ||
629 | static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) | ||
630 | { | ||
631 | unsigned rocketMode; | ||
632 | struct r_port *info; | ||
633 | int line; | ||
634 | CONTROLLER_T *ctlp; | ||
635 | |||
636 | /* Get the next available line number */ | ||
637 | line = SetLineNumber(board, aiop, chan); | ||
638 | |||
639 | ctlp = sCtlNumToCtlPtr(board); | ||
640 | |||
641 | /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ | ||
642 | info = kzalloc(sizeof (struct r_port), GFP_KERNEL); | ||
643 | if (!info) { | ||
644 | printk(KERN_ERR "Couldn't allocate info struct for line #%d\n", | ||
645 | line); | ||
646 | return; | ||
647 | } | ||
648 | |||
649 | info->magic = RPORT_MAGIC; | ||
650 | info->line = line; | ||
651 | info->ctlp = ctlp; | ||
652 | info->board = board; | ||
653 | info->aiop = aiop; | ||
654 | info->chan = chan; | ||
655 | tty_port_init(&info->port); | ||
656 | info->port.ops = &rocket_port_ops; | ||
657 | init_completion(&info->close_wait); | ||
658 | info->flags &= ~ROCKET_MODE_MASK; | ||
659 | switch (pc104[board][line]) { | ||
660 | case 422: | ||
661 | info->flags |= ROCKET_MODE_RS422; | ||
662 | break; | ||
663 | case 485: | ||
664 | info->flags |= ROCKET_MODE_RS485; | ||
665 | break; | ||
666 | case 232: | ||
667 | default: | ||
668 | info->flags |= ROCKET_MODE_RS232; | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; | ||
673 | if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { | ||
674 | printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n", | ||
675 | board, aiop, chan); | ||
676 | kfree(info); | ||
677 | return; | ||
678 | } | ||
679 | |||
680 | rocketMode = info->flags & ROCKET_MODE_MASK; | ||
681 | |||
682 | if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) | ||
683 | sEnRTSToggle(&info->channel); | ||
684 | else | ||
685 | sDisRTSToggle(&info->channel); | ||
686 | |||
687 | if (ctlp->boardType == ROCKET_TYPE_PC104) { | ||
688 | switch (rocketMode) { | ||
689 | case ROCKET_MODE_RS485: | ||
690 | sSetInterfaceMode(&info->channel, InterfaceModeRS485); | ||
691 | break; | ||
692 | case ROCKET_MODE_RS422: | ||
693 | sSetInterfaceMode(&info->channel, InterfaceModeRS422); | ||
694 | break; | ||
695 | case ROCKET_MODE_RS232: | ||
696 | default: | ||
697 | if (info->flags & ROCKET_RTS_TOGGLE) | ||
698 | sSetInterfaceMode(&info->channel, InterfaceModeRS232T); | ||
699 | else | ||
700 | sSetInterfaceMode(&info->channel, InterfaceModeRS232); | ||
701 | break; | ||
702 | } | ||
703 | } | ||
704 | spin_lock_init(&info->slock); | ||
705 | mutex_init(&info->write_mtx); | ||
706 | rp_table[line] = info; | ||
707 | tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev : | ||
708 | NULL); | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * Configures a rocketport port according to its termio settings. Called from | ||
713 | * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. | ||
714 | */ | ||
715 | static void configure_r_port(struct tty_struct *tty, struct r_port *info, | ||
716 | struct ktermios *old_termios) | ||
717 | { | ||
718 | unsigned cflag; | ||
719 | unsigned long flags; | ||
720 | unsigned rocketMode; | ||
721 | int bits, baud, divisor; | ||
722 | CHANNEL_t *cp; | ||
723 | struct ktermios *t = tty->termios; | ||
724 | |||
725 | cp = &info->channel; | ||
726 | cflag = t->c_cflag; | ||
727 | |||
728 | /* Byte size and parity */ | ||
729 | if ((cflag & CSIZE) == CS8) { | ||
730 | sSetData8(cp); | ||
731 | bits = 10; | ||
732 | } else { | ||
733 | sSetData7(cp); | ||
734 | bits = 9; | ||
735 | } | ||
736 | if (cflag & CSTOPB) { | ||
737 | sSetStop2(cp); | ||
738 | bits++; | ||
739 | } else { | ||
740 | sSetStop1(cp); | ||
741 | } | ||
742 | |||
743 | if (cflag & PARENB) { | ||
744 | sEnParity(cp); | ||
745 | bits++; | ||
746 | if (cflag & PARODD) { | ||
747 | sSetOddParity(cp); | ||
748 | } else { | ||
749 | sSetEvenParity(cp); | ||
750 | } | ||
751 | } else { | ||
752 | sDisParity(cp); | ||
753 | } | ||
754 | |||
755 | /* baud rate */ | ||
756 | baud = tty_get_baud_rate(tty); | ||
757 | if (!baud) | ||
758 | baud = 9600; | ||
759 | divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; | ||
760 | if ((divisor >= 8192 || divisor < 0) && old_termios) { | ||
761 | baud = tty_termios_baud_rate(old_termios); | ||
762 | if (!baud) | ||
763 | baud = 9600; | ||
764 | divisor = (rp_baud_base[info->board] / baud) - 1; | ||
765 | } | ||
766 | if (divisor >= 8192 || divisor < 0) { | ||
767 | baud = 9600; | ||
768 | divisor = (rp_baud_base[info->board] / baud) - 1; | ||
769 | } | ||
770 | info->cps = baud / bits; | ||
771 | sSetBaud(cp, divisor); | ||
772 | |||
773 | /* FIXME: Should really back compute a baud rate from the divisor */ | ||
774 | tty_encode_baud_rate(tty, baud, baud); | ||
775 | |||
776 | if (cflag & CRTSCTS) { | ||
777 | info->intmask |= DELTA_CTS; | ||
778 | sEnCTSFlowCtl(cp); | ||
779 | } else { | ||
780 | info->intmask &= ~DELTA_CTS; | ||
781 | sDisCTSFlowCtl(cp); | ||
782 | } | ||
783 | if (cflag & CLOCAL) { | ||
784 | info->intmask &= ~DELTA_CD; | ||
785 | } else { | ||
786 | spin_lock_irqsave(&info->slock, flags); | ||
787 | if (sGetChanStatus(cp) & CD_ACT) | ||
788 | info->cd_status = 1; | ||
789 | else | ||
790 | info->cd_status = 0; | ||
791 | info->intmask |= DELTA_CD; | ||
792 | spin_unlock_irqrestore(&info->slock, flags); | ||
793 | } | ||
794 | |||
795 | /* | ||
796 | * Handle software flow control in the board | ||
797 | */ | ||
798 | #ifdef ROCKET_SOFT_FLOW | ||
799 | if (I_IXON(tty)) { | ||
800 | sEnTxSoftFlowCtl(cp); | ||
801 | if (I_IXANY(tty)) { | ||
802 | sEnIXANY(cp); | ||
803 | } else { | ||
804 | sDisIXANY(cp); | ||
805 | } | ||
806 | sSetTxXONChar(cp, START_CHAR(tty)); | ||
807 | sSetTxXOFFChar(cp, STOP_CHAR(tty)); | ||
808 | } else { | ||
809 | sDisTxSoftFlowCtl(cp); | ||
810 | sDisIXANY(cp); | ||
811 | sClrTxXOFF(cp); | ||
812 | } | ||
813 | #endif | ||
814 | |||
815 | /* | ||
816 | * Set up ignore/read mask words | ||
817 | */ | ||
818 | info->read_status_mask = STMRCVROVRH | 0xFF; | ||
819 | if (I_INPCK(tty)) | ||
820 | info->read_status_mask |= STMFRAMEH | STMPARITYH; | ||
821 | if (I_BRKINT(tty) || I_PARMRK(tty)) | ||
822 | info->read_status_mask |= STMBREAKH; | ||
823 | |||
824 | /* | ||
825 | * Characters to ignore | ||
826 | */ | ||
827 | info->ignore_status_mask = 0; | ||
828 | if (I_IGNPAR(tty)) | ||
829 | info->ignore_status_mask |= STMFRAMEH | STMPARITYH; | ||
830 | if (I_IGNBRK(tty)) { | ||
831 | info->ignore_status_mask |= STMBREAKH; | ||
832 | /* | ||
833 | * If we're ignoring parity and break indicators, | ||
834 | * ignore overruns too. (For real raw support). | ||
835 | */ | ||
836 | if (I_IGNPAR(tty)) | ||
837 | info->ignore_status_mask |= STMRCVROVRH; | ||
838 | } | ||
839 | |||
840 | rocketMode = info->flags & ROCKET_MODE_MASK; | ||
841 | |||
842 | if ((info->flags & ROCKET_RTS_TOGGLE) | ||
843 | || (rocketMode == ROCKET_MODE_RS485)) | ||
844 | sEnRTSToggle(cp); | ||
845 | else | ||
846 | sDisRTSToggle(cp); | ||
847 | |||
848 | sSetRTS(&info->channel); | ||
849 | |||
850 | if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { | ||
851 | switch (rocketMode) { | ||
852 | case ROCKET_MODE_RS485: | ||
853 | sSetInterfaceMode(cp, InterfaceModeRS485); | ||
854 | break; | ||
855 | case ROCKET_MODE_RS422: | ||
856 | sSetInterfaceMode(cp, InterfaceModeRS422); | ||
857 | break; | ||
858 | case ROCKET_MODE_RS232: | ||
859 | default: | ||
860 | if (info->flags & ROCKET_RTS_TOGGLE) | ||
861 | sSetInterfaceMode(cp, InterfaceModeRS232T); | ||
862 | else | ||
863 | sSetInterfaceMode(cp, InterfaceModeRS232); | ||
864 | break; | ||
865 | } | ||
866 | } | ||
867 | } | ||
868 | |||
869 | static int carrier_raised(struct tty_port *port) | ||
870 | { | ||
871 | struct r_port *info = container_of(port, struct r_port, port); | ||
872 | return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; | ||
873 | } | ||
874 | |||
875 | static void dtr_rts(struct tty_port *port, int on) | ||
876 | { | ||
877 | struct r_port *info = container_of(port, struct r_port, port); | ||
878 | if (on) { | ||
879 | sSetDTR(&info->channel); | ||
880 | sSetRTS(&info->channel); | ||
881 | } else { | ||
882 | sClrDTR(&info->channel); | ||
883 | sClrRTS(&info->channel); | ||
884 | } | ||
885 | } | ||
886 | |||
887 | /* | ||
888 | * Exception handler that opens a serial port. Creates xmit_buf storage, fills in | ||
889 | * port's r_port struct. Initializes the port hardware. | ||
890 | */ | ||
891 | static int rp_open(struct tty_struct *tty, struct file *filp) | ||
892 | { | ||
893 | struct r_port *info; | ||
894 | struct tty_port *port; | ||
895 | int line = 0, retval; | ||
896 | CHANNEL_t *cp; | ||
897 | unsigned long page; | ||
898 | |||
899 | line = tty->index; | ||
900 | if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL)) | ||
901 | return -ENXIO; | ||
902 | port = &info->port; | ||
903 | |||
904 | page = __get_free_page(GFP_KERNEL); | ||
905 | if (!page) | ||
906 | return -ENOMEM; | ||
907 | |||
908 | if (port->flags & ASYNC_CLOSING) { | ||
909 | retval = wait_for_completion_interruptible(&info->close_wait); | ||
910 | free_page(page); | ||
911 | if (retval) | ||
912 | return retval; | ||
913 | return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); | ||
914 | } | ||
915 | |||
916 | /* | ||
917 | * We must not sleep from here until the port is marked fully in use. | ||
918 | */ | ||
919 | if (info->xmit_buf) | ||
920 | free_page(page); | ||
921 | else | ||
922 | info->xmit_buf = (unsigned char *) page; | ||
923 | |||
924 | tty->driver_data = info; | ||
925 | tty_port_tty_set(port, tty); | ||
926 | |||
927 | if (port->count++ == 0) { | ||
928 | atomic_inc(&rp_num_ports_open); | ||
929 | |||
930 | #ifdef ROCKET_DEBUG_OPEN | ||
931 | printk(KERN_INFO "rocket mod++ = %d...\n", | ||
932 | atomic_read(&rp_num_ports_open)); | ||
933 | #endif | ||
934 | } | ||
935 | #ifdef ROCKET_DEBUG_OPEN | ||
936 | printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count); | ||
937 | #endif | ||
938 | |||
939 | /* | ||
940 | * Info->count is now 1; so it's safe to sleep now. | ||
941 | */ | ||
942 | if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { | ||
943 | cp = &info->channel; | ||
944 | sSetRxTrigger(cp, TRIG_1); | ||
945 | if (sGetChanStatus(cp) & CD_ACT) | ||
946 | info->cd_status = 1; | ||
947 | else | ||
948 | info->cd_status = 0; | ||
949 | sDisRxStatusMode(cp); | ||
950 | sFlushRxFIFO(cp); | ||
951 | sFlushTxFIFO(cp); | ||
952 | |||
953 | sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); | ||
954 | sSetRxTrigger(cp, TRIG_1); | ||
955 | |||
956 | sGetChanStatus(cp); | ||
957 | sDisRxStatusMode(cp); | ||
958 | sClrTxXOFF(cp); | ||
959 | |||
960 | sDisCTSFlowCtl(cp); | ||
961 | sDisTxSoftFlowCtl(cp); | ||
962 | |||
963 | sEnRxFIFO(cp); | ||
964 | sEnTransmit(cp); | ||
965 | |||
966 | set_bit(ASYNCB_INITIALIZED, &info->port.flags); | ||
967 | |||
968 | /* | ||
969 | * Set up the tty->alt_speed kludge | ||
970 | */ | ||
971 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) | ||
972 | tty->alt_speed = 57600; | ||
973 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) | ||
974 | tty->alt_speed = 115200; | ||
975 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) | ||
976 | tty->alt_speed = 230400; | ||
977 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) | ||
978 | tty->alt_speed = 460800; | ||
979 | |||
980 | configure_r_port(tty, info, NULL); | ||
981 | if (tty->termios->c_cflag & CBAUD) { | ||
982 | sSetDTR(cp); | ||
983 | sSetRTS(cp); | ||
984 | } | ||
985 | } | ||
986 | /* Starts (or resets) the maint polling loop */ | ||
987 | mod_timer(&rocket_timer, jiffies + POLL_PERIOD); | ||
988 | |||
989 | retval = tty_port_block_til_ready(port, tty, filp); | ||
990 | if (retval) { | ||
991 | #ifdef ROCKET_DEBUG_OPEN | ||
992 | printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); | ||
993 | #endif | ||
994 | return retval; | ||
995 | } | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | /* | ||
1000 | * Exception handler that closes a serial port. info->port.count is considered critical. | ||
1001 | */ | ||
1002 | static void rp_close(struct tty_struct *tty, struct file *filp) | ||
1003 | { | ||
1004 | struct r_port *info = tty->driver_data; | ||
1005 | struct tty_port *port = &info->port; | ||
1006 | int timeout; | ||
1007 | CHANNEL_t *cp; | ||
1008 | |||
1009 | if (rocket_paranoia_check(info, "rp_close")) | ||
1010 | return; | ||
1011 | |||
1012 | #ifdef ROCKET_DEBUG_OPEN | ||
1013 | printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count); | ||
1014 | #endif | ||
1015 | |||
1016 | if (tty_port_close_start(port, tty, filp) == 0) | ||
1017 | return; | ||
1018 | |||
1019 | mutex_lock(&port->mutex); | ||
1020 | cp = &info->channel; | ||
1021 | /* | ||
1022 | * Before we drop DTR, make sure the UART transmitter | ||
1023 | * has completely drained; this is especially | ||
1024 | * important if there is a transmit FIFO! | ||
1025 | */ | ||
1026 | timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; | ||
1027 | if (timeout == 0) | ||
1028 | timeout = 1; | ||
1029 | rp_wait_until_sent(tty, timeout); | ||
1030 | clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
1031 | |||
1032 | sDisTransmit(cp); | ||
1033 | sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); | ||
1034 | sDisCTSFlowCtl(cp); | ||
1035 | sDisTxSoftFlowCtl(cp); | ||
1036 | sClrTxXOFF(cp); | ||
1037 | sFlushRxFIFO(cp); | ||
1038 | sFlushTxFIFO(cp); | ||
1039 | sClrRTS(cp); | ||
1040 | if (C_HUPCL(tty)) | ||
1041 | sClrDTR(cp); | ||
1042 | |||
1043 | rp_flush_buffer(tty); | ||
1044 | |||
1045 | tty_ldisc_flush(tty); | ||
1046 | |||
1047 | clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
1048 | |||
1049 | /* We can't yet use tty_port_close_end as the buffer handling in this | ||
1050 | driver is a bit different to the usual */ | ||
1051 | |||
1052 | if (port->blocked_open) { | ||
1053 | if (port->close_delay) { | ||
1054 | msleep_interruptible(jiffies_to_msecs(port->close_delay)); | ||
1055 | } | ||
1056 | wake_up_interruptible(&port->open_wait); | ||
1057 | } else { | ||
1058 | if (info->xmit_buf) { | ||
1059 | free_page((unsigned long) info->xmit_buf); | ||
1060 | info->xmit_buf = NULL; | ||
1061 | } | ||
1062 | } | ||
1063 | spin_lock_irq(&port->lock); | ||
1064 | info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE); | ||
1065 | tty->closing = 0; | ||
1066 | spin_unlock_irq(&port->lock); | ||
1067 | mutex_unlock(&port->mutex); | ||
1068 | tty_port_tty_set(port, NULL); | ||
1069 | |||
1070 | wake_up_interruptible(&port->close_wait); | ||
1071 | complete_all(&info->close_wait); | ||
1072 | atomic_dec(&rp_num_ports_open); | ||
1073 | |||
1074 | #ifdef ROCKET_DEBUG_OPEN | ||
1075 | printk(KERN_INFO "rocket mod-- = %d...\n", | ||
1076 | atomic_read(&rp_num_ports_open)); | ||
1077 | printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); | ||
1078 | #endif | ||
1079 | |||
1080 | } | ||
1081 | |||
1082 | static void rp_set_termios(struct tty_struct *tty, | ||
1083 | struct ktermios *old_termios) | ||
1084 | { | ||
1085 | struct r_port *info = tty->driver_data; | ||
1086 | CHANNEL_t *cp; | ||
1087 | unsigned cflag; | ||
1088 | |||
1089 | if (rocket_paranoia_check(info, "rp_set_termios")) | ||
1090 | return; | ||
1091 | |||
1092 | cflag = tty->termios->c_cflag; | ||
1093 | |||
1094 | /* | ||
1095 | * This driver doesn't support CS5 or CS6 | ||
1096 | */ | ||
1097 | if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) | ||
1098 | tty->termios->c_cflag = | ||
1099 | ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); | ||
1100 | /* Or CMSPAR */ | ||
1101 | tty->termios->c_cflag &= ~CMSPAR; | ||
1102 | |||
1103 | configure_r_port(tty, info, old_termios); | ||
1104 | |||
1105 | cp = &info->channel; | ||
1106 | |||
1107 | /* Handle transition to B0 status */ | ||
1108 | if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { | ||
1109 | sClrDTR(cp); | ||
1110 | sClrRTS(cp); | ||
1111 | } | ||
1112 | |||
1113 | /* Handle transition away from B0 status */ | ||
1114 | if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { | ||
1115 | if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) | ||
1116 | sSetRTS(cp); | ||
1117 | sSetDTR(cp); | ||
1118 | } | ||
1119 | |||
1120 | if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { | ||
1121 | tty->hw_stopped = 0; | ||
1122 | rp_start(tty); | ||
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | static int rp_break(struct tty_struct *tty, int break_state) | ||
1127 | { | ||
1128 | struct r_port *info = tty->driver_data; | ||
1129 | unsigned long flags; | ||
1130 | |||
1131 | if (rocket_paranoia_check(info, "rp_break")) | ||
1132 | return -EINVAL; | ||
1133 | |||
1134 | spin_lock_irqsave(&info->slock, flags); | ||
1135 | if (break_state == -1) | ||
1136 | sSendBreak(&info->channel); | ||
1137 | else | ||
1138 | sClrBreak(&info->channel); | ||
1139 | spin_unlock_irqrestore(&info->slock, flags); | ||
1140 | return 0; | ||
1141 | } | ||
1142 | |||
1143 | /* | ||
1144 | * sGetChanRI used to be a macro in rocket_int.h. When the functionality for | ||
1145 | * the UPCI boards was added, it was decided to make this a function because | ||
1146 | * the macro was getting too complicated. All cases except the first one | ||
1147 | * (UPCIRingInd) are taken directly from the original macro. | ||
1148 | */ | ||
1149 | static int sGetChanRI(CHANNEL_T * ChP) | ||
1150 | { | ||
1151 | CONTROLLER_t *CtlP = ChP->CtlP; | ||
1152 | int ChanNum = ChP->ChanNum; | ||
1153 | int RingInd = 0; | ||
1154 | |||
1155 | if (CtlP->UPCIRingInd) | ||
1156 | RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); | ||
1157 | else if (CtlP->AltChanRingIndicator) | ||
1158 | RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; | ||
1159 | else if (CtlP->boardType == ROCKET_TYPE_PC104) | ||
1160 | RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); | ||
1161 | |||
1162 | return RingInd; | ||
1163 | } | ||
1164 | |||
1165 | /********************************************************************************************/ | ||
1166 | /* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ | ||
1167 | |||
1168 | /* | ||
1169 | * Returns the state of the serial modem control lines. These next 2 functions | ||
1170 | * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. | ||
1171 | */ | ||
1172 | static int rp_tiocmget(struct tty_struct *tty) | ||
1173 | { | ||
1174 | struct r_port *info = tty->driver_data; | ||
1175 | unsigned int control, result, ChanStatus; | ||
1176 | |||
1177 | ChanStatus = sGetChanStatusLo(&info->channel); | ||
1178 | control = info->channel.TxControl[3]; | ||
1179 | result = ((control & SET_RTS) ? TIOCM_RTS : 0) | | ||
1180 | ((control & SET_DTR) ? TIOCM_DTR : 0) | | ||
1181 | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | | ||
1182 | (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | | ||
1183 | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | | ||
1184 | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); | ||
1185 | |||
1186 | return result; | ||
1187 | } | ||
1188 | |||
1189 | /* | ||
1190 | * Sets the modem control lines | ||
1191 | */ | ||
1192 | static int rp_tiocmset(struct tty_struct *tty, | ||
1193 | unsigned int set, unsigned int clear) | ||
1194 | { | ||
1195 | struct r_port *info = tty->driver_data; | ||
1196 | |||
1197 | if (set & TIOCM_RTS) | ||
1198 | info->channel.TxControl[3] |= SET_RTS; | ||
1199 | if (set & TIOCM_DTR) | ||
1200 | info->channel.TxControl[3] |= SET_DTR; | ||
1201 | if (clear & TIOCM_RTS) | ||
1202 | info->channel.TxControl[3] &= ~SET_RTS; | ||
1203 | if (clear & TIOCM_DTR) | ||
1204 | info->channel.TxControl[3] &= ~SET_DTR; | ||
1205 | |||
1206 | out32(info->channel.IndexAddr, info->channel.TxControl); | ||
1207 | return 0; | ||
1208 | } | ||
1209 | |||
1210 | static int get_config(struct r_port *info, struct rocket_config __user *retinfo) | ||
1211 | { | ||
1212 | struct rocket_config tmp; | ||
1213 | |||
1214 | if (!retinfo) | ||
1215 | return -EFAULT; | ||
1216 | memset(&tmp, 0, sizeof (tmp)); | ||
1217 | mutex_lock(&info->port.mutex); | ||
1218 | tmp.line = info->line; | ||
1219 | tmp.flags = info->flags; | ||
1220 | tmp.close_delay = info->port.close_delay; | ||
1221 | tmp.closing_wait = info->port.closing_wait; | ||
1222 | tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; | ||
1223 | mutex_unlock(&info->port.mutex); | ||
1224 | |||
1225 | if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) | ||
1226 | return -EFAULT; | ||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int set_config(struct tty_struct *tty, struct r_port *info, | ||
1231 | struct rocket_config __user *new_info) | ||
1232 | { | ||
1233 | struct rocket_config new_serial; | ||
1234 | |||
1235 | if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) | ||
1236 | return -EFAULT; | ||
1237 | |||
1238 | mutex_lock(&info->port.mutex); | ||
1239 | if (!capable(CAP_SYS_ADMIN)) | ||
1240 | { | ||
1241 | if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) { | ||
1242 | mutex_unlock(&info->port.mutex); | ||
1243 | return -EPERM; | ||
1244 | } | ||
1245 | info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); | ||
1246 | configure_r_port(tty, info, NULL); | ||
1247 | mutex_unlock(&info->port.mutex); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); | ||
1252 | info->port.close_delay = new_serial.close_delay; | ||
1253 | info->port.closing_wait = new_serial.closing_wait; | ||
1254 | |||
1255 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) | ||
1256 | tty->alt_speed = 57600; | ||
1257 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) | ||
1258 | tty->alt_speed = 115200; | ||
1259 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) | ||
1260 | tty->alt_speed = 230400; | ||
1261 | if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) | ||
1262 | tty->alt_speed = 460800; | ||
1263 | mutex_unlock(&info->port.mutex); | ||
1264 | |||
1265 | configure_r_port(tty, info, NULL); | ||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1270 | * This function fills in a rocket_ports struct with information | ||
1271 | * about what boards/ports are in the system. This info is passed | ||
1272 | * to user space. See setrocket.c where the info is used to create | ||
1273 | * the /dev/ttyRx ports. | ||
1274 | */ | ||
1275 | static int get_ports(struct r_port *info, struct rocket_ports __user *retports) | ||
1276 | { | ||
1277 | struct rocket_ports tmp; | ||
1278 | int board; | ||
1279 | |||
1280 | if (!retports) | ||
1281 | return -EFAULT; | ||
1282 | memset(&tmp, 0, sizeof (tmp)); | ||
1283 | tmp.tty_major = rocket_driver->major; | ||
1284 | |||
1285 | for (board = 0; board < 4; board++) { | ||
1286 | tmp.rocketModel[board].model = rocketModel[board].model; | ||
1287 | strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString); | ||
1288 | tmp.rocketModel[board].numPorts = rocketModel[board].numPorts; | ||
1289 | tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2; | ||
1290 | tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber; | ||
1291 | } | ||
1292 | if (copy_to_user(retports, &tmp, sizeof (*retports))) | ||
1293 | return -EFAULT; | ||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1297 | static int reset_rm2(struct r_port *info, void __user *arg) | ||
1298 | { | ||
1299 | int reset; | ||
1300 | |||
1301 | if (!capable(CAP_SYS_ADMIN)) | ||
1302 | return -EPERM; | ||
1303 | |||
1304 | if (copy_from_user(&reset, arg, sizeof (int))) | ||
1305 | return -EFAULT; | ||
1306 | if (reset) | ||
1307 | reset = 1; | ||
1308 | |||
1309 | if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && | ||
1310 | rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) | ||
1311 | return -EINVAL; | ||
1312 | |||
1313 | if (info->ctlp->BusType == isISA) | ||
1314 | sModemReset(info->ctlp, info->chan, reset); | ||
1315 | else | ||
1316 | sPCIModemReset(info->ctlp, info->chan, reset); | ||
1317 | |||
1318 | return 0; | ||
1319 | } | ||
1320 | |||
1321 | static int get_version(struct r_port *info, struct rocket_version __user *retvers) | ||
1322 | { | ||
1323 | if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) | ||
1324 | return -EFAULT; | ||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | /* IOCTL call handler into the driver */ | ||
1329 | static int rp_ioctl(struct tty_struct *tty, | ||
1330 | unsigned int cmd, unsigned long arg) | ||
1331 | { | ||
1332 | struct r_port *info = tty->driver_data; | ||
1333 | void __user *argp = (void __user *)arg; | ||
1334 | int ret = 0; | ||
1335 | |||
1336 | if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) | ||
1337 | return -ENXIO; | ||
1338 | |||
1339 | switch (cmd) { | ||
1340 | case RCKP_GET_STRUCT: | ||
1341 | if (copy_to_user(argp, info, sizeof (struct r_port))) | ||
1342 | ret = -EFAULT; | ||
1343 | break; | ||
1344 | case RCKP_GET_CONFIG: | ||
1345 | ret = get_config(info, argp); | ||
1346 | break; | ||
1347 | case RCKP_SET_CONFIG: | ||
1348 | ret = set_config(tty, info, argp); | ||
1349 | break; | ||
1350 | case RCKP_GET_PORTS: | ||
1351 | ret = get_ports(info, argp); | ||
1352 | break; | ||
1353 | case RCKP_RESET_RM2: | ||
1354 | ret = reset_rm2(info, argp); | ||
1355 | break; | ||
1356 | case RCKP_GET_VERSION: | ||
1357 | ret = get_version(info, argp); | ||
1358 | break; | ||
1359 | default: | ||
1360 | ret = -ENOIOCTLCMD; | ||
1361 | } | ||
1362 | return ret; | ||
1363 | } | ||
1364 | |||
1365 | static void rp_send_xchar(struct tty_struct *tty, char ch) | ||
1366 | { | ||
1367 | struct r_port *info = tty->driver_data; | ||
1368 | CHANNEL_t *cp; | ||
1369 | |||
1370 | if (rocket_paranoia_check(info, "rp_send_xchar")) | ||
1371 | return; | ||
1372 | |||
1373 | cp = &info->channel; | ||
1374 | if (sGetTxCnt(cp)) | ||
1375 | sWriteTxPrioByte(cp, ch); | ||
1376 | else | ||
1377 | sWriteTxByte(sGetTxRxDataIO(cp), ch); | ||
1378 | } | ||
1379 | |||
1380 | static void rp_throttle(struct tty_struct *tty) | ||
1381 | { | ||
1382 | struct r_port *info = tty->driver_data; | ||
1383 | CHANNEL_t *cp; | ||
1384 | |||
1385 | #ifdef ROCKET_DEBUG_THROTTLE | ||
1386 | printk(KERN_INFO "throttle %s: %d....\n", tty->name, | ||
1387 | tty->ldisc.chars_in_buffer(tty)); | ||
1388 | #endif | ||
1389 | |||
1390 | if (rocket_paranoia_check(info, "rp_throttle")) | ||
1391 | return; | ||
1392 | |||
1393 | cp = &info->channel; | ||
1394 | if (I_IXOFF(tty)) | ||
1395 | rp_send_xchar(tty, STOP_CHAR(tty)); | ||
1396 | |||
1397 | sClrRTS(&info->channel); | ||
1398 | } | ||
1399 | |||
1400 | static void rp_unthrottle(struct tty_struct *tty) | ||
1401 | { | ||
1402 | struct r_port *info = tty->driver_data; | ||
1403 | CHANNEL_t *cp; | ||
1404 | #ifdef ROCKET_DEBUG_THROTTLE | ||
1405 | printk(KERN_INFO "unthrottle %s: %d....\n", tty->name, | ||
1406 | tty->ldisc.chars_in_buffer(tty)); | ||
1407 | #endif | ||
1408 | |||
1409 | if (rocket_paranoia_check(info, "rp_throttle")) | ||
1410 | return; | ||
1411 | |||
1412 | cp = &info->channel; | ||
1413 | if (I_IXOFF(tty)) | ||
1414 | rp_send_xchar(tty, START_CHAR(tty)); | ||
1415 | |||
1416 | sSetRTS(&info->channel); | ||
1417 | } | ||
1418 | |||
1419 | /* | ||
1420 | * ------------------------------------------------------------ | ||
1421 | * rp_stop() and rp_start() | ||
1422 | * | ||
1423 | * This routines are called before setting or resetting tty->stopped. | ||
1424 | * They enable or disable transmitter interrupts, as necessary. | ||
1425 | * ------------------------------------------------------------ | ||
1426 | */ | ||
1427 | static void rp_stop(struct tty_struct *tty) | ||
1428 | { | ||
1429 | struct r_port *info = tty->driver_data; | ||
1430 | |||
1431 | #ifdef ROCKET_DEBUG_FLOW | ||
1432 | printk(KERN_INFO "stop %s: %d %d....\n", tty->name, | ||
1433 | info->xmit_cnt, info->xmit_fifo_room); | ||
1434 | #endif | ||
1435 | |||
1436 | if (rocket_paranoia_check(info, "rp_stop")) | ||
1437 | return; | ||
1438 | |||
1439 | if (sGetTxCnt(&info->channel)) | ||
1440 | sDisTransmit(&info->channel); | ||
1441 | } | ||
1442 | |||
1443 | static void rp_start(struct tty_struct *tty) | ||
1444 | { | ||
1445 | struct r_port *info = tty->driver_data; | ||
1446 | |||
1447 | #ifdef ROCKET_DEBUG_FLOW | ||
1448 | printk(KERN_INFO "start %s: %d %d....\n", tty->name, | ||
1449 | info->xmit_cnt, info->xmit_fifo_room); | ||
1450 | #endif | ||
1451 | |||
1452 | if (rocket_paranoia_check(info, "rp_stop")) | ||
1453 | return; | ||
1454 | |||
1455 | sEnTransmit(&info->channel); | ||
1456 | set_bit((info->aiop * 8) + info->chan, | ||
1457 | (void *) &xmit_flags[info->board]); | ||
1458 | } | ||
1459 | |||
1460 | /* | ||
1461 | * rp_wait_until_sent() --- wait until the transmitter is empty | ||
1462 | */ | ||
1463 | static void rp_wait_until_sent(struct tty_struct *tty, int timeout) | ||
1464 | { | ||
1465 | struct r_port *info = tty->driver_data; | ||
1466 | CHANNEL_t *cp; | ||
1467 | unsigned long orig_jiffies; | ||
1468 | int check_time, exit_time; | ||
1469 | int txcnt; | ||
1470 | |||
1471 | if (rocket_paranoia_check(info, "rp_wait_until_sent")) | ||
1472 | return; | ||
1473 | |||
1474 | cp = &info->channel; | ||
1475 | |||
1476 | orig_jiffies = jiffies; | ||
1477 | #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT | ||
1478 | printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout, | ||
1479 | jiffies); | ||
1480 | printk(KERN_INFO "cps=%d...\n", info->cps); | ||
1481 | #endif | ||
1482 | while (1) { | ||
1483 | txcnt = sGetTxCnt(cp); | ||
1484 | if (!txcnt) { | ||
1485 | if (sGetChanStatusLo(cp) & TXSHRMT) | ||
1486 | break; | ||
1487 | check_time = (HZ / info->cps) / 5; | ||
1488 | } else { | ||
1489 | check_time = HZ * txcnt / info->cps; | ||
1490 | } | ||
1491 | if (timeout) { | ||
1492 | exit_time = orig_jiffies + timeout - jiffies; | ||
1493 | if (exit_time <= 0) | ||
1494 | break; | ||
1495 | if (exit_time < check_time) | ||
1496 | check_time = exit_time; | ||
1497 | } | ||
1498 | if (check_time == 0) | ||
1499 | check_time = 1; | ||
1500 | #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT | ||
1501 | printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt, | ||
1502 | jiffies, check_time); | ||
1503 | #endif | ||
1504 | msleep_interruptible(jiffies_to_msecs(check_time)); | ||
1505 | if (signal_pending(current)) | ||
1506 | break; | ||
1507 | } | ||
1508 | __set_current_state(TASK_RUNNING); | ||
1509 | #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT | ||
1510 | printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); | ||
1511 | #endif | ||
1512 | } | ||
1513 | |||
1514 | /* | ||
1515 | * rp_hangup() --- called by tty_hangup() when a hangup is signaled. | ||
1516 | */ | ||
1517 | static void rp_hangup(struct tty_struct *tty) | ||
1518 | { | ||
1519 | CHANNEL_t *cp; | ||
1520 | struct r_port *info = tty->driver_data; | ||
1521 | unsigned long flags; | ||
1522 | |||
1523 | if (rocket_paranoia_check(info, "rp_hangup")) | ||
1524 | return; | ||
1525 | |||
1526 | #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) | ||
1527 | printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); | ||
1528 | #endif | ||
1529 | rp_flush_buffer(tty); | ||
1530 | spin_lock_irqsave(&info->port.lock, flags); | ||
1531 | if (info->port.flags & ASYNC_CLOSING) { | ||
1532 | spin_unlock_irqrestore(&info->port.lock, flags); | ||
1533 | return; | ||
1534 | } | ||
1535 | if (info->port.count) | ||
1536 | atomic_dec(&rp_num_ports_open); | ||
1537 | clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
1538 | spin_unlock_irqrestore(&info->port.lock, flags); | ||
1539 | |||
1540 | tty_port_hangup(&info->port); | ||
1541 | |||
1542 | cp = &info->channel; | ||
1543 | sDisRxFIFO(cp); | ||
1544 | sDisTransmit(cp); | ||
1545 | sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); | ||
1546 | sDisCTSFlowCtl(cp); | ||
1547 | sDisTxSoftFlowCtl(cp); | ||
1548 | sClrTxXOFF(cp); | ||
1549 | clear_bit(ASYNCB_INITIALIZED, &info->port.flags); | ||
1550 | |||
1551 | wake_up_interruptible(&info->port.open_wait); | ||
1552 | } | ||
1553 | |||
1554 | /* | ||
1555 | * Exception handler - write char routine. The RocketPort driver uses a | ||
1556 | * double-buffering strategy, with the twist that if the in-memory CPU | ||
1557 | * buffer is empty, and there's space in the transmit FIFO, the | ||
1558 | * writing routines will write directly to transmit FIFO. | ||
1559 | * Write buffer and counters protected by spinlocks | ||
1560 | */ | ||
1561 | static int rp_put_char(struct tty_struct *tty, unsigned char ch) | ||
1562 | { | ||
1563 | struct r_port *info = tty->driver_data; | ||
1564 | CHANNEL_t *cp; | ||
1565 | unsigned long flags; | ||
1566 | |||
1567 | if (rocket_paranoia_check(info, "rp_put_char")) | ||
1568 | return 0; | ||
1569 | |||
1570 | /* | ||
1571 | * Grab the port write mutex, locking out other processes that try to | ||
1572 | * write to this port | ||
1573 | */ | ||
1574 | mutex_lock(&info->write_mtx); | ||
1575 | |||
1576 | #ifdef ROCKET_DEBUG_WRITE | ||
1577 | printk(KERN_INFO "rp_put_char %c...\n", ch); | ||
1578 | #endif | ||
1579 | |||
1580 | spin_lock_irqsave(&info->slock, flags); | ||
1581 | cp = &info->channel; | ||
1582 | |||
1583 | if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) | ||
1584 | info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); | ||
1585 | |||
1586 | if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { | ||
1587 | info->xmit_buf[info->xmit_head++] = ch; | ||
1588 | info->xmit_head &= XMIT_BUF_SIZE - 1; | ||
1589 | info->xmit_cnt++; | ||
1590 | set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
1591 | } else { | ||
1592 | sOutB(sGetTxRxDataIO(cp), ch); | ||
1593 | info->xmit_fifo_room--; | ||
1594 | } | ||
1595 | spin_unlock_irqrestore(&info->slock, flags); | ||
1596 | mutex_unlock(&info->write_mtx); | ||
1597 | return 1; | ||
1598 | } | ||
1599 | |||
1600 | /* | ||
1601 | * Exception handler - write routine, called when user app writes to the device. | ||
1602 | * A per port write mutex is used to protect from another process writing to | ||
1603 | * this port at the same time. This other process could be running on the other CPU | ||
1604 | * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). | ||
1605 | * Spinlocks protect the info xmit members. | ||
1606 | */ | ||
1607 | static int rp_write(struct tty_struct *tty, | ||
1608 | const unsigned char *buf, int count) | ||
1609 | { | ||
1610 | struct r_port *info = tty->driver_data; | ||
1611 | CHANNEL_t *cp; | ||
1612 | const unsigned char *b; | ||
1613 | int c, retval = 0; | ||
1614 | unsigned long flags; | ||
1615 | |||
1616 | if (count <= 0 || rocket_paranoia_check(info, "rp_write")) | ||
1617 | return 0; | ||
1618 | |||
1619 | if (mutex_lock_interruptible(&info->write_mtx)) | ||
1620 | return -ERESTARTSYS; | ||
1621 | |||
1622 | #ifdef ROCKET_DEBUG_WRITE | ||
1623 | printk(KERN_INFO "rp_write %d chars...\n", count); | ||
1624 | #endif | ||
1625 | cp = &info->channel; | ||
1626 | |||
1627 | if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count) | ||
1628 | info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); | ||
1629 | |||
1630 | /* | ||
1631 | * If the write queue for the port is empty, and there is FIFO space, stuff bytes | ||
1632 | * into FIFO. Use the write queue for temp storage. | ||
1633 | */ | ||
1634 | if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { | ||
1635 | c = min(count, info->xmit_fifo_room); | ||
1636 | b = buf; | ||
1637 | |||
1638 | /* Push data into FIFO, 2 bytes at a time */ | ||
1639 | sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); | ||
1640 | |||
1641 | /* If there is a byte remaining, write it */ | ||
1642 | if (c & 1) | ||
1643 | sOutB(sGetTxRxDataIO(cp), b[c - 1]); | ||
1644 | |||
1645 | retval += c; | ||
1646 | buf += c; | ||
1647 | count -= c; | ||
1648 | |||
1649 | spin_lock_irqsave(&info->slock, flags); | ||
1650 | info->xmit_fifo_room -= c; | ||
1651 | spin_unlock_irqrestore(&info->slock, flags); | ||
1652 | } | ||
1653 | |||
1654 | /* If count is zero, we wrote it all and are done */ | ||
1655 | if (!count) | ||
1656 | goto end; | ||
1657 | |||
1658 | /* Write remaining data into the port's xmit_buf */ | ||
1659 | while (1) { | ||
1660 | /* Hung up ? */ | ||
1661 | if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags)) | ||
1662 | goto end; | ||
1663 | c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); | ||
1664 | c = min(c, XMIT_BUF_SIZE - info->xmit_head); | ||
1665 | if (c <= 0) | ||
1666 | break; | ||
1667 | |||
1668 | b = buf; | ||
1669 | memcpy(info->xmit_buf + info->xmit_head, b, c); | ||
1670 | |||
1671 | spin_lock_irqsave(&info->slock, flags); | ||
1672 | info->xmit_head = | ||
1673 | (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); | ||
1674 | info->xmit_cnt += c; | ||
1675 | spin_unlock_irqrestore(&info->slock, flags); | ||
1676 | |||
1677 | buf += c; | ||
1678 | count -= c; | ||
1679 | retval += c; | ||
1680 | } | ||
1681 | |||
1682 | if ((retval > 0) && !tty->stopped && !tty->hw_stopped) | ||
1683 | set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); | ||
1684 | |||
1685 | end: | ||
1686 | if (info->xmit_cnt < WAKEUP_CHARS) { | ||
1687 | tty_wakeup(tty); | ||
1688 | #ifdef ROCKETPORT_HAVE_POLL_WAIT | ||
1689 | wake_up_interruptible(&tty->poll_wait); | ||
1690 | #endif | ||
1691 | } | ||
1692 | mutex_unlock(&info->write_mtx); | ||
1693 | return retval; | ||
1694 | } | ||
1695 | |||
1696 | /* | ||
1697 | * Return the number of characters that can be sent. We estimate | ||
1698 | * only using the in-memory transmit buffer only, and ignore the | ||
1699 | * potential space in the transmit FIFO. | ||
1700 | */ | ||
1701 | static int rp_write_room(struct tty_struct *tty) | ||
1702 | { | ||
1703 | struct r_port *info = tty->driver_data; | ||
1704 | int ret; | ||
1705 | |||
1706 | if (rocket_paranoia_check(info, "rp_write_room")) | ||
1707 | return 0; | ||
1708 | |||
1709 | ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; | ||
1710 | if (ret < 0) | ||
1711 | ret = 0; | ||
1712 | #ifdef ROCKET_DEBUG_WRITE | ||
1713 | printk(KERN_INFO "rp_write_room returns %d...\n", ret); | ||
1714 | #endif | ||
1715 | return ret; | ||
1716 | } | ||
1717 | |||
1718 | /* | ||
1719 | * Return the number of characters in the buffer. Again, this only | ||
1720 | * counts those characters in the in-memory transmit buffer. | ||
1721 | */ | ||
1722 | static int rp_chars_in_buffer(struct tty_struct *tty) | ||
1723 | { | ||
1724 | struct r_port *info = tty->driver_data; | ||
1725 | CHANNEL_t *cp; | ||
1726 | |||
1727 | if (rocket_paranoia_check(info, "rp_chars_in_buffer")) | ||
1728 | return 0; | ||
1729 | |||
1730 | cp = &info->channel; | ||
1731 | |||
1732 | #ifdef ROCKET_DEBUG_WRITE | ||
1733 | printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt); | ||
1734 | #endif | ||
1735 | return info->xmit_cnt; | ||
1736 | } | ||
1737 | |||
1738 | /* | ||
1739 | * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the | ||
1740 | * r_port struct for the port. Note that spinlock are used to protect info members, | ||
1741 | * do not call this function if the spinlock is already held. | ||
1742 | */ | ||
1743 | static void rp_flush_buffer(struct tty_struct *tty) | ||
1744 | { | ||
1745 | struct r_port *info = tty->driver_data; | ||
1746 | CHANNEL_t *cp; | ||
1747 | unsigned long flags; | ||
1748 | |||
1749 | if (rocket_paranoia_check(info, "rp_flush_buffer")) | ||
1750 | return; | ||
1751 | |||
1752 | spin_lock_irqsave(&info->slock, flags); | ||
1753 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1754 | spin_unlock_irqrestore(&info->slock, flags); | ||
1755 | |||
1756 | #ifdef ROCKETPORT_HAVE_POLL_WAIT | ||
1757 | wake_up_interruptible(&tty->poll_wait); | ||
1758 | #endif | ||
1759 | tty_wakeup(tty); | ||
1760 | |||
1761 | cp = &info->channel; | ||
1762 | sFlushTxFIFO(cp); | ||
1763 | } | ||
1764 | |||
1765 | #ifdef CONFIG_PCI | ||
1766 | |||
1767 | static struct pci_device_id __devinitdata __used rocket_pci_ids[] = { | ||
1768 | { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) }, | ||
1769 | { } | ||
1770 | }; | ||
1771 | MODULE_DEVICE_TABLE(pci, rocket_pci_ids); | ||
1772 | |||
1773 | /* | ||
1774 | * Called when a PCI card is found. Retrieves and stores model information, | ||
1775 | * init's aiopic and serial port hardware. | ||
1776 | * Inputs: i is the board number (0-n) | ||
1777 | */ | ||
1778 | static __init int register_PCI(int i, struct pci_dev *dev) | ||
1779 | { | ||
1780 | int num_aiops, aiop, max_num_aiops, num_chan, chan; | ||
1781 | unsigned int aiopio[MAX_AIOPS_PER_BOARD]; | ||
1782 | char *str, *board_type; | ||
1783 | CONTROLLER_t *ctlp; | ||
1784 | |||
1785 | int fast_clock = 0; | ||
1786 | int altChanRingIndicator = 0; | ||
1787 | int ports_per_aiop = 8; | ||
1788 | WordIO_t ConfigIO = 0; | ||
1789 | ByteIO_t UPCIRingInd = 0; | ||
1790 | |||
1791 | if (!dev || pci_enable_device(dev)) | ||
1792 | return 0; | ||
1793 | |||
1794 | rcktpt_io_addr[i] = pci_resource_start(dev, 0); | ||
1795 | |||
1796 | rcktpt_type[i] = ROCKET_TYPE_NORMAL; | ||
1797 | rocketModel[i].loadrm2 = 0; | ||
1798 | rocketModel[i].startingPortNumber = nextLineNumber; | ||
1799 | |||
1800 | /* Depending on the model, set up some config variables */ | ||
1801 | switch (dev->device) { | ||
1802 | case PCI_DEVICE_ID_RP4QUAD: | ||
1803 | str = "Quadcable"; | ||
1804 | max_num_aiops = 1; | ||
1805 | ports_per_aiop = 4; | ||
1806 | rocketModel[i].model = MODEL_RP4QUAD; | ||
1807 | strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); | ||
1808 | rocketModel[i].numPorts = 4; | ||
1809 | break; | ||
1810 | case PCI_DEVICE_ID_RP8OCTA: | ||
1811 | str = "Octacable"; | ||
1812 | max_num_aiops = 1; | ||
1813 | rocketModel[i].model = MODEL_RP8OCTA; | ||
1814 | strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); | ||
1815 | rocketModel[i].numPorts = 8; | ||
1816 | break; | ||
1817 | case PCI_DEVICE_ID_URP8OCTA: | ||
1818 | str = "Octacable"; | ||
1819 | max_num_aiops = 1; | ||
1820 | rocketModel[i].model = MODEL_UPCI_RP8OCTA; | ||
1821 | strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); | ||
1822 | rocketModel[i].numPorts = 8; | ||
1823 | break; | ||
1824 | case PCI_DEVICE_ID_RP8INTF: | ||
1825 | str = "8"; | ||
1826 | max_num_aiops = 1; | ||
1827 | rocketModel[i].model = MODEL_RP8INTF; | ||
1828 | strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); | ||
1829 | rocketModel[i].numPorts = 8; | ||
1830 | break; | ||
1831 | case PCI_DEVICE_ID_URP8INTF: | ||
1832 | str = "8"; | ||
1833 | max_num_aiops = 1; | ||
1834 | rocketModel[i].model = MODEL_UPCI_RP8INTF; | ||
1835 | strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); | ||
1836 | rocketModel[i].numPorts = 8; | ||
1837 | break; | ||
1838 | case PCI_DEVICE_ID_RP8J: | ||
1839 | str = "8J"; | ||
1840 | max_num_aiops = 1; | ||
1841 | rocketModel[i].model = MODEL_RP8J; | ||
1842 | strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); | ||
1843 | rocketModel[i].numPorts = 8; | ||
1844 | break; | ||
1845 | case PCI_DEVICE_ID_RP4J: | ||
1846 | str = "4J"; | ||
1847 | max_num_aiops = 1; | ||
1848 | ports_per_aiop = 4; | ||
1849 | rocketModel[i].model = MODEL_RP4J; | ||
1850 | strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); | ||
1851 | rocketModel[i].numPorts = 4; | ||
1852 | break; | ||
1853 | case PCI_DEVICE_ID_RP8SNI: | ||
1854 | str = "8 (DB78 Custom)"; | ||
1855 | max_num_aiops = 1; | ||
1856 | rocketModel[i].model = MODEL_RP8SNI; | ||
1857 | strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); | ||
1858 | rocketModel[i].numPorts = 8; | ||
1859 | break; | ||
1860 | case PCI_DEVICE_ID_RP16SNI: | ||
1861 | str = "16 (DB78 Custom)"; | ||
1862 | max_num_aiops = 2; | ||
1863 | rocketModel[i].model = MODEL_RP16SNI; | ||
1864 | strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); | ||
1865 | rocketModel[i].numPorts = 16; | ||
1866 | break; | ||
1867 | case PCI_DEVICE_ID_RP16INTF: | ||
1868 | str = "16"; | ||
1869 | max_num_aiops = 2; | ||
1870 | rocketModel[i].model = MODEL_RP16INTF; | ||
1871 | strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); | ||
1872 | rocketModel[i].numPorts = 16; | ||
1873 | break; | ||
1874 | case PCI_DEVICE_ID_URP16INTF: | ||
1875 | str = "16"; | ||
1876 | max_num_aiops = 2; | ||
1877 | rocketModel[i].model = MODEL_UPCI_RP16INTF; | ||
1878 | strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); | ||
1879 | rocketModel[i].numPorts = 16; | ||
1880 | break; | ||
1881 | case PCI_DEVICE_ID_CRP16INTF: | ||
1882 | str = "16"; | ||
1883 | max_num_aiops = 2; | ||
1884 | rocketModel[i].model = MODEL_CPCI_RP16INTF; | ||
1885 | strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); | ||
1886 | rocketModel[i].numPorts = 16; | ||
1887 | break; | ||
1888 | case PCI_DEVICE_ID_RP32INTF: | ||
1889 | str = "32"; | ||
1890 | max_num_aiops = 4; | ||
1891 | rocketModel[i].model = MODEL_RP32INTF; | ||
1892 | strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); | ||
1893 | rocketModel[i].numPorts = 32; | ||
1894 | break; | ||
1895 | case PCI_DEVICE_ID_URP32INTF: | ||
1896 | str = "32"; | ||
1897 | max_num_aiops = 4; | ||
1898 | rocketModel[i].model = MODEL_UPCI_RP32INTF; | ||
1899 | strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); | ||
1900 | rocketModel[i].numPorts = 32; | ||
1901 | break; | ||
1902 | case PCI_DEVICE_ID_RPP4: | ||
1903 | str = "Plus Quadcable"; | ||
1904 | max_num_aiops = 1; | ||
1905 | ports_per_aiop = 4; | ||
1906 | altChanRingIndicator++; | ||
1907 | fast_clock++; | ||
1908 | rocketModel[i].model = MODEL_RPP4; | ||
1909 | strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); | ||
1910 | rocketModel[i].numPorts = 4; | ||
1911 | break; | ||
1912 | case PCI_DEVICE_ID_RPP8: | ||
1913 | str = "Plus Octacable"; | ||
1914 | max_num_aiops = 2; | ||
1915 | ports_per_aiop = 4; | ||
1916 | altChanRingIndicator++; | ||
1917 | fast_clock++; | ||
1918 | rocketModel[i].model = MODEL_RPP8; | ||
1919 | strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); | ||
1920 | rocketModel[i].numPorts = 8; | ||
1921 | break; | ||
1922 | case PCI_DEVICE_ID_RP2_232: | ||
1923 | str = "Plus 2 (RS-232)"; | ||
1924 | max_num_aiops = 1; | ||
1925 | ports_per_aiop = 2; | ||
1926 | altChanRingIndicator++; | ||
1927 | fast_clock++; | ||
1928 | rocketModel[i].model = MODEL_RP2_232; | ||
1929 | strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); | ||
1930 | rocketModel[i].numPorts = 2; | ||
1931 | break; | ||
1932 | case PCI_DEVICE_ID_RP2_422: | ||
1933 | str = "Plus 2 (RS-422)"; | ||
1934 | max_num_aiops = 1; | ||
1935 | ports_per_aiop = 2; | ||
1936 | altChanRingIndicator++; | ||
1937 | fast_clock++; | ||
1938 | rocketModel[i].model = MODEL_RP2_422; | ||
1939 | strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); | ||
1940 | rocketModel[i].numPorts = 2; | ||
1941 | break; | ||
1942 | case PCI_DEVICE_ID_RP6M: | ||
1943 | |||
1944 | max_num_aiops = 1; | ||
1945 | ports_per_aiop = 6; | ||
1946 | str = "6-port"; | ||
1947 | |||
1948 | /* If revision is 1, the rocketmodem flash must be loaded. | ||
1949 | * If it is 2 it is a "socketed" version. */ | ||
1950 | if (dev->revision == 1) { | ||
1951 | rcktpt_type[i] = ROCKET_TYPE_MODEMII; | ||
1952 | rocketModel[i].loadrm2 = 1; | ||
1953 | } else { | ||
1954 | rcktpt_type[i] = ROCKET_TYPE_MODEM; | ||
1955 | } | ||
1956 | |||
1957 | rocketModel[i].model = MODEL_RP6M; | ||
1958 | strcpy(rocketModel[i].modelString, "RocketModem 6 port"); | ||
1959 | rocketModel[i].numPorts = 6; | ||
1960 | break; | ||
1961 | case PCI_DEVICE_ID_RP4M: | ||
1962 | max_num_aiops = 1; | ||
1963 | ports_per_aiop = 4; | ||
1964 | str = "4-port"; | ||
1965 | if (dev->revision == 1) { | ||
1966 | rcktpt_type[i] = ROCKET_TYPE_MODEMII; | ||
1967 | rocketModel[i].loadrm2 = 1; | ||
1968 | } else { | ||
1969 | rcktpt_type[i] = ROCKET_TYPE_MODEM; | ||
1970 | } | ||
1971 | |||
1972 | rocketModel[i].model = MODEL_RP4M; | ||
1973 | strcpy(rocketModel[i].modelString, "RocketModem 4 port"); | ||
1974 | rocketModel[i].numPorts = 4; | ||
1975 | break; | ||
1976 | default: | ||
1977 | str = "(unknown/unsupported)"; | ||
1978 | max_num_aiops = 0; | ||
1979 | break; | ||
1980 | } | ||
1981 | |||
1982 | /* | ||
1983 | * Check for UPCI boards. | ||
1984 | */ | ||
1985 | |||
1986 | switch (dev->device) { | ||
1987 | case PCI_DEVICE_ID_URP32INTF: | ||
1988 | case PCI_DEVICE_ID_URP8INTF: | ||
1989 | case PCI_DEVICE_ID_URP16INTF: | ||
1990 | case PCI_DEVICE_ID_CRP16INTF: | ||
1991 | case PCI_DEVICE_ID_URP8OCTA: | ||
1992 | rcktpt_io_addr[i] = pci_resource_start(dev, 2); | ||
1993 | ConfigIO = pci_resource_start(dev, 1); | ||
1994 | if (dev->device == PCI_DEVICE_ID_URP8OCTA) { | ||
1995 | UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; | ||
1996 | |||
1997 | /* | ||
1998 | * Check for octa or quad cable. | ||
1999 | */ | ||
2000 | if (! | ||
2001 | (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & | ||
2002 | PCI_GPIO_CTRL_8PORT)) { | ||
2003 | str = "Quadcable"; | ||
2004 | ports_per_aiop = 4; | ||
2005 | rocketModel[i].numPorts = 4; | ||
2006 | } | ||
2007 | } | ||
2008 | break; | ||
2009 | case PCI_DEVICE_ID_UPCI_RM3_8PORT: | ||
2010 | str = "8 ports"; | ||
2011 | max_num_aiops = 1; | ||
2012 | rocketModel[i].model = MODEL_UPCI_RM3_8PORT; | ||
2013 | strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); | ||
2014 | rocketModel[i].numPorts = 8; | ||
2015 | rcktpt_io_addr[i] = pci_resource_start(dev, 2); | ||
2016 | UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; | ||
2017 | ConfigIO = pci_resource_start(dev, 1); | ||
2018 | rcktpt_type[i] = ROCKET_TYPE_MODEMIII; | ||
2019 | break; | ||
2020 | case PCI_DEVICE_ID_UPCI_RM3_4PORT: | ||
2021 | str = "4 ports"; | ||
2022 | max_num_aiops = 1; | ||
2023 | rocketModel[i].model = MODEL_UPCI_RM3_4PORT; | ||
2024 | strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); | ||
2025 | rocketModel[i].numPorts = 4; | ||
2026 | rcktpt_io_addr[i] = pci_resource_start(dev, 2); | ||
2027 | UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; | ||
2028 | ConfigIO = pci_resource_start(dev, 1); | ||
2029 | rcktpt_type[i] = ROCKET_TYPE_MODEMIII; | ||
2030 | break; | ||
2031 | default: | ||
2032 | break; | ||
2033 | } | ||
2034 | |||
2035 | switch (rcktpt_type[i]) { | ||
2036 | case ROCKET_TYPE_MODEM: | ||
2037 | board_type = "RocketModem"; | ||
2038 | break; | ||
2039 | case ROCKET_TYPE_MODEMII: | ||
2040 | board_type = "RocketModem II"; | ||
2041 | break; | ||
2042 | case ROCKET_TYPE_MODEMIII: | ||
2043 | board_type = "RocketModem III"; | ||
2044 | break; | ||
2045 | default: | ||
2046 | board_type = "RocketPort"; | ||
2047 | break; | ||
2048 | } | ||
2049 | |||
2050 | if (fast_clock) { | ||
2051 | sClockPrescale = 0x12; /* mod 2 (divide by 3) */ | ||
2052 | rp_baud_base[i] = 921600; | ||
2053 | } else { | ||
2054 | /* | ||
2055 | * If support_low_speed is set, use the slow clock | ||
2056 | * prescale, which supports 50 bps | ||
2057 | */ | ||
2058 | if (support_low_speed) { | ||
2059 | /* mod 9 (divide by 10) prescale */ | ||
2060 | sClockPrescale = 0x19; | ||
2061 | rp_baud_base[i] = 230400; | ||
2062 | } else { | ||
2063 | /* mod 4 (devide by 5) prescale */ | ||
2064 | sClockPrescale = 0x14; | ||
2065 | rp_baud_base[i] = 460800; | ||
2066 | } | ||
2067 | } | ||
2068 | |||
2069 | for (aiop = 0; aiop < max_num_aiops; aiop++) | ||
2070 | aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); | ||
2071 | ctlp = sCtlNumToCtlPtr(i); | ||
2072 | num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); | ||
2073 | for (aiop = 0; aiop < max_num_aiops; aiop++) | ||
2074 | ctlp->AiopNumChan[aiop] = ports_per_aiop; | ||
2075 | |||
2076 | dev_info(&dev->dev, "comtrol PCI controller #%d found at " | ||
2077 | "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n", | ||
2078 | i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString, | ||
2079 | rocketModel[i].startingPortNumber, | ||
2080 | rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1); | ||
2081 | |||
2082 | if (num_aiops <= 0) { | ||
2083 | rcktpt_io_addr[i] = 0; | ||
2084 | return (0); | ||
2085 | } | ||
2086 | is_PCI[i] = 1; | ||
2087 | |||
2088 | /* Reset the AIOPIC, init the serial ports */ | ||
2089 | for (aiop = 0; aiop < num_aiops; aiop++) { | ||
2090 | sResetAiopByNum(ctlp, aiop); | ||
2091 | num_chan = ports_per_aiop; | ||
2092 | for (chan = 0; chan < num_chan; chan++) | ||
2093 | init_r_port(i, aiop, chan, dev); | ||
2094 | } | ||
2095 | |||
2096 | /* Rocket modems must be reset */ | ||
2097 | if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || | ||
2098 | (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || | ||
2099 | (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { | ||
2100 | num_chan = ports_per_aiop; | ||
2101 | for (chan = 0; chan < num_chan; chan++) | ||
2102 | sPCIModemReset(ctlp, chan, 1); | ||
2103 | msleep(500); | ||
2104 | for (chan = 0; chan < num_chan; chan++) | ||
2105 | sPCIModemReset(ctlp, chan, 0); | ||
2106 | msleep(500); | ||
2107 | rmSpeakerReset(ctlp, rocketModel[i].model); | ||
2108 | } | ||
2109 | return (1); | ||
2110 | } | ||
2111 | |||
2112 | /* | ||
2113 | * Probes for PCI cards, inits them if found | ||
2114 | * Input: board_found = number of ISA boards already found, or the | ||
2115 | * starting board number | ||
2116 | * Returns: Number of PCI boards found | ||
2117 | */ | ||
2118 | static int __init init_PCI(int boards_found) | ||
2119 | { | ||
2120 | struct pci_dev *dev = NULL; | ||
2121 | int count = 0; | ||
2122 | |||
2123 | /* Work through the PCI device list, pulling out ours */ | ||
2124 | while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { | ||
2125 | if (register_PCI(count + boards_found, dev)) | ||
2126 | count++; | ||
2127 | } | ||
2128 | return (count); | ||
2129 | } | ||
2130 | |||
2131 | #endif /* CONFIG_PCI */ | ||
2132 | |||
2133 | /* | ||
2134 | * Probes for ISA cards | ||
2135 | * Input: i = the board number to look for | ||
2136 | * Returns: 1 if board found, 0 else | ||
2137 | */ | ||
2138 | static int __init init_ISA(int i) | ||
2139 | { | ||
2140 | int num_aiops, num_chan = 0, total_num_chan = 0; | ||
2141 | int aiop, chan; | ||
2142 | unsigned int aiopio[MAX_AIOPS_PER_BOARD]; | ||
2143 | CONTROLLER_t *ctlp; | ||
2144 | char *type_string; | ||
2145 | |||
2146 | /* If io_addr is zero, no board configured */ | ||
2147 | if (rcktpt_io_addr[i] == 0) | ||
2148 | return (0); | ||
2149 | |||
2150 | /* Reserve the IO region */ | ||
2151 | if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) { | ||
2152 | printk(KERN_ERR "Unable to reserve IO region for configured " | ||
2153 | "ISA RocketPort at address 0x%lx, board not " | ||
2154 | "installed...\n", rcktpt_io_addr[i]); | ||
2155 | rcktpt_io_addr[i] = 0; | ||
2156 | return (0); | ||
2157 | } | ||
2158 | |||
2159 | ctlp = sCtlNumToCtlPtr(i); | ||
2160 | |||
2161 | ctlp->boardType = rcktpt_type[i]; | ||
2162 | |||
2163 | switch (rcktpt_type[i]) { | ||
2164 | case ROCKET_TYPE_PC104: | ||
2165 | type_string = "(PC104)"; | ||
2166 | break; | ||
2167 | case ROCKET_TYPE_MODEM: | ||
2168 | type_string = "(RocketModem)"; | ||
2169 | break; | ||
2170 | case ROCKET_TYPE_MODEMII: | ||
2171 | type_string = "(RocketModem II)"; | ||
2172 | break; | ||
2173 | default: | ||
2174 | type_string = ""; | ||
2175 | break; | ||
2176 | } | ||
2177 | |||
2178 | /* | ||
2179 | * If support_low_speed is set, use the slow clock prescale, | ||
2180 | * which supports 50 bps | ||
2181 | */ | ||
2182 | if (support_low_speed) { | ||
2183 | sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ | ||
2184 | rp_baud_base[i] = 230400; | ||
2185 | } else { | ||
2186 | sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ | ||
2187 | rp_baud_base[i] = 460800; | ||
2188 | } | ||
2189 | |||
2190 | for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++) | ||
2191 | aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400); | ||
2192 | |||
2193 | num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0); | ||
2194 | |||
2195 | if (ctlp->boardType == ROCKET_TYPE_PC104) { | ||
2196 | sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ | ||
2197 | sEnAiop(ctlp, 3); /* CSels used for other stuff */ | ||
2198 | } | ||
2199 | |||
2200 | /* If something went wrong initing the AIOP's release the ISA IO memory */ | ||
2201 | if (num_aiops <= 0) { | ||
2202 | release_region(rcktpt_io_addr[i], 64); | ||
2203 | rcktpt_io_addr[i] = 0; | ||
2204 | return (0); | ||
2205 | } | ||
2206 | |||
2207 | rocketModel[i].startingPortNumber = nextLineNumber; | ||
2208 | |||
2209 | for (aiop = 0; aiop < num_aiops; aiop++) { | ||
2210 | sResetAiopByNum(ctlp, aiop); | ||
2211 | sEnAiop(ctlp, aiop); | ||
2212 | num_chan = sGetAiopNumChan(ctlp, aiop); | ||
2213 | total_num_chan += num_chan; | ||
2214 | for (chan = 0; chan < num_chan; chan++) | ||
2215 | init_r_port(i, aiop, chan, NULL); | ||
2216 | } | ||
2217 | is_PCI[i] = 0; | ||
2218 | if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { | ||
2219 | num_chan = sGetAiopNumChan(ctlp, 0); | ||
2220 | total_num_chan = num_chan; | ||
2221 | for (chan = 0; chan < num_chan; chan++) | ||
2222 | sModemReset(ctlp, chan, 1); | ||
2223 | msleep(500); | ||
2224 | for (chan = 0; chan < num_chan; chan++) | ||
2225 | sModemReset(ctlp, chan, 0); | ||
2226 | msleep(500); | ||
2227 | strcpy(rocketModel[i].modelString, "RocketModem ISA"); | ||
2228 | } else { | ||
2229 | strcpy(rocketModel[i].modelString, "RocketPort ISA"); | ||
2230 | } | ||
2231 | rocketModel[i].numPorts = total_num_chan; | ||
2232 | rocketModel[i].model = MODEL_ISA; | ||
2233 | |||
2234 | printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n", | ||
2235 | i, rcktpt_io_addr[i], num_aiops, type_string); | ||
2236 | |||
2237 | printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", | ||
2238 | rocketModel[i].modelString, | ||
2239 | rocketModel[i].startingPortNumber, | ||
2240 | rocketModel[i].startingPortNumber + | ||
2241 | rocketModel[i].numPorts - 1); | ||
2242 | |||
2243 | return (1); | ||
2244 | } | ||
2245 | |||
2246 | static const struct tty_operations rocket_ops = { | ||
2247 | .open = rp_open, | ||
2248 | .close = rp_close, | ||
2249 | .write = rp_write, | ||
2250 | .put_char = rp_put_char, | ||
2251 | .write_room = rp_write_room, | ||
2252 | .chars_in_buffer = rp_chars_in_buffer, | ||
2253 | .flush_buffer = rp_flush_buffer, | ||
2254 | .ioctl = rp_ioctl, | ||
2255 | .throttle = rp_throttle, | ||
2256 | .unthrottle = rp_unthrottle, | ||
2257 | .set_termios = rp_set_termios, | ||
2258 | .stop = rp_stop, | ||
2259 | .start = rp_start, | ||
2260 | .hangup = rp_hangup, | ||
2261 | .break_ctl = rp_break, | ||
2262 | .send_xchar = rp_send_xchar, | ||
2263 | .wait_until_sent = rp_wait_until_sent, | ||
2264 | .tiocmget = rp_tiocmget, | ||
2265 | .tiocmset = rp_tiocmset, | ||
2266 | }; | ||
2267 | |||
2268 | static const struct tty_port_operations rocket_port_ops = { | ||
2269 | .carrier_raised = carrier_raised, | ||
2270 | .dtr_rts = dtr_rts, | ||
2271 | }; | ||
2272 | |||
2273 | /* | ||
2274 | * The module "startup" routine; it's run when the module is loaded. | ||
2275 | */ | ||
2276 | static int __init rp_init(void) | ||
2277 | { | ||
2278 | int ret = -ENOMEM, pci_boards_found, isa_boards_found, i; | ||
2279 | |||
2280 | printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", | ||
2281 | ROCKET_VERSION, ROCKET_DATE); | ||
2282 | |||
2283 | rocket_driver = alloc_tty_driver(MAX_RP_PORTS); | ||
2284 | if (!rocket_driver) | ||
2285 | goto err; | ||
2286 | |||
2287 | /* | ||
2288 | * If board 1 is non-zero, there is at least one ISA configured. If controller is | ||
2289 | * zero, use the default controller IO address of board1 + 0x40. | ||
2290 | */ | ||
2291 | if (board1) { | ||
2292 | if (controller == 0) | ||
2293 | controller = board1 + 0x40; | ||
2294 | } else { | ||
2295 | controller = 0; /* Used as a flag, meaning no ISA boards */ | ||
2296 | } | ||
2297 | |||
2298 | /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */ | ||
2299 | if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) { | ||
2300 | printk(KERN_ERR "Unable to reserve IO region for first " | ||
2301 | "configured ISA RocketPort controller 0x%lx. " | ||
2302 | "Driver exiting\n", controller); | ||
2303 | ret = -EBUSY; | ||
2304 | goto err_tty; | ||
2305 | } | ||
2306 | |||
2307 | /* Store ISA variable retrieved from command line or .conf file. */ | ||
2308 | rcktpt_io_addr[0] = board1; | ||
2309 | rcktpt_io_addr[1] = board2; | ||
2310 | rcktpt_io_addr[2] = board3; | ||
2311 | rcktpt_io_addr[3] = board4; | ||
2312 | |||
2313 | rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; | ||
2314 | rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; | ||
2315 | rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; | ||
2316 | rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; | ||
2317 | rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; | ||
2318 | rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; | ||
2319 | rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; | ||
2320 | rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; | ||
2321 | |||
2322 | /* | ||
2323 | * Set up the tty driver structure and then register this | ||
2324 | * driver with the tty layer. | ||
2325 | */ | ||
2326 | |||
2327 | rocket_driver->owner = THIS_MODULE; | ||
2328 | rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV; | ||
2329 | rocket_driver->name = "ttyR"; | ||
2330 | rocket_driver->driver_name = "Comtrol RocketPort"; | ||
2331 | rocket_driver->major = TTY_ROCKET_MAJOR; | ||
2332 | rocket_driver->minor_start = 0; | ||
2333 | rocket_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
2334 | rocket_driver->subtype = SERIAL_TYPE_NORMAL; | ||
2335 | rocket_driver->init_termios = tty_std_termios; | ||
2336 | rocket_driver->init_termios.c_cflag = | ||
2337 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
2338 | rocket_driver->init_termios.c_ispeed = 9600; | ||
2339 | rocket_driver->init_termios.c_ospeed = 9600; | ||
2340 | #ifdef ROCKET_SOFT_FLOW | ||
2341 | rocket_driver->flags |= TTY_DRIVER_REAL_RAW; | ||
2342 | #endif | ||
2343 | tty_set_operations(rocket_driver, &rocket_ops); | ||
2344 | |||
2345 | ret = tty_register_driver(rocket_driver); | ||
2346 | if (ret < 0) { | ||
2347 | printk(KERN_ERR "Couldn't install tty RocketPort driver\n"); | ||
2348 | goto err_controller; | ||
2349 | } | ||
2350 | |||
2351 | #ifdef ROCKET_DEBUG_OPEN | ||
2352 | printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); | ||
2353 | #endif | ||
2354 | |||
2355 | /* | ||
2356 | * OK, let's probe each of the controllers looking for boards. Any boards found | ||
2357 | * will be initialized here. | ||
2358 | */ | ||
2359 | isa_boards_found = 0; | ||
2360 | pci_boards_found = 0; | ||
2361 | |||
2362 | for (i = 0; i < NUM_BOARDS; i++) { | ||
2363 | if (init_ISA(i)) | ||
2364 | isa_boards_found++; | ||
2365 | } | ||
2366 | |||
2367 | #ifdef CONFIG_PCI | ||
2368 | if (isa_boards_found < NUM_BOARDS) | ||
2369 | pci_boards_found = init_PCI(isa_boards_found); | ||
2370 | #endif | ||
2371 | |||
2372 | max_board = pci_boards_found + isa_boards_found; | ||
2373 | |||
2374 | if (max_board == 0) { | ||
2375 | printk(KERN_ERR "No rocketport ports found; unloading driver\n"); | ||
2376 | ret = -ENXIO; | ||
2377 | goto err_ttyu; | ||
2378 | } | ||
2379 | |||
2380 | return 0; | ||
2381 | err_ttyu: | ||
2382 | tty_unregister_driver(rocket_driver); | ||
2383 | err_controller: | ||
2384 | if (controller) | ||
2385 | release_region(controller, 4); | ||
2386 | err_tty: | ||
2387 | put_tty_driver(rocket_driver); | ||
2388 | err: | ||
2389 | return ret; | ||
2390 | } | ||
2391 | |||
2392 | |||
2393 | static void rp_cleanup_module(void) | ||
2394 | { | ||
2395 | int retval; | ||
2396 | int i; | ||
2397 | |||
2398 | del_timer_sync(&rocket_timer); | ||
2399 | |||
2400 | retval = tty_unregister_driver(rocket_driver); | ||
2401 | if (retval) | ||
2402 | printk(KERN_ERR "Error %d while trying to unregister " | ||
2403 | "rocketport driver\n", -retval); | ||
2404 | |||
2405 | for (i = 0; i < MAX_RP_PORTS; i++) | ||
2406 | if (rp_table[i]) { | ||
2407 | tty_unregister_device(rocket_driver, i); | ||
2408 | kfree(rp_table[i]); | ||
2409 | } | ||
2410 | |||
2411 | put_tty_driver(rocket_driver); | ||
2412 | |||
2413 | for (i = 0; i < NUM_BOARDS; i++) { | ||
2414 | if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) | ||
2415 | continue; | ||
2416 | release_region(rcktpt_io_addr[i], 64); | ||
2417 | } | ||
2418 | if (controller) | ||
2419 | release_region(controller, 4); | ||
2420 | } | ||
2421 | |||
2422 | /*************************************************************************** | ||
2423 | Function: sInitController | ||
2424 | Purpose: Initialization of controller global registers and controller | ||
2425 | structure. | ||
2426 | Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, | ||
2427 | IRQNum,Frequency,PeriodicOnly) | ||
2428 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
2429 | int CtlNum; Controller number | ||
2430 | ByteIO_t MudbacIO; Mudbac base I/O address. | ||
2431 | ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. | ||
2432 | This list must be in the order the AIOPs will be found on the | ||
2433 | controller. Once an AIOP in the list is not found, it is | ||
2434 | assumed that there are no more AIOPs on the controller. | ||
2435 | int AiopIOListSize; Number of addresses in AiopIOList | ||
2436 | int IRQNum; Interrupt Request number. Can be any of the following: | ||
2437 | 0: Disable global interrupts | ||
2438 | 3: IRQ 3 | ||
2439 | 4: IRQ 4 | ||
2440 | 5: IRQ 5 | ||
2441 | 9: IRQ 9 | ||
2442 | 10: IRQ 10 | ||
2443 | 11: IRQ 11 | ||
2444 | 12: IRQ 12 | ||
2445 | 15: IRQ 15 | ||
2446 | Byte_t Frequency: A flag identifying the frequency | ||
2447 | of the periodic interrupt, can be any one of the following: | ||
2448 | FREQ_DIS - periodic interrupt disabled | ||
2449 | FREQ_137HZ - 137 Hertz | ||
2450 | FREQ_69HZ - 69 Hertz | ||
2451 | FREQ_34HZ - 34 Hertz | ||
2452 | FREQ_17HZ - 17 Hertz | ||
2453 | FREQ_9HZ - 9 Hertz | ||
2454 | FREQ_4HZ - 4 Hertz | ||
2455 | If IRQNum is set to 0 the Frequency parameter is | ||
2456 | overidden, it is forced to a value of FREQ_DIS. | ||
2457 | int PeriodicOnly: 1 if all interrupts except the periodic | ||
2458 | interrupt are to be blocked. | ||
2459 | 0 is both the periodic interrupt and | ||
2460 | other channel interrupts are allowed. | ||
2461 | If IRQNum is set to 0 the PeriodicOnly parameter is | ||
2462 | overidden, it is forced to a value of 0. | ||
2463 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller | ||
2464 | initialization failed. | ||
2465 | |||
2466 | Comments: | ||
2467 | If periodic interrupts are to be disabled but AIOP interrupts | ||
2468 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. | ||
2469 | |||
2470 | If interrupts are to be completely disabled set IRQNum to 0. | ||
2471 | |||
2472 | Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an | ||
2473 | invalid combination. | ||
2474 | |||
2475 | This function performs initialization of global interrupt modes, | ||
2476 | but it does not actually enable global interrupts. To enable | ||
2477 | and disable global interrupts use functions sEnGlobalInt() and | ||
2478 | sDisGlobalInt(). Enabling of global interrupts is normally not | ||
2479 | done until all other initializations are complete. | ||
2480 | |||
2481 | Even if interrupts are globally enabled, they must also be | ||
2482 | individually enabled for each channel that is to generate | ||
2483 | interrupts. | ||
2484 | |||
2485 | Warnings: No range checking on any of the parameters is done. | ||
2486 | |||
2487 | No context switches are allowed while executing this function. | ||
2488 | |||
2489 | After this function all AIOPs on the controller are disabled, | ||
2490 | they can be enabled with sEnAiop(). | ||
2491 | */ | ||
2492 | static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, | ||
2493 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
2494 | int IRQNum, Byte_t Frequency, int PeriodicOnly) | ||
2495 | { | ||
2496 | int i; | ||
2497 | ByteIO_t io; | ||
2498 | int done; | ||
2499 | |||
2500 | CtlP->AiopIntrBits = aiop_intr_bits; | ||
2501 | CtlP->AltChanRingIndicator = 0; | ||
2502 | CtlP->CtlNum = CtlNum; | ||
2503 | CtlP->CtlID = CTLID_0001; /* controller release 1 */ | ||
2504 | CtlP->BusType = isISA; | ||
2505 | CtlP->MBaseIO = MudbacIO; | ||
2506 | CtlP->MReg1IO = MudbacIO + 1; | ||
2507 | CtlP->MReg2IO = MudbacIO + 2; | ||
2508 | CtlP->MReg3IO = MudbacIO + 3; | ||
2509 | #if 1 | ||
2510 | CtlP->MReg2 = 0; /* interrupt disable */ | ||
2511 | CtlP->MReg3 = 0; /* no periodic interrupts */ | ||
2512 | #else | ||
2513 | if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ | ||
2514 | CtlP->MReg2 = 0; /* interrupt disable */ | ||
2515 | CtlP->MReg3 = 0; /* no periodic interrupts */ | ||
2516 | } else { | ||
2517 | CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ | ||
2518 | CtlP->MReg3 = Frequency; /* set frequency */ | ||
2519 | if (PeriodicOnly) { /* periodic interrupt only */ | ||
2520 | CtlP->MReg3 |= PERIODIC_ONLY; | ||
2521 | } | ||
2522 | } | ||
2523 | #endif | ||
2524 | sOutB(CtlP->MReg2IO, CtlP->MReg2); | ||
2525 | sOutB(CtlP->MReg3IO, CtlP->MReg3); | ||
2526 | sControllerEOI(CtlP); /* clear EOI if warm init */ | ||
2527 | /* Init AIOPs */ | ||
2528 | CtlP->NumAiop = 0; | ||
2529 | for (i = done = 0; i < AiopIOListSize; i++) { | ||
2530 | io = AiopIOList[i]; | ||
2531 | CtlP->AiopIO[i] = (WordIO_t) io; | ||
2532 | CtlP->AiopIntChanIO[i] = io + _INT_CHAN; | ||
2533 | sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ | ||
2534 | sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ | ||
2535 | if (done) | ||
2536 | continue; | ||
2537 | sEnAiop(CtlP, i); /* enable the AIOP */ | ||
2538 | CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ | ||
2539 | if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ | ||
2540 | done = 1; /* done looking for AIOPs */ | ||
2541 | else { | ||
2542 | CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ | ||
2543 | sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ | ||
2544 | sOutB(io + _INDX_DATA, sClockPrescale); | ||
2545 | CtlP->NumAiop++; /* bump count of AIOPs */ | ||
2546 | } | ||
2547 | sDisAiop(CtlP, i); /* disable AIOP */ | ||
2548 | } | ||
2549 | |||
2550 | if (CtlP->NumAiop == 0) | ||
2551 | return (-1); | ||
2552 | else | ||
2553 | return (CtlP->NumAiop); | ||
2554 | } | ||
2555 | |||
2556 | /*************************************************************************** | ||
2557 | Function: sPCIInitController | ||
2558 | Purpose: Initialization of controller global registers and controller | ||
2559 | structure. | ||
2560 | Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, | ||
2561 | IRQNum,Frequency,PeriodicOnly) | ||
2562 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
2563 | int CtlNum; Controller number | ||
2564 | ByteIO_t *AiopIOList; List of I/O addresses for each AIOP. | ||
2565 | This list must be in the order the AIOPs will be found on the | ||
2566 | controller. Once an AIOP in the list is not found, it is | ||
2567 | assumed that there are no more AIOPs on the controller. | ||
2568 | int AiopIOListSize; Number of addresses in AiopIOList | ||
2569 | int IRQNum; Interrupt Request number. Can be any of the following: | ||
2570 | 0: Disable global interrupts | ||
2571 | 3: IRQ 3 | ||
2572 | 4: IRQ 4 | ||
2573 | 5: IRQ 5 | ||
2574 | 9: IRQ 9 | ||
2575 | 10: IRQ 10 | ||
2576 | 11: IRQ 11 | ||
2577 | 12: IRQ 12 | ||
2578 | 15: IRQ 15 | ||
2579 | Byte_t Frequency: A flag identifying the frequency | ||
2580 | of the periodic interrupt, can be any one of the following: | ||
2581 | FREQ_DIS - periodic interrupt disabled | ||
2582 | FREQ_137HZ - 137 Hertz | ||
2583 | FREQ_69HZ - 69 Hertz | ||
2584 | FREQ_34HZ - 34 Hertz | ||
2585 | FREQ_17HZ - 17 Hertz | ||
2586 | FREQ_9HZ - 9 Hertz | ||
2587 | FREQ_4HZ - 4 Hertz | ||
2588 | If IRQNum is set to 0 the Frequency parameter is | ||
2589 | overidden, it is forced to a value of FREQ_DIS. | ||
2590 | int PeriodicOnly: 1 if all interrupts except the periodic | ||
2591 | interrupt are to be blocked. | ||
2592 | 0 is both the periodic interrupt and | ||
2593 | other channel interrupts are allowed. | ||
2594 | If IRQNum is set to 0 the PeriodicOnly parameter is | ||
2595 | overidden, it is forced to a value of 0. | ||
2596 | Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller | ||
2597 | initialization failed. | ||
2598 | |||
2599 | Comments: | ||
2600 | If periodic interrupts are to be disabled but AIOP interrupts | ||
2601 | are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. | ||
2602 | |||
2603 | If interrupts are to be completely disabled set IRQNum to 0. | ||
2604 | |||
2605 | Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an | ||
2606 | invalid combination. | ||
2607 | |||
2608 | This function performs initialization of global interrupt modes, | ||
2609 | but it does not actually enable global interrupts. To enable | ||
2610 | and disable global interrupts use functions sEnGlobalInt() and | ||
2611 | sDisGlobalInt(). Enabling of global interrupts is normally not | ||
2612 | done until all other initializations are complete. | ||
2613 | |||
2614 | Even if interrupts are globally enabled, they must also be | ||
2615 | individually enabled for each channel that is to generate | ||
2616 | interrupts. | ||
2617 | |||
2618 | Warnings: No range checking on any of the parameters is done. | ||
2619 | |||
2620 | No context switches are allowed while executing this function. | ||
2621 | |||
2622 | After this function all AIOPs on the controller are disabled, | ||
2623 | they can be enabled with sEnAiop(). | ||
2624 | */ | ||
2625 | static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, | ||
2626 | ByteIO_t * AiopIOList, int AiopIOListSize, | ||
2627 | WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, | ||
2628 | int PeriodicOnly, int altChanRingIndicator, | ||
2629 | int UPCIRingInd) | ||
2630 | { | ||
2631 | int i; | ||
2632 | ByteIO_t io; | ||
2633 | |||
2634 | CtlP->AltChanRingIndicator = altChanRingIndicator; | ||
2635 | CtlP->UPCIRingInd = UPCIRingInd; | ||
2636 | CtlP->CtlNum = CtlNum; | ||
2637 | CtlP->CtlID = CTLID_0001; /* controller release 1 */ | ||
2638 | CtlP->BusType = isPCI; /* controller release 1 */ | ||
2639 | |||
2640 | if (ConfigIO) { | ||
2641 | CtlP->isUPCI = 1; | ||
2642 | CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; | ||
2643 | CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; | ||
2644 | CtlP->AiopIntrBits = upci_aiop_intr_bits; | ||
2645 | } else { | ||
2646 | CtlP->isUPCI = 0; | ||
2647 | CtlP->PCIIO = | ||
2648 | (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); | ||
2649 | CtlP->AiopIntrBits = aiop_intr_bits; | ||
2650 | } | ||
2651 | |||
2652 | sPCIControllerEOI(CtlP); /* clear EOI if warm init */ | ||
2653 | /* Init AIOPs */ | ||
2654 | CtlP->NumAiop = 0; | ||
2655 | for (i = 0; i < AiopIOListSize; i++) { | ||
2656 | io = AiopIOList[i]; | ||
2657 | CtlP->AiopIO[i] = (WordIO_t) io; | ||
2658 | CtlP->AiopIntChanIO[i] = io + _INT_CHAN; | ||
2659 | |||
2660 | CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ | ||
2661 | if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ | ||
2662 | break; /* done looking for AIOPs */ | ||
2663 | |||
2664 | CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ | ||
2665 | sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ | ||
2666 | sOutB(io + _INDX_DATA, sClockPrescale); | ||
2667 | CtlP->NumAiop++; /* bump count of AIOPs */ | ||
2668 | } | ||
2669 | |||
2670 | if (CtlP->NumAiop == 0) | ||
2671 | return (-1); | ||
2672 | else | ||
2673 | return (CtlP->NumAiop); | ||
2674 | } | ||
2675 | |||
2676 | /*************************************************************************** | ||
2677 | Function: sReadAiopID | ||
2678 | Purpose: Read the AIOP idenfication number directly from an AIOP. | ||
2679 | Call: sReadAiopID(io) | ||
2680 | ByteIO_t io: AIOP base I/O address | ||
2681 | Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X | ||
2682 | is replace by an identifying number. | ||
2683 | Flag AIOPID_NULL if no valid AIOP is found | ||
2684 | Warnings: No context switches are allowed while executing this function. | ||
2685 | |||
2686 | */ | ||
2687 | static int sReadAiopID(ByteIO_t io) | ||
2688 | { | ||
2689 | Byte_t AiopID; /* ID byte from AIOP */ | ||
2690 | |||
2691 | sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ | ||
2692 | sOutB(io + _CMD_REG, 0x0); | ||
2693 | AiopID = sInW(io + _CHN_STAT0) & 0x07; | ||
2694 | if (AiopID == 0x06) | ||
2695 | return (1); | ||
2696 | else /* AIOP does not exist */ | ||
2697 | return (-1); | ||
2698 | } | ||
2699 | |||
2700 | /*************************************************************************** | ||
2701 | Function: sReadAiopNumChan | ||
2702 | Purpose: Read the number of channels available in an AIOP directly from | ||
2703 | an AIOP. | ||
2704 | Call: sReadAiopNumChan(io) | ||
2705 | WordIO_t io: AIOP base I/O address | ||
2706 | Return: int: The number of channels available | ||
2707 | Comments: The number of channels is determined by write/reads from identical | ||
2708 | offsets within the SRAM address spaces for channels 0 and 4. | ||
2709 | If the channel 4 space is mirrored to channel 0 it is a 4 channel | ||
2710 | AIOP, otherwise it is an 8 channel. | ||
2711 | Warnings: No context switches are allowed while executing this function. | ||
2712 | */ | ||
2713 | static int sReadAiopNumChan(WordIO_t io) | ||
2714 | { | ||
2715 | Word_t x; | ||
2716 | static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; | ||
2717 | |||
2718 | /* write to chan 0 SRAM */ | ||
2719 | out32((DWordIO_t) io + _INDX_ADDR, R); | ||
2720 | sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ | ||
2721 | x = sInW(io + _INDX_DATA); | ||
2722 | sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ | ||
2723 | if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ | ||
2724 | return (8); | ||
2725 | else | ||
2726 | return (4); | ||
2727 | } | ||
2728 | |||
2729 | /*************************************************************************** | ||
2730 | Function: sInitChan | ||
2731 | Purpose: Initialization of a channel and channel structure | ||
2732 | Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) | ||
2733 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
2734 | CHANNEL_T *ChP; Ptr to channel structure | ||
2735 | int AiopNum; AIOP number within controller | ||
2736 | int ChanNum; Channel number within AIOP | ||
2737 | Return: int: 1 if initialization succeeded, 0 if it fails because channel | ||
2738 | number exceeds number of channels available in AIOP. | ||
2739 | Comments: This function must be called before a channel can be used. | ||
2740 | Warnings: No range checking on any of the parameters is done. | ||
2741 | |||
2742 | No context switches are allowed while executing this function. | ||
2743 | */ | ||
2744 | static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, | ||
2745 | int ChanNum) | ||
2746 | { | ||
2747 | int i; | ||
2748 | WordIO_t AiopIO; | ||
2749 | WordIO_t ChIOOff; | ||
2750 | Byte_t *ChR; | ||
2751 | Word_t ChOff; | ||
2752 | static Byte_t R[4]; | ||
2753 | int brd9600; | ||
2754 | |||
2755 | if (ChanNum >= CtlP->AiopNumChan[AiopNum]) | ||
2756 | return 0; /* exceeds num chans in AIOP */ | ||
2757 | |||
2758 | /* Channel, AIOP, and controller identifiers */ | ||
2759 | ChP->CtlP = CtlP; | ||
2760 | ChP->ChanID = CtlP->AiopID[AiopNum]; | ||
2761 | ChP->AiopNum = AiopNum; | ||
2762 | ChP->ChanNum = ChanNum; | ||
2763 | |||
2764 | /* Global direct addresses */ | ||
2765 | AiopIO = CtlP->AiopIO[AiopNum]; | ||
2766 | ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; | ||
2767 | ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; | ||
2768 | ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; | ||
2769 | ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; | ||
2770 | ChP->IndexData = AiopIO + _INDX_DATA; | ||
2771 | |||
2772 | /* Channel direct addresses */ | ||
2773 | ChIOOff = AiopIO + ChP->ChanNum * 2; | ||
2774 | ChP->TxRxData = ChIOOff + _TD0; | ||
2775 | ChP->ChanStat = ChIOOff + _CHN_STAT0; | ||
2776 | ChP->TxRxCount = ChIOOff + _FIFO_CNT0; | ||
2777 | ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; | ||
2778 | |||
2779 | /* Initialize the channel from the RData array */ | ||
2780 | for (i = 0; i < RDATASIZE; i += 4) { | ||
2781 | R[0] = RData[i]; | ||
2782 | R[1] = RData[i + 1] + 0x10 * ChanNum; | ||
2783 | R[2] = RData[i + 2]; | ||
2784 | R[3] = RData[i + 3]; | ||
2785 | out32(ChP->IndexAddr, R); | ||
2786 | } | ||
2787 | |||
2788 | ChR = ChP->R; | ||
2789 | for (i = 0; i < RREGDATASIZE; i += 4) { | ||
2790 | ChR[i] = RRegData[i]; | ||
2791 | ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; | ||
2792 | ChR[i + 2] = RRegData[i + 2]; | ||
2793 | ChR[i + 3] = RRegData[i + 3]; | ||
2794 | } | ||
2795 | |||
2796 | /* Indexed registers */ | ||
2797 | ChOff = (Word_t) ChanNum *0x1000; | ||
2798 | |||
2799 | if (sClockPrescale == 0x14) | ||
2800 | brd9600 = 47; | ||
2801 | else | ||
2802 | brd9600 = 23; | ||
2803 | |||
2804 | ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); | ||
2805 | ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); | ||
2806 | ChP->BaudDiv[2] = (Byte_t) brd9600; | ||
2807 | ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); | ||
2808 | out32(ChP->IndexAddr, ChP->BaudDiv); | ||
2809 | |||
2810 | ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); | ||
2811 | ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); | ||
2812 | ChP->TxControl[2] = 0; | ||
2813 | ChP->TxControl[3] = 0; | ||
2814 | out32(ChP->IndexAddr, ChP->TxControl); | ||
2815 | |||
2816 | ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); | ||
2817 | ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); | ||
2818 | ChP->RxControl[2] = 0; | ||
2819 | ChP->RxControl[3] = 0; | ||
2820 | out32(ChP->IndexAddr, ChP->RxControl); | ||
2821 | |||
2822 | ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); | ||
2823 | ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); | ||
2824 | ChP->TxEnables[2] = 0; | ||
2825 | ChP->TxEnables[3] = 0; | ||
2826 | out32(ChP->IndexAddr, ChP->TxEnables); | ||
2827 | |||
2828 | ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); | ||
2829 | ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); | ||
2830 | ChP->TxCompare[2] = 0; | ||
2831 | ChP->TxCompare[3] = 0; | ||
2832 | out32(ChP->IndexAddr, ChP->TxCompare); | ||
2833 | |||
2834 | ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); | ||
2835 | ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); | ||
2836 | ChP->TxReplace1[2] = 0; | ||
2837 | ChP->TxReplace1[3] = 0; | ||
2838 | out32(ChP->IndexAddr, ChP->TxReplace1); | ||
2839 | |||
2840 | ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); | ||
2841 | ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); | ||
2842 | ChP->TxReplace2[2] = 0; | ||
2843 | ChP->TxReplace2[3] = 0; | ||
2844 | out32(ChP->IndexAddr, ChP->TxReplace2); | ||
2845 | |||
2846 | ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; | ||
2847 | ChP->TxFIFO = ChOff + _TX_FIFO; | ||
2848 | |||
2849 | sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ | ||
2850 | sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ | ||
2851 | sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ | ||
2852 | sOutW(ChP->IndexData, 0); | ||
2853 | ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; | ||
2854 | ChP->RxFIFO = ChOff + _RX_FIFO; | ||
2855 | |||
2856 | sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ | ||
2857 | sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ | ||
2858 | sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ | ||
2859 | sOutW(ChP->IndexData, 0); | ||
2860 | sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ | ||
2861 | sOutW(ChP->IndexData, 0); | ||
2862 | ChP->TxPrioCnt = ChOff + _TXP_CNT; | ||
2863 | sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); | ||
2864 | sOutB(ChP->IndexData, 0); | ||
2865 | ChP->TxPrioPtr = ChOff + _TXP_PNTR; | ||
2866 | sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); | ||
2867 | sOutB(ChP->IndexData, 0); | ||
2868 | ChP->TxPrioBuf = ChOff + _TXP_BUF; | ||
2869 | sEnRxProcessor(ChP); /* start the Rx processor */ | ||
2870 | |||
2871 | return 1; | ||
2872 | } | ||
2873 | |||
2874 | /*************************************************************************** | ||
2875 | Function: sStopRxProcessor | ||
2876 | Purpose: Stop the receive processor from processing a channel. | ||
2877 | Call: sStopRxProcessor(ChP) | ||
2878 | CHANNEL_T *ChP; Ptr to channel structure | ||
2879 | |||
2880 | Comments: The receive processor can be started again with sStartRxProcessor(). | ||
2881 | This function causes the receive processor to skip over the | ||
2882 | stopped channel. It does not stop it from processing other channels. | ||
2883 | |||
2884 | Warnings: No context switches are allowed while executing this function. | ||
2885 | |||
2886 | Do not leave the receive processor stopped for more than one | ||
2887 | character time. | ||
2888 | |||
2889 | After calling this function a delay of 4 uS is required to ensure | ||
2890 | that the receive processor is no longer processing this channel. | ||
2891 | */ | ||
2892 | static void sStopRxProcessor(CHANNEL_T * ChP) | ||
2893 | { | ||
2894 | Byte_t R[4]; | ||
2895 | |||
2896 | R[0] = ChP->R[0]; | ||
2897 | R[1] = ChP->R[1]; | ||
2898 | R[2] = 0x0a; | ||
2899 | R[3] = ChP->R[3]; | ||
2900 | out32(ChP->IndexAddr, R); | ||
2901 | } | ||
2902 | |||
2903 | /*************************************************************************** | ||
2904 | Function: sFlushRxFIFO | ||
2905 | Purpose: Flush the Rx FIFO | ||
2906 | Call: sFlushRxFIFO(ChP) | ||
2907 | CHANNEL_T *ChP; Ptr to channel structure | ||
2908 | Return: void | ||
2909 | Comments: To prevent data from being enqueued or dequeued in the Tx FIFO | ||
2910 | while it is being flushed the receive processor is stopped | ||
2911 | and the transmitter is disabled. After these operations a | ||
2912 | 4 uS delay is done before clearing the pointers to allow | ||
2913 | the receive processor to stop. These items are handled inside | ||
2914 | this function. | ||
2915 | Warnings: No context switches are allowed while executing this function. | ||
2916 | */ | ||
2917 | static void sFlushRxFIFO(CHANNEL_T * ChP) | ||
2918 | { | ||
2919 | int i; | ||
2920 | Byte_t Ch; /* channel number within AIOP */ | ||
2921 | int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ | ||
2922 | |||
2923 | if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ | ||
2924 | return; /* don't need to flush */ | ||
2925 | |||
2926 | RxFIFOEnabled = 0; | ||
2927 | if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ | ||
2928 | RxFIFOEnabled = 1; | ||
2929 | sDisRxFIFO(ChP); /* disable it */ | ||
2930 | for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ | ||
2931 | sInB(ChP->IntChan); /* depends on bus i/o timing */ | ||
2932 | } | ||
2933 | sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ | ||
2934 | Ch = (Byte_t) sGetChanNum(ChP); | ||
2935 | sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ | ||
2936 | sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ | ||
2937 | sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ | ||
2938 | sOutW(ChP->IndexData, 0); | ||
2939 | sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ | ||
2940 | sOutW(ChP->IndexData, 0); | ||
2941 | if (RxFIFOEnabled) | ||
2942 | sEnRxFIFO(ChP); /* enable Rx FIFO */ | ||
2943 | } | ||
2944 | |||
2945 | /*************************************************************************** | ||
2946 | Function: sFlushTxFIFO | ||
2947 | Purpose: Flush the Tx FIFO | ||
2948 | Call: sFlushTxFIFO(ChP) | ||
2949 | CHANNEL_T *ChP; Ptr to channel structure | ||
2950 | Return: void | ||
2951 | Comments: To prevent data from being enqueued or dequeued in the Tx FIFO | ||
2952 | while it is being flushed the receive processor is stopped | ||
2953 | and the transmitter is disabled. After these operations a | ||
2954 | 4 uS delay is done before clearing the pointers to allow | ||
2955 | the receive processor to stop. These items are handled inside | ||
2956 | this function. | ||
2957 | Warnings: No context switches are allowed while executing this function. | ||
2958 | */ | ||
2959 | static void sFlushTxFIFO(CHANNEL_T * ChP) | ||
2960 | { | ||
2961 | int i; | ||
2962 | Byte_t Ch; /* channel number within AIOP */ | ||
2963 | int TxEnabled; /* 1 if transmitter enabled */ | ||
2964 | |||
2965 | if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ | ||
2966 | return; /* don't need to flush */ | ||
2967 | |||
2968 | TxEnabled = 0; | ||
2969 | if (ChP->TxControl[3] & TX_ENABLE) { | ||
2970 | TxEnabled = 1; | ||
2971 | sDisTransmit(ChP); /* disable transmitter */ | ||
2972 | } | ||
2973 | sStopRxProcessor(ChP); /* stop Rx processor */ | ||
2974 | for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ | ||
2975 | sInB(ChP->IntChan); /* depends on bus i/o timing */ | ||
2976 | Ch = (Byte_t) sGetChanNum(ChP); | ||
2977 | sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ | ||
2978 | sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ | ||
2979 | sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ | ||
2980 | sOutW(ChP->IndexData, 0); | ||
2981 | if (TxEnabled) | ||
2982 | sEnTransmit(ChP); /* enable transmitter */ | ||
2983 | sStartRxProcessor(ChP); /* restart Rx processor */ | ||
2984 | } | ||
2985 | |||
2986 | /*************************************************************************** | ||
2987 | Function: sWriteTxPrioByte | ||
2988 | Purpose: Write a byte of priority transmit data to a channel | ||
2989 | Call: sWriteTxPrioByte(ChP,Data) | ||
2990 | CHANNEL_T *ChP; Ptr to channel structure | ||
2991 | Byte_t Data; The transmit data byte | ||
2992 | |||
2993 | Return: int: 1 if the bytes is successfully written, otherwise 0. | ||
2994 | |||
2995 | Comments: The priority byte is transmitted before any data in the Tx FIFO. | ||
2996 | |||
2997 | Warnings: No context switches are allowed while executing this function. | ||
2998 | */ | ||
2999 | static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) | ||
3000 | { | ||
3001 | Byte_t DWBuf[4]; /* buffer for double word writes */ | ||
3002 | Word_t *WordPtr; /* must be far because Win SS != DS */ | ||
3003 | register DWordIO_t IndexAddr; | ||
3004 | |||
3005 | if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ | ||
3006 | IndexAddr = ChP->IndexAddr; | ||
3007 | sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ | ||
3008 | if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ | ||
3009 | return (0); /* nothing sent */ | ||
3010 | |||
3011 | WordPtr = (Word_t *) (&DWBuf[0]); | ||
3012 | *WordPtr = ChP->TxPrioBuf; /* data byte address */ | ||
3013 | |||
3014 | DWBuf[2] = Data; /* data byte value */ | ||
3015 | out32(IndexAddr, DWBuf); /* write it out */ | ||
3016 | |||
3017 | *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ | ||
3018 | |||
3019 | DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ | ||
3020 | DWBuf[3] = 0; /* priority buffer pointer */ | ||
3021 | out32(IndexAddr, DWBuf); /* write it out */ | ||
3022 | } else { /* write it to Tx FIFO */ | ||
3023 | |||
3024 | sWriteTxByte(sGetTxRxDataIO(ChP), Data); | ||
3025 | } | ||
3026 | return (1); /* 1 byte sent */ | ||
3027 | } | ||
3028 | |||
3029 | /*************************************************************************** | ||
3030 | Function: sEnInterrupts | ||
3031 | Purpose: Enable one or more interrupts for a channel | ||
3032 | Call: sEnInterrupts(ChP,Flags) | ||
3033 | CHANNEL_T *ChP; Ptr to channel structure | ||
3034 | Word_t Flags: Interrupt enable flags, can be any combination | ||
3035 | of the following flags: | ||
3036 | TXINT_EN: Interrupt on Tx FIFO empty | ||
3037 | RXINT_EN: Interrupt on Rx FIFO at trigger level (see | ||
3038 | sSetRxTrigger()) | ||
3039 | SRCINT_EN: Interrupt on SRC (Special Rx Condition) | ||
3040 | MCINT_EN: Interrupt on modem input change | ||
3041 | CHANINT_EN: Allow channel interrupt signal to the AIOP's | ||
3042 | Interrupt Channel Register. | ||
3043 | Return: void | ||
3044 | Comments: If an interrupt enable flag is set in Flags, that interrupt will be | ||
3045 | enabled. If an interrupt enable flag is not set in Flags, that | ||
3046 | interrupt will not be changed. Interrupts can be disabled with | ||
3047 | function sDisInterrupts(). | ||
3048 | |||
3049 | This function sets the appropriate bit for the channel in the AIOP's | ||
3050 | Interrupt Mask Register if the CHANINT_EN flag is set. This allows | ||
3051 | this channel's bit to be set in the AIOP's Interrupt Channel Register. | ||
3052 | |||
3053 | Interrupts must also be globally enabled before channel interrupts | ||
3054 | will be passed on to the host. This is done with function | ||
3055 | sEnGlobalInt(). | ||
3056 | |||
3057 | In some cases it may be desirable to disable interrupts globally but | ||
3058 | enable channel interrupts. This would allow the global interrupt | ||
3059 | status register to be used to determine which AIOPs need service. | ||
3060 | */ | ||
3061 | static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) | ||
3062 | { | ||
3063 | Byte_t Mask; /* Interrupt Mask Register */ | ||
3064 | |||
3065 | ChP->RxControl[2] |= | ||
3066 | ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); | ||
3067 | |||
3068 | out32(ChP->IndexAddr, ChP->RxControl); | ||
3069 | |||
3070 | ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); | ||
3071 | |||
3072 | out32(ChP->IndexAddr, ChP->TxControl); | ||
3073 | |||
3074 | if (Flags & CHANINT_EN) { | ||
3075 | Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; | ||
3076 | sOutB(ChP->IntMask, Mask); | ||
3077 | } | ||
3078 | } | ||
3079 | |||
3080 | /*************************************************************************** | ||
3081 | Function: sDisInterrupts | ||
3082 | Purpose: Disable one or more interrupts for a channel | ||
3083 | Call: sDisInterrupts(ChP,Flags) | ||
3084 | CHANNEL_T *ChP; Ptr to channel structure | ||
3085 | Word_t Flags: Interrupt flags, can be any combination | ||
3086 | of the following flags: | ||
3087 | TXINT_EN: Interrupt on Tx FIFO empty | ||
3088 | RXINT_EN: Interrupt on Rx FIFO at trigger level (see | ||
3089 | sSetRxTrigger()) | ||
3090 | SRCINT_EN: Interrupt on SRC (Special Rx Condition) | ||
3091 | MCINT_EN: Interrupt on modem input change | ||
3092 | CHANINT_EN: Disable channel interrupt signal to the | ||
3093 | AIOP's Interrupt Channel Register. | ||
3094 | Return: void | ||
3095 | Comments: If an interrupt flag is set in Flags, that interrupt will be | ||
3096 | disabled. If an interrupt flag is not set in Flags, that | ||
3097 | interrupt will not be changed. Interrupts can be enabled with | ||
3098 | function sEnInterrupts(). | ||
3099 | |||
3100 | This function clears the appropriate bit for the channel in the AIOP's | ||
3101 | Interrupt Mask Register if the CHANINT_EN flag is set. This blocks | ||
3102 | this channel's bit from being set in the AIOP's Interrupt Channel | ||
3103 | Register. | ||
3104 | */ | ||
3105 | static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) | ||
3106 | { | ||
3107 | Byte_t Mask; /* Interrupt Mask Register */ | ||
3108 | |||
3109 | ChP->RxControl[2] &= | ||
3110 | ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); | ||
3111 | out32(ChP->IndexAddr, ChP->RxControl); | ||
3112 | ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); | ||
3113 | out32(ChP->IndexAddr, ChP->TxControl); | ||
3114 | |||
3115 | if (Flags & CHANINT_EN) { | ||
3116 | Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; | ||
3117 | sOutB(ChP->IntMask, Mask); | ||
3118 | } | ||
3119 | } | ||
3120 | |||
3121 | static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) | ||
3122 | { | ||
3123 | sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); | ||
3124 | } | ||
3125 | |||
3126 | /* | ||
3127 | * Not an official SSCI function, but how to reset RocketModems. | ||
3128 | * ISA bus version | ||
3129 | */ | ||
3130 | static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) | ||
3131 | { | ||
3132 | ByteIO_t addr; | ||
3133 | Byte_t val; | ||
3134 | |||
3135 | addr = CtlP->AiopIO[0] + 0x400; | ||
3136 | val = sInB(CtlP->MReg3IO); | ||
3137 | /* if AIOP[1] is not enabled, enable it */ | ||
3138 | if ((val & 2) == 0) { | ||
3139 | val = sInB(CtlP->MReg2IO); | ||
3140 | sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); | ||
3141 | sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); | ||
3142 | } | ||
3143 | |||
3144 | sEnAiop(CtlP, 1); | ||
3145 | if (!on) | ||
3146 | addr += 8; | ||
3147 | sOutB(addr + chan, 0); /* apply or remove reset */ | ||
3148 | sDisAiop(CtlP, 1); | ||
3149 | } | ||
3150 | |||
3151 | /* | ||
3152 | * Not an official SSCI function, but how to reset RocketModems. | ||
3153 | * PCI bus version | ||
3154 | */ | ||
3155 | static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) | ||
3156 | { | ||
3157 | ByteIO_t addr; | ||
3158 | |||
3159 | addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ | ||
3160 | if (!on) | ||
3161 | addr += 8; | ||
3162 | sOutB(addr + chan, 0); /* apply or remove reset */ | ||
3163 | } | ||
3164 | |||
3165 | /* Resets the speaker controller on RocketModem II and III devices */ | ||
3166 | static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) | ||
3167 | { | ||
3168 | ByteIO_t addr; | ||
3169 | |||
3170 | /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ | ||
3171 | if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { | ||
3172 | addr = CtlP->AiopIO[0] + 0x4F; | ||
3173 | sOutB(addr, 0); | ||
3174 | } | ||
3175 | |||
3176 | /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ | ||
3177 | if ((model == MODEL_UPCI_RM3_8PORT) | ||
3178 | || (model == MODEL_UPCI_RM3_4PORT)) { | ||
3179 | addr = CtlP->AiopIO[0] + 0x88; | ||
3180 | sOutB(addr, 0); | ||
3181 | } | ||
3182 | } | ||
3183 | |||
3184 | /* Returns the line number given the controller (board), aiop and channel number */ | ||
3185 | static unsigned char GetLineNumber(int ctrl, int aiop, int ch) | ||
3186 | { | ||
3187 | return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; | ||
3188 | } | ||
3189 | |||
3190 | /* | ||
3191 | * Stores the line number associated with a given controller (board), aiop | ||
3192 | * and channel number. | ||
3193 | * Returns: The line number assigned | ||
3194 | */ | ||
3195 | static unsigned char SetLineNumber(int ctrl, int aiop, int ch) | ||
3196 | { | ||
3197 | lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; | ||
3198 | return (nextLineNumber - 1); | ||
3199 | } | ||
diff --git a/drivers/tty/rocket.h b/drivers/tty/rocket.h new file mode 100644 index 000000000000..ec863f35f1a9 --- /dev/null +++ b/drivers/tty/rocket.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * rocket.h --- the exported interface of the rocket driver to its configuration program. | ||
3 | * | ||
4 | * Written by Theodore Ts'o, Copyright 1997. | ||
5 | * Copyright 1997 Comtrol Corporation. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | /* Model Information Struct */ | ||
10 | typedef struct { | ||
11 | unsigned long model; | ||
12 | char modelString[80]; | ||
13 | unsigned long numPorts; | ||
14 | int loadrm2; | ||
15 | int startingPortNumber; | ||
16 | } rocketModel_t; | ||
17 | |||
18 | struct rocket_config { | ||
19 | int line; | ||
20 | int flags; | ||
21 | int closing_wait; | ||
22 | int close_delay; | ||
23 | int port; | ||
24 | int reserved[32]; | ||
25 | }; | ||
26 | |||
27 | struct rocket_ports { | ||
28 | int tty_major; | ||
29 | int callout_major; | ||
30 | rocketModel_t rocketModel[8]; | ||
31 | }; | ||
32 | |||
33 | struct rocket_version { | ||
34 | char rocket_version[32]; | ||
35 | char rocket_date[32]; | ||
36 | char reserved[64]; | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Rocketport flags | ||
41 | */ | ||
42 | /*#define ROCKET_CALLOUT_NOHUP 0x00000001 */ | ||
43 | #define ROCKET_FORCE_CD 0x00000002 | ||
44 | #define ROCKET_HUP_NOTIFY 0x00000004 | ||
45 | #define ROCKET_SPLIT_TERMIOS 0x00000008 | ||
46 | #define ROCKET_SPD_MASK 0x00000070 | ||
47 | #define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ | ||
48 | #define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ | ||
49 | #define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ | ||
50 | #define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ | ||
51 | #define ROCKET_SAK 0x00000080 | ||
52 | #define ROCKET_SESSION_LOCKOUT 0x00000100 | ||
53 | #define ROCKET_PGRP_LOCKOUT 0x00000200 | ||
54 | #define ROCKET_RTS_TOGGLE 0x00000400 | ||
55 | #define ROCKET_MODE_MASK 0x00003000 | ||
56 | #define ROCKET_MODE_RS232 0x00000000 | ||
57 | #define ROCKET_MODE_RS485 0x00001000 | ||
58 | #define ROCKET_MODE_RS422 0x00002000 | ||
59 | #define ROCKET_FLAGS 0x00003FFF | ||
60 | |||
61 | #define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged | ||
62 | * users can set or reset */ | ||
63 | |||
64 | /* | ||
65 | * For closing_wait and closing_wait2 | ||
66 | */ | ||
67 | #define ROCKET_CLOSING_WAIT_NONE ASYNC_CLOSING_WAIT_NONE | ||
68 | #define ROCKET_CLOSING_WAIT_INF ASYNC_CLOSING_WAIT_INF | ||
69 | |||
70 | /* | ||
71 | * Rocketport ioctls -- "RP" | ||
72 | */ | ||
73 | #define RCKP_GET_STRUCT 0x00525001 | ||
74 | #define RCKP_GET_CONFIG 0x00525002 | ||
75 | #define RCKP_SET_CONFIG 0x00525003 | ||
76 | #define RCKP_GET_PORTS 0x00525004 | ||
77 | #define RCKP_RESET_RM2 0x00525005 | ||
78 | #define RCKP_GET_VERSION 0x00525006 | ||
79 | |||
80 | /* Rocketport Models */ | ||
81 | #define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */ | ||
82 | #define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */ | ||
83 | #define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */ | ||
84 | #define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */ | ||
85 | #define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */ | ||
86 | #define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */ | ||
87 | #define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */ | ||
88 | #define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */ | ||
89 | #define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */ | ||
90 | #define MODEL_RPP4 0x000A /* RP Plus 4 port */ | ||
91 | #define MODEL_RPP8 0x000B /* RP Plus 8 port */ | ||
92 | #define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */ | ||
93 | #define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */ | ||
94 | |||
95 | /* Rocketmodem II Models */ | ||
96 | #define MODEL_RP6M 0x000C /* RM 6 port */ | ||
97 | #define MODEL_RP4M 0x000D /* RM 4 port */ | ||
98 | |||
99 | /* Universal PCI boards */ | ||
100 | #define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */ | ||
101 | #define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */ | ||
102 | #define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */ | ||
103 | #define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */ | ||
104 | #define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */ | ||
105 | #define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */ | ||
106 | |||
107 | /* Compact PCI 16 port */ | ||
108 | #define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */ | ||
109 | |||
110 | /* All ISA boards */ | ||
111 | #define MODEL_ISA 0x1000 | ||
diff --git a/drivers/tty/rocket_int.h b/drivers/tty/rocket_int.h new file mode 100644 index 000000000000..67e0f1e778a2 --- /dev/null +++ b/drivers/tty/rocket_int.h | |||
@@ -0,0 +1,1214 @@ | |||
1 | /* | ||
2 | * rocket_int.h --- internal header file for rocket.c | ||
3 | * | ||
4 | * Written by Theodore Ts'o, Copyright 1997. | ||
5 | * Copyright 1997 Comtrol Corporation. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * Definition of the types in rcktpt_type | ||
11 | */ | ||
12 | #define ROCKET_TYPE_NORMAL 0 | ||
13 | #define ROCKET_TYPE_MODEM 1 | ||
14 | #define ROCKET_TYPE_MODEMII 2 | ||
15 | #define ROCKET_TYPE_MODEMIII 3 | ||
16 | #define ROCKET_TYPE_PC104 4 | ||
17 | |||
18 | #include <linux/mutex.h> | ||
19 | |||
20 | #include <asm/io.h> | ||
21 | #include <asm/byteorder.h> | ||
22 | |||
23 | typedef unsigned char Byte_t; | ||
24 | typedef unsigned int ByteIO_t; | ||
25 | |||
26 | typedef unsigned int Word_t; | ||
27 | typedef unsigned int WordIO_t; | ||
28 | |||
29 | typedef unsigned int DWordIO_t; | ||
30 | |||
31 | /* | ||
32 | * Note! Normally the Linux I/O macros already take care of | ||
33 | * byte-swapping the I/O instructions. However, all accesses using | ||
34 | * sOutDW aren't really 32-bit accesses, but should be handled in byte | ||
35 | * order. Hence the use of the cpu_to_le32() macro to byte-swap | ||
36 | * things to no-op the byte swapping done by the big-endian outl() | ||
37 | * instruction. | ||
38 | */ | ||
39 | |||
40 | static inline void sOutB(unsigned short port, unsigned char value) | ||
41 | { | ||
42 | #ifdef ROCKET_DEBUG_IO | ||
43 | printk(KERN_DEBUG "sOutB(%x, %x)...\n", port, value); | ||
44 | #endif | ||
45 | outb_p(value, port); | ||
46 | } | ||
47 | |||
48 | static inline void sOutW(unsigned short port, unsigned short value) | ||
49 | { | ||
50 | #ifdef ROCKET_DEBUG_IO | ||
51 | printk(KERN_DEBUG "sOutW(%x, %x)...\n", port, value); | ||
52 | #endif | ||
53 | outw_p(value, port); | ||
54 | } | ||
55 | |||
56 | static inline void out32(unsigned short port, Byte_t *p) | ||
57 | { | ||
58 | u32 value = get_unaligned_le32(p); | ||
59 | #ifdef ROCKET_DEBUG_IO | ||
60 | printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); | ||
61 | #endif | ||
62 | outl_p(value, port); | ||
63 | } | ||
64 | |||
65 | static inline unsigned char sInB(unsigned short port) | ||
66 | { | ||
67 | return inb_p(port); | ||
68 | } | ||
69 | |||
70 | static inline unsigned short sInW(unsigned short port) | ||
71 | { | ||
72 | return inw_p(port); | ||
73 | } | ||
74 | |||
75 | /* This is used to move arrays of bytes so byte swapping isn't appropriate. */ | ||
76 | #define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) | ||
77 | #define sInStrW(port, addr, count) if (count) insw(port, addr, count) | ||
78 | |||
79 | #define CTL_SIZE 8 | ||
80 | #define AIOP_CTL_SIZE 4 | ||
81 | #define CHAN_AIOP_SIZE 8 | ||
82 | #define MAX_PORTS_PER_AIOP 8 | ||
83 | #define MAX_AIOPS_PER_BOARD 4 | ||
84 | #define MAX_PORTS_PER_BOARD 32 | ||
85 | |||
86 | /* Bus type ID */ | ||
87 | #define isISA 0 | ||
88 | #define isPCI 1 | ||
89 | #define isMC 2 | ||
90 | |||
91 | /* Controller ID numbers */ | ||
92 | #define CTLID_NULL -1 /* no controller exists */ | ||
93 | #define CTLID_0001 0x0001 /* controller release 1 */ | ||
94 | |||
95 | /* AIOP ID numbers, identifies AIOP type implementing channel */ | ||
96 | #define AIOPID_NULL -1 /* no AIOP or channel exists */ | ||
97 | #define AIOPID_0001 0x0001 /* AIOP release 1 */ | ||
98 | |||
99 | /************************************************************************ | ||
100 | Global Register Offsets - Direct Access - Fixed values | ||
101 | ************************************************************************/ | ||
102 | |||
103 | #define _CMD_REG 0x38 /* Command Register 8 Write */ | ||
104 | #define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ | ||
105 | #define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ | ||
106 | #define _UNUSED 0x3B /* Unused 8 */ | ||
107 | #define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ | ||
108 | #define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ | ||
109 | |||
110 | /************************************************************************ | ||
111 | Channel Register Offsets for 1st channel in AIOP - Direct Access | ||
112 | ************************************************************************/ | ||
113 | #define _TD0 0x00 /* Transmit Data 16 Write */ | ||
114 | #define _RD0 0x00 /* Receive Data 16 Read */ | ||
115 | #define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ | ||
116 | #define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ | ||
117 | #define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ | ||
118 | |||
119 | /************************************************************************ | ||
120 | Tx Control Register Offsets - Indexed - External - Fixed | ||
121 | ************************************************************************/ | ||
122 | #define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ | ||
123 | #define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ | ||
124 | #define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ | ||
125 | #define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ | ||
126 | #define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ | ||
127 | #define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ | ||
128 | |||
129 | /************************************************************************ | ||
130 | Memory Controller Register Offsets - Indexed - External - Fixed | ||
131 | ************************************************************************/ | ||
132 | #define _RX_FIFO 0x000 /* Rx FIFO */ | ||
133 | #define _TX_FIFO 0x800 /* Tx FIFO */ | ||
134 | #define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ | ||
135 | #define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ | ||
136 | #define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ | ||
137 | #define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ | ||
138 | #define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ | ||
139 | #define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ | ||
140 | |||
141 | #define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ | ||
142 | #define TXFIFO_SIZE 255 /* size of Tx FIFO */ | ||
143 | #define RXFIFO_SIZE 1023 /* size of Rx FIFO */ | ||
144 | |||
145 | /************************************************************************ | ||
146 | Tx Priority Buffer - Indexed - External - Fixed | ||
147 | ************************************************************************/ | ||
148 | #define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ | ||
149 | #define TXP_SIZE 0x20 /* 32 bytes */ | ||
150 | |||
151 | /************************************************************************ | ||
152 | Channel Register Offsets - Indexed - Internal - Fixed | ||
153 | ************************************************************************/ | ||
154 | |||
155 | #define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ | ||
156 | #define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ | ||
157 | #define _BAUD 0xFF4 /* Baud Rate 16 Write */ | ||
158 | #define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ | ||
159 | |||
160 | #define STMBREAK 0x08 /* BREAK */ | ||
161 | #define STMFRAME 0x04 /* framing error */ | ||
162 | #define STMRCVROVR 0x02 /* receiver over run error */ | ||
163 | #define STMPARITY 0x01 /* parity error */ | ||
164 | #define STMERROR (STMBREAK | STMFRAME | STMPARITY) | ||
165 | #define STMBREAKH 0x800 /* BREAK */ | ||
166 | #define STMFRAMEH 0x400 /* framing error */ | ||
167 | #define STMRCVROVRH 0x200 /* receiver over run error */ | ||
168 | #define STMPARITYH 0x100 /* parity error */ | ||
169 | #define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) | ||
170 | |||
171 | #define CTS_ACT 0x20 /* CTS input asserted */ | ||
172 | #define DSR_ACT 0x10 /* DSR input asserted */ | ||
173 | #define CD_ACT 0x08 /* CD input asserted */ | ||
174 | #define TXFIFOMT 0x04 /* Tx FIFO is empty */ | ||
175 | #define TXSHRMT 0x02 /* Tx shift register is empty */ | ||
176 | #define RDA 0x01 /* Rx data available */ | ||
177 | #define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ | ||
178 | |||
179 | #define STATMODE 0x8000 /* status mode enable bit */ | ||
180 | #define RXFOVERFL 0x2000 /* receive FIFO overflow */ | ||
181 | #define RX2MATCH 0x1000 /* receive compare byte 2 match */ | ||
182 | #define RX1MATCH 0x0800 /* receive compare byte 1 match */ | ||
183 | #define RXBREAK 0x0400 /* received BREAK */ | ||
184 | #define RXFRAME 0x0200 /* received framing error */ | ||
185 | #define RXPARITY 0x0100 /* received parity error */ | ||
186 | #define STATERROR (RXBREAK | RXFRAME | RXPARITY) | ||
187 | |||
188 | #define CTSFC_EN 0x80 /* CTS flow control enable bit */ | ||
189 | #define RTSTOG_EN 0x40 /* RTS toggle enable bit */ | ||
190 | #define TXINT_EN 0x10 /* transmit interrupt enable */ | ||
191 | #define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ | ||
192 | #define PARITY_EN 0x04 /* enable parity (0 = no parity) */ | ||
193 | #define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ | ||
194 | #define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ | ||
195 | |||
196 | #define SETBREAK 0x10 /* send break condition (must clear) */ | ||
197 | #define LOCALLOOP 0x08 /* local loopback set for test */ | ||
198 | #define SET_DTR 0x04 /* assert DTR */ | ||
199 | #define SET_RTS 0x02 /* assert RTS */ | ||
200 | #define TX_ENABLE 0x01 /* enable transmitter */ | ||
201 | |||
202 | #define RTSFC_EN 0x40 /* RTS flow control enable */ | ||
203 | #define RXPROC_EN 0x20 /* receive processor enable */ | ||
204 | #define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ | ||
205 | #define TRIG_1 0x08 /* trigger level 1 char */ | ||
206 | #define TRIG_1_2 0x10 /* trigger level 1/2 */ | ||
207 | #define TRIG_7_8 0x18 /* trigger level 7/8 */ | ||
208 | #define TRIG_MASK 0x18 /* trigger level mask */ | ||
209 | #define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ | ||
210 | #define RXINT_EN 0x02 /* Rx interrupt enable */ | ||
211 | #define MCINT_EN 0x01 /* modem change interrupt enable */ | ||
212 | |||
213 | #define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ | ||
214 | #define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ | ||
215 | #define SRC_INT 0x08 /* special receive condition interrupt */ | ||
216 | #define DELTA_CD 0x04 /* CD change interrupt */ | ||
217 | #define DELTA_CTS 0x02 /* CTS change interrupt */ | ||
218 | #define DELTA_DSR 0x01 /* DSR change interrupt */ | ||
219 | |||
220 | #define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ | ||
221 | #define IGN2_EN 0x08 /* ignore byte 2 enable */ | ||
222 | #define IGN1_EN 0x04 /* ignore byte 1 enable */ | ||
223 | #define COMP2_EN 0x02 /* compare byte 2 enable */ | ||
224 | #define COMP1_EN 0x01 /* compare byte 1 enable */ | ||
225 | |||
226 | #define RESET_ALL 0x80 /* reset AIOP (all channels) */ | ||
227 | #define TXOVERIDE 0x40 /* Transmit software off override */ | ||
228 | #define RESETUART 0x20 /* reset channel's UART */ | ||
229 | #define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ | ||
230 | #define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ | ||
231 | |||
232 | #define INTSTAT0 0x01 /* AIOP 0 interrupt status */ | ||
233 | #define INTSTAT1 0x02 /* AIOP 1 interrupt status */ | ||
234 | #define INTSTAT2 0x04 /* AIOP 2 interrupt status */ | ||
235 | #define INTSTAT3 0x08 /* AIOP 3 interrupt status */ | ||
236 | |||
237 | #define INTR_EN 0x08 /* allow interrupts to host */ | ||
238 | #define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ | ||
239 | |||
240 | /************************************************************************** | ||
241 | MUDBAC remapped for PCI | ||
242 | **************************************************************************/ | ||
243 | |||
244 | #define _CFG_INT_PCI 0x40 | ||
245 | #define _PCI_INT_FUNC 0x3A | ||
246 | |||
247 | #define PCI_STROB 0x2000 /* bit 13 of int aiop register */ | ||
248 | #define INTR_EN_PCI 0x0010 /* allow interrupts to host */ | ||
249 | |||
250 | /* | ||
251 | * Definitions for Universal PCI board registers | ||
252 | */ | ||
253 | #define _PCI_9030_INT_CTRL 0x4c /* Offsets from BAR1 */ | ||
254 | #define _PCI_9030_GPIO_CTRL 0x54 | ||
255 | #define PCI_INT_CTRL_AIOP 0x0001 | ||
256 | #define PCI_GPIO_CTRL_8PORT 0x4000 | ||
257 | #define _PCI_9030_RING_IND 0xc0 /* Offsets from BAR1 */ | ||
258 | |||
259 | #define CHAN3_EN 0x08 /* enable AIOP 3 */ | ||
260 | #define CHAN2_EN 0x04 /* enable AIOP 2 */ | ||
261 | #define CHAN1_EN 0x02 /* enable AIOP 1 */ | ||
262 | #define CHAN0_EN 0x01 /* enable AIOP 0 */ | ||
263 | #define FREQ_DIS 0x00 | ||
264 | #define FREQ_274HZ 0x60 | ||
265 | #define FREQ_137HZ 0x50 | ||
266 | #define FREQ_69HZ 0x40 | ||
267 | #define FREQ_34HZ 0x30 | ||
268 | #define FREQ_17HZ 0x20 | ||
269 | #define FREQ_9HZ 0x10 | ||
270 | #define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ | ||
271 | |||
272 | #define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ | ||
273 | |||
274 | #define RDATASIZE 72 | ||
275 | #define RREGDATASIZE 52 | ||
276 | |||
277 | /* | ||
278 | * AIOP interrupt bits for ISA/PCI boards and UPCI boards. | ||
279 | */ | ||
280 | #define AIOP_INTR_BIT_0 0x0001 | ||
281 | #define AIOP_INTR_BIT_1 0x0002 | ||
282 | #define AIOP_INTR_BIT_2 0x0004 | ||
283 | #define AIOP_INTR_BIT_3 0x0008 | ||
284 | |||
285 | #define AIOP_INTR_BITS ( \ | ||
286 | AIOP_INTR_BIT_0 \ | ||
287 | | AIOP_INTR_BIT_1 \ | ||
288 | | AIOP_INTR_BIT_2 \ | ||
289 | | AIOP_INTR_BIT_3) | ||
290 | |||
291 | #define UPCI_AIOP_INTR_BIT_0 0x0004 | ||
292 | #define UPCI_AIOP_INTR_BIT_1 0x0020 | ||
293 | #define UPCI_AIOP_INTR_BIT_2 0x0100 | ||
294 | #define UPCI_AIOP_INTR_BIT_3 0x0800 | ||
295 | |||
296 | #define UPCI_AIOP_INTR_BITS ( \ | ||
297 | UPCI_AIOP_INTR_BIT_0 \ | ||
298 | | UPCI_AIOP_INTR_BIT_1 \ | ||
299 | | UPCI_AIOP_INTR_BIT_2 \ | ||
300 | | UPCI_AIOP_INTR_BIT_3) | ||
301 | |||
302 | /* Controller level information structure */ | ||
303 | typedef struct { | ||
304 | int CtlID; | ||
305 | int CtlNum; | ||
306 | int BusType; | ||
307 | int boardType; | ||
308 | int isUPCI; | ||
309 | WordIO_t PCIIO; | ||
310 | WordIO_t PCIIO2; | ||
311 | ByteIO_t MBaseIO; | ||
312 | ByteIO_t MReg1IO; | ||
313 | ByteIO_t MReg2IO; | ||
314 | ByteIO_t MReg3IO; | ||
315 | Byte_t MReg2; | ||
316 | Byte_t MReg3; | ||
317 | int NumAiop; | ||
318 | int AltChanRingIndicator; | ||
319 | ByteIO_t UPCIRingInd; | ||
320 | WordIO_t AiopIO[AIOP_CTL_SIZE]; | ||
321 | ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; | ||
322 | int AiopID[AIOP_CTL_SIZE]; | ||
323 | int AiopNumChan[AIOP_CTL_SIZE]; | ||
324 | Word_t *AiopIntrBits; | ||
325 | } CONTROLLER_T; | ||
326 | |||
327 | typedef CONTROLLER_T CONTROLLER_t; | ||
328 | |||
329 | /* Channel level information structure */ | ||
330 | typedef struct { | ||
331 | CONTROLLER_T *CtlP; | ||
332 | int AiopNum; | ||
333 | int ChanID; | ||
334 | int ChanNum; | ||
335 | int rtsToggle; | ||
336 | |||
337 | ByteIO_t Cmd; | ||
338 | ByteIO_t IntChan; | ||
339 | ByteIO_t IntMask; | ||
340 | DWordIO_t IndexAddr; | ||
341 | WordIO_t IndexData; | ||
342 | |||
343 | WordIO_t TxRxData; | ||
344 | WordIO_t ChanStat; | ||
345 | WordIO_t TxRxCount; | ||
346 | ByteIO_t IntID; | ||
347 | |||
348 | Word_t TxFIFO; | ||
349 | Word_t TxFIFOPtrs; | ||
350 | Word_t RxFIFO; | ||
351 | Word_t RxFIFOPtrs; | ||
352 | Word_t TxPrioCnt; | ||
353 | Word_t TxPrioPtr; | ||
354 | Word_t TxPrioBuf; | ||
355 | |||
356 | Byte_t R[RREGDATASIZE]; | ||
357 | |||
358 | Byte_t BaudDiv[4]; | ||
359 | Byte_t TxControl[4]; | ||
360 | Byte_t RxControl[4]; | ||
361 | Byte_t TxEnables[4]; | ||
362 | Byte_t TxCompare[4]; | ||
363 | Byte_t TxReplace1[4]; | ||
364 | Byte_t TxReplace2[4]; | ||
365 | } CHANNEL_T; | ||
366 | |||
367 | typedef CHANNEL_T CHANNEL_t; | ||
368 | typedef CHANNEL_T *CHANPTR_T; | ||
369 | |||
370 | #define InterfaceModeRS232 0x00 | ||
371 | #define InterfaceModeRS422 0x08 | ||
372 | #define InterfaceModeRS485 0x10 | ||
373 | #define InterfaceModeRS232T 0x18 | ||
374 | |||
375 | /*************************************************************************** | ||
376 | Function: sClrBreak | ||
377 | Purpose: Stop sending a transmit BREAK signal | ||
378 | Call: sClrBreak(ChP) | ||
379 | CHANNEL_T *ChP; Ptr to channel structure | ||
380 | */ | ||
381 | #define sClrBreak(ChP) \ | ||
382 | do { \ | ||
383 | (ChP)->TxControl[3] &= ~SETBREAK; \ | ||
384 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
385 | } while (0) | ||
386 | |||
387 | /*************************************************************************** | ||
388 | Function: sClrDTR | ||
389 | Purpose: Clr the DTR output | ||
390 | Call: sClrDTR(ChP) | ||
391 | CHANNEL_T *ChP; Ptr to channel structure | ||
392 | */ | ||
393 | #define sClrDTR(ChP) \ | ||
394 | do { \ | ||
395 | (ChP)->TxControl[3] &= ~SET_DTR; \ | ||
396 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
397 | } while (0) | ||
398 | |||
399 | /*************************************************************************** | ||
400 | Function: sClrRTS | ||
401 | Purpose: Clr the RTS output | ||
402 | Call: sClrRTS(ChP) | ||
403 | CHANNEL_T *ChP; Ptr to channel structure | ||
404 | */ | ||
405 | #define sClrRTS(ChP) \ | ||
406 | do { \ | ||
407 | if ((ChP)->rtsToggle) break; \ | ||
408 | (ChP)->TxControl[3] &= ~SET_RTS; \ | ||
409 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
410 | } while (0) | ||
411 | |||
412 | /*************************************************************************** | ||
413 | Function: sClrTxXOFF | ||
414 | Purpose: Clear any existing transmit software flow control off condition | ||
415 | Call: sClrTxXOFF(ChP) | ||
416 | CHANNEL_T *ChP; Ptr to channel structure | ||
417 | */ | ||
418 | #define sClrTxXOFF(ChP) \ | ||
419 | do { \ | ||
420 | sOutB((ChP)->Cmd,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ | ||
421 | sOutB((ChP)->Cmd,(Byte_t)(ChP)->ChanNum); \ | ||
422 | } while (0) | ||
423 | |||
424 | /*************************************************************************** | ||
425 | Function: sCtlNumToCtlPtr | ||
426 | Purpose: Convert a controller number to controller structure pointer | ||
427 | Call: sCtlNumToCtlPtr(CtlNum) | ||
428 | int CtlNum; Controller number | ||
429 | Return: CONTROLLER_T *: Ptr to controller structure | ||
430 | */ | ||
431 | #define sCtlNumToCtlPtr(CTLNUM) &sController[CTLNUM] | ||
432 | |||
433 | /*************************************************************************** | ||
434 | Function: sControllerEOI | ||
435 | Purpose: Strobe the MUDBAC's End Of Interrupt bit. | ||
436 | Call: sControllerEOI(CtlP) | ||
437 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
438 | */ | ||
439 | #define sControllerEOI(CTLP) sOutB((CTLP)->MReg2IO,(CTLP)->MReg2 | INT_STROB) | ||
440 | |||
441 | /*************************************************************************** | ||
442 | Function: sPCIControllerEOI | ||
443 | Purpose: Strobe the PCI End Of Interrupt bit. | ||
444 | For the UPCI boards, toggle the AIOP interrupt enable bit | ||
445 | (this was taken from the Windows driver). | ||
446 | Call: sPCIControllerEOI(CtlP) | ||
447 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
448 | */ | ||
449 | #define sPCIControllerEOI(CTLP) \ | ||
450 | do { \ | ||
451 | if ((CTLP)->isUPCI) { \ | ||
452 | Word_t w = sInW((CTLP)->PCIIO); \ | ||
453 | sOutW((CTLP)->PCIIO, (w ^ PCI_INT_CTRL_AIOP)); \ | ||
454 | sOutW((CTLP)->PCIIO, w); \ | ||
455 | } \ | ||
456 | else { \ | ||
457 | sOutW((CTLP)->PCIIO, PCI_STROB); \ | ||
458 | } \ | ||
459 | } while (0) | ||
460 | |||
461 | /*************************************************************************** | ||
462 | Function: sDisAiop | ||
463 | Purpose: Disable I/O access to an AIOP | ||
464 | Call: sDisAiop(CltP) | ||
465 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
466 | int AiopNum; Number of AIOP on controller | ||
467 | */ | ||
468 | #define sDisAiop(CTLP,AIOPNUM) \ | ||
469 | do { \ | ||
470 | (CTLP)->MReg3 &= sBitMapClrTbl[AIOPNUM]; \ | ||
471 | sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ | ||
472 | } while (0) | ||
473 | |||
474 | /*************************************************************************** | ||
475 | Function: sDisCTSFlowCtl | ||
476 | Purpose: Disable output flow control using CTS | ||
477 | Call: sDisCTSFlowCtl(ChP) | ||
478 | CHANNEL_T *ChP; Ptr to channel structure | ||
479 | */ | ||
480 | #define sDisCTSFlowCtl(ChP) \ | ||
481 | do { \ | ||
482 | (ChP)->TxControl[2] &= ~CTSFC_EN; \ | ||
483 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
484 | } while (0) | ||
485 | |||
486 | /*************************************************************************** | ||
487 | Function: sDisIXANY | ||
488 | Purpose: Disable IXANY Software Flow Control | ||
489 | Call: sDisIXANY(ChP) | ||
490 | CHANNEL_T *ChP; Ptr to channel structure | ||
491 | */ | ||
492 | #define sDisIXANY(ChP) \ | ||
493 | do { \ | ||
494 | (ChP)->R[0x0e] = 0x86; \ | ||
495 | out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ | ||
496 | } while (0) | ||
497 | |||
498 | /*************************************************************************** | ||
499 | Function: DisParity | ||
500 | Purpose: Disable parity | ||
501 | Call: sDisParity(ChP) | ||
502 | CHANNEL_T *ChP; Ptr to channel structure | ||
503 | Comments: Function sSetParity() can be used in place of functions sEnParity(), | ||
504 | sDisParity(), sSetOddParity(), and sSetEvenParity(). | ||
505 | */ | ||
506 | #define sDisParity(ChP) \ | ||
507 | do { \ | ||
508 | (ChP)->TxControl[2] &= ~PARITY_EN; \ | ||
509 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
510 | } while (0) | ||
511 | |||
512 | /*************************************************************************** | ||
513 | Function: sDisRTSToggle | ||
514 | Purpose: Disable RTS toggle | ||
515 | Call: sDisRTSToggle(ChP) | ||
516 | CHANNEL_T *ChP; Ptr to channel structure | ||
517 | */ | ||
518 | #define sDisRTSToggle(ChP) \ | ||
519 | do { \ | ||
520 | (ChP)->TxControl[2] &= ~RTSTOG_EN; \ | ||
521 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
522 | (ChP)->rtsToggle = 0; \ | ||
523 | } while (0) | ||
524 | |||
525 | /*************************************************************************** | ||
526 | Function: sDisRxFIFO | ||
527 | Purpose: Disable Rx FIFO | ||
528 | Call: sDisRxFIFO(ChP) | ||
529 | CHANNEL_T *ChP; Ptr to channel structure | ||
530 | */ | ||
531 | #define sDisRxFIFO(ChP) \ | ||
532 | do { \ | ||
533 | (ChP)->R[0x32] = 0x0a; \ | ||
534 | out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ | ||
535 | } while (0) | ||
536 | |||
537 | /*************************************************************************** | ||
538 | Function: sDisRxStatusMode | ||
539 | Purpose: Disable the Rx status mode | ||
540 | Call: sDisRxStatusMode(ChP) | ||
541 | CHANNEL_T *ChP; Ptr to channel structure | ||
542 | Comments: This takes the channel out of the receive status mode. All | ||
543 | subsequent reads of receive data using sReadRxWord() will return | ||
544 | two data bytes. | ||
545 | */ | ||
546 | #define sDisRxStatusMode(ChP) sOutW((ChP)->ChanStat,0) | ||
547 | |||
548 | /*************************************************************************** | ||
549 | Function: sDisTransmit | ||
550 | Purpose: Disable transmit | ||
551 | Call: sDisTransmit(ChP) | ||
552 | CHANNEL_T *ChP; Ptr to channel structure | ||
553 | This disables movement of Tx data from the Tx FIFO into the 1 byte | ||
554 | Tx buffer. Therefore there could be up to a 2 byte latency | ||
555 | between the time sDisTransmit() is called and the transmit buffer | ||
556 | and transmit shift register going completely empty. | ||
557 | */ | ||
558 | #define sDisTransmit(ChP) \ | ||
559 | do { \ | ||
560 | (ChP)->TxControl[3] &= ~TX_ENABLE; \ | ||
561 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
562 | } while (0) | ||
563 | |||
564 | /*************************************************************************** | ||
565 | Function: sDisTxSoftFlowCtl | ||
566 | Purpose: Disable Tx Software Flow Control | ||
567 | Call: sDisTxSoftFlowCtl(ChP) | ||
568 | CHANNEL_T *ChP; Ptr to channel structure | ||
569 | */ | ||
570 | #define sDisTxSoftFlowCtl(ChP) \ | ||
571 | do { \ | ||
572 | (ChP)->R[0x06] = 0x8a; \ | ||
573 | out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ | ||
574 | } while (0) | ||
575 | |||
576 | /*************************************************************************** | ||
577 | Function: sEnAiop | ||
578 | Purpose: Enable I/O access to an AIOP | ||
579 | Call: sEnAiop(CltP) | ||
580 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
581 | int AiopNum; Number of AIOP on controller | ||
582 | */ | ||
583 | #define sEnAiop(CTLP,AIOPNUM) \ | ||
584 | do { \ | ||
585 | (CTLP)->MReg3 |= sBitMapSetTbl[AIOPNUM]; \ | ||
586 | sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ | ||
587 | } while (0) | ||
588 | |||
589 | /*************************************************************************** | ||
590 | Function: sEnCTSFlowCtl | ||
591 | Purpose: Enable output flow control using CTS | ||
592 | Call: sEnCTSFlowCtl(ChP) | ||
593 | CHANNEL_T *ChP; Ptr to channel structure | ||
594 | */ | ||
595 | #define sEnCTSFlowCtl(ChP) \ | ||
596 | do { \ | ||
597 | (ChP)->TxControl[2] |= CTSFC_EN; \ | ||
598 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
599 | } while (0) | ||
600 | |||
601 | /*************************************************************************** | ||
602 | Function: sEnIXANY | ||
603 | Purpose: Enable IXANY Software Flow Control | ||
604 | Call: sEnIXANY(ChP) | ||
605 | CHANNEL_T *ChP; Ptr to channel structure | ||
606 | */ | ||
607 | #define sEnIXANY(ChP) \ | ||
608 | do { \ | ||
609 | (ChP)->R[0x0e] = 0x21; \ | ||
610 | out32((ChP)->IndexAddr,&(ChP)->R[0x0c]); \ | ||
611 | } while (0) | ||
612 | |||
613 | /*************************************************************************** | ||
614 | Function: EnParity | ||
615 | Purpose: Enable parity | ||
616 | Call: sEnParity(ChP) | ||
617 | CHANNEL_T *ChP; Ptr to channel structure | ||
618 | Comments: Function sSetParity() can be used in place of functions sEnParity(), | ||
619 | sDisParity(), sSetOddParity(), and sSetEvenParity(). | ||
620 | |||
621 | Warnings: Before enabling parity odd or even parity should be chosen using | ||
622 | functions sSetOddParity() or sSetEvenParity(). | ||
623 | */ | ||
624 | #define sEnParity(ChP) \ | ||
625 | do { \ | ||
626 | (ChP)->TxControl[2] |= PARITY_EN; \ | ||
627 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
628 | } while (0) | ||
629 | |||
630 | /*************************************************************************** | ||
631 | Function: sEnRTSToggle | ||
632 | Purpose: Enable RTS toggle | ||
633 | Call: sEnRTSToggle(ChP) | ||
634 | CHANNEL_T *ChP; Ptr to channel structure | ||
635 | Comments: This function will disable RTS flow control and clear the RTS | ||
636 | line to allow operation of RTS toggle. | ||
637 | */ | ||
638 | #define sEnRTSToggle(ChP) \ | ||
639 | do { \ | ||
640 | (ChP)->RxControl[2] &= ~RTSFC_EN; \ | ||
641 | out32((ChP)->IndexAddr,(ChP)->RxControl); \ | ||
642 | (ChP)->TxControl[2] |= RTSTOG_EN; \ | ||
643 | (ChP)->TxControl[3] &= ~SET_RTS; \ | ||
644 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
645 | (ChP)->rtsToggle = 1; \ | ||
646 | } while (0) | ||
647 | |||
648 | /*************************************************************************** | ||
649 | Function: sEnRxFIFO | ||
650 | Purpose: Enable Rx FIFO | ||
651 | Call: sEnRxFIFO(ChP) | ||
652 | CHANNEL_T *ChP; Ptr to channel structure | ||
653 | */ | ||
654 | #define sEnRxFIFO(ChP) \ | ||
655 | do { \ | ||
656 | (ChP)->R[0x32] = 0x08; \ | ||
657 | out32((ChP)->IndexAddr,&(ChP)->R[0x30]); \ | ||
658 | } while (0) | ||
659 | |||
660 | /*************************************************************************** | ||
661 | Function: sEnRxProcessor | ||
662 | Purpose: Enable the receive processor | ||
663 | Call: sEnRxProcessor(ChP) | ||
664 | CHANNEL_T *ChP; Ptr to channel structure | ||
665 | Comments: This function is used to start the receive processor. When | ||
666 | the channel is in the reset state the receive processor is not | ||
667 | running. This is done to prevent the receive processor from | ||
668 | executing invalid microcode instructions prior to the | ||
669 | downloading of the microcode. | ||
670 | |||
671 | Warnings: This function must be called after valid microcode has been | ||
672 | downloaded to the AIOP, and it must not be called before the | ||
673 | microcode has been downloaded. | ||
674 | */ | ||
675 | #define sEnRxProcessor(ChP) \ | ||
676 | do { \ | ||
677 | (ChP)->RxControl[2] |= RXPROC_EN; \ | ||
678 | out32((ChP)->IndexAddr,(ChP)->RxControl); \ | ||
679 | } while (0) | ||
680 | |||
681 | /*************************************************************************** | ||
682 | Function: sEnRxStatusMode | ||
683 | Purpose: Enable the Rx status mode | ||
684 | Call: sEnRxStatusMode(ChP) | ||
685 | CHANNEL_T *ChP; Ptr to channel structure | ||
686 | Comments: This places the channel in the receive status mode. All subsequent | ||
687 | reads of receive data using sReadRxWord() will return a data byte | ||
688 | in the low word and a status byte in the high word. | ||
689 | |||
690 | */ | ||
691 | #define sEnRxStatusMode(ChP) sOutW((ChP)->ChanStat,STATMODE) | ||
692 | |||
693 | /*************************************************************************** | ||
694 | Function: sEnTransmit | ||
695 | Purpose: Enable transmit | ||
696 | Call: sEnTransmit(ChP) | ||
697 | CHANNEL_T *ChP; Ptr to channel structure | ||
698 | */ | ||
699 | #define sEnTransmit(ChP) \ | ||
700 | do { \ | ||
701 | (ChP)->TxControl[3] |= TX_ENABLE; \ | ||
702 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
703 | } while (0) | ||
704 | |||
705 | /*************************************************************************** | ||
706 | Function: sEnTxSoftFlowCtl | ||
707 | Purpose: Enable Tx Software Flow Control | ||
708 | Call: sEnTxSoftFlowCtl(ChP) | ||
709 | CHANNEL_T *ChP; Ptr to channel structure | ||
710 | */ | ||
711 | #define sEnTxSoftFlowCtl(ChP) \ | ||
712 | do { \ | ||
713 | (ChP)->R[0x06] = 0xc5; \ | ||
714 | out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ | ||
715 | } while (0) | ||
716 | |||
717 | /*************************************************************************** | ||
718 | Function: sGetAiopIntStatus | ||
719 | Purpose: Get the AIOP interrupt status | ||
720 | Call: sGetAiopIntStatus(CtlP,AiopNum) | ||
721 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
722 | int AiopNum; AIOP number | ||
723 | Return: Byte_t: The AIOP interrupt status. Bits 0 through 7 | ||
724 | represent channels 0 through 7 respectively. If a | ||
725 | bit is set that channel is interrupting. | ||
726 | */ | ||
727 | #define sGetAiopIntStatus(CTLP,AIOPNUM) sInB((CTLP)->AiopIntChanIO[AIOPNUM]) | ||
728 | |||
729 | /*************************************************************************** | ||
730 | Function: sGetAiopNumChan | ||
731 | Purpose: Get the number of channels supported by an AIOP | ||
732 | Call: sGetAiopNumChan(CtlP,AiopNum) | ||
733 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
734 | int AiopNum; AIOP number | ||
735 | Return: int: The number of channels supported by the AIOP | ||
736 | */ | ||
737 | #define sGetAiopNumChan(CTLP,AIOPNUM) (CTLP)->AiopNumChan[AIOPNUM] | ||
738 | |||
739 | /*************************************************************************** | ||
740 | Function: sGetChanIntID | ||
741 | Purpose: Get a channel's interrupt identification byte | ||
742 | Call: sGetChanIntID(ChP) | ||
743 | CHANNEL_T *ChP; Ptr to channel structure | ||
744 | Return: Byte_t: The channel interrupt ID. Can be any | ||
745 | combination of the following flags: | ||
746 | RXF_TRIG: Rx FIFO trigger level interrupt | ||
747 | TXFIFO_MT: Tx FIFO empty interrupt | ||
748 | SRC_INT: Special receive condition interrupt | ||
749 | DELTA_CD: CD change interrupt | ||
750 | DELTA_CTS: CTS change interrupt | ||
751 | DELTA_DSR: DSR change interrupt | ||
752 | */ | ||
753 | #define sGetChanIntID(ChP) (sInB((ChP)->IntID) & (RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR)) | ||
754 | |||
755 | /*************************************************************************** | ||
756 | Function: sGetChanNum | ||
757 | Purpose: Get the number of a channel within an AIOP | ||
758 | Call: sGetChanNum(ChP) | ||
759 | CHANNEL_T *ChP; Ptr to channel structure | ||
760 | Return: int: Channel number within AIOP, or NULLCHAN if channel does | ||
761 | not exist. | ||
762 | */ | ||
763 | #define sGetChanNum(ChP) (ChP)->ChanNum | ||
764 | |||
765 | /*************************************************************************** | ||
766 | Function: sGetChanStatus | ||
767 | Purpose: Get the channel status | ||
768 | Call: sGetChanStatus(ChP) | ||
769 | CHANNEL_T *ChP; Ptr to channel structure | ||
770 | Return: Word_t: The channel status. Can be any combination of | ||
771 | the following flags: | ||
772 | LOW BYTE FLAGS | ||
773 | CTS_ACT: CTS input asserted | ||
774 | DSR_ACT: DSR input asserted | ||
775 | CD_ACT: CD input asserted | ||
776 | TXFIFOMT: Tx FIFO is empty | ||
777 | TXSHRMT: Tx shift register is empty | ||
778 | RDA: Rx data available | ||
779 | |||
780 | HIGH BYTE FLAGS | ||
781 | STATMODE: status mode enable bit | ||
782 | RXFOVERFL: receive FIFO overflow | ||
783 | RX2MATCH: receive compare byte 2 match | ||
784 | RX1MATCH: receive compare byte 1 match | ||
785 | RXBREAK: received BREAK | ||
786 | RXFRAME: received framing error | ||
787 | RXPARITY: received parity error | ||
788 | Warnings: This function will clear the high byte flags in the Channel | ||
789 | Status Register. | ||
790 | */ | ||
791 | #define sGetChanStatus(ChP) sInW((ChP)->ChanStat) | ||
792 | |||
793 | /*************************************************************************** | ||
794 | Function: sGetChanStatusLo | ||
795 | Purpose: Get the low byte only of the channel status | ||
796 | Call: sGetChanStatusLo(ChP) | ||
797 | CHANNEL_T *ChP; Ptr to channel structure | ||
798 | Return: Byte_t: The channel status low byte. Can be any combination | ||
799 | of the following flags: | ||
800 | CTS_ACT: CTS input asserted | ||
801 | DSR_ACT: DSR input asserted | ||
802 | CD_ACT: CD input asserted | ||
803 | TXFIFOMT: Tx FIFO is empty | ||
804 | TXSHRMT: Tx shift register is empty | ||
805 | RDA: Rx data available | ||
806 | */ | ||
807 | #define sGetChanStatusLo(ChP) sInB((ByteIO_t)(ChP)->ChanStat) | ||
808 | |||
809 | /********************************************************************** | ||
810 | * Get RI status of channel | ||
811 | * Defined as a function in rocket.c -aes | ||
812 | */ | ||
813 | #if 0 | ||
814 | #define sGetChanRI(ChP) ((ChP)->CtlP->AltChanRingIndicator ? \ | ||
815 | (sInB((ByteIO_t)((ChP)->ChanStat+8)) & DSR_ACT) : \ | ||
816 | (((ChP)->CtlP->boardType == ROCKET_TYPE_PC104) ? \ | ||
817 | (!(sInB((ChP)->CtlP->AiopIO[3]) & sBitMapSetTbl[(ChP)->ChanNum])) : \ | ||
818 | 0)) | ||
819 | #endif | ||
820 | |||
821 | /*************************************************************************** | ||
822 | Function: sGetControllerIntStatus | ||
823 | Purpose: Get the controller interrupt status | ||
824 | Call: sGetControllerIntStatus(CtlP) | ||
825 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
826 | Return: Byte_t: The controller interrupt status in the lower 4 | ||
827 | bits. Bits 0 through 3 represent AIOP's 0 | ||
828 | through 3 respectively. If a bit is set that | ||
829 | AIOP is interrupting. Bits 4 through 7 will | ||
830 | always be cleared. | ||
831 | */ | ||
832 | #define sGetControllerIntStatus(CTLP) (sInB((CTLP)->MReg1IO) & 0x0f) | ||
833 | |||
834 | /*************************************************************************** | ||
835 | Function: sPCIGetControllerIntStatus | ||
836 | Purpose: Get the controller interrupt status | ||
837 | Call: sPCIGetControllerIntStatus(CtlP) | ||
838 | CONTROLLER_T *CtlP; Ptr to controller structure | ||
839 | Return: unsigned char: The controller interrupt status in the lower 4 | ||
840 | bits and bit 4. Bits 0 through 3 represent AIOP's 0 | ||
841 | through 3 respectively. Bit 4 is set if the int | ||
842 | was generated from periodic. If a bit is set the | ||
843 | AIOP is interrupting. | ||
844 | */ | ||
845 | #define sPCIGetControllerIntStatus(CTLP) \ | ||
846 | ((CTLP)->isUPCI ? \ | ||
847 | (sInW((CTLP)->PCIIO2) & UPCI_AIOP_INTR_BITS) : \ | ||
848 | ((sInW((CTLP)->PCIIO) >> 8) & AIOP_INTR_BITS)) | ||
849 | |||
850 | /*************************************************************************** | ||
851 | |||
852 | Function: sGetRxCnt | ||
853 | Purpose: Get the number of data bytes in the Rx FIFO | ||
854 | Call: sGetRxCnt(ChP) | ||
855 | CHANNEL_T *ChP; Ptr to channel structure | ||
856 | Return: int: The number of data bytes in the Rx FIFO. | ||
857 | Comments: Byte read of count register is required to obtain Rx count. | ||
858 | |||
859 | */ | ||
860 | #define sGetRxCnt(ChP) sInW((ChP)->TxRxCount) | ||
861 | |||
862 | /*************************************************************************** | ||
863 | Function: sGetTxCnt | ||
864 | Purpose: Get the number of data bytes in the Tx FIFO | ||
865 | Call: sGetTxCnt(ChP) | ||
866 | CHANNEL_T *ChP; Ptr to channel structure | ||
867 | Return: Byte_t: The number of data bytes in the Tx FIFO. | ||
868 | Comments: Byte read of count register is required to obtain Tx count. | ||
869 | |||
870 | */ | ||
871 | #define sGetTxCnt(ChP) sInB((ByteIO_t)(ChP)->TxRxCount) | ||
872 | |||
873 | /***************************************************************************** | ||
874 | Function: sGetTxRxDataIO | ||
875 | Purpose: Get the I/O address of a channel's TxRx Data register | ||
876 | Call: sGetTxRxDataIO(ChP) | ||
877 | CHANNEL_T *ChP; Ptr to channel structure | ||
878 | Return: WordIO_t: I/O address of a channel's TxRx Data register | ||
879 | */ | ||
880 | #define sGetTxRxDataIO(ChP) (ChP)->TxRxData | ||
881 | |||
882 | /*************************************************************************** | ||
883 | Function: sInitChanDefaults | ||
884 | Purpose: Initialize a channel structure to it's default state. | ||
885 | Call: sInitChanDefaults(ChP) | ||
886 | CHANNEL_T *ChP; Ptr to the channel structure | ||
887 | Comments: This function must be called once for every channel structure | ||
888 | that exists before any other SSCI calls can be made. | ||
889 | |||
890 | */ | ||
891 | #define sInitChanDefaults(ChP) \ | ||
892 | do { \ | ||
893 | (ChP)->CtlP = NULLCTLPTR; \ | ||
894 | (ChP)->AiopNum = NULLAIOP; \ | ||
895 | (ChP)->ChanID = AIOPID_NULL; \ | ||
896 | (ChP)->ChanNum = NULLCHAN; \ | ||
897 | } while (0) | ||
898 | |||
899 | /*************************************************************************** | ||
900 | Function: sResetAiopByNum | ||
901 | Purpose: Reset the AIOP by number | ||
902 | Call: sResetAiopByNum(CTLP,AIOPNUM) | ||
903 | CONTROLLER_T CTLP; Ptr to controller structure | ||
904 | AIOPNUM; AIOP index | ||
905 | */ | ||
906 | #define sResetAiopByNum(CTLP,AIOPNUM) \ | ||
907 | do { \ | ||
908 | sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,RESET_ALL); \ | ||
909 | sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,0x0); \ | ||
910 | } while (0) | ||
911 | |||
912 | /*************************************************************************** | ||
913 | Function: sSendBreak | ||
914 | Purpose: Send a transmit BREAK signal | ||
915 | Call: sSendBreak(ChP) | ||
916 | CHANNEL_T *ChP; Ptr to channel structure | ||
917 | */ | ||
918 | #define sSendBreak(ChP) \ | ||
919 | do { \ | ||
920 | (ChP)->TxControl[3] |= SETBREAK; \ | ||
921 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
922 | } while (0) | ||
923 | |||
924 | /*************************************************************************** | ||
925 | Function: sSetBaud | ||
926 | Purpose: Set baud rate | ||
927 | Call: sSetBaud(ChP,Divisor) | ||
928 | CHANNEL_T *ChP; Ptr to channel structure | ||
929 | Word_t Divisor; 16 bit baud rate divisor for channel | ||
930 | */ | ||
931 | #define sSetBaud(ChP,DIVISOR) \ | ||
932 | do { \ | ||
933 | (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ | ||
934 | (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ | ||
935 | out32((ChP)->IndexAddr,(ChP)->BaudDiv); \ | ||
936 | } while (0) | ||
937 | |||
938 | /*************************************************************************** | ||
939 | Function: sSetData7 | ||
940 | Purpose: Set data bits to 7 | ||
941 | Call: sSetData7(ChP) | ||
942 | CHANNEL_T *ChP; Ptr to channel structure | ||
943 | */ | ||
944 | #define sSetData7(ChP) \ | ||
945 | do { \ | ||
946 | (ChP)->TxControl[2] &= ~DATA8BIT; \ | ||
947 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
948 | } while (0) | ||
949 | |||
950 | /*************************************************************************** | ||
951 | Function: sSetData8 | ||
952 | Purpose: Set data bits to 8 | ||
953 | Call: sSetData8(ChP) | ||
954 | CHANNEL_T *ChP; Ptr to channel structure | ||
955 | */ | ||
956 | #define sSetData8(ChP) \ | ||
957 | do { \ | ||
958 | (ChP)->TxControl[2] |= DATA8BIT; \ | ||
959 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
960 | } while (0) | ||
961 | |||
962 | /*************************************************************************** | ||
963 | Function: sSetDTR | ||
964 | Purpose: Set the DTR output | ||
965 | Call: sSetDTR(ChP) | ||
966 | CHANNEL_T *ChP; Ptr to channel structure | ||
967 | */ | ||
968 | #define sSetDTR(ChP) \ | ||
969 | do { \ | ||
970 | (ChP)->TxControl[3] |= SET_DTR; \ | ||
971 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
972 | } while (0) | ||
973 | |||
974 | /*************************************************************************** | ||
975 | Function: sSetEvenParity | ||
976 | Purpose: Set even parity | ||
977 | Call: sSetEvenParity(ChP) | ||
978 | CHANNEL_T *ChP; Ptr to channel structure | ||
979 | Comments: Function sSetParity() can be used in place of functions sEnParity(), | ||
980 | sDisParity(), sSetOddParity(), and sSetEvenParity(). | ||
981 | |||
982 | Warnings: This function has no effect unless parity is enabled with function | ||
983 | sEnParity(). | ||
984 | */ | ||
985 | #define sSetEvenParity(ChP) \ | ||
986 | do { \ | ||
987 | (ChP)->TxControl[2] |= EVEN_PAR; \ | ||
988 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
989 | } while (0) | ||
990 | |||
991 | /*************************************************************************** | ||
992 | Function: sSetOddParity | ||
993 | Purpose: Set odd parity | ||
994 | Call: sSetOddParity(ChP) | ||
995 | CHANNEL_T *ChP; Ptr to channel structure | ||
996 | Comments: Function sSetParity() can be used in place of functions sEnParity(), | ||
997 | sDisParity(), sSetOddParity(), and sSetEvenParity(). | ||
998 | |||
999 | Warnings: This function has no effect unless parity is enabled with function | ||
1000 | sEnParity(). | ||
1001 | */ | ||
1002 | #define sSetOddParity(ChP) \ | ||
1003 | do { \ | ||
1004 | (ChP)->TxControl[2] &= ~EVEN_PAR; \ | ||
1005 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
1006 | } while (0) | ||
1007 | |||
1008 | /*************************************************************************** | ||
1009 | Function: sSetRTS | ||
1010 | Purpose: Set the RTS output | ||
1011 | Call: sSetRTS(ChP) | ||
1012 | CHANNEL_T *ChP; Ptr to channel structure | ||
1013 | */ | ||
1014 | #define sSetRTS(ChP) \ | ||
1015 | do { \ | ||
1016 | if ((ChP)->rtsToggle) break; \ | ||
1017 | (ChP)->TxControl[3] |= SET_RTS; \ | ||
1018 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
1019 | } while (0) | ||
1020 | |||
1021 | /*************************************************************************** | ||
1022 | Function: sSetRxTrigger | ||
1023 | Purpose: Set the Rx FIFO trigger level | ||
1024 | Call: sSetRxProcessor(ChP,Level) | ||
1025 | CHANNEL_T *ChP; Ptr to channel structure | ||
1026 | Byte_t Level; Number of characters in Rx FIFO at which the | ||
1027 | interrupt will be generated. Can be any of the following flags: | ||
1028 | |||
1029 | TRIG_NO: no trigger | ||
1030 | TRIG_1: 1 character in FIFO | ||
1031 | TRIG_1_2: FIFO 1/2 full | ||
1032 | TRIG_7_8: FIFO 7/8 full | ||
1033 | Comments: An interrupt will be generated when the trigger level is reached | ||
1034 | only if function sEnInterrupt() has been called with flag | ||
1035 | RXINT_EN set. The RXF_TRIG flag in the Interrupt Idenfification | ||
1036 | register will be set whenever the trigger level is reached | ||
1037 | regardless of the setting of RXINT_EN. | ||
1038 | |||
1039 | */ | ||
1040 | #define sSetRxTrigger(ChP,LEVEL) \ | ||
1041 | do { \ | ||
1042 | (ChP)->RxControl[2] &= ~TRIG_MASK; \ | ||
1043 | (ChP)->RxControl[2] |= LEVEL; \ | ||
1044 | out32((ChP)->IndexAddr,(ChP)->RxControl); \ | ||
1045 | } while (0) | ||
1046 | |||
1047 | /*************************************************************************** | ||
1048 | Function: sSetStop1 | ||
1049 | Purpose: Set stop bits to 1 | ||
1050 | Call: sSetStop1(ChP) | ||
1051 | CHANNEL_T *ChP; Ptr to channel structure | ||
1052 | */ | ||
1053 | #define sSetStop1(ChP) \ | ||
1054 | do { \ | ||
1055 | (ChP)->TxControl[2] &= ~STOP2; \ | ||
1056 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
1057 | } while (0) | ||
1058 | |||
1059 | /*************************************************************************** | ||
1060 | Function: sSetStop2 | ||
1061 | Purpose: Set stop bits to 2 | ||
1062 | Call: sSetStop2(ChP) | ||
1063 | CHANNEL_T *ChP; Ptr to channel structure | ||
1064 | */ | ||
1065 | #define sSetStop2(ChP) \ | ||
1066 | do { \ | ||
1067 | (ChP)->TxControl[2] |= STOP2; \ | ||
1068 | out32((ChP)->IndexAddr,(ChP)->TxControl); \ | ||
1069 | } while (0) | ||
1070 | |||
1071 | /*************************************************************************** | ||
1072 | Function: sSetTxXOFFChar | ||
1073 | Purpose: Set the Tx XOFF flow control character | ||
1074 | Call: sSetTxXOFFChar(ChP,Ch) | ||
1075 | CHANNEL_T *ChP; Ptr to channel structure | ||
1076 | Byte_t Ch; The value to set the Tx XOFF character to | ||
1077 | */ | ||
1078 | #define sSetTxXOFFChar(ChP,CH) \ | ||
1079 | do { \ | ||
1080 | (ChP)->R[0x07] = (CH); \ | ||
1081 | out32((ChP)->IndexAddr,&(ChP)->R[0x04]); \ | ||
1082 | } while (0) | ||
1083 | |||
1084 | /*************************************************************************** | ||
1085 | Function: sSetTxXONChar | ||
1086 | Purpose: Set the Tx XON flow control character | ||
1087 | Call: sSetTxXONChar(ChP,Ch) | ||
1088 | CHANNEL_T *ChP; Ptr to channel structure | ||
1089 | Byte_t Ch; The value to set the Tx XON character to | ||
1090 | */ | ||
1091 | #define sSetTxXONChar(ChP,CH) \ | ||
1092 | do { \ | ||
1093 | (ChP)->R[0x0b] = (CH); \ | ||
1094 | out32((ChP)->IndexAddr,&(ChP)->R[0x08]); \ | ||
1095 | } while (0) | ||
1096 | |||
1097 | /*************************************************************************** | ||
1098 | Function: sStartRxProcessor | ||
1099 | Purpose: Start a channel's receive processor | ||
1100 | Call: sStartRxProcessor(ChP) | ||
1101 | CHANNEL_T *ChP; Ptr to channel structure | ||
1102 | Comments: This function is used to start a Rx processor after it was | ||
1103 | stopped with sStopRxProcessor() or sStopSWInFlowCtl(). It | ||
1104 | will restart both the Rx processor and software input flow control. | ||
1105 | |||
1106 | */ | ||
1107 | #define sStartRxProcessor(ChP) out32((ChP)->IndexAddr,&(ChP)->R[0]) | ||
1108 | |||
1109 | /*************************************************************************** | ||
1110 | Function: sWriteTxByte | ||
1111 | Purpose: Write a transmit data byte to a channel. | ||
1112 | ByteIO_t io: Channel transmit register I/O address. This can | ||
1113 | be obtained with sGetTxRxDataIO(). | ||
1114 | Byte_t Data; The transmit data byte. | ||
1115 | Warnings: This function writes the data byte without checking to see if | ||
1116 | sMaxTxSize is exceeded in the Tx FIFO. | ||
1117 | */ | ||
1118 | #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) | ||
1119 | |||
1120 | /* | ||
1121 | * Begin Linux specific definitions for the Rocketport driver | ||
1122 | * | ||
1123 | * This code is Copyright Theodore Ts'o, 1995-1997 | ||
1124 | */ | ||
1125 | |||
1126 | struct r_port { | ||
1127 | int magic; | ||
1128 | struct tty_port port; | ||
1129 | int line; | ||
1130 | int flags; /* Don't yet match the ASY_ flags!! */ | ||
1131 | unsigned int board:3; | ||
1132 | unsigned int aiop:2; | ||
1133 | unsigned int chan:3; | ||
1134 | CONTROLLER_t *ctlp; | ||
1135 | CHANNEL_t channel; | ||
1136 | int intmask; | ||
1137 | int xmit_fifo_room; /* room in xmit fifo */ | ||
1138 | unsigned char *xmit_buf; | ||
1139 | int xmit_head; | ||
1140 | int xmit_tail; | ||
1141 | int xmit_cnt; | ||
1142 | int cd_status; | ||
1143 | int ignore_status_mask; | ||
1144 | int read_status_mask; | ||
1145 | int cps; | ||
1146 | |||
1147 | struct completion close_wait; /* Not yet matching the core */ | ||
1148 | spinlock_t slock; | ||
1149 | struct mutex write_mtx; | ||
1150 | }; | ||
1151 | |||
1152 | #define RPORT_MAGIC 0x525001 | ||
1153 | |||
1154 | #define NUM_BOARDS 8 | ||
1155 | #define MAX_RP_PORTS (32*NUM_BOARDS) | ||
1156 | |||
1157 | /* | ||
1158 | * The size of the xmit buffer is 1 page, or 4096 bytes | ||
1159 | */ | ||
1160 | #define XMIT_BUF_SIZE 4096 | ||
1161 | |||
1162 | /* number of characters left in xmit buffer before we ask for more */ | ||
1163 | #define WAKEUP_CHARS 256 | ||
1164 | |||
1165 | /* | ||
1166 | * Assigned major numbers for the Comtrol Rocketport | ||
1167 | */ | ||
1168 | #define TTY_ROCKET_MAJOR 46 | ||
1169 | #define CUA_ROCKET_MAJOR 47 | ||
1170 | |||
1171 | #ifdef PCI_VENDOR_ID_RP | ||
1172 | #undef PCI_VENDOR_ID_RP | ||
1173 | #undef PCI_DEVICE_ID_RP8OCTA | ||
1174 | #undef PCI_DEVICE_ID_RP8INTF | ||
1175 | #undef PCI_DEVICE_ID_RP16INTF | ||
1176 | #undef PCI_DEVICE_ID_RP32INTF | ||
1177 | #undef PCI_DEVICE_ID_URP8OCTA | ||
1178 | #undef PCI_DEVICE_ID_URP8INTF | ||
1179 | #undef PCI_DEVICE_ID_URP16INTF | ||
1180 | #undef PCI_DEVICE_ID_CRP16INTF | ||
1181 | #undef PCI_DEVICE_ID_URP32INTF | ||
1182 | #endif | ||
1183 | |||
1184 | /* Comtrol PCI Vendor ID */ | ||
1185 | #define PCI_VENDOR_ID_RP 0x11fe | ||
1186 | |||
1187 | /* Comtrol Device ID's */ | ||
1188 | #define PCI_DEVICE_ID_RP32INTF 0x0001 /* Rocketport 32 port w/external I/F */ | ||
1189 | #define PCI_DEVICE_ID_RP8INTF 0x0002 /* Rocketport 8 port w/external I/F */ | ||
1190 | #define PCI_DEVICE_ID_RP16INTF 0x0003 /* Rocketport 16 port w/external I/F */ | ||
1191 | #define PCI_DEVICE_ID_RP4QUAD 0x0004 /* Rocketport 4 port w/quad cable */ | ||
1192 | #define PCI_DEVICE_ID_RP8OCTA 0x0005 /* Rocketport 8 port w/octa cable */ | ||
1193 | #define PCI_DEVICE_ID_RP8J 0x0006 /* Rocketport 8 port w/RJ11 connectors */ | ||
1194 | #define PCI_DEVICE_ID_RP4J 0x0007 /* Rocketport 4 port w/RJ11 connectors */ | ||
1195 | #define PCI_DEVICE_ID_RP8SNI 0x0008 /* Rocketport 8 port w/ DB78 SNI (Siemens) connector */ | ||
1196 | #define PCI_DEVICE_ID_RP16SNI 0x0009 /* Rocketport 16 port w/ DB78 SNI (Siemens) connector */ | ||
1197 | #define PCI_DEVICE_ID_RPP4 0x000A /* Rocketport Plus 4 port */ | ||
1198 | #define PCI_DEVICE_ID_RPP8 0x000B /* Rocketport Plus 8 port */ | ||
1199 | #define PCI_DEVICE_ID_RP6M 0x000C /* RocketModem 6 port */ | ||
1200 | #define PCI_DEVICE_ID_RP4M 0x000D /* RocketModem 4 port */ | ||
1201 | #define PCI_DEVICE_ID_RP2_232 0x000E /* Rocketport Plus 2 port RS232 */ | ||
1202 | #define PCI_DEVICE_ID_RP2_422 0x000F /* Rocketport Plus 2 port RS422 */ | ||
1203 | |||
1204 | /* Universal PCI boards */ | ||
1205 | #define PCI_DEVICE_ID_URP32INTF 0x0801 /* Rocketport UPCI 32 port w/external I/F */ | ||
1206 | #define PCI_DEVICE_ID_URP8INTF 0x0802 /* Rocketport UPCI 8 port w/external I/F */ | ||
1207 | #define PCI_DEVICE_ID_URP16INTF 0x0803 /* Rocketport UPCI 16 port w/external I/F */ | ||
1208 | #define PCI_DEVICE_ID_URP8OCTA 0x0805 /* Rocketport UPCI 8 port w/octa cable */ | ||
1209 | #define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C /* Rocketmodem III 8 port */ | ||
1210 | #define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D /* Rocketmodem III 4 port */ | ||
1211 | |||
1212 | /* Compact PCI device */ | ||
1213 | #define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */ | ||
1214 | |||
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index be0ebce36e54..d5bfd41707e7 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c | |||
@@ -262,7 +262,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status) | |||
262 | 262 | ||
263 | static void receive_chars(struct m68k_serial *info, unsigned short rx) | 263 | static void receive_chars(struct m68k_serial *info, unsigned short rx) |
264 | { | 264 | { |
265 | struct tty_struct *tty = info->port.tty; | 265 | struct tty_struct *tty = info->tty; |
266 | m68328_uart *uart = &uart_addr[info->line]; | 266 | m68328_uart *uart = &uart_addr[info->line]; |
267 | unsigned char ch, flag; | 267 | unsigned char ch, flag; |
268 | 268 | ||
@@ -329,7 +329,7 @@ static void transmit_chars(struct m68k_serial *info) | |||
329 | goto clear_and_return; | 329 | goto clear_and_return; |
330 | } | 330 | } |
331 | 331 | ||
332 | if((info->xmit_cnt <= 0) || info->port.tty->stopped) { | 332 | if((info->xmit_cnt <= 0) || info->tty->stopped) { |
333 | /* That's peculiar... TX ints off */ | 333 | /* That's peculiar... TX ints off */ |
334 | uart->ustcnt &= ~USTCNT_TX_INTR_MASK; | 334 | uart->ustcnt &= ~USTCNT_TX_INTR_MASK; |
335 | goto clear_and_return; | 335 | goto clear_and_return; |
@@ -383,7 +383,7 @@ static void do_softint(struct work_struct *work) | |||
383 | struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); | 383 | struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue); |
384 | struct tty_struct *tty; | 384 | struct tty_struct *tty; |
385 | 385 | ||
386 | tty = info->port.tty; | 386 | tty = info->tty; |
387 | if (!tty) | 387 | if (!tty) |
388 | return; | 388 | return; |
389 | #if 0 | 389 | #if 0 |
@@ -393,28 +393,6 @@ static void do_softint(struct work_struct *work) | |||
393 | #endif | 393 | #endif |
394 | } | 394 | } |
395 | 395 | ||
396 | /* | ||
397 | * This routine is called from the scheduler tqueue when the interrupt | ||
398 | * routine has signalled that a hangup has occurred. The path of | ||
399 | * hangup processing is: | ||
400 | * | ||
401 | * serial interrupt routine -> (scheduler tqueue) -> | ||
402 | * do_serial_hangup() -> tty->hangup() -> rs_hangup() | ||
403 | * | ||
404 | */ | ||
405 | static void do_serial_hangup(struct work_struct *work) | ||
406 | { | ||
407 | struct m68k_serial *info = container_of(work, struct m68k_serial, tqueue_hangup); | ||
408 | struct tty_struct *tty; | ||
409 | |||
410 | tty = info->port.tty; | ||
411 | if (!tty) | ||
412 | return; | ||
413 | |||
414 | tty_hangup(tty); | ||
415 | } | ||
416 | |||
417 | |||
418 | static int startup(struct m68k_serial * info) | 396 | static int startup(struct m68k_serial * info) |
419 | { | 397 | { |
420 | m68328_uart *uart = &uart_addr[info->line]; | 398 | m68328_uart *uart = &uart_addr[info->line]; |
@@ -451,8 +429,8 @@ static int startup(struct m68k_serial * info) | |||
451 | uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; | 429 | uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; |
452 | #endif | 430 | #endif |
453 | 431 | ||
454 | if (info->port.tty) | 432 | if (info->tty) |
455 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | 433 | clear_bit(TTY_IO_ERROR, &info->tty->flags); |
456 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | 434 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; |
457 | 435 | ||
458 | /* | 436 | /* |
@@ -486,8 +464,8 @@ static void shutdown(struct m68k_serial * info) | |||
486 | info->xmit_buf = 0; | 464 | info->xmit_buf = 0; |
487 | } | 465 | } |
488 | 466 | ||
489 | if (info->port.tty) | 467 | if (info->tty) |
490 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | 468 | set_bit(TTY_IO_ERROR, &info->tty->flags); |
491 | 469 | ||
492 | info->flags &= ~S_INITIALIZED; | 470 | info->flags &= ~S_INITIALIZED; |
493 | local_irq_restore(flags); | 471 | local_irq_restore(flags); |
@@ -553,9 +531,9 @@ static void change_speed(struct m68k_serial *info) | |||
553 | unsigned cflag; | 531 | unsigned cflag; |
554 | int i; | 532 | int i; |
555 | 533 | ||
556 | if (!info->port.tty || !info->port.tty->termios) | 534 | if (!info->tty || !info->tty->termios) |
557 | return; | 535 | return; |
558 | cflag = info->port.tty->termios->c_cflag; | 536 | cflag = info->tty->termios->c_cflag; |
559 | if (!(port = info->port)) | 537 | if (!(port = info->port)) |
560 | return; | 538 | return; |
561 | 539 | ||
@@ -967,10 +945,9 @@ static void send_break(struct m68k_serial * info, unsigned int duration) | |||
967 | local_irq_restore(flags); | 945 | local_irq_restore(flags); |
968 | } | 946 | } |
969 | 947 | ||
970 | static int rs_ioctl(struct tty_struct *tty, struct file * file, | 948 | static int rs_ioctl(struct tty_struct *tty, |
971 | unsigned int cmd, unsigned long arg) | 949 | unsigned int cmd, unsigned long arg) |
972 | { | 950 | { |
973 | int error; | ||
974 | struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; | 951 | struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; |
975 | int retval; | 952 | int retval; |
976 | 953 | ||
@@ -1104,7 +1081,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) | |||
1104 | tty_ldisc_flush(tty); | 1081 | tty_ldisc_flush(tty); |
1105 | tty->closing = 0; | 1082 | tty->closing = 0; |
1106 | info->event = 0; | 1083 | info->event = 0; |
1107 | info->port.tty = NULL; | 1084 | info->tty = NULL; |
1108 | #warning "This is not and has never been valid so fix it" | 1085 | #warning "This is not and has never been valid so fix it" |
1109 | #if 0 | 1086 | #if 0 |
1110 | if (tty->ldisc.num != ldiscs[N_TTY].num) { | 1087 | if (tty->ldisc.num != ldiscs[N_TTY].num) { |
@@ -1142,7 +1119,7 @@ void rs_hangup(struct tty_struct *tty) | |||
1142 | info->event = 0; | 1119 | info->event = 0; |
1143 | info->count = 0; | 1120 | info->count = 0; |
1144 | info->flags &= ~S_NORMAL_ACTIVE; | 1121 | info->flags &= ~S_NORMAL_ACTIVE; |
1145 | info->port.tty = NULL; | 1122 | info->tty = NULL; |
1146 | wake_up_interruptible(&info->open_wait); | 1123 | wake_up_interruptible(&info->open_wait); |
1147 | } | 1124 | } |
1148 | 1125 | ||
@@ -1261,7 +1238,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) | |||
1261 | 1238 | ||
1262 | info->count++; | 1239 | info->count++; |
1263 | tty->driver_data = info; | 1240 | tty->driver_data = info; |
1264 | info->port.tty = tty; | 1241 | info->tty = tty; |
1265 | 1242 | ||
1266 | /* | 1243 | /* |
1267 | * Start up serial port | 1244 | * Start up serial port |
@@ -1338,7 +1315,7 @@ rs68328_init(void) | |||
1338 | info = &m68k_soft[i]; | 1315 | info = &m68k_soft[i]; |
1339 | info->magic = SERIAL_MAGIC; | 1316 | info->magic = SERIAL_MAGIC; |
1340 | info->port = (int) &uart_addr[i]; | 1317 | info->port = (int) &uart_addr[i]; |
1341 | info->port.tty = NULL; | 1318 | info->tty = NULL; |
1342 | info->irq = uart_irqs[i]; | 1319 | info->irq = uart_irqs[i]; |
1343 | info->custom_divisor = 16; | 1320 | info->custom_divisor = 16; |
1344 | info->close_delay = 50; | 1321 | info->close_delay = 50; |
@@ -1348,7 +1325,6 @@ rs68328_init(void) | |||
1348 | info->count = 0; | 1325 | info->count = 0; |
1349 | info->blocked_open = 0; | 1326 | info->blocked_open = 0; |
1350 | INIT_WORK(&info->tqueue, do_softint); | 1327 | INIT_WORK(&info->tqueue, do_softint); |
1351 | INIT_WORK(&info->tqueue_hangup, do_serial_hangup); | ||
1352 | init_waitqueue_head(&info->open_wait); | 1328 | init_waitqueue_head(&info->open_wait); |
1353 | init_waitqueue_head(&info->close_wait); | 1329 | init_waitqueue_head(&info->close_wait); |
1354 | info->line = i; | 1330 | info->line = i; |
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h index 664ceb0a158c..8c9c3c0745db 100644 --- a/drivers/tty/serial/68328serial.h +++ b/drivers/tty/serial/68328serial.h | |||
@@ -159,7 +159,6 @@ struct m68k_serial { | |||
159 | int xmit_tail; | 159 | int xmit_tail; |
160 | int xmit_cnt; | 160 | int xmit_cnt; |
161 | struct work_struct tqueue; | 161 | struct work_struct tqueue; |
162 | struct work_struct tqueue_hangup; | ||
163 | wait_queue_head_t open_wait; | 162 | wait_queue_head_t open_wait; |
164 | wait_queue_head_t close_wait; | 163 | wait_queue_head_t close_wait; |
165 | }; | 164 | }; |
diff --git a/drivers/tty/serial/68360serial.c b/drivers/tty/serial/68360serial.c index bc21eeae8fde..0a3e8787ed50 100644 --- a/drivers/tty/serial/68360serial.c +++ b/drivers/tty/serial/68360serial.c | |||
@@ -1240,7 +1240,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value) | |||
1240 | } | 1240 | } |
1241 | #endif | 1241 | #endif |
1242 | 1242 | ||
1243 | static int rs_360_tiocmget(struct tty_struct *tty, struct file *file) | 1243 | static int rs_360_tiocmget(struct tty_struct *tty) |
1244 | { | 1244 | { |
1245 | ser_info_t *info = (ser_info_t *)tty->driver_data; | 1245 | ser_info_t *info = (ser_info_t *)tty->driver_data; |
1246 | unsigned int result = 0; | 1246 | unsigned int result = 0; |
@@ -1271,7 +1271,7 @@ static int rs_360_tiocmget(struct tty_struct *tty, struct file *file) | |||
1271 | return result; | 1271 | return result; |
1272 | } | 1272 | } |
1273 | 1273 | ||
1274 | static int rs_360_tiocmset(struct tty_struct *tty, struct file *file, | 1274 | static int rs_360_tiocmset(struct tty_struct *tty, |
1275 | unsigned int set, unsigned int clear) | 1275 | unsigned int set, unsigned int clear) |
1276 | { | 1276 | { |
1277 | #ifdef modem_control | 1277 | #ifdef modem_control |
@@ -1405,7 +1405,7 @@ static int rs_360_get_icount(struct tty_struct *tty, | |||
1405 | return 0; | 1405 | return 0; |
1406 | } | 1406 | } |
1407 | 1407 | ||
1408 | static int rs_360_ioctl(struct tty_struct *tty, struct file * file, | 1408 | static int rs_360_ioctl(struct tty_struct *tty, |
1409 | unsigned int cmd, unsigned long arg) | 1409 | unsigned int cmd, unsigned long arg) |
1410 | { | 1410 | { |
1411 | int error; | 1411 | int error; |
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index 3975df6f7fdb..b3b881bc4712 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c | |||
@@ -954,6 +954,23 @@ static int broken_efr(struct uart_8250_port *up) | |||
954 | return 0; | 954 | return 0; |
955 | } | 955 | } |
956 | 956 | ||
957 | static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) | ||
958 | { | ||
959 | unsigned char status; | ||
960 | |||
961 | status = serial_in(up, 0x04); /* EXCR2 */ | ||
962 | #define PRESL(x) ((x) & 0x30) | ||
963 | if (PRESL(status) == 0x10) { | ||
964 | /* already in high speed mode */ | ||
965 | return 0; | ||
966 | } else { | ||
967 | status &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ | ||
968 | status |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | ||
969 | serial_outp(up, 0x04, status); | ||
970 | } | ||
971 | return 1; | ||
972 | } | ||
973 | |||
957 | /* | 974 | /* |
958 | * We know that the chip has FIFOs. Does it have an EFR? The | 975 | * We know that the chip has FIFOs. Does it have an EFR? The |
959 | * EFR is located in the same register position as the IIR and | 976 | * EFR is located in the same register position as the IIR and |
@@ -1025,12 +1042,8 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
1025 | quot = serial_dl_read(up); | 1042 | quot = serial_dl_read(up); |
1026 | quot <<= 3; | 1043 | quot <<= 3; |
1027 | 1044 | ||
1028 | status1 = serial_in(up, 0x04); /* EXCR2 */ | 1045 | if (ns16550a_goto_highspeed(up)) |
1029 | status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ | 1046 | serial_dl_write(up, quot); |
1030 | status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | ||
1031 | serial_outp(up, 0x04, status1); | ||
1032 | |||
1033 | serial_dl_write(up, quot); | ||
1034 | 1047 | ||
1035 | serial_outp(up, UART_LCR, 0); | 1048 | serial_outp(up, UART_LCR, 0); |
1036 | 1049 | ||
@@ -3025,17 +3038,13 @@ void serial8250_resume_port(int line) | |||
3025 | struct uart_8250_port *up = &serial8250_ports[line]; | 3038 | struct uart_8250_port *up = &serial8250_ports[line]; |
3026 | 3039 | ||
3027 | if (up->capabilities & UART_NATSEMI) { | 3040 | if (up->capabilities & UART_NATSEMI) { |
3028 | unsigned char tmp; | ||
3029 | |||
3030 | /* Ensure it's still in high speed mode */ | 3041 | /* Ensure it's still in high speed mode */ |
3031 | serial_outp(up, UART_LCR, 0xE0); | 3042 | serial_outp(up, UART_LCR, 0xE0); |
3032 | 3043 | ||
3033 | tmp = serial_in(up, 0x04); /* EXCR2 */ | 3044 | ns16550a_goto_highspeed(up); |
3034 | tmp &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */ | ||
3035 | tmp |= 0x10; /* 1.625 divisor for baud_base --> 921600 */ | ||
3036 | serial_outp(up, 0x04, tmp); | ||
3037 | 3045 | ||
3038 | serial_outp(up, UART_LCR, 0); | 3046 | serial_outp(up, UART_LCR, 0); |
3047 | up->port.uartclk = 921600*16; | ||
3039 | } | 3048 | } |
3040 | uart_resume_port(&serial8250_reg, &up->port); | 3049 | uart_resume_port(&serial8250_reg, &up->port); |
3041 | } | 3050 | } |
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2b8334601c8b..e461be164f67 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig | |||
@@ -1110,29 +1110,6 @@ config SERIAL_PMACZILOG_CONSOLE | |||
1110 | on your (Power)Mac as the console, you can do so by answering | 1110 | on your (Power)Mac as the console, you can do so by answering |
1111 | Y to this option. | 1111 | Y to this option. |
1112 | 1112 | ||
1113 | config SERIAL_LH7A40X | ||
1114 | tristate "Sharp LH7A40X embedded UART support" | ||
1115 | depends on ARM && ARCH_LH7A40X | ||
1116 | select SERIAL_CORE | ||
1117 | help | ||
1118 | This enables support for the three on-board UARTs of the | ||
1119 | Sharp LH7A40X series CPUs. Choose Y or M. | ||
1120 | |||
1121 | config SERIAL_LH7A40X_CONSOLE | ||
1122 | bool "Support for console on Sharp LH7A40X serial port" | ||
1123 | depends on SERIAL_LH7A40X=y | ||
1124 | select SERIAL_CORE_CONSOLE | ||
1125 | help | ||
1126 | Say Y here if you wish to use one of the serial ports as the | ||
1127 | system console--the system console is the device which | ||
1128 | receives all kernel messages and warnings and which allows | ||
1129 | logins in single user mode. | ||
1130 | |||
1131 | Even if you say Y here, the currently visible framebuffer console | ||
1132 | (/dev/tty0) will still be used as the default system console, but | ||
1133 | you can alter that using a kernel command line, for example | ||
1134 | "console=ttyAM1". | ||
1135 | |||
1136 | config SERIAL_CPM | 1113 | config SERIAL_CPM |
1137 | tristate "CPM SCC/SMC serial port support" | 1114 | tristate "CPM SCC/SMC serial port support" |
1138 | depends on CPM2 || 8xx | 1115 | depends on CPM2 || 8xx |
@@ -1319,6 +1296,18 @@ config SERIAL_MSM_CONSOLE | |||
1319 | depends on SERIAL_MSM=y | 1296 | depends on SERIAL_MSM=y |
1320 | select SERIAL_CORE_CONSOLE | 1297 | select SERIAL_CORE_CONSOLE |
1321 | 1298 | ||
1299 | config SERIAL_MSM_HS | ||
1300 | tristate "MSM UART High Speed: Serial Driver" | ||
1301 | depends on ARCH_MSM | ||
1302 | select SERIAL_CORE | ||
1303 | help | ||
1304 | If you have a machine based on MSM family of SoCs, you | ||
1305 | can enable its onboard high speed serial port by enabling | ||
1306 | this option. | ||
1307 | |||
1308 | Choose M here to compile it as a module. The module will be | ||
1309 | called msm_serial_hs. | ||
1310 | |||
1322 | config SERIAL_VT8500 | 1311 | config SERIAL_VT8500 |
1323 | bool "VIA VT8500 on-chip serial port support" | 1312 | bool "VIA VT8500 on-chip serial port support" |
1324 | depends on ARM && ARCH_VT8500 | 1313 | depends on ARM && ARCH_VT8500 |
@@ -1588,12 +1577,25 @@ config SERIAL_IFX6X60 | |||
1588 | Support for the IFX6x60 modem devices on Intel MID platforms. | 1577 | Support for the IFX6x60 modem devices on Intel MID platforms. |
1589 | 1578 | ||
1590 | config SERIAL_PCH_UART | 1579 | config SERIAL_PCH_UART |
1591 | tristate "Intel EG20T PCH UART" | 1580 | tristate "Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH" |
1592 | depends on PCI && DMADEVICES | 1581 | depends on PCI |
1593 | select SERIAL_CORE | 1582 | select SERIAL_CORE |
1594 | select PCH_DMA | ||
1595 | help | 1583 | help |
1596 | This driver is for PCH(Platform controller Hub) UART of Intel EG20T | 1584 | This driver is for PCH(Platform controller Hub) UART of Intel EG20T |
1597 | which is an IOH(Input/Output Hub) for x86 embedded processor. | 1585 | which is an IOH(Input/Output Hub) for x86 embedded processor. |
1598 | Enabling PCH_DMA, this PCH UART works as DMA mode. | 1586 | Enabling PCH_DMA, this PCH UART works as DMA mode. |
1587 | |||
1588 | This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/ | ||
1589 | Output Hub) which is for IVI(In-Vehicle Infotainment) use. | ||
1590 | ML7213 is companion chip for Intel Atom E6xx series. | ||
1591 | ML7213 is completely compatible for Intel EG20T PCH. | ||
1592 | |||
1593 | config SERIAL_MSM_SMD | ||
1594 | bool "Enable tty device interface for some SMD ports" | ||
1595 | default n | ||
1596 | depends on MSM_SMD | ||
1597 | help | ||
1598 | Enables userspace clients to read and write to some streaming SMD | ||
1599 | ports via tty device interface for MSM chipset. | ||
1600 | |||
1599 | endmenu | 1601 | endmenu |
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 8ea92e9c73b0..31e868cb49b2 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile | |||
@@ -54,7 +54,6 @@ obj-$(CONFIG_SERIAL_68328) += 68328serial.o | |||
54 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o | 54 | obj-$(CONFIG_SERIAL_68360) += 68360serial.o |
55 | obj-$(CONFIG_SERIAL_MCF) += mcf.o | 55 | obj-$(CONFIG_SERIAL_MCF) += mcf.o |
56 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o | 56 | obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o |
57 | obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o | ||
58 | obj-$(CONFIG_SERIAL_DZ) += dz.o | 57 | obj-$(CONFIG_SERIAL_DZ) += dz.o |
59 | obj-$(CONFIG_SERIAL_ZS) += zs.o | 58 | obj-$(CONFIG_SERIAL_ZS) += zs.o |
60 | obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o | 59 | obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o |
@@ -76,6 +75,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o | |||
76 | obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o | 75 | obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o |
77 | obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o | 76 | obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o |
78 | obj-$(CONFIG_SERIAL_MSM) += msm_serial.o | 77 | obj-$(CONFIG_SERIAL_MSM) += msm_serial.o |
78 | obj-$(CONFIG_SERIAL_MSM_HS) += msm_serial_hs.o | ||
79 | obj-$(CONFIG_SERIAL_NETX) += netx-serial.o | 79 | obj-$(CONFIG_SERIAL_NETX) += netx-serial.o |
80 | obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o | 80 | obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o |
81 | obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o | 81 | obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o |
@@ -92,3 +92,4 @@ obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o | |||
92 | obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o | 92 | obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o |
93 | obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o | 93 | obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o |
94 | obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o | 94 | obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o |
95 | obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o | ||
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index f9b49b5ff5e1..60e049b041a7 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c | |||
@@ -305,28 +305,6 @@ static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS]; | |||
305 | 305 | ||
306 | #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) | 306 | #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE) |
307 | 307 | ||
308 | int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart | ||
309 | *platp) | ||
310 | { | ||
311 | struct uart_port *port; | ||
312 | int i; | ||
313 | |||
314 | for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { | ||
315 | port = &altera_jtaguart_ports[i].port; | ||
316 | |||
317 | port->line = i; | ||
318 | port->type = PORT_ALTERA_JTAGUART; | ||
319 | port->mapbase = platp[i].mapbase; | ||
320 | port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); | ||
321 | port->iotype = SERIAL_IO_MEM; | ||
322 | port->irq = platp[i].irq; | ||
323 | port->flags = ASYNC_BOOT_AUTOCONF; | ||
324 | port->ops = &altera_jtaguart_ops; | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) | 308 | #if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS) |
331 | static void altera_jtaguart_console_putc(struct console *co, const char c) | 309 | static void altera_jtaguart_console_putc(struct console *co, const char c) |
332 | { | 310 | { |
@@ -384,7 +362,7 @@ static int __init altera_jtaguart_console_setup(struct console *co, | |||
384 | if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS) | 362 | if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS) |
385 | return -EINVAL; | 363 | return -EINVAL; |
386 | port = &altera_jtaguart_ports[co->index].port; | 364 | port = &altera_jtaguart_ports[co->index].port; |
387 | if (port->membase == 0) | 365 | if (port->membase == NULL) |
388 | return -ENODEV; | 366 | return -ENODEV; |
389 | return 0; | 367 | return 0; |
390 | } | 368 | } |
@@ -431,22 +409,45 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev) | |||
431 | { | 409 | { |
432 | struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data; | 410 | struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data; |
433 | struct uart_port *port; | 411 | struct uart_port *port; |
434 | int i; | 412 | struct resource *res_irq, *res_mem; |
413 | int i = pdev->id; | ||
435 | 414 | ||
436 | for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) { | 415 | /* -1 emphasizes that the platform must have one port, no .N suffix */ |
437 | port = &altera_jtaguart_ports[i].port; | 416 | if (i == -1) |
417 | i = 0; | ||
438 | 418 | ||
439 | port->line = i; | 419 | if (i >= ALTERA_JTAGUART_MAXPORTS) |
440 | port->type = PORT_ALTERA_JTAGUART; | 420 | return -EINVAL; |
441 | port->mapbase = platp[i].mapbase; | ||
442 | port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); | ||
443 | port->iotype = SERIAL_IO_MEM; | ||
444 | port->irq = platp[i].irq; | ||
445 | port->ops = &altera_jtaguart_ops; | ||
446 | port->flags = ASYNC_BOOT_AUTOCONF; | ||
447 | 421 | ||
448 | uart_add_one_port(&altera_jtaguart_driver, port); | 422 | port = &altera_jtaguart_ports[i].port; |
449 | } | 423 | |
424 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
425 | if (res_mem) | ||
426 | port->mapbase = res_mem->start; | ||
427 | else if (platp) | ||
428 | port->mapbase = platp->mapbase; | ||
429 | else | ||
430 | return -ENODEV; | ||
431 | |||
432 | res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
433 | if (res_irq) | ||
434 | port->irq = res_irq->start; | ||
435 | else if (platp) | ||
436 | port->irq = platp->irq; | ||
437 | else | ||
438 | return -ENODEV; | ||
439 | |||
440 | port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE); | ||
441 | if (!port->membase) | ||
442 | return -ENOMEM; | ||
443 | |||
444 | port->line = i; | ||
445 | port->type = PORT_ALTERA_JTAGUART; | ||
446 | port->iotype = SERIAL_IO_MEM; | ||
447 | port->ops = &altera_jtaguart_ops; | ||
448 | port->flags = UPF_BOOT_AUTOCONF; | ||
449 | |||
450 | uart_add_one_port(&altera_jtaguart_driver, port); | ||
450 | 451 | ||
451 | return 0; | 452 | return 0; |
452 | } | 453 | } |
@@ -454,23 +455,34 @@ static int __devinit altera_jtaguart_probe(struct platform_device *pdev) | |||
454 | static int __devexit altera_jtaguart_remove(struct platform_device *pdev) | 455 | static int __devexit altera_jtaguart_remove(struct platform_device *pdev) |
455 | { | 456 | { |
456 | struct uart_port *port; | 457 | struct uart_port *port; |
457 | int i; | 458 | int i = pdev->id; |
458 | 459 | ||
459 | for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) { | 460 | if (i == -1) |
460 | port = &altera_jtaguart_ports[i].port; | 461 | i = 0; |
461 | if (port) | 462 | |
462 | uart_remove_one_port(&altera_jtaguart_driver, port); | 463 | port = &altera_jtaguart_ports[i].port; |
463 | } | 464 | uart_remove_one_port(&altera_jtaguart_driver, port); |
464 | 465 | ||
465 | return 0; | 466 | return 0; |
466 | } | 467 | } |
467 | 468 | ||
469 | #ifdef CONFIG_OF | ||
470 | static struct of_device_id altera_jtaguart_match[] = { | ||
471 | { .compatible = "ALTR,juart-1.0", }, | ||
472 | {}, | ||
473 | }; | ||
474 | MODULE_DEVICE_TABLE(of, altera_jtaguart_match); | ||
475 | #else | ||
476 | #define altera_jtaguart_match NULL | ||
477 | #endif /* CONFIG_OF */ | ||
478 | |||
468 | static struct platform_driver altera_jtaguart_platform_driver = { | 479 | static struct platform_driver altera_jtaguart_platform_driver = { |
469 | .probe = altera_jtaguart_probe, | 480 | .probe = altera_jtaguart_probe, |
470 | .remove = __devexit_p(altera_jtaguart_remove), | 481 | .remove = __devexit_p(altera_jtaguart_remove), |
471 | .driver = { | 482 | .driver = { |
472 | .name = DRV_NAME, | 483 | .name = DRV_NAME, |
473 | .owner = THIS_MODULE, | 484 | .owner = THIS_MODULE, |
485 | .of_match_table = altera_jtaguart_match, | ||
474 | }, | 486 | }, |
475 | }; | 487 | }; |
476 | 488 | ||
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 721216292a50..6d5b036ac783 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/serial.h> | 24 | #include <linux/serial.h> |
25 | #include <linux/serial_core.h> | 25 | #include <linux/serial_core.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/of.h> | ||
27 | #include <linux/io.h> | 28 | #include <linux/io.h> |
28 | #include <linux/altera_uart.h> | 29 | #include <linux/altera_uart.h> |
29 | 30 | ||
@@ -86,16 +87,12 @@ struct altera_uart { | |||
86 | 87 | ||
87 | static u32 altera_uart_readl(struct uart_port *port, int reg) | 88 | static u32 altera_uart_readl(struct uart_port *port, int reg) |
88 | { | 89 | { |
89 | struct altera_uart_platform_uart *platp = port->private_data; | 90 | return readl(port->membase + (reg << port->regshift)); |
90 | |||
91 | return readl(port->membase + (reg << platp->bus_shift)); | ||
92 | } | 91 | } |
93 | 92 | ||
94 | static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) | 93 | static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) |
95 | { | 94 | { |
96 | struct altera_uart_platform_uart *platp = port->private_data; | 95 | writel(dat, port->membase + (reg << port->regshift)); |
97 | |||
98 | writel(dat, port->membase + (reg << platp->bus_shift)); | ||
99 | } | 96 | } |
100 | 97 | ||
101 | static unsigned int altera_uart_tx_empty(struct uart_port *port) | 98 | static unsigned int altera_uart_tx_empty(struct uart_port *port) |
@@ -511,6 +508,29 @@ static struct uart_driver altera_uart_driver = { | |||
511 | .cons = ALTERA_UART_CONSOLE, | 508 | .cons = ALTERA_UART_CONSOLE, |
512 | }; | 509 | }; |
513 | 510 | ||
511 | #ifdef CONFIG_OF | ||
512 | static int altera_uart_get_of_uartclk(struct platform_device *pdev, | ||
513 | struct uart_port *port) | ||
514 | { | ||
515 | int len; | ||
516 | const __be32 *clk; | ||
517 | |||
518 | clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len); | ||
519 | if (!clk || len < sizeof(__be32)) | ||
520 | return -ENODEV; | ||
521 | |||
522 | port->uartclk = be32_to_cpup(clk); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | #else | ||
527 | static int altera_uart_get_of_uartclk(struct platform_device *pdev, | ||
528 | struct uart_port *port) | ||
529 | { | ||
530 | return -ENODEV; | ||
531 | } | ||
532 | #endif /* CONFIG_OF */ | ||
533 | |||
514 | static int __devinit altera_uart_probe(struct platform_device *pdev) | 534 | static int __devinit altera_uart_probe(struct platform_device *pdev) |
515 | { | 535 | { |
516 | struct altera_uart_platform_uart *platp = pdev->dev.platform_data; | 536 | struct altera_uart_platform_uart *platp = pdev->dev.platform_data; |
@@ -518,6 +538,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) | |||
518 | struct resource *res_mem; | 538 | struct resource *res_mem; |
519 | struct resource *res_irq; | 539 | struct resource *res_irq; |
520 | int i = pdev->id; | 540 | int i = pdev->id; |
541 | int ret; | ||
521 | 542 | ||
522 | /* -1 emphasizes that the platform must have one port, no .N suffix */ | 543 | /* -1 emphasizes that the platform must have one port, no .N suffix */ |
523 | if (i == -1) | 544 | if (i == -1) |
@@ -542,17 +563,29 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) | |||
542 | else if (platp->irq) | 563 | else if (platp->irq) |
543 | port->irq = platp->irq; | 564 | port->irq = platp->irq; |
544 | 565 | ||
566 | /* Check platform data first so we can override device node data */ | ||
567 | if (platp) | ||
568 | port->uartclk = platp->uartclk; | ||
569 | else { | ||
570 | ret = altera_uart_get_of_uartclk(pdev, port); | ||
571 | if (ret) | ||
572 | return ret; | ||
573 | } | ||
574 | |||
545 | port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); | 575 | port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE); |
546 | if (!port->membase) | 576 | if (!port->membase) |
547 | return -ENOMEM; | 577 | return -ENOMEM; |
548 | 578 | ||
579 | if (platp) | ||
580 | port->regshift = platp->bus_shift; | ||
581 | else | ||
582 | port->regshift = 0; | ||
583 | |||
549 | port->line = i; | 584 | port->line = i; |
550 | port->type = PORT_ALTERA_UART; | 585 | port->type = PORT_ALTERA_UART; |
551 | port->iotype = SERIAL_IO_MEM; | 586 | port->iotype = SERIAL_IO_MEM; |
552 | port->uartclk = platp->uartclk; | ||
553 | port->ops = &altera_uart_ops; | 587 | port->ops = &altera_uart_ops; |
554 | port->flags = UPF_BOOT_AUTOCONF; | 588 | port->flags = UPF_BOOT_AUTOCONF; |
555 | port->private_data = platp; | ||
556 | 589 | ||
557 | uart_add_one_port(&altera_uart_driver, port); | 590 | uart_add_one_port(&altera_uart_driver, port); |
558 | 591 | ||
@@ -561,19 +594,35 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) | |||
561 | 594 | ||
562 | static int __devexit altera_uart_remove(struct platform_device *pdev) | 595 | static int __devexit altera_uart_remove(struct platform_device *pdev) |
563 | { | 596 | { |
564 | struct uart_port *port = &altera_uart_ports[pdev->id].port; | 597 | struct uart_port *port; |
598 | int i = pdev->id; | ||
599 | |||
600 | if (i == -1) | ||
601 | i = 0; | ||
565 | 602 | ||
603 | port = &altera_uart_ports[i].port; | ||
566 | uart_remove_one_port(&altera_uart_driver, port); | 604 | uart_remove_one_port(&altera_uart_driver, port); |
605 | |||
567 | return 0; | 606 | return 0; |
568 | } | 607 | } |
569 | 608 | ||
609 | #ifdef CONFIG_OF | ||
610 | static struct of_device_id altera_uart_match[] = { | ||
611 | { .compatible = "ALTR,uart-1.0", }, | ||
612 | {}, | ||
613 | }; | ||
614 | MODULE_DEVICE_TABLE(of, altera_uart_match); | ||
615 | #else | ||
616 | #define altera_uart_match NULL | ||
617 | #endif /* CONFIG_OF */ | ||
618 | |||
570 | static struct platform_driver altera_uart_platform_driver = { | 619 | static struct platform_driver altera_uart_platform_driver = { |
571 | .probe = altera_uart_probe, | 620 | .probe = altera_uart_probe, |
572 | .remove = __devexit_p(altera_uart_remove), | 621 | .remove = __devexit_p(altera_uart_remove), |
573 | .driver = { | 622 | .driver = { |
574 | .name = DRV_NAME, | 623 | .name = DRV_NAME, |
575 | .owner = THIS_MODULE, | 624 | .owner = THIS_MODULE, |
576 | .pm = NULL, | 625 | .of_match_table = altera_uart_match, |
577 | }, | 626 | }, |
578 | }; | 627 | }; |
579 | 628 | ||
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 095a5d562618..1ab999b04ef3 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c | |||
@@ -553,8 +553,7 @@ static struct uart_driver grlib_apbuart_driver = { | |||
553 | /* OF Platform Driver */ | 553 | /* OF Platform Driver */ |
554 | /* ======================================================================== */ | 554 | /* ======================================================================== */ |
555 | 555 | ||
556 | static int __devinit apbuart_probe(struct platform_device *op, | 556 | static int __devinit apbuart_probe(struct platform_device *op) |
557 | const struct of_device_id *match) | ||
558 | { | 557 | { |
559 | int i = -1; | 558 | int i = -1; |
560 | struct uart_port *port = NULL; | 559 | struct uart_port *port = NULL; |
@@ -587,7 +586,7 @@ static struct of_device_id __initdata apbuart_match[] = { | |||
587 | {}, | 586 | {}, |
588 | }; | 587 | }; |
589 | 588 | ||
590 | static struct of_platform_driver grlib_apbuart_of_driver = { | 589 | static struct platform_driver grlib_apbuart_of_driver = { |
591 | .probe = apbuart_probe, | 590 | .probe = apbuart_probe, |
592 | .driver = { | 591 | .driver = { |
593 | .owner = THIS_MODULE, | 592 | .owner = THIS_MODULE, |
@@ -676,10 +675,10 @@ static int __init grlib_apbuart_init(void) | |||
676 | return ret; | 675 | return ret; |
677 | } | 676 | } |
678 | 677 | ||
679 | ret = of_register_platform_driver(&grlib_apbuart_of_driver); | 678 | ret = platform_driver_register(&grlib_apbuart_of_driver); |
680 | if (ret) { | 679 | if (ret) { |
681 | printk(KERN_ERR | 680 | printk(KERN_ERR |
682 | "%s: of_register_platform_driver failed (%i)\n", | 681 | "%s: platform_driver_register failed (%i)\n", |
683 | __FILE__, ret); | 682 | __FILE__, ret); |
684 | uart_unregister_driver(&grlib_apbuart_driver); | 683 | uart_unregister_driver(&grlib_apbuart_driver); |
685 | return ret; | 684 | return ret; |
@@ -697,7 +696,7 @@ static void __exit grlib_apbuart_exit(void) | |||
697 | &grlib_apbuart_ports[i]); | 696 | &grlib_apbuart_ports[i]); |
698 | 697 | ||
699 | uart_unregister_driver(&grlib_apbuart_driver); | 698 | uart_unregister_driver(&grlib_apbuart_driver); |
700 | of_unregister_platform_driver(&grlib_apbuart_of_driver); | 699 | platform_driver_unregister(&grlib_apbuart_of_driver); |
701 | } | 700 | } |
702 | 701 | ||
703 | module_init(grlib_apbuart_init); | 702 | module_init(grlib_apbuart_init); |
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2a1d52fb4936..f119d1761106 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c | |||
@@ -1240,6 +1240,21 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, | |||
1240 | spin_unlock_irqrestore(&port->lock, flags); | 1240 | spin_unlock_irqrestore(&port->lock, flags); |
1241 | } | 1241 | } |
1242 | 1242 | ||
1243 | static void atmel_set_ldisc(struct uart_port *port, int new) | ||
1244 | { | ||
1245 | int line = port->line; | ||
1246 | |||
1247 | if (line >= port->state->port.tty->driver->num) | ||
1248 | return; | ||
1249 | |||
1250 | if (port->state->port.tty->ldisc->ops->num == N_PPS) { | ||
1251 | port->flags |= UPF_HARDPPS_CD; | ||
1252 | atmel_enable_ms(port); | ||
1253 | } else { | ||
1254 | port->flags &= ~UPF_HARDPPS_CD; | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1243 | /* | 1258 | /* |
1244 | * Return string describing the specified port | 1259 | * Return string describing the specified port |
1245 | */ | 1260 | */ |
@@ -1380,6 +1395,7 @@ static struct uart_ops atmel_pops = { | |||
1380 | .shutdown = atmel_shutdown, | 1395 | .shutdown = atmel_shutdown, |
1381 | .flush_buffer = atmel_flush_buffer, | 1396 | .flush_buffer = atmel_flush_buffer, |
1382 | .set_termios = atmel_set_termios, | 1397 | .set_termios = atmel_set_termios, |
1398 | .set_ldisc = atmel_set_ldisc, | ||
1383 | .type = atmel_type, | 1399 | .type = atmel_type, |
1384 | .release_port = atmel_release_port, | 1400 | .release_port = atmel_release_port, |
1385 | .request_port = atmel_request_port, | 1401 | .request_port = atmel_request_port, |
diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index e95c524d9d18..c3ec0a61d859 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c | |||
@@ -788,7 +788,7 @@ static int __devinit sport_uart_probe(struct platform_device *pdev) | |||
788 | sport->port.mapbase = res->start; | 788 | sport->port.mapbase = res->start; |
789 | 789 | ||
790 | sport->port.irq = platform_get_irq(pdev, 0); | 790 | sport->port.irq = platform_get_irq(pdev, 0); |
791 | if (sport->port.irq < 0) { | 791 | if ((int)sport->port.irq < 0) { |
792 | dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n"); | 792 | dev_err(&pdev->dev, "No sport RX/TX IRQ specified\n"); |
793 | ret = -ENOENT; | 793 | ret = -ENOENT; |
794 | goto out_error_unmap; | 794 | goto out_error_unmap; |
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 8692ff98fc07..a9a6a5fd169e 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c | |||
@@ -1359,8 +1359,7 @@ static struct uart_driver cpm_reg = { | |||
1359 | 1359 | ||
1360 | static int probe_index; | 1360 | static int probe_index; |
1361 | 1361 | ||
1362 | static int __devinit cpm_uart_probe(struct platform_device *ofdev, | 1362 | static int __devinit cpm_uart_probe(struct platform_device *ofdev) |
1363 | const struct of_device_id *match) | ||
1364 | { | 1363 | { |
1365 | int index = probe_index++; | 1364 | int index = probe_index++; |
1366 | struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; | 1365 | struct uart_cpm_port *pinfo = &cpm_uart_ports[index]; |
@@ -1405,7 +1404,7 @@ static struct of_device_id cpm_uart_match[] = { | |||
1405 | {} | 1404 | {} |
1406 | }; | 1405 | }; |
1407 | 1406 | ||
1408 | static struct of_platform_driver cpm_uart_driver = { | 1407 | static struct platform_driver cpm_uart_driver = { |
1409 | .driver = { | 1408 | .driver = { |
1410 | .name = "cpm_uart", | 1409 | .name = "cpm_uart", |
1411 | .owner = THIS_MODULE, | 1410 | .owner = THIS_MODULE, |
@@ -1421,7 +1420,7 @@ static int __init cpm_uart_init(void) | |||
1421 | if (ret) | 1420 | if (ret) |
1422 | return ret; | 1421 | return ret; |
1423 | 1422 | ||
1424 | ret = of_register_platform_driver(&cpm_uart_driver); | 1423 | ret = platform_driver_register(&cpm_uart_driver); |
1425 | if (ret) | 1424 | if (ret) |
1426 | uart_unregister_driver(&cpm_reg); | 1425 | uart_unregister_driver(&cpm_reg); |
1427 | 1426 | ||
@@ -1430,7 +1429,7 @@ static int __init cpm_uart_init(void) | |||
1430 | 1429 | ||
1431 | static void __exit cpm_uart_exit(void) | 1430 | static void __exit cpm_uart_exit(void) |
1432 | { | 1431 | { |
1433 | of_unregister_platform_driver(&cpm_uart_driver); | 1432 | platform_driver_unregister(&cpm_uart_driver); |
1434 | uart_unregister_driver(&cpm_reg); | 1433 | uart_unregister_driver(&cpm_reg); |
1435 | } | 1434 | } |
1436 | 1435 | ||
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index bcc31f2140ac..225123b37f19 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c | |||
@@ -3581,8 +3581,7 @@ rs_break(struct tty_struct *tty, int break_state) | |||
3581 | } | 3581 | } |
3582 | 3582 | ||
3583 | static int | 3583 | static int |
3584 | rs_tiocmset(struct tty_struct *tty, struct file *file, | 3584 | rs_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) |
3585 | unsigned int set, unsigned int clear) | ||
3586 | { | 3585 | { |
3587 | struct e100_serial *info = (struct e100_serial *)tty->driver_data; | 3586 | struct e100_serial *info = (struct e100_serial *)tty->driver_data; |
3588 | unsigned long flags; | 3587 | unsigned long flags; |
@@ -3614,7 +3613,7 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, | |||
3614 | } | 3613 | } |
3615 | 3614 | ||
3616 | static int | 3615 | static int |
3617 | rs_tiocmget(struct tty_struct *tty, struct file *file) | 3616 | rs_tiocmget(struct tty_struct *tty) |
3618 | { | 3617 | { |
3619 | struct e100_serial *info = (struct e100_serial *)tty->driver_data; | 3618 | struct e100_serial *info = (struct e100_serial *)tty->driver_data; |
3620 | unsigned int result; | 3619 | unsigned int result; |
@@ -3648,7 +3647,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) | |||
3648 | 3647 | ||
3649 | 3648 | ||
3650 | static int | 3649 | static int |
3651 | rs_ioctl(struct tty_struct *tty, struct file * file, | 3650 | rs_ioctl(struct tty_struct *tty, |
3652 | unsigned int cmd, unsigned long arg) | 3651 | unsigned int cmd, unsigned long arg) |
3653 | { | 3652 | { |
3654 | struct e100_serial * info = (struct e100_serial *)tty->driver_data; | 3653 | struct e100_serial * info = (struct e100_serial *)tty->driver_data; |
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index ab93763862d5..8ee5a41d340d 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * Jan Dumon <j.dumon@option.com> | 8 | * Jan Dumon <j.dumon@option.com> |
9 | * | 9 | * |
10 | * Copyright (C) 2009, 2010 Intel Corp | 10 | * Copyright (C) 2009, 2010 Intel Corp |
11 | * Russ Gorby <richardx.r.gorby@intel.com> | 11 | * Russ Gorby <russ.gorby@intel.com> |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
14 | * it under the terms of the GNU General Public License version 2 as | 14 | * it under the terms of the GNU General Public License version 2 as |
@@ -67,6 +67,7 @@ | |||
67 | #define IFX_SPI_MORE_MASK 0x10 | 67 | #define IFX_SPI_MORE_MASK 0x10 |
68 | #define IFX_SPI_MORE_BIT 12 /* bit position in u16 */ | 68 | #define IFX_SPI_MORE_BIT 12 /* bit position in u16 */ |
69 | #define IFX_SPI_CTS_BIT 13 /* bit position in u16 */ | 69 | #define IFX_SPI_CTS_BIT 13 /* bit position in u16 */ |
70 | #define IFX_SPI_MODE SPI_MODE_1 | ||
70 | #define IFX_SPI_TTY_ID 0 | 71 | #define IFX_SPI_TTY_ID 0 |
71 | #define IFX_SPI_TIMEOUT_SEC 2 | 72 | #define IFX_SPI_TIMEOUT_SEC 2 |
72 | #define IFX_SPI_HEADER_0 (-1) | 73 | #define IFX_SPI_HEADER_0 (-1) |
@@ -76,7 +77,7 @@ | |||
76 | static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); | 77 | static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); |
77 | 78 | ||
78 | /* local variables */ | 79 | /* local variables */ |
79 | static int spi_b16 = 1; /* 8 or 16 bit word length */ | 80 | static int spi_bpw = 16; /* 8, 16 or 32 bit word length */ |
80 | static struct tty_driver *tty_drv; | 81 | static struct tty_driver *tty_drv; |
81 | static struct ifx_spi_device *saved_ifx_dev; | 82 | static struct ifx_spi_device *saved_ifx_dev; |
82 | static struct lock_class_key ifx_spi_key; | 83 | static struct lock_class_key ifx_spi_key; |
@@ -244,7 +245,7 @@ static void ifx_spi_timeout(unsigned long arg) | |||
244 | * Map the signal state into Linux modem flags and report the value | 245 | * Map the signal state into Linux modem flags and report the value |
245 | * in Linux terms | 246 | * in Linux terms |
246 | */ | 247 | */ |
247 | static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp) | 248 | static int ifx_spi_tiocmget(struct tty_struct *tty) |
248 | { | 249 | { |
249 | unsigned int value; | 250 | unsigned int value; |
250 | struct ifx_spi_device *ifx_dev = tty->driver_data; | 251 | struct ifx_spi_device *ifx_dev = tty->driver_data; |
@@ -262,7 +263,6 @@ static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp) | |||
262 | /** | 263 | /** |
263 | * ifx_spi_tiocmset - set modem bits | 264 | * ifx_spi_tiocmset - set modem bits |
264 | * @tty: the tty structure | 265 | * @tty: the tty structure |
265 | * @filp: file handle issuing the request | ||
266 | * @set: bits to set | 266 | * @set: bits to set |
267 | * @clear: bits to clear | 267 | * @clear: bits to clear |
268 | * | 268 | * |
@@ -271,7 +271,7 @@ static int ifx_spi_tiocmget(struct tty_struct *tty, struct file *filp) | |||
271 | * | 271 | * |
272 | * FIXME: do we need to kick the tranfers when we do this ? | 272 | * FIXME: do we need to kick the tranfers when we do this ? |
273 | */ | 273 | */ |
274 | static int ifx_spi_tiocmset(struct tty_struct *tty, struct file *filp, | 274 | static int ifx_spi_tiocmset(struct tty_struct *tty, |
275 | unsigned int set, unsigned int clear) | 275 | unsigned int set, unsigned int clear) |
276 | { | 276 | { |
277 | struct ifx_spi_device *ifx_dev = tty->driver_data; | 277 | struct ifx_spi_device *ifx_dev = tty->driver_data; |
@@ -722,9 +722,9 @@ static void ifx_spi_io(unsigned long data) | |||
722 | /* note len is BYTES, not transfers */ | 722 | /* note len is BYTES, not transfers */ |
723 | ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; | 723 | ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; |
724 | ifx_dev->spi_xfer.cs_change = 0; | 724 | ifx_dev->spi_xfer.cs_change = 0; |
725 | ifx_dev->spi_xfer.speed_hz = 12500000; | 725 | ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; |
726 | /* ifx_dev->spi_xfer.speed_hz = 390625; */ | 726 | /* ifx_dev->spi_xfer.speed_hz = 390625; */ |
727 | ifx_dev->spi_xfer.bits_per_word = spi_b16 ? 16 : 8; | 727 | ifx_dev->spi_xfer.bits_per_word = spi_bpw; |
728 | 728 | ||
729 | ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; | 729 | ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; |
730 | ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; | 730 | ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; |
@@ -732,7 +732,7 @@ static void ifx_spi_io(unsigned long data) | |||
732 | /* | 732 | /* |
733 | * setup dma pointers | 733 | * setup dma pointers |
734 | */ | 734 | */ |
735 | if (ifx_dev->is_6160) { | 735 | if (ifx_dev->use_dma) { |
736 | ifx_dev->spi_msg.is_dma_mapped = 1; | 736 | ifx_dev->spi_msg.is_dma_mapped = 1; |
737 | ifx_dev->tx_dma = ifx_dev->tx_bus; | 737 | ifx_dev->tx_dma = ifx_dev->tx_bus; |
738 | ifx_dev->rx_dma = ifx_dev->rx_bus; | 738 | ifx_dev->rx_dma = ifx_dev->rx_bus; |
@@ -798,8 +798,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) | |||
798 | goto error_ret; | 798 | goto error_ret; |
799 | } | 799 | } |
800 | 800 | ||
801 | pport->ops = &ifx_tty_port_ops; | ||
802 | tty_port_init(pport); | 801 | tty_port_init(pport); |
802 | pport->ops = &ifx_tty_port_ops; | ||
803 | ifx_dev->minor = IFX_SPI_TTY_ID; | 803 | ifx_dev->minor = IFX_SPI_TTY_ID; |
804 | ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor, | 804 | ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor, |
805 | &ifx_dev->spi_dev->dev); | 805 | &ifx_dev->spi_dev->dev); |
@@ -960,7 +960,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) | |||
960 | { | 960 | { |
961 | int ret; | 961 | int ret; |
962 | int srdy; | 962 | int srdy; |
963 | struct ifx_modem_platform_data *pl_data = NULL; | 963 | struct ifx_modem_platform_data *pl_data; |
964 | struct ifx_spi_device *ifx_dev; | 964 | struct ifx_spi_device *ifx_dev; |
965 | 965 | ||
966 | if (saved_ifx_dev) { | 966 | if (saved_ifx_dev) { |
@@ -968,6 +968,12 @@ static int ifx_spi_spi_probe(struct spi_device *spi) | |||
968 | return -ENODEV; | 968 | return -ENODEV; |
969 | } | 969 | } |
970 | 970 | ||
971 | pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data; | ||
972 | if (!pl_data) { | ||
973 | dev_err(&spi->dev, "missing platform data!"); | ||
974 | return -ENODEV; | ||
975 | } | ||
976 | |||
971 | /* initialize structure to hold our device variables */ | 977 | /* initialize structure to hold our device variables */ |
972 | ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); | 978 | ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); |
973 | if (!ifx_dev) { | 979 | if (!ifx_dev) { |
@@ -983,14 +989,25 @@ static int ifx_spi_spi_probe(struct spi_device *spi) | |||
983 | init_timer(&ifx_dev->spi_timer); | 989 | init_timer(&ifx_dev->spi_timer); |
984 | ifx_dev->spi_timer.function = ifx_spi_timeout; | 990 | ifx_dev->spi_timer.function = ifx_spi_timeout; |
985 | ifx_dev->spi_timer.data = (unsigned long)ifx_dev; | 991 | ifx_dev->spi_timer.data = (unsigned long)ifx_dev; |
986 | ifx_dev->is_6160 = pl_data->is_6160; | 992 | ifx_dev->modem = pl_data->modem_type; |
993 | ifx_dev->use_dma = pl_data->use_dma; | ||
994 | ifx_dev->max_hz = pl_data->max_hz; | ||
995 | /* initialize spi mode, etc */ | ||
996 | spi->max_speed_hz = ifx_dev->max_hz; | ||
997 | spi->mode = IFX_SPI_MODE | (SPI_LOOP & spi->mode); | ||
998 | spi->bits_per_word = spi_bpw; | ||
999 | ret = spi_setup(spi); | ||
1000 | if (ret) { | ||
1001 | dev_err(&spi->dev, "SPI setup wasn't successful %d", ret); | ||
1002 | return -ENODEV; | ||
1003 | } | ||
987 | 1004 | ||
988 | /* ensure SPI protocol flags are initialized to enable transfer */ | 1005 | /* ensure SPI protocol flags are initialized to enable transfer */ |
989 | ifx_dev->spi_more = 0; | 1006 | ifx_dev->spi_more = 0; |
990 | ifx_dev->spi_slave_cts = 0; | 1007 | ifx_dev->spi_slave_cts = 0; |
991 | 1008 | ||
992 | /*initialize transfer and dma buffers */ | 1009 | /*initialize transfer and dma buffers */ |
993 | ifx_dev->tx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, | 1010 | ifx_dev->tx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, |
994 | IFX_SPI_TRANSFER_SIZE, | 1011 | IFX_SPI_TRANSFER_SIZE, |
995 | &ifx_dev->tx_bus, | 1012 | &ifx_dev->tx_bus, |
996 | GFP_KERNEL); | 1013 | GFP_KERNEL); |
@@ -999,7 +1016,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) | |||
999 | ret = -ENOMEM; | 1016 | ret = -ENOMEM; |
1000 | goto error_ret; | 1017 | goto error_ret; |
1001 | } | 1018 | } |
1002 | ifx_dev->rx_buffer = dma_alloc_coherent(&ifx_dev->spi_dev->dev, | 1019 | ifx_dev->rx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, |
1003 | IFX_SPI_TRANSFER_SIZE, | 1020 | IFX_SPI_TRANSFER_SIZE, |
1004 | &ifx_dev->rx_bus, | 1021 | &ifx_dev->rx_bus, |
1005 | GFP_KERNEL); | 1022 | GFP_KERNEL); |
@@ -1025,18 +1042,11 @@ static int ifx_spi_spi_probe(struct spi_device *spi) | |||
1025 | goto error_ret; | 1042 | goto error_ret; |
1026 | } | 1043 | } |
1027 | 1044 | ||
1028 | pl_data = (struct ifx_modem_platform_data *)spi->dev.platform_data; | 1045 | ifx_dev->gpio.reset = pl_data->rst_pmu; |
1029 | if (pl_data) { | 1046 | ifx_dev->gpio.po = pl_data->pwr_on; |
1030 | ifx_dev->gpio.reset = pl_data->rst_pmu; | 1047 | ifx_dev->gpio.mrdy = pl_data->mrdy; |
1031 | ifx_dev->gpio.po = pl_data->pwr_on; | 1048 | ifx_dev->gpio.srdy = pl_data->srdy; |
1032 | ifx_dev->gpio.mrdy = pl_data->mrdy; | 1049 | ifx_dev->gpio.reset_out = pl_data->rst_out; |
1033 | ifx_dev->gpio.srdy = pl_data->srdy; | ||
1034 | ifx_dev->gpio.reset_out = pl_data->rst_out; | ||
1035 | } else { | ||
1036 | dev_err(&spi->dev, "missing platform data!"); | ||
1037 | ret = -ENODEV; | ||
1038 | goto error_ret; | ||
1039 | } | ||
1040 | 1050 | ||
1041 | dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d", | 1051 | dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d", |
1042 | ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, | 1052 | ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy, |
@@ -1322,9 +1332,9 @@ static const struct spi_device_id ifx_id_table[] = { | |||
1322 | MODULE_DEVICE_TABLE(spi, ifx_id_table); | 1332 | MODULE_DEVICE_TABLE(spi, ifx_id_table); |
1323 | 1333 | ||
1324 | /* spi operations */ | 1334 | /* spi operations */ |
1325 | static const struct spi_driver ifx_spi_driver_6160 = { | 1335 | static const struct spi_driver ifx_spi_driver = { |
1326 | .driver = { | 1336 | .driver = { |
1327 | .name = "ifx6160", | 1337 | .name = DRVNAME, |
1328 | .bus = &spi_bus_type, | 1338 | .bus = &spi_bus_type, |
1329 | .pm = &ifx_spi_pm, | 1339 | .pm = &ifx_spi_pm, |
1330 | .owner = THIS_MODULE}, | 1340 | .owner = THIS_MODULE}, |
@@ -1346,7 +1356,7 @@ static void __exit ifx_spi_exit(void) | |||
1346 | { | 1356 | { |
1347 | /* unregister */ | 1357 | /* unregister */ |
1348 | tty_unregister_driver(tty_drv); | 1358 | tty_unregister_driver(tty_drv); |
1349 | spi_unregister_driver((void *)&ifx_spi_driver_6160); | 1359 | spi_unregister_driver((void *)&ifx_spi_driver); |
1350 | } | 1360 | } |
1351 | 1361 | ||
1352 | /** | 1362 | /** |
@@ -1388,7 +1398,7 @@ static int __init ifx_spi_init(void) | |||
1388 | return result; | 1398 | return result; |
1389 | } | 1399 | } |
1390 | 1400 | ||
1391 | result = spi_register_driver((void *)&ifx_spi_driver_6160); | 1401 | result = spi_register_driver((void *)&ifx_spi_driver); |
1392 | if (result) { | 1402 | if (result) { |
1393 | pr_err("%s: spi_register_driver failed(%d)", | 1403 | pr_err("%s: spi_register_driver failed(%d)", |
1394 | DRVNAME, result); | 1404 | DRVNAME, result); |
diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h index deb7b8d977dc..e8464baf9e75 100644 --- a/drivers/tty/serial/ifx6x60.h +++ b/drivers/tty/serial/ifx6x60.h | |||
@@ -29,8 +29,6 @@ | |||
29 | #define DRVNAME "ifx6x60" | 29 | #define DRVNAME "ifx6x60" |
30 | #define TTYNAME "ttyIFX" | 30 | #define TTYNAME "ttyIFX" |
31 | 31 | ||
32 | /* #define IFX_THROTTLE_CODE */ | ||
33 | |||
34 | #define IFX_SPI_MAX_MINORS 1 | 32 | #define IFX_SPI_MAX_MINORS 1 |
35 | #define IFX_SPI_TRANSFER_SIZE 2048 | 33 | #define IFX_SPI_TRANSFER_SIZE 2048 |
36 | #define IFX_SPI_FIFO_SIZE 4096 | 34 | #define IFX_SPI_FIFO_SIZE 4096 |
@@ -88,7 +86,9 @@ struct ifx_spi_device { | |||
88 | dma_addr_t rx_dma; | 86 | dma_addr_t rx_dma; |
89 | dma_addr_t tx_dma; | 87 | dma_addr_t tx_dma; |
90 | 88 | ||
91 | int is_6160; /* Modem type */ | 89 | int modem; /* Modem type */ |
90 | int use_dma; /* provide dma-able addrs in SPI msg */ | ||
91 | long max_hz; /* max SPI frequency */ | ||
92 | 92 | ||
93 | spinlock_t write_lock; | 93 | spinlock_t write_lock; |
94 | int write_pending; | 94 | int write_pending; |
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index beb1afa27d8d..7b951adac54b 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c | |||
@@ -601,7 +601,7 @@ static int max3100_startup(struct uart_port *port) | |||
601 | s->rts = 0; | 601 | s->rts = 0; |
602 | 602 | ||
603 | sprintf(b, "max3100-%d", s->minor); | 603 | sprintf(b, "max3100-%d", s->minor); |
604 | s->workqueue = create_freezeable_workqueue(b); | 604 | s->workqueue = create_freezable_workqueue(b); |
605 | if (!s->workqueue) { | 605 | if (!s->workqueue) { |
606 | dev_warn(&s->spi->dev, "cannot create workqueue\n"); | 606 | dev_warn(&s->spi->dev, "cannot create workqueue\n"); |
607 | return -EBUSY; | 607 | return -EBUSY; |
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c index 910870edf708..750b4f627315 100644 --- a/drivers/tty/serial/max3107.c +++ b/drivers/tty/serial/max3107.c | |||
@@ -833,7 +833,7 @@ static int max3107_startup(struct uart_port *port) | |||
833 | struct max3107_port *s = container_of(port, struct max3107_port, port); | 833 | struct max3107_port *s = container_of(port, struct max3107_port, port); |
834 | 834 | ||
835 | /* Initialize work queue */ | 835 | /* Initialize work queue */ |
836 | s->workqueue = create_freezeable_workqueue("max3107"); | 836 | s->workqueue = create_freezable_workqueue("max3107"); |
837 | if (!s->workqueue) { | 837 | if (!s->workqueue) { |
838 | dev_err(&s->spi->dev, "Workqueue creation failed\n"); | 838 | dev_err(&s->spi->dev, "Workqueue creation failed\n"); |
839 | return -EBUSY; | 839 | return -EBUSY; |
diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index d40010a22ecd..c111f36f5d21 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c | |||
@@ -16,9 +16,7 @@ | |||
16 | * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans | 16 | * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans |
17 | * are used for RX, odd chans for TX | 17 | * are used for RX, odd chans for TX |
18 | * | 18 | * |
19 | * 2. In A0 stepping, UART will not support TX half empty flag | 19 | * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always |
20 | * | ||
21 | * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always | ||
22 | * asserted, only when the HW is reset the DDCD and DDSR will | 20 | * asserted, only when the HW is reset the DDCD and DDSR will |
23 | * be triggered | 21 | * be triggered |
24 | */ | 22 | */ |
@@ -41,8 +39,6 @@ | |||
41 | #include <linux/io.h> | 39 | #include <linux/io.h> |
42 | #include <linux/debugfs.h> | 40 | #include <linux/debugfs.h> |
43 | 41 | ||
44 | #define MFD_HSU_A0_STEPPING 1 | ||
45 | |||
46 | #define HSU_DMA_BUF_SIZE 2048 | 42 | #define HSU_DMA_BUF_SIZE 2048 |
47 | 43 | ||
48 | #define chan_readl(chan, offset) readl(chan->reg + offset) | 44 | #define chan_readl(chan, offset) readl(chan->reg + offset) |
@@ -51,7 +47,10 @@ | |||
51 | #define mfd_readl(obj, offset) readl(obj->reg + offset) | 47 | #define mfd_readl(obj, offset) readl(obj->reg + offset) |
52 | #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) | 48 | #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) |
53 | 49 | ||
54 | #define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) | 50 | static int hsu_dma_enable; |
51 | module_param(hsu_dma_enable, int, 0); | ||
52 | MODULE_PARM_DESC(hsu_dma_enable, "It is a bitmap to set working mode, if \ | ||
53 | bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode."); | ||
55 | 54 | ||
56 | struct hsu_dma_buffer { | 55 | struct hsu_dma_buffer { |
57 | u8 *buf; | 56 | u8 *buf; |
@@ -65,7 +64,6 @@ struct hsu_dma_chan { | |||
65 | enum dma_data_direction dirt; | 64 | enum dma_data_direction dirt; |
66 | struct uart_hsu_port *uport; | 65 | struct uart_hsu_port *uport; |
67 | void __iomem *reg; | 66 | void __iomem *reg; |
68 | struct timer_list rx_timer; /* only needed by RX channel */ | ||
69 | }; | 67 | }; |
70 | 68 | ||
71 | struct uart_hsu_port { | 69 | struct uart_hsu_port { |
@@ -355,8 +353,6 @@ void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf | |||
355 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ | 353 | | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ |
356 | ); | 354 | ); |
357 | chan_writel(rxc, HSU_CH_CR, 0x3); | 355 | chan_writel(rxc, HSU_CH_CR, 0x3); |
358 | |||
359 | mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); | ||
360 | } | 356 | } |
361 | 357 | ||
362 | /* Protected by spin_lock_irqsave(port->lock) */ | 358 | /* Protected by spin_lock_irqsave(port->lock) */ |
@@ -420,7 +416,6 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) | |||
420 | chan_writel(chan, HSU_CH_CR, 0x3); | 416 | chan_writel(chan, HSU_CH_CR, 0x3); |
421 | return; | 417 | return; |
422 | } | 418 | } |
423 | del_timer(&chan->rx_timer); | ||
424 | 419 | ||
425 | dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, | 420 | dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, |
426 | dbuf->dma_size, DMA_FROM_DEVICE); | 421 | dbuf->dma_size, DMA_FROM_DEVICE); |
@@ -448,8 +443,6 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) | |||
448 | tty_flip_buffer_push(tty); | 443 | tty_flip_buffer_push(tty); |
449 | 444 | ||
450 | chan_writel(chan, HSU_CH_CR, 0x3); | 445 | chan_writel(chan, HSU_CH_CR, 0x3); |
451 | chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; | ||
452 | add_timer(&chan->rx_timer); | ||
453 | 446 | ||
454 | } | 447 | } |
455 | 448 | ||
@@ -551,16 +544,9 @@ static void transmit_chars(struct uart_hsu_port *up) | |||
551 | return; | 544 | return; |
552 | } | 545 | } |
553 | 546 | ||
554 | #ifndef MFD_HSU_A0_STEPPING | 547 | /* The IRQ is for TX FIFO half-empty */ |
555 | count = up->port.fifosize / 2; | 548 | count = up->port.fifosize / 2; |
556 | #else | 549 | |
557 | /* | ||
558 | * A0 only supports fully empty IRQ, and the first char written | ||
559 | * into it won't clear the EMPT bit, so we may need be cautious | ||
560 | * by useing a shorter buffer | ||
561 | */ | ||
562 | count = up->port.fifosize - 4; | ||
563 | #endif | ||
564 | do { | 550 | do { |
565 | serial_out(up, UART_TX, xmit->buf[xmit->tail]); | 551 | serial_out(up, UART_TX, xmit->buf[xmit->tail]); |
566 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 552 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
@@ -769,9 +755,8 @@ static void serial_hsu_break_ctl(struct uart_port *port, int break_state) | |||
769 | /* | 755 | /* |
770 | * What special to do: | 756 | * What special to do: |
771 | * 1. chose the 64B fifo mode | 757 | * 1. chose the 64B fifo mode |
772 | * 2. make sure not to select half empty mode for A0 stepping | 758 | * 2. start dma or pio depends on configuration |
773 | * 3. start dma or pio depends on configuration | 759 | * 3. we only allocate dma memory when needed |
774 | * 4. we only allocate dma memory when needed | ||
775 | */ | 760 | */ |
776 | static int serial_hsu_startup(struct uart_port *port) | 761 | static int serial_hsu_startup(struct uart_port *port) |
777 | { | 762 | { |
@@ -870,8 +855,6 @@ static void serial_hsu_shutdown(struct uart_port *port) | |||
870 | container_of(port, struct uart_hsu_port, port); | 855 | container_of(port, struct uart_hsu_port, port); |
871 | unsigned long flags; | 856 | unsigned long flags; |
872 | 857 | ||
873 | del_timer_sync(&up->rxc->rx_timer); | ||
874 | |||
875 | /* Disable interrupts from this port */ | 858 | /* Disable interrupts from this port */ |
876 | up->ier = 0; | 859 | up->ier = 0; |
877 | serial_out(up, UART_IER, 0); | 860 | serial_out(up, UART_IER, 0); |
@@ -977,10 +960,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, | |||
977 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; | 960 | fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; |
978 | 961 | ||
979 | fcr |= UART_FCR_HSU_64B_FIFO; | 962 | fcr |= UART_FCR_HSU_64B_FIFO; |
980 | #ifdef MFD_HSU_A0_STEPPING | ||
981 | /* A0 doesn't support half empty IRQ */ | ||
982 | fcr |= UART_FCR_FULL_EMPT_TXI; | ||
983 | #endif | ||
984 | 963 | ||
985 | /* | 964 | /* |
986 | * Ok, we're now changing the port state. Do it with | 965 | * Ok, we're now changing the port state. Do it with |
@@ -1343,28 +1322,6 @@ err_disable: | |||
1343 | return ret; | 1322 | return ret; |
1344 | } | 1323 | } |
1345 | 1324 | ||
1346 | static void hsu_dma_rx_timeout(unsigned long data) | ||
1347 | { | ||
1348 | struct hsu_dma_chan *chan = (void *)data; | ||
1349 | struct uart_hsu_port *up = chan->uport; | ||
1350 | struct hsu_dma_buffer *dbuf = &up->rxbuf; | ||
1351 | int count = 0; | ||
1352 | unsigned long flags; | ||
1353 | |||
1354 | spin_lock_irqsave(&up->port.lock, flags); | ||
1355 | |||
1356 | count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; | ||
1357 | |||
1358 | if (!count) { | ||
1359 | mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); | ||
1360 | goto exit; | ||
1361 | } | ||
1362 | |||
1363 | hsu_dma_rx(up, 0); | ||
1364 | exit: | ||
1365 | spin_unlock_irqrestore(&up->port.lock, flags); | ||
1366 | } | ||
1367 | |||
1368 | static void hsu_global_init(void) | 1325 | static void hsu_global_init(void) |
1369 | { | 1326 | { |
1370 | struct hsu_port *hsu; | 1327 | struct hsu_port *hsu; |
@@ -1415,6 +1372,12 @@ static void hsu_global_init(void) | |||
1415 | 1372 | ||
1416 | serial_hsu_ports[i] = uport; | 1373 | serial_hsu_ports[i] = uport; |
1417 | uport->index = i; | 1374 | uport->index = i; |
1375 | |||
1376 | if (hsu_dma_enable & (1<<i)) | ||
1377 | uport->use_dma = 1; | ||
1378 | else | ||
1379 | uport->use_dma = 0; | ||
1380 | |||
1418 | uport++; | 1381 | uport++; |
1419 | } | 1382 | } |
1420 | 1383 | ||
@@ -1427,12 +1390,6 @@ static void hsu_global_init(void) | |||
1427 | dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + | 1390 | dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + |
1428 | i * HSU_DMA_CHANS_REG_LENGTH; | 1391 | i * HSU_DMA_CHANS_REG_LENGTH; |
1429 | 1392 | ||
1430 | /* Work around for RX */ | ||
1431 | if (dchan->dirt == DMA_FROM_DEVICE) { | ||
1432 | init_timer(&dchan->rx_timer); | ||
1433 | dchan->rx_timer.function = hsu_dma_rx_timeout; | ||
1434 | dchan->rx_timer.data = (unsigned long)dchan; | ||
1435 | } | ||
1436 | dchan++; | 1393 | dchan++; |
1437 | } | 1394 | } |
1438 | 1395 | ||
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 126ec7f568ec..a0bcd8a3758d 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c | |||
@@ -1302,8 +1302,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { | |||
1302 | {}, | 1302 | {}, |
1303 | }; | 1303 | }; |
1304 | 1304 | ||
1305 | static int __devinit | 1305 | static int __devinit mpc52xx_uart_of_probe(struct platform_device *op) |
1306 | mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match) | ||
1307 | { | 1306 | { |
1308 | int idx = -1; | 1307 | int idx = -1; |
1309 | unsigned int uartclk; | 1308 | unsigned int uartclk; |
@@ -1311,8 +1310,6 @@ mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *mat | |||
1311 | struct resource res; | 1310 | struct resource res; |
1312 | int ret; | 1311 | int ret; |
1313 | 1312 | ||
1314 | dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match); | ||
1315 | |||
1316 | /* Check validity & presence */ | 1313 | /* Check validity & presence */ |
1317 | for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) | 1314 | for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++) |
1318 | if (mpc52xx_uart_nodes[idx] == op->dev.of_node) | 1315 | if (mpc52xx_uart_nodes[idx] == op->dev.of_node) |
@@ -1453,7 +1450,7 @@ mpc52xx_uart_of_enumerate(void) | |||
1453 | 1450 | ||
1454 | MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); | 1451 | MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match); |
1455 | 1452 | ||
1456 | static struct of_platform_driver mpc52xx_uart_of_driver = { | 1453 | static struct platform_driver mpc52xx_uart_of_driver = { |
1457 | .probe = mpc52xx_uart_of_probe, | 1454 | .probe = mpc52xx_uart_of_probe, |
1458 | .remove = mpc52xx_uart_of_remove, | 1455 | .remove = mpc52xx_uart_of_remove, |
1459 | #ifdef CONFIG_PM | 1456 | #ifdef CONFIG_PM |
@@ -1497,9 +1494,9 @@ mpc52xx_uart_init(void) | |||
1497 | return ret; | 1494 | return ret; |
1498 | } | 1495 | } |
1499 | 1496 | ||
1500 | ret = of_register_platform_driver(&mpc52xx_uart_of_driver); | 1497 | ret = platform_driver_register(&mpc52xx_uart_of_driver); |
1501 | if (ret) { | 1498 | if (ret) { |
1502 | printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n", | 1499 | printk(KERN_ERR "%s: platform_driver_register failed (%i)\n", |
1503 | __FILE__, ret); | 1500 | __FILE__, ret); |
1504 | uart_unregister_driver(&mpc52xx_uart_driver); | 1501 | uart_unregister_driver(&mpc52xx_uart_driver); |
1505 | return ret; | 1502 | return ret; |
@@ -1514,7 +1511,7 @@ mpc52xx_uart_exit(void) | |||
1514 | if (psc_ops->fifoc_uninit) | 1511 | if (psc_ops->fifoc_uninit) |
1515 | psc_ops->fifoc_uninit(); | 1512 | psc_ops->fifoc_uninit(); |
1516 | 1513 | ||
1517 | of_unregister_platform_driver(&mpc52xx_uart_of_driver); | 1514 | platform_driver_unregister(&mpc52xx_uart_of_driver); |
1518 | uart_unregister_driver(&mpc52xx_uart_driver); | 1515 | uart_unregister_driver(&mpc52xx_uart_driver); |
1519 | } | 1516 | } |
1520 | 1517 | ||
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index b62857bf2fdb..37e13c3d91d9 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c | |||
@@ -51,7 +51,7 @@ | |||
51 | struct uart_max3110 { | 51 | struct uart_max3110 { |
52 | struct uart_port port; | 52 | struct uart_port port; |
53 | struct spi_device *spi; | 53 | struct spi_device *spi; |
54 | char name[24]; | 54 | char name[SPI_NAME_SIZE]; |
55 | 55 | ||
56 | wait_queue_head_t wq; | 56 | wait_queue_head_t wq; |
57 | struct task_struct *main_thread; | 57 | struct task_struct *main_thread; |
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c new file mode 100644 index 000000000000..2e7fc9cee9cc --- /dev/null +++ b/drivers/tty/serial/msm_serial_hs.c | |||
@@ -0,0 +1,1880 @@ | |||
1 | /* | ||
2 | * MSM 7k/8k High speed uart driver | ||
3 | * | ||
4 | * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved. | ||
5 | * Copyright (c) 2008 Google Inc. | ||
6 | * Modified: Nick Pelly <npelly@google.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | * See the GNU General Public License for more details. | ||
16 | * | ||
17 | * Has optional support for uart power management independent of linux | ||
18 | * suspend/resume: | ||
19 | * | ||
20 | * RX wakeup. | ||
21 | * UART wakeup can be triggered by RX activity (using a wakeup GPIO on the | ||
22 | * UART RX pin). This should only be used if there is not a wakeup | ||
23 | * GPIO on the UART CTS, and the first RX byte is known (for example, with the | ||
24 | * Bluetooth Texas Instruments HCILL protocol), since the first RX byte will | ||
25 | * always be lost. RTS will be asserted even while the UART is off in this mode | ||
26 | * of operation. See msm_serial_hs_platform_data.rx_wakeup_irq. | ||
27 | */ | ||
28 | |||
29 | #include <linux/module.h> | ||
30 | |||
31 | #include <linux/serial.h> | ||
32 | #include <linux/serial_core.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/irq.h> | ||
37 | #include <linux/io.h> | ||
38 | #include <linux/ioport.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/clk.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | #include <linux/pm_runtime.h> | ||
44 | #include <linux/dma-mapping.h> | ||
45 | #include <linux/dmapool.h> | ||
46 | #include <linux/wait.h> | ||
47 | #include <linux/workqueue.h> | ||
48 | |||
49 | #include <linux/atomic.h> | ||
50 | #include <asm/irq.h> | ||
51 | #include <asm/system.h> | ||
52 | |||
53 | #include <mach/hardware.h> | ||
54 | #include <mach/dma.h> | ||
55 | #include <linux/platform_data/msm_serial_hs.h> | ||
56 | |||
57 | /* HSUART Registers */ | ||
58 | #define UARTDM_MR1_ADDR 0x0 | ||
59 | #define UARTDM_MR2_ADDR 0x4 | ||
60 | |||
61 | /* Data Mover result codes */ | ||
62 | #define RSLT_FIFO_CNTR_BMSK (0xE << 28) | ||
63 | #define RSLT_VLD BIT(1) | ||
64 | |||
65 | /* write only register */ | ||
66 | #define UARTDM_CSR_ADDR 0x8 | ||
67 | #define UARTDM_CSR_115200 0xFF | ||
68 | #define UARTDM_CSR_57600 0xEE | ||
69 | #define UARTDM_CSR_38400 0xDD | ||
70 | #define UARTDM_CSR_28800 0xCC | ||
71 | #define UARTDM_CSR_19200 0xBB | ||
72 | #define UARTDM_CSR_14400 0xAA | ||
73 | #define UARTDM_CSR_9600 0x99 | ||
74 | #define UARTDM_CSR_7200 0x88 | ||
75 | #define UARTDM_CSR_4800 0x77 | ||
76 | #define UARTDM_CSR_3600 0x66 | ||
77 | #define UARTDM_CSR_2400 0x55 | ||
78 | #define UARTDM_CSR_1200 0x44 | ||
79 | #define UARTDM_CSR_600 0x33 | ||
80 | #define UARTDM_CSR_300 0x22 | ||
81 | #define UARTDM_CSR_150 0x11 | ||
82 | #define UARTDM_CSR_75 0x00 | ||
83 | |||
84 | /* write only register */ | ||
85 | #define UARTDM_TF_ADDR 0x70 | ||
86 | #define UARTDM_TF2_ADDR 0x74 | ||
87 | #define UARTDM_TF3_ADDR 0x78 | ||
88 | #define UARTDM_TF4_ADDR 0x7C | ||
89 | |||
90 | /* write only register */ | ||
91 | #define UARTDM_CR_ADDR 0x10 | ||
92 | #define UARTDM_IMR_ADDR 0x14 | ||
93 | |||
94 | #define UARTDM_IPR_ADDR 0x18 | ||
95 | #define UARTDM_TFWR_ADDR 0x1c | ||
96 | #define UARTDM_RFWR_ADDR 0x20 | ||
97 | #define UARTDM_HCR_ADDR 0x24 | ||
98 | #define UARTDM_DMRX_ADDR 0x34 | ||
99 | #define UARTDM_IRDA_ADDR 0x38 | ||
100 | #define UARTDM_DMEN_ADDR 0x3c | ||
101 | |||
102 | /* UART_DM_NO_CHARS_FOR_TX */ | ||
103 | #define UARTDM_NCF_TX_ADDR 0x40 | ||
104 | |||
105 | #define UARTDM_BADR_ADDR 0x44 | ||
106 | |||
107 | #define UARTDM_SIM_CFG_ADDR 0x80 | ||
108 | /* Read Only register */ | ||
109 | #define UARTDM_SR_ADDR 0x8 | ||
110 | |||
111 | /* Read Only register */ | ||
112 | #define UARTDM_RF_ADDR 0x70 | ||
113 | #define UARTDM_RF2_ADDR 0x74 | ||
114 | #define UARTDM_RF3_ADDR 0x78 | ||
115 | #define UARTDM_RF4_ADDR 0x7C | ||
116 | |||
117 | /* Read Only register */ | ||
118 | #define UARTDM_MISR_ADDR 0x10 | ||
119 | |||
120 | /* Read Only register */ | ||
121 | #define UARTDM_ISR_ADDR 0x14 | ||
122 | #define UARTDM_RX_TOTAL_SNAP_ADDR 0x38 | ||
123 | |||
124 | #define UARTDM_RXFS_ADDR 0x50 | ||
125 | |||
126 | /* Register field Mask Mapping */ | ||
127 | #define UARTDM_SR_PAR_FRAME_BMSK BIT(5) | ||
128 | #define UARTDM_SR_OVERRUN_BMSK BIT(4) | ||
129 | #define UARTDM_SR_TXEMT_BMSK BIT(3) | ||
130 | #define UARTDM_SR_TXRDY_BMSK BIT(2) | ||
131 | #define UARTDM_SR_RXRDY_BMSK BIT(0) | ||
132 | |||
133 | #define UARTDM_CR_TX_DISABLE_BMSK BIT(3) | ||
134 | #define UARTDM_CR_RX_DISABLE_BMSK BIT(1) | ||
135 | #define UARTDM_CR_TX_EN_BMSK BIT(2) | ||
136 | #define UARTDM_CR_RX_EN_BMSK BIT(0) | ||
137 | |||
138 | /* UARTDM_CR channel_comman bit value (register field is bits 8:4) */ | ||
139 | #define RESET_RX 0x10 | ||
140 | #define RESET_TX 0x20 | ||
141 | #define RESET_ERROR_STATUS 0x30 | ||
142 | #define RESET_BREAK_INT 0x40 | ||
143 | #define START_BREAK 0x50 | ||
144 | #define STOP_BREAK 0x60 | ||
145 | #define RESET_CTS 0x70 | ||
146 | #define RESET_STALE_INT 0x80 | ||
147 | #define RFR_LOW 0xD0 | ||
148 | #define RFR_HIGH 0xE0 | ||
149 | #define CR_PROTECTION_EN 0x100 | ||
150 | #define STALE_EVENT_ENABLE 0x500 | ||
151 | #define STALE_EVENT_DISABLE 0x600 | ||
152 | #define FORCE_STALE_EVENT 0x400 | ||
153 | #define CLEAR_TX_READY 0x300 | ||
154 | #define RESET_TX_ERROR 0x800 | ||
155 | #define RESET_TX_DONE 0x810 | ||
156 | |||
157 | #define UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK 0xffffff00 | ||
158 | #define UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK 0x3f | ||
159 | #define UARTDM_MR1_CTS_CTL_BMSK 0x40 | ||
160 | #define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80 | ||
161 | |||
162 | #define UARTDM_MR2_ERROR_MODE_BMSK 0x40 | ||
163 | #define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30 | ||
164 | |||
165 | /* bits per character configuration */ | ||
166 | #define FIVE_BPC (0 << 4) | ||
167 | #define SIX_BPC (1 << 4) | ||
168 | #define SEVEN_BPC (2 << 4) | ||
169 | #define EIGHT_BPC (3 << 4) | ||
170 | |||
171 | #define UARTDM_MR2_STOP_BIT_LEN_BMSK 0xc | ||
172 | #define STOP_BIT_ONE (1 << 2) | ||
173 | #define STOP_BIT_TWO (3 << 2) | ||
174 | |||
175 | #define UARTDM_MR2_PARITY_MODE_BMSK 0x3 | ||
176 | |||
177 | /* Parity configuration */ | ||
178 | #define NO_PARITY 0x0 | ||
179 | #define EVEN_PARITY 0x1 | ||
180 | #define ODD_PARITY 0x2 | ||
181 | #define SPACE_PARITY 0x3 | ||
182 | |||
183 | #define UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK 0xffffff80 | ||
184 | #define UARTDM_IPR_STALE_LSB_BMSK 0x1f | ||
185 | |||
186 | /* These can be used for both ISR and IMR register */ | ||
187 | #define UARTDM_ISR_TX_READY_BMSK BIT(7) | ||
188 | #define UARTDM_ISR_CURRENT_CTS_BMSK BIT(6) | ||
189 | #define UARTDM_ISR_DELTA_CTS_BMSK BIT(5) | ||
190 | #define UARTDM_ISR_RXLEV_BMSK BIT(4) | ||
191 | #define UARTDM_ISR_RXSTALE_BMSK BIT(3) | ||
192 | #define UARTDM_ISR_RXBREAK_BMSK BIT(2) | ||
193 | #define UARTDM_ISR_RXHUNT_BMSK BIT(1) | ||
194 | #define UARTDM_ISR_TXLEV_BMSK BIT(0) | ||
195 | |||
196 | /* Field definitions for UART_DM_DMEN*/ | ||
197 | #define UARTDM_TX_DM_EN_BMSK 0x1 | ||
198 | #define UARTDM_RX_DM_EN_BMSK 0x2 | ||
199 | |||
200 | #define UART_FIFOSIZE 64 | ||
201 | #define UARTCLK 7372800 | ||
202 | |||
203 | /* Rx DMA request states */ | ||
204 | enum flush_reason { | ||
205 | FLUSH_NONE, | ||
206 | FLUSH_DATA_READY, | ||
207 | FLUSH_DATA_INVALID, /* values after this indicate invalid data */ | ||
208 | FLUSH_IGNORE = FLUSH_DATA_INVALID, | ||
209 | FLUSH_STOP, | ||
210 | FLUSH_SHUTDOWN, | ||
211 | }; | ||
212 | |||
213 | /* UART clock states */ | ||
214 | enum msm_hs_clk_states_e { | ||
215 | MSM_HS_CLK_PORT_OFF, /* port not in use */ | ||
216 | MSM_HS_CLK_OFF, /* clock disabled */ | ||
217 | MSM_HS_CLK_REQUEST_OFF, /* disable after TX and RX flushed */ | ||
218 | MSM_HS_CLK_ON, /* clock enabled */ | ||
219 | }; | ||
220 | |||
221 | /* Track the forced RXSTALE flush during clock off sequence. | ||
222 | * These states are only valid during MSM_HS_CLK_REQUEST_OFF */ | ||
223 | enum msm_hs_clk_req_off_state_e { | ||
224 | CLK_REQ_OFF_START, | ||
225 | CLK_REQ_OFF_RXSTALE_ISSUED, | ||
226 | CLK_REQ_OFF_FLUSH_ISSUED, | ||
227 | CLK_REQ_OFF_RXSTALE_FLUSHED, | ||
228 | }; | ||
229 | |||
230 | /** | ||
231 | * struct msm_hs_tx | ||
232 | * @tx_ready_int_en: ok to dma more tx? | ||
233 | * @dma_in_flight: tx dma in progress | ||
234 | * @xfer: top level DMA command pointer structure | ||
235 | * @command_ptr: third level command struct pointer | ||
236 | * @command_ptr_ptr: second level command list struct pointer | ||
237 | * @mapped_cmd_ptr: DMA view of third level command struct | ||
238 | * @mapped_cmd_ptr_ptr: DMA view of second level command list struct | ||
239 | * @tx_count: number of bytes to transfer in DMA transfer | ||
240 | * @dma_base: DMA view of UART xmit buffer | ||
241 | * | ||
242 | * This structure describes a single Tx DMA transaction. MSM DMA | ||
243 | * commands have two levels of indirection. The top level command | ||
244 | * ptr points to a list of command ptr which in turn points to a | ||
245 | * single DMA 'command'. In our case each Tx transaction consists | ||
246 | * of a single second level pointer pointing to a 'box type' command. | ||
247 | */ | ||
248 | struct msm_hs_tx { | ||
249 | unsigned int tx_ready_int_en; | ||
250 | unsigned int dma_in_flight; | ||
251 | struct msm_dmov_cmd xfer; | ||
252 | dmov_box *command_ptr; | ||
253 | u32 *command_ptr_ptr; | ||
254 | dma_addr_t mapped_cmd_ptr; | ||
255 | dma_addr_t mapped_cmd_ptr_ptr; | ||
256 | int tx_count; | ||
257 | dma_addr_t dma_base; | ||
258 | }; | ||
259 | |||
260 | /** | ||
261 | * struct msm_hs_rx | ||
262 | * @flush: Rx DMA request state | ||
263 | * @xfer: top level DMA command pointer structure | ||
264 | * @cmdptr_dmaaddr: DMA view of second level command structure | ||
265 | * @command_ptr: third level DMA command pointer structure | ||
266 | * @command_ptr_ptr: second level DMA command list pointer | ||
267 | * @mapped_cmd_ptr: DMA view of the third level command structure | ||
268 | * @wait: wait for DMA completion before shutdown | ||
269 | * @buffer: destination buffer for RX DMA | ||
270 | * @rbuffer: DMA view of buffer | ||
271 | * @pool: dma pool out of which coherent rx buffer is allocated | ||
272 | * @tty_work: private work-queue for tty flip buffer push task | ||
273 | * | ||
274 | * This structure describes a single Rx DMA transaction. Rx DMA | ||
275 | * transactions use box mode DMA commands. | ||
276 | */ | ||
277 | struct msm_hs_rx { | ||
278 | enum flush_reason flush; | ||
279 | struct msm_dmov_cmd xfer; | ||
280 | dma_addr_t cmdptr_dmaaddr; | ||
281 | dmov_box *command_ptr; | ||
282 | u32 *command_ptr_ptr; | ||
283 | dma_addr_t mapped_cmd_ptr; | ||
284 | wait_queue_head_t wait; | ||
285 | dma_addr_t rbuffer; | ||
286 | unsigned char *buffer; | ||
287 | struct dma_pool *pool; | ||
288 | struct work_struct tty_work; | ||
289 | }; | ||
290 | |||
291 | /** | ||
292 | * struct msm_hs_rx_wakeup | ||
293 | * @irq: IRQ line to be configured as interrupt source on Rx activity | ||
294 | * @ignore: boolean value. 1 = ignore the wakeup interrupt | ||
295 | * @rx_to_inject: extra character to be inserted to Rx tty on wakeup | ||
296 | * @inject_rx: 1 = insert rx_to_inject. 0 = do not insert extra character | ||
297 | * | ||
298 | * This is an optional structure required for UART Rx GPIO IRQ based | ||
299 | * wakeup from low power state. UART wakeup can be triggered by RX activity | ||
300 | * (using a wakeup GPIO on the UART RX pin). This should only be used if | ||
301 | * there is not a wakeup GPIO on the UART CTS, and the first RX byte is | ||
302 | * known (eg., with the Bluetooth Texas Instruments HCILL protocol), | ||
303 | * since the first RX byte will always be lost. RTS will be asserted even | ||
304 | * while the UART is clocked off in this mode of operation. | ||
305 | */ | ||
306 | struct msm_hs_rx_wakeup { | ||
307 | int irq; /* < 0 indicates low power wakeup disabled */ | ||
308 | unsigned char ignore; | ||
309 | unsigned char inject_rx; | ||
310 | char rx_to_inject; | ||
311 | }; | ||
312 | |||
313 | /** | ||
314 | * struct msm_hs_port | ||
315 | * @uport: embedded uart port structure | ||
316 | * @imr_reg: shadow value of UARTDM_IMR | ||
317 | * @clk: uart input clock handle | ||
318 | * @tx: Tx transaction related data structure | ||
319 | * @rx: Rx transaction related data structure | ||
320 | * @dma_tx_channel: Tx DMA command channel | ||
321 | * @dma_rx_channel Rx DMA command channel | ||
322 | * @dma_tx_crci: Tx channel rate control interface number | ||
323 | * @dma_rx_crci: Rx channel rate control interface number | ||
324 | * @clk_off_timer: Timer to poll DMA event completion before clock off | ||
325 | * @clk_off_delay: clk_off_timer poll interval | ||
326 | * @clk_state: overall clock state | ||
327 | * @clk_req_off_state: post flush clock states | ||
328 | * @rx_wakeup: optional rx_wakeup feature related data | ||
329 | * @exit_lpm_cb: optional callback to exit low power mode | ||
330 | * | ||
331 | * Low level serial port structure. | ||
332 | */ | ||
333 | struct msm_hs_port { | ||
334 | struct uart_port uport; | ||
335 | unsigned long imr_reg; | ||
336 | struct clk *clk; | ||
337 | struct msm_hs_tx tx; | ||
338 | struct msm_hs_rx rx; | ||
339 | |||
340 | int dma_tx_channel; | ||
341 | int dma_rx_channel; | ||
342 | int dma_tx_crci; | ||
343 | int dma_rx_crci; | ||
344 | |||
345 | struct hrtimer clk_off_timer; | ||
346 | ktime_t clk_off_delay; | ||
347 | enum msm_hs_clk_states_e clk_state; | ||
348 | enum msm_hs_clk_req_off_state_e clk_req_off_state; | ||
349 | |||
350 | struct msm_hs_rx_wakeup rx_wakeup; | ||
351 | void (*exit_lpm_cb)(struct uart_port *); | ||
352 | }; | ||
353 | |||
354 | #define MSM_UARTDM_BURST_SIZE 16 /* DM burst size (in bytes) */ | ||
355 | #define UARTDM_TX_BUF_SIZE UART_XMIT_SIZE | ||
356 | #define UARTDM_RX_BUF_SIZE 512 | ||
357 | |||
358 | #define UARTDM_NR 2 | ||
359 | |||
360 | static struct msm_hs_port q_uart_port[UARTDM_NR]; | ||
361 | static struct platform_driver msm_serial_hs_platform_driver; | ||
362 | static struct uart_driver msm_hs_driver; | ||
363 | static struct uart_ops msm_hs_ops; | ||
364 | static struct workqueue_struct *msm_hs_workqueue; | ||
365 | |||
366 | #define UARTDM_TO_MSM(uart_port) \ | ||
367 | container_of((uart_port), struct msm_hs_port, uport) | ||
368 | |||
369 | static unsigned int use_low_power_rx_wakeup(struct msm_hs_port | ||
370 | *msm_uport) | ||
371 | { | ||
372 | return (msm_uport->rx_wakeup.irq >= 0); | ||
373 | } | ||
374 | |||
375 | static unsigned int msm_hs_read(struct uart_port *uport, | ||
376 | unsigned int offset) | ||
377 | { | ||
378 | return ioread32(uport->membase + offset); | ||
379 | } | ||
380 | |||
381 | static void msm_hs_write(struct uart_port *uport, unsigned int offset, | ||
382 | unsigned int value) | ||
383 | { | ||
384 | iowrite32(value, uport->membase + offset); | ||
385 | } | ||
386 | |||
387 | static void msm_hs_release_port(struct uart_port *port) | ||
388 | { | ||
389 | iounmap(port->membase); | ||
390 | } | ||
391 | |||
392 | static int msm_hs_request_port(struct uart_port *port) | ||
393 | { | ||
394 | port->membase = ioremap(port->mapbase, PAGE_SIZE); | ||
395 | if (unlikely(!port->membase)) | ||
396 | return -ENOMEM; | ||
397 | |||
398 | /* configure the CR Protection to Enable */ | ||
399 | msm_hs_write(port, UARTDM_CR_ADDR, CR_PROTECTION_EN); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int __devexit msm_hs_remove(struct platform_device *pdev) | ||
404 | { | ||
405 | |||
406 | struct msm_hs_port *msm_uport; | ||
407 | struct device *dev; | ||
408 | |||
409 | if (pdev->id < 0 || pdev->id >= UARTDM_NR) { | ||
410 | printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); | ||
411 | return -EINVAL; | ||
412 | } | ||
413 | |||
414 | msm_uport = &q_uart_port[pdev->id]; | ||
415 | dev = msm_uport->uport.dev; | ||
416 | |||
417 | dma_unmap_single(dev, msm_uport->rx.mapped_cmd_ptr, sizeof(dmov_box), | ||
418 | DMA_TO_DEVICE); | ||
419 | dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, | ||
420 | msm_uport->rx.rbuffer); | ||
421 | dma_pool_destroy(msm_uport->rx.pool); | ||
422 | |||
423 | dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *), | ||
424 | DMA_TO_DEVICE); | ||
425 | dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *), | ||
426 | DMA_TO_DEVICE); | ||
427 | dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box), | ||
428 | DMA_TO_DEVICE); | ||
429 | |||
430 | uart_remove_one_port(&msm_hs_driver, &msm_uport->uport); | ||
431 | clk_put(msm_uport->clk); | ||
432 | |||
433 | /* Free the tx resources */ | ||
434 | kfree(msm_uport->tx.command_ptr); | ||
435 | kfree(msm_uport->tx.command_ptr_ptr); | ||
436 | |||
437 | /* Free the rx resources */ | ||
438 | kfree(msm_uport->rx.command_ptr); | ||
439 | kfree(msm_uport->rx.command_ptr_ptr); | ||
440 | |||
441 | iounmap(msm_uport->uport.membase); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static int msm_hs_init_clk_locked(struct uart_port *uport) | ||
447 | { | ||
448 | int ret; | ||
449 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
450 | |||
451 | ret = clk_enable(msm_uport->clk); | ||
452 | if (ret) { | ||
453 | printk(KERN_ERR "Error could not turn on UART clk\n"); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | /* Set up the MREG/NREG/DREG/MNDREG */ | ||
458 | ret = clk_set_rate(msm_uport->clk, uport->uartclk); | ||
459 | if (ret) { | ||
460 | printk(KERN_WARNING "Error setting clock rate on UART\n"); | ||
461 | clk_disable(msm_uport->clk); | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | msm_uport->clk_state = MSM_HS_CLK_ON; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | /* Enable and Disable clocks (Used for power management) */ | ||
470 | static void msm_hs_pm(struct uart_port *uport, unsigned int state, | ||
471 | unsigned int oldstate) | ||
472 | { | ||
473 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
474 | |||
475 | if (use_low_power_rx_wakeup(msm_uport) || | ||
476 | msm_uport->exit_lpm_cb) | ||
477 | return; /* ignore linux PM states, | ||
478 | use msm_hs_request_clock API */ | ||
479 | |||
480 | switch (state) { | ||
481 | case 0: | ||
482 | clk_enable(msm_uport->clk); | ||
483 | break; | ||
484 | case 3: | ||
485 | clk_disable(msm_uport->clk); | ||
486 | break; | ||
487 | default: | ||
488 | dev_err(uport->dev, "msm_serial: Unknown PM state %d\n", | ||
489 | state); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | /* | ||
494 | * programs the UARTDM_CSR register with correct bit rates | ||
495 | * | ||
496 | * Interrupts should be disabled before we are called, as | ||
497 | * we modify Set Baud rate | ||
498 | * Set receive stale interrupt level, dependant on Bit Rate | ||
499 | * Goal is to have around 8 ms before indicate stale. | ||
500 | * roundup (((Bit Rate * .008) / 10) + 1 | ||
501 | */ | ||
502 | static void msm_hs_set_bps_locked(struct uart_port *uport, | ||
503 | unsigned int bps) | ||
504 | { | ||
505 | unsigned long rxstale; | ||
506 | unsigned long data; | ||
507 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
508 | |||
509 | switch (bps) { | ||
510 | case 300: | ||
511 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_75); | ||
512 | rxstale = 1; | ||
513 | break; | ||
514 | case 600: | ||
515 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_150); | ||
516 | rxstale = 1; | ||
517 | break; | ||
518 | case 1200: | ||
519 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_300); | ||
520 | rxstale = 1; | ||
521 | break; | ||
522 | case 2400: | ||
523 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_600); | ||
524 | rxstale = 1; | ||
525 | break; | ||
526 | case 4800: | ||
527 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_1200); | ||
528 | rxstale = 1; | ||
529 | break; | ||
530 | case 9600: | ||
531 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); | ||
532 | rxstale = 2; | ||
533 | break; | ||
534 | case 14400: | ||
535 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_3600); | ||
536 | rxstale = 3; | ||
537 | break; | ||
538 | case 19200: | ||
539 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_4800); | ||
540 | rxstale = 4; | ||
541 | break; | ||
542 | case 28800: | ||
543 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_7200); | ||
544 | rxstale = 6; | ||
545 | break; | ||
546 | case 38400: | ||
547 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_9600); | ||
548 | rxstale = 8; | ||
549 | break; | ||
550 | case 57600: | ||
551 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_14400); | ||
552 | rxstale = 16; | ||
553 | break; | ||
554 | case 76800: | ||
555 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_19200); | ||
556 | rxstale = 16; | ||
557 | break; | ||
558 | case 115200: | ||
559 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_28800); | ||
560 | rxstale = 31; | ||
561 | break; | ||
562 | case 230400: | ||
563 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_57600); | ||
564 | rxstale = 31; | ||
565 | break; | ||
566 | case 460800: | ||
567 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); | ||
568 | rxstale = 31; | ||
569 | break; | ||
570 | case 4000000: | ||
571 | case 3686400: | ||
572 | case 3200000: | ||
573 | case 3500000: | ||
574 | case 3000000: | ||
575 | case 2500000: | ||
576 | case 1500000: | ||
577 | case 1152000: | ||
578 | case 1000000: | ||
579 | case 921600: | ||
580 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_115200); | ||
581 | rxstale = 31; | ||
582 | break; | ||
583 | default: | ||
584 | msm_hs_write(uport, UARTDM_CSR_ADDR, UARTDM_CSR_2400); | ||
585 | /* default to 9600 */ | ||
586 | bps = 9600; | ||
587 | rxstale = 2; | ||
588 | break; | ||
589 | } | ||
590 | if (bps > 460800) | ||
591 | uport->uartclk = bps * 16; | ||
592 | else | ||
593 | uport->uartclk = UARTCLK; | ||
594 | |||
595 | if (clk_set_rate(msm_uport->clk, uport->uartclk)) { | ||
596 | printk(KERN_WARNING "Error setting clock rate on UART\n"); | ||
597 | return; | ||
598 | } | ||
599 | |||
600 | data = rxstale & UARTDM_IPR_STALE_LSB_BMSK; | ||
601 | data |= UARTDM_IPR_STALE_TIMEOUT_MSB_BMSK & (rxstale << 2); | ||
602 | |||
603 | msm_hs_write(uport, UARTDM_IPR_ADDR, data); | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | * termios : new ktermios | ||
608 | * oldtermios: old ktermios previous setting | ||
609 | * | ||
610 | * Configure the serial port | ||
611 | */ | ||
612 | static void msm_hs_set_termios(struct uart_port *uport, | ||
613 | struct ktermios *termios, | ||
614 | struct ktermios *oldtermios) | ||
615 | { | ||
616 | unsigned int bps; | ||
617 | unsigned long data; | ||
618 | unsigned long flags; | ||
619 | unsigned int c_cflag = termios->c_cflag; | ||
620 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
621 | |||
622 | spin_lock_irqsave(&uport->lock, flags); | ||
623 | clk_enable(msm_uport->clk); | ||
624 | |||
625 | /* 300 is the minimum baud support by the driver */ | ||
626 | bps = uart_get_baud_rate(uport, termios, oldtermios, 200, 4000000); | ||
627 | |||
628 | /* Temporary remapping 200 BAUD to 3.2 mbps */ | ||
629 | if (bps == 200) | ||
630 | bps = 3200000; | ||
631 | |||
632 | msm_hs_set_bps_locked(uport, bps); | ||
633 | |||
634 | data = msm_hs_read(uport, UARTDM_MR2_ADDR); | ||
635 | data &= ~UARTDM_MR2_PARITY_MODE_BMSK; | ||
636 | /* set parity */ | ||
637 | if (PARENB == (c_cflag & PARENB)) { | ||
638 | if (PARODD == (c_cflag & PARODD)) | ||
639 | data |= ODD_PARITY; | ||
640 | else if (CMSPAR == (c_cflag & CMSPAR)) | ||
641 | data |= SPACE_PARITY; | ||
642 | else | ||
643 | data |= EVEN_PARITY; | ||
644 | } | ||
645 | |||
646 | /* Set bits per char */ | ||
647 | data &= ~UARTDM_MR2_BITS_PER_CHAR_BMSK; | ||
648 | |||
649 | switch (c_cflag & CSIZE) { | ||
650 | case CS5: | ||
651 | data |= FIVE_BPC; | ||
652 | break; | ||
653 | case CS6: | ||
654 | data |= SIX_BPC; | ||
655 | break; | ||
656 | case CS7: | ||
657 | data |= SEVEN_BPC; | ||
658 | break; | ||
659 | default: | ||
660 | data |= EIGHT_BPC; | ||
661 | break; | ||
662 | } | ||
663 | /* stop bits */ | ||
664 | if (c_cflag & CSTOPB) { | ||
665 | data |= STOP_BIT_TWO; | ||
666 | } else { | ||
667 | /* otherwise 1 stop bit */ | ||
668 | data |= STOP_BIT_ONE; | ||
669 | } | ||
670 | data |= UARTDM_MR2_ERROR_MODE_BMSK; | ||
671 | /* write parity/bits per char/stop bit configuration */ | ||
672 | msm_hs_write(uport, UARTDM_MR2_ADDR, data); | ||
673 | |||
674 | /* Configure HW flow control */ | ||
675 | data = msm_hs_read(uport, UARTDM_MR1_ADDR); | ||
676 | |||
677 | data &= ~(UARTDM_MR1_CTS_CTL_BMSK | UARTDM_MR1_RX_RDY_CTL_BMSK); | ||
678 | |||
679 | if (c_cflag & CRTSCTS) { | ||
680 | data |= UARTDM_MR1_CTS_CTL_BMSK; | ||
681 | data |= UARTDM_MR1_RX_RDY_CTL_BMSK; | ||
682 | } | ||
683 | |||
684 | msm_hs_write(uport, UARTDM_MR1_ADDR, data); | ||
685 | |||
686 | uport->ignore_status_mask = termios->c_iflag & INPCK; | ||
687 | uport->ignore_status_mask |= termios->c_iflag & IGNPAR; | ||
688 | uport->read_status_mask = (termios->c_cflag & CREAD); | ||
689 | |||
690 | msm_hs_write(uport, UARTDM_IMR_ADDR, 0); | ||
691 | |||
692 | /* Set Transmit software time out */ | ||
693 | uart_update_timeout(uport, c_cflag, bps); | ||
694 | |||
695 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); | ||
696 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); | ||
697 | |||
698 | if (msm_uport->rx.flush == FLUSH_NONE) { | ||
699 | msm_uport->rx.flush = FLUSH_IGNORE; | ||
700 | msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); | ||
701 | } | ||
702 | |||
703 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
704 | |||
705 | clk_disable(msm_uport->clk); | ||
706 | spin_unlock_irqrestore(&uport->lock, flags); | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Standard API, Transmitter | ||
711 | * Any character in the transmit shift register is sent | ||
712 | */ | ||
713 | static unsigned int msm_hs_tx_empty(struct uart_port *uport) | ||
714 | { | ||
715 | unsigned int data; | ||
716 | unsigned int ret = 0; | ||
717 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
718 | |||
719 | clk_enable(msm_uport->clk); | ||
720 | |||
721 | data = msm_hs_read(uport, UARTDM_SR_ADDR); | ||
722 | if (data & UARTDM_SR_TXEMT_BMSK) | ||
723 | ret = TIOCSER_TEMT; | ||
724 | |||
725 | clk_disable(msm_uport->clk); | ||
726 | |||
727 | return ret; | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | * Standard API, Stop transmitter. | ||
732 | * Any character in the transmit shift register is sent as | ||
733 | * well as the current data mover transfer . | ||
734 | */ | ||
735 | static void msm_hs_stop_tx_locked(struct uart_port *uport) | ||
736 | { | ||
737 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
738 | |||
739 | msm_uport->tx.tx_ready_int_en = 0; | ||
740 | } | ||
741 | |||
742 | /* | ||
743 | * Standard API, Stop receiver as soon as possible. | ||
744 | * | ||
745 | * Function immediately terminates the operation of the | ||
746 | * channel receiver and any incoming characters are lost. None | ||
747 | * of the receiver status bits are affected by this command and | ||
748 | * characters that are already in the receive FIFO there. | ||
749 | */ | ||
750 | static void msm_hs_stop_rx_locked(struct uart_port *uport) | ||
751 | { | ||
752 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
753 | unsigned int data; | ||
754 | |||
755 | clk_enable(msm_uport->clk); | ||
756 | |||
757 | /* disable dlink */ | ||
758 | data = msm_hs_read(uport, UARTDM_DMEN_ADDR); | ||
759 | data &= ~UARTDM_RX_DM_EN_BMSK; | ||
760 | msm_hs_write(uport, UARTDM_DMEN_ADDR, data); | ||
761 | |||
762 | /* Disable the receiver */ | ||
763 | if (msm_uport->rx.flush == FLUSH_NONE) | ||
764 | msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); | ||
765 | |||
766 | if (msm_uport->rx.flush != FLUSH_SHUTDOWN) | ||
767 | msm_uport->rx.flush = FLUSH_STOP; | ||
768 | |||
769 | clk_disable(msm_uport->clk); | ||
770 | } | ||
771 | |||
772 | /* Transmit the next chunk of data */ | ||
773 | static void msm_hs_submit_tx_locked(struct uart_port *uport) | ||
774 | { | ||
775 | int left; | ||
776 | int tx_count; | ||
777 | dma_addr_t src_addr; | ||
778 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
779 | struct msm_hs_tx *tx = &msm_uport->tx; | ||
780 | struct circ_buf *tx_buf = &msm_uport->uport.state->xmit; | ||
781 | |||
782 | if (uart_circ_empty(tx_buf) || uport->state->port.tty->stopped) { | ||
783 | msm_hs_stop_tx_locked(uport); | ||
784 | return; | ||
785 | } | ||
786 | |||
787 | tx->dma_in_flight = 1; | ||
788 | |||
789 | tx_count = uart_circ_chars_pending(tx_buf); | ||
790 | |||
791 | if (UARTDM_TX_BUF_SIZE < tx_count) | ||
792 | tx_count = UARTDM_TX_BUF_SIZE; | ||
793 | |||
794 | left = UART_XMIT_SIZE - tx_buf->tail; | ||
795 | |||
796 | if (tx_count > left) | ||
797 | tx_count = left; | ||
798 | |||
799 | src_addr = tx->dma_base + tx_buf->tail; | ||
800 | dma_sync_single_for_device(uport->dev, src_addr, tx_count, | ||
801 | DMA_TO_DEVICE); | ||
802 | |||
803 | tx->command_ptr->num_rows = (((tx_count + 15) >> 4) << 16) | | ||
804 | ((tx_count + 15) >> 4); | ||
805 | tx->command_ptr->src_row_addr = src_addr; | ||
806 | |||
807 | dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr, | ||
808 | sizeof(dmov_box), DMA_TO_DEVICE); | ||
809 | |||
810 | *tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr); | ||
811 | |||
812 | dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr, | ||
813 | sizeof(u32 *), DMA_TO_DEVICE); | ||
814 | |||
815 | /* Save tx_count to use in Callback */ | ||
816 | tx->tx_count = tx_count; | ||
817 | msm_hs_write(uport, UARTDM_NCF_TX_ADDR, tx_count); | ||
818 | |||
819 | /* Disable the tx_ready interrupt */ | ||
820 | msm_uport->imr_reg &= ~UARTDM_ISR_TX_READY_BMSK; | ||
821 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
822 | msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer); | ||
823 | } | ||
824 | |||
825 | /* Start to receive the next chunk of data */ | ||
826 | static void msm_hs_start_rx_locked(struct uart_port *uport) | ||
827 | { | ||
828 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
829 | |||
830 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); | ||
831 | msm_hs_write(uport, UARTDM_DMRX_ADDR, UARTDM_RX_BUF_SIZE); | ||
832 | msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_ENABLE); | ||
833 | msm_uport->imr_reg |= UARTDM_ISR_RXLEV_BMSK; | ||
834 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
835 | |||
836 | msm_uport->rx.flush = FLUSH_NONE; | ||
837 | msm_dmov_enqueue_cmd(msm_uport->dma_rx_channel, &msm_uport->rx.xfer); | ||
838 | |||
839 | /* might have finished RX and be ready to clock off */ | ||
840 | hrtimer_start(&msm_uport->clk_off_timer, msm_uport->clk_off_delay, | ||
841 | HRTIMER_MODE_REL); | ||
842 | } | ||
843 | |||
844 | /* Enable the transmitter Interrupt */ | ||
845 | static void msm_hs_start_tx_locked(struct uart_port *uport) | ||
846 | { | ||
847 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
848 | |||
849 | clk_enable(msm_uport->clk); | ||
850 | |||
851 | if (msm_uport->exit_lpm_cb) | ||
852 | msm_uport->exit_lpm_cb(uport); | ||
853 | |||
854 | if (msm_uport->tx.tx_ready_int_en == 0) { | ||
855 | msm_uport->tx.tx_ready_int_en = 1; | ||
856 | msm_hs_submit_tx_locked(uport); | ||
857 | } | ||
858 | |||
859 | clk_disable(msm_uport->clk); | ||
860 | } | ||
861 | |||
862 | /* | ||
863 | * This routine is called when we are done with a DMA transfer | ||
864 | * | ||
865 | * This routine is registered with Data mover when we set | ||
866 | * up a Data Mover transfer. It is called from Data mover ISR | ||
867 | * when the DMA transfer is done. | ||
868 | */ | ||
869 | static void msm_hs_dmov_tx_callback(struct msm_dmov_cmd *cmd_ptr, | ||
870 | unsigned int result, | ||
871 | struct msm_dmov_errdata *err) | ||
872 | { | ||
873 | unsigned long flags; | ||
874 | struct msm_hs_port *msm_uport; | ||
875 | |||
876 | /* DMA did not finish properly */ | ||
877 | WARN_ON((((result & RSLT_FIFO_CNTR_BMSK) >> 28) == 1) && | ||
878 | !(result & RSLT_VLD)); | ||
879 | |||
880 | msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer); | ||
881 | |||
882 | spin_lock_irqsave(&msm_uport->uport.lock, flags); | ||
883 | clk_enable(msm_uport->clk); | ||
884 | |||
885 | msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK; | ||
886 | msm_hs_write(&msm_uport->uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
887 | |||
888 | clk_disable(msm_uport->clk); | ||
889 | spin_unlock_irqrestore(&msm_uport->uport.lock, flags); | ||
890 | } | ||
891 | |||
892 | /* | ||
893 | * This routine is called when we are done with a DMA transfer or the | ||
894 | * a flush has been sent to the data mover driver. | ||
895 | * | ||
896 | * This routine is registered with Data mover when we set up a Data Mover | ||
897 | * transfer. It is called from Data mover ISR when the DMA transfer is done. | ||
898 | */ | ||
899 | static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr, | ||
900 | unsigned int result, | ||
901 | struct msm_dmov_errdata *err) | ||
902 | { | ||
903 | int retval; | ||
904 | int rx_count; | ||
905 | unsigned long status; | ||
906 | unsigned int error_f = 0; | ||
907 | unsigned long flags; | ||
908 | unsigned int flush; | ||
909 | struct tty_struct *tty; | ||
910 | struct uart_port *uport; | ||
911 | struct msm_hs_port *msm_uport; | ||
912 | |||
913 | msm_uport = container_of(cmd_ptr, struct msm_hs_port, rx.xfer); | ||
914 | uport = &msm_uport->uport; | ||
915 | |||
916 | spin_lock_irqsave(&uport->lock, flags); | ||
917 | clk_enable(msm_uport->clk); | ||
918 | |||
919 | tty = uport->state->port.tty; | ||
920 | |||
921 | msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); | ||
922 | |||
923 | status = msm_hs_read(uport, UARTDM_SR_ADDR); | ||
924 | |||
925 | /* overflow is not connect to data in a FIFO */ | ||
926 | if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) && | ||
927 | (uport->read_status_mask & CREAD))) { | ||
928 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
929 | uport->icount.buf_overrun++; | ||
930 | error_f = 1; | ||
931 | } | ||
932 | |||
933 | if (!(uport->ignore_status_mask & INPCK)) | ||
934 | status = status & ~(UARTDM_SR_PAR_FRAME_BMSK); | ||
935 | |||
936 | if (unlikely(status & UARTDM_SR_PAR_FRAME_BMSK)) { | ||
937 | /* Can not tell difference between parity & frame error */ | ||
938 | uport->icount.parity++; | ||
939 | error_f = 1; | ||
940 | if (uport->ignore_status_mask & IGNPAR) | ||
941 | tty_insert_flip_char(tty, 0, TTY_PARITY); | ||
942 | } | ||
943 | |||
944 | if (error_f) | ||
945 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); | ||
946 | |||
947 | if (msm_uport->clk_req_off_state == CLK_REQ_OFF_FLUSH_ISSUED) | ||
948 | msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_FLUSHED; | ||
949 | |||
950 | flush = msm_uport->rx.flush; | ||
951 | if (flush == FLUSH_IGNORE) | ||
952 | msm_hs_start_rx_locked(uport); | ||
953 | if (flush == FLUSH_STOP) | ||
954 | msm_uport->rx.flush = FLUSH_SHUTDOWN; | ||
955 | if (flush >= FLUSH_DATA_INVALID) | ||
956 | goto out; | ||
957 | |||
958 | rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR); | ||
959 | |||
960 | if (0 != (uport->read_status_mask & CREAD)) { | ||
961 | retval = tty_insert_flip_string(tty, msm_uport->rx.buffer, | ||
962 | rx_count); | ||
963 | BUG_ON(retval != rx_count); | ||
964 | } | ||
965 | |||
966 | msm_hs_start_rx_locked(uport); | ||
967 | |||
968 | out: | ||
969 | clk_disable(msm_uport->clk); | ||
970 | |||
971 | spin_unlock_irqrestore(&uport->lock, flags); | ||
972 | |||
973 | if (flush < FLUSH_DATA_INVALID) | ||
974 | queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); | ||
975 | } | ||
976 | |||
977 | static void msm_hs_tty_flip_buffer_work(struct work_struct *work) | ||
978 | { | ||
979 | struct msm_hs_port *msm_uport = | ||
980 | container_of(work, struct msm_hs_port, rx.tty_work); | ||
981 | struct tty_struct *tty = msm_uport->uport.state->port.tty; | ||
982 | |||
983 | tty_flip_buffer_push(tty); | ||
984 | } | ||
985 | |||
986 | /* | ||
987 | * Standard API, Current states of modem control inputs | ||
988 | * | ||
989 | * Since CTS can be handled entirely by HARDWARE we always | ||
990 | * indicate clear to send and count on the TX FIFO to block when | ||
991 | * it fills up. | ||
992 | * | ||
993 | * - TIOCM_DCD | ||
994 | * - TIOCM_CTS | ||
995 | * - TIOCM_DSR | ||
996 | * - TIOCM_RI | ||
997 | * (Unsupported) DCD and DSR will return them high. RI will return low. | ||
998 | */ | ||
999 | static unsigned int msm_hs_get_mctrl_locked(struct uart_port *uport) | ||
1000 | { | ||
1001 | return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * True enables UART auto RFR, which indicates we are ready for data if the RX | ||
1006 | * buffer is not full. False disables auto RFR, and deasserts RFR to indicate | ||
1007 | * we are not ready for data. Must be called with UART clock on. | ||
1008 | */ | ||
1009 | static void set_rfr_locked(struct uart_port *uport, int auto_rfr) | ||
1010 | { | ||
1011 | unsigned int data; | ||
1012 | |||
1013 | data = msm_hs_read(uport, UARTDM_MR1_ADDR); | ||
1014 | |||
1015 | if (auto_rfr) { | ||
1016 | /* enable auto ready-for-receiving */ | ||
1017 | data |= UARTDM_MR1_RX_RDY_CTL_BMSK; | ||
1018 | msm_hs_write(uport, UARTDM_MR1_ADDR, data); | ||
1019 | } else { | ||
1020 | /* disable auto ready-for-receiving */ | ||
1021 | data &= ~UARTDM_MR1_RX_RDY_CTL_BMSK; | ||
1022 | msm_hs_write(uport, UARTDM_MR1_ADDR, data); | ||
1023 | /* RFR is active low, set high */ | ||
1024 | msm_hs_write(uport, UARTDM_CR_ADDR, RFR_HIGH); | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
1029 | * Standard API, used to set or clear RFR | ||
1030 | */ | ||
1031 | static void msm_hs_set_mctrl_locked(struct uart_port *uport, | ||
1032 | unsigned int mctrl) | ||
1033 | { | ||
1034 | unsigned int auto_rfr; | ||
1035 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1036 | |||
1037 | clk_enable(msm_uport->clk); | ||
1038 | |||
1039 | auto_rfr = TIOCM_RTS & mctrl ? 1 : 0; | ||
1040 | set_rfr_locked(uport, auto_rfr); | ||
1041 | |||
1042 | clk_disable(msm_uport->clk); | ||
1043 | } | ||
1044 | |||
1045 | /* Standard API, Enable modem status (CTS) interrupt */ | ||
1046 | static void msm_hs_enable_ms_locked(struct uart_port *uport) | ||
1047 | { | ||
1048 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1049 | |||
1050 | clk_enable(msm_uport->clk); | ||
1051 | |||
1052 | /* Enable DELTA_CTS Interrupt */ | ||
1053 | msm_uport->imr_reg |= UARTDM_ISR_DELTA_CTS_BMSK; | ||
1054 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
1055 | |||
1056 | clk_disable(msm_uport->clk); | ||
1057 | |||
1058 | } | ||
1059 | |||
1060 | /* | ||
1061 | * Standard API, Break Signal | ||
1062 | * | ||
1063 | * Control the transmission of a break signal. ctl eq 0 => break | ||
1064 | * signal terminate ctl ne 0 => start break signal | ||
1065 | */ | ||
1066 | static void msm_hs_break_ctl(struct uart_port *uport, int ctl) | ||
1067 | { | ||
1068 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1069 | |||
1070 | clk_enable(msm_uport->clk); | ||
1071 | msm_hs_write(uport, UARTDM_CR_ADDR, ctl ? START_BREAK : STOP_BREAK); | ||
1072 | clk_disable(msm_uport->clk); | ||
1073 | } | ||
1074 | |||
1075 | static void msm_hs_config_port(struct uart_port *uport, int cfg_flags) | ||
1076 | { | ||
1077 | unsigned long flags; | ||
1078 | |||
1079 | spin_lock_irqsave(&uport->lock, flags); | ||
1080 | if (cfg_flags & UART_CONFIG_TYPE) { | ||
1081 | uport->type = PORT_MSM; | ||
1082 | msm_hs_request_port(uport); | ||
1083 | } | ||
1084 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1085 | } | ||
1086 | |||
1087 | /* Handle CTS changes (Called from interrupt handler) */ | ||
1088 | static void msm_hs_handle_delta_cts(struct uart_port *uport) | ||
1089 | { | ||
1090 | unsigned long flags; | ||
1091 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1092 | |||
1093 | spin_lock_irqsave(&uport->lock, flags); | ||
1094 | clk_enable(msm_uport->clk); | ||
1095 | |||
1096 | /* clear interrupt */ | ||
1097 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); | ||
1098 | uport->icount.cts++; | ||
1099 | |||
1100 | clk_disable(msm_uport->clk); | ||
1101 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1102 | |||
1103 | /* clear the IOCTL TIOCMIWAIT if called */ | ||
1104 | wake_up_interruptible(&uport->state->port.delta_msr_wait); | ||
1105 | } | ||
1106 | |||
1107 | /* check if the TX path is flushed, and if so clock off | ||
1108 | * returns 0 did not clock off, need to retry (still sending final byte) | ||
1109 | * -1 did not clock off, do not retry | ||
1110 | * 1 if we clocked off | ||
1111 | */ | ||
1112 | static int msm_hs_check_clock_off_locked(struct uart_port *uport) | ||
1113 | { | ||
1114 | unsigned long sr_status; | ||
1115 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1116 | struct circ_buf *tx_buf = &uport->state->xmit; | ||
1117 | |||
1118 | /* Cancel if tx tty buffer is not empty, dma is in flight, | ||
1119 | * or tx fifo is not empty, or rx fifo is not empty */ | ||
1120 | if (msm_uport->clk_state != MSM_HS_CLK_REQUEST_OFF || | ||
1121 | !uart_circ_empty(tx_buf) || msm_uport->tx.dma_in_flight || | ||
1122 | (msm_uport->imr_reg & UARTDM_ISR_TXLEV_BMSK) || | ||
1123 | !(msm_uport->imr_reg & UARTDM_ISR_RXLEV_BMSK)) { | ||
1124 | return -1; | ||
1125 | } | ||
1126 | |||
1127 | /* Make sure the uart is finished with the last byte */ | ||
1128 | sr_status = msm_hs_read(uport, UARTDM_SR_ADDR); | ||
1129 | if (!(sr_status & UARTDM_SR_TXEMT_BMSK)) | ||
1130 | return 0; /* retry */ | ||
1131 | |||
1132 | /* Make sure forced RXSTALE flush complete */ | ||
1133 | switch (msm_uport->clk_req_off_state) { | ||
1134 | case CLK_REQ_OFF_START: | ||
1135 | msm_uport->clk_req_off_state = CLK_REQ_OFF_RXSTALE_ISSUED; | ||
1136 | msm_hs_write(uport, UARTDM_CR_ADDR, FORCE_STALE_EVENT); | ||
1137 | return 0; /* RXSTALE flush not complete - retry */ | ||
1138 | case CLK_REQ_OFF_RXSTALE_ISSUED: | ||
1139 | case CLK_REQ_OFF_FLUSH_ISSUED: | ||
1140 | return 0; /* RXSTALE flush not complete - retry */ | ||
1141 | case CLK_REQ_OFF_RXSTALE_FLUSHED: | ||
1142 | break; /* continue */ | ||
1143 | } | ||
1144 | |||
1145 | if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { | ||
1146 | if (msm_uport->rx.flush == FLUSH_NONE) | ||
1147 | msm_hs_stop_rx_locked(uport); | ||
1148 | return 0; /* come back later to really clock off */ | ||
1149 | } | ||
1150 | |||
1151 | /* we really want to clock off */ | ||
1152 | clk_disable(msm_uport->clk); | ||
1153 | msm_uport->clk_state = MSM_HS_CLK_OFF; | ||
1154 | |||
1155 | if (use_low_power_rx_wakeup(msm_uport)) { | ||
1156 | msm_uport->rx_wakeup.ignore = 1; | ||
1157 | enable_irq(msm_uport->rx_wakeup.irq); | ||
1158 | } | ||
1159 | return 1; | ||
1160 | } | ||
1161 | |||
1162 | static enum hrtimer_restart msm_hs_clk_off_retry(struct hrtimer *timer) | ||
1163 | { | ||
1164 | unsigned long flags; | ||
1165 | int ret = HRTIMER_NORESTART; | ||
1166 | struct msm_hs_port *msm_uport = container_of(timer, struct msm_hs_port, | ||
1167 | clk_off_timer); | ||
1168 | struct uart_port *uport = &msm_uport->uport; | ||
1169 | |||
1170 | spin_lock_irqsave(&uport->lock, flags); | ||
1171 | |||
1172 | if (!msm_hs_check_clock_off_locked(uport)) { | ||
1173 | hrtimer_forward_now(timer, msm_uport->clk_off_delay); | ||
1174 | ret = HRTIMER_RESTART; | ||
1175 | } | ||
1176 | |||
1177 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1178 | |||
1179 | return ret; | ||
1180 | } | ||
1181 | |||
1182 | static irqreturn_t msm_hs_isr(int irq, void *dev) | ||
1183 | { | ||
1184 | unsigned long flags; | ||
1185 | unsigned long isr_status; | ||
1186 | struct msm_hs_port *msm_uport = dev; | ||
1187 | struct uart_port *uport = &msm_uport->uport; | ||
1188 | struct circ_buf *tx_buf = &uport->state->xmit; | ||
1189 | struct msm_hs_tx *tx = &msm_uport->tx; | ||
1190 | struct msm_hs_rx *rx = &msm_uport->rx; | ||
1191 | |||
1192 | spin_lock_irqsave(&uport->lock, flags); | ||
1193 | |||
1194 | isr_status = msm_hs_read(uport, UARTDM_MISR_ADDR); | ||
1195 | |||
1196 | /* Uart RX starting */ | ||
1197 | if (isr_status & UARTDM_ISR_RXLEV_BMSK) { | ||
1198 | msm_uport->imr_reg &= ~UARTDM_ISR_RXLEV_BMSK; | ||
1199 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
1200 | } | ||
1201 | /* Stale rx interrupt */ | ||
1202 | if (isr_status & UARTDM_ISR_RXSTALE_BMSK) { | ||
1203 | msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE); | ||
1204 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); | ||
1205 | |||
1206 | if (msm_uport->clk_req_off_state == CLK_REQ_OFF_RXSTALE_ISSUED) | ||
1207 | msm_uport->clk_req_off_state = | ||
1208 | CLK_REQ_OFF_FLUSH_ISSUED; | ||
1209 | if (rx->flush == FLUSH_NONE) { | ||
1210 | rx->flush = FLUSH_DATA_READY; | ||
1211 | msm_dmov_stop_cmd(msm_uport->dma_rx_channel, NULL, 1); | ||
1212 | } | ||
1213 | } | ||
1214 | /* tx ready interrupt */ | ||
1215 | if (isr_status & UARTDM_ISR_TX_READY_BMSK) { | ||
1216 | /* Clear TX Ready */ | ||
1217 | msm_hs_write(uport, UARTDM_CR_ADDR, CLEAR_TX_READY); | ||
1218 | |||
1219 | if (msm_uport->clk_state == MSM_HS_CLK_REQUEST_OFF) { | ||
1220 | msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; | ||
1221 | msm_hs_write(uport, UARTDM_IMR_ADDR, | ||
1222 | msm_uport->imr_reg); | ||
1223 | } | ||
1224 | |||
1225 | /* Complete DMA TX transactions and submit new transactions */ | ||
1226 | tx_buf->tail = (tx_buf->tail + tx->tx_count) & ~UART_XMIT_SIZE; | ||
1227 | |||
1228 | tx->dma_in_flight = 0; | ||
1229 | |||
1230 | uport->icount.tx += tx->tx_count; | ||
1231 | if (tx->tx_ready_int_en) | ||
1232 | msm_hs_submit_tx_locked(uport); | ||
1233 | |||
1234 | if (uart_circ_chars_pending(tx_buf) < WAKEUP_CHARS) | ||
1235 | uart_write_wakeup(uport); | ||
1236 | } | ||
1237 | if (isr_status & UARTDM_ISR_TXLEV_BMSK) { | ||
1238 | /* TX FIFO is empty */ | ||
1239 | msm_uport->imr_reg &= ~UARTDM_ISR_TXLEV_BMSK; | ||
1240 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
1241 | if (!msm_hs_check_clock_off_locked(uport)) | ||
1242 | hrtimer_start(&msm_uport->clk_off_timer, | ||
1243 | msm_uport->clk_off_delay, | ||
1244 | HRTIMER_MODE_REL); | ||
1245 | } | ||
1246 | |||
1247 | /* Change in CTS interrupt */ | ||
1248 | if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK) | ||
1249 | msm_hs_handle_delta_cts(uport); | ||
1250 | |||
1251 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1252 | |||
1253 | return IRQ_HANDLED; | ||
1254 | } | ||
1255 | |||
1256 | void msm_hs_request_clock_off_locked(struct uart_port *uport) | ||
1257 | { | ||
1258 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1259 | |||
1260 | if (msm_uport->clk_state == MSM_HS_CLK_ON) { | ||
1261 | msm_uport->clk_state = MSM_HS_CLK_REQUEST_OFF; | ||
1262 | msm_uport->clk_req_off_state = CLK_REQ_OFF_START; | ||
1263 | if (!use_low_power_rx_wakeup(msm_uport)) | ||
1264 | set_rfr_locked(uport, 0); | ||
1265 | msm_uport->imr_reg |= UARTDM_ISR_TXLEV_BMSK; | ||
1266 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
1267 | } | ||
1268 | } | ||
1269 | |||
1270 | /** | ||
1271 | * msm_hs_request_clock_off - request to (i.e. asynchronously) turn off uart | ||
1272 | * clock once pending TX is flushed and Rx DMA command is terminated. | ||
1273 | * @uport: uart_port structure for the device instance. | ||
1274 | * | ||
1275 | * This functions puts the device into a partially active low power mode. It | ||
1276 | * waits to complete all pending tx transactions, flushes ongoing Rx DMA | ||
1277 | * command and terminates UART side Rx transaction, puts UART HW in non DMA | ||
1278 | * mode and then clocks off the device. A client calls this when no UART | ||
1279 | * data is expected. msm_request_clock_on() must be called before any further | ||
1280 | * UART can be sent or received. | ||
1281 | */ | ||
1282 | void msm_hs_request_clock_off(struct uart_port *uport) | ||
1283 | { | ||
1284 | unsigned long flags; | ||
1285 | |||
1286 | spin_lock_irqsave(&uport->lock, flags); | ||
1287 | msm_hs_request_clock_off_locked(uport); | ||
1288 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1289 | } | ||
1290 | |||
1291 | void msm_hs_request_clock_on_locked(struct uart_port *uport) | ||
1292 | { | ||
1293 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1294 | unsigned int data; | ||
1295 | |||
1296 | switch (msm_uport->clk_state) { | ||
1297 | case MSM_HS_CLK_OFF: | ||
1298 | clk_enable(msm_uport->clk); | ||
1299 | disable_irq_nosync(msm_uport->rx_wakeup.irq); | ||
1300 | /* fall-through */ | ||
1301 | case MSM_HS_CLK_REQUEST_OFF: | ||
1302 | if (msm_uport->rx.flush == FLUSH_STOP || | ||
1303 | msm_uport->rx.flush == FLUSH_SHUTDOWN) { | ||
1304 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); | ||
1305 | data = msm_hs_read(uport, UARTDM_DMEN_ADDR); | ||
1306 | data |= UARTDM_RX_DM_EN_BMSK; | ||
1307 | msm_hs_write(uport, UARTDM_DMEN_ADDR, data); | ||
1308 | } | ||
1309 | hrtimer_try_to_cancel(&msm_uport->clk_off_timer); | ||
1310 | if (msm_uport->rx.flush == FLUSH_SHUTDOWN) | ||
1311 | msm_hs_start_rx_locked(uport); | ||
1312 | if (!use_low_power_rx_wakeup(msm_uport)) | ||
1313 | set_rfr_locked(uport, 1); | ||
1314 | if (msm_uport->rx.flush == FLUSH_STOP) | ||
1315 | msm_uport->rx.flush = FLUSH_IGNORE; | ||
1316 | msm_uport->clk_state = MSM_HS_CLK_ON; | ||
1317 | break; | ||
1318 | case MSM_HS_CLK_ON: | ||
1319 | break; | ||
1320 | case MSM_HS_CLK_PORT_OFF: | ||
1321 | break; | ||
1322 | } | ||
1323 | } | ||
1324 | |||
1325 | /** | ||
1326 | * msm_hs_request_clock_on - Switch the device from partially active low | ||
1327 | * power mode to fully active (i.e. clock on) mode. | ||
1328 | * @uport: uart_port structure for the device. | ||
1329 | * | ||
1330 | * This function switches on the input clock, puts UART HW into DMA mode | ||
1331 | * and enqueues an Rx DMA command if the device was in partially active | ||
1332 | * mode. It has no effect if called with the device in inactive state. | ||
1333 | */ | ||
1334 | void msm_hs_request_clock_on(struct uart_port *uport) | ||
1335 | { | ||
1336 | unsigned long flags; | ||
1337 | |||
1338 | spin_lock_irqsave(&uport->lock, flags); | ||
1339 | msm_hs_request_clock_on_locked(uport); | ||
1340 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1341 | } | ||
1342 | |||
1343 | static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) | ||
1344 | { | ||
1345 | unsigned int wakeup = 0; | ||
1346 | unsigned long flags; | ||
1347 | struct msm_hs_port *msm_uport = dev; | ||
1348 | struct uart_port *uport = &msm_uport->uport; | ||
1349 | struct tty_struct *tty = NULL; | ||
1350 | |||
1351 | spin_lock_irqsave(&uport->lock, flags); | ||
1352 | if (msm_uport->clk_state == MSM_HS_CLK_OFF) { | ||
1353 | /* ignore the first irq - it is a pending irq that occured | ||
1354 | * before enable_irq() */ | ||
1355 | if (msm_uport->rx_wakeup.ignore) | ||
1356 | msm_uport->rx_wakeup.ignore = 0; | ||
1357 | else | ||
1358 | wakeup = 1; | ||
1359 | } | ||
1360 | |||
1361 | if (wakeup) { | ||
1362 | /* the uart was clocked off during an rx, wake up and | ||
1363 | * optionally inject char into tty rx */ | ||
1364 | msm_hs_request_clock_on_locked(uport); | ||
1365 | if (msm_uport->rx_wakeup.inject_rx) { | ||
1366 | tty = uport->state->port.tty; | ||
1367 | tty_insert_flip_char(tty, | ||
1368 | msm_uport->rx_wakeup.rx_to_inject, | ||
1369 | TTY_NORMAL); | ||
1370 | queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work); | ||
1371 | } | ||
1372 | } | ||
1373 | |||
1374 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1375 | |||
1376 | return IRQ_HANDLED; | ||
1377 | } | ||
1378 | |||
1379 | static const char *msm_hs_type(struct uart_port *port) | ||
1380 | { | ||
1381 | return (port->type == PORT_MSM) ? "MSM_HS_UART" : NULL; | ||
1382 | } | ||
1383 | |||
1384 | /* Called when port is opened */ | ||
1385 | static int msm_hs_startup(struct uart_port *uport) | ||
1386 | { | ||
1387 | int ret; | ||
1388 | int rfr_level; | ||
1389 | unsigned long flags; | ||
1390 | unsigned int data; | ||
1391 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1392 | struct circ_buf *tx_buf = &uport->state->xmit; | ||
1393 | struct msm_hs_tx *tx = &msm_uport->tx; | ||
1394 | struct msm_hs_rx *rx = &msm_uport->rx; | ||
1395 | |||
1396 | rfr_level = uport->fifosize; | ||
1397 | if (rfr_level > 16) | ||
1398 | rfr_level -= 16; | ||
1399 | |||
1400 | tx->dma_base = dma_map_single(uport->dev, tx_buf->buf, UART_XMIT_SIZE, | ||
1401 | DMA_TO_DEVICE); | ||
1402 | |||
1403 | /* do not let tty layer execute RX in global workqueue, use a | ||
1404 | * dedicated workqueue managed by this driver */ | ||
1405 | uport->state->port.tty->low_latency = 1; | ||
1406 | |||
1407 | /* turn on uart clk */ | ||
1408 | ret = msm_hs_init_clk_locked(uport); | ||
1409 | if (unlikely(ret)) { | ||
1410 | printk(KERN_ERR "Turning uartclk failed!\n"); | ||
1411 | goto err_msm_hs_init_clk; | ||
1412 | } | ||
1413 | |||
1414 | /* Set auto RFR Level */ | ||
1415 | data = msm_hs_read(uport, UARTDM_MR1_ADDR); | ||
1416 | data &= ~UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK; | ||
1417 | data &= ~UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK; | ||
1418 | data |= (UARTDM_MR1_AUTO_RFR_LEVEL1_BMSK & (rfr_level << 2)); | ||
1419 | data |= (UARTDM_MR1_AUTO_RFR_LEVEL0_BMSK & rfr_level); | ||
1420 | msm_hs_write(uport, UARTDM_MR1_ADDR, data); | ||
1421 | |||
1422 | /* Make sure RXSTALE count is non-zero */ | ||
1423 | data = msm_hs_read(uport, UARTDM_IPR_ADDR); | ||
1424 | if (!data) { | ||
1425 | data |= 0x1f & UARTDM_IPR_STALE_LSB_BMSK; | ||
1426 | msm_hs_write(uport, UARTDM_IPR_ADDR, data); | ||
1427 | } | ||
1428 | |||
1429 | /* Enable Data Mover Mode */ | ||
1430 | data = UARTDM_TX_DM_EN_BMSK | UARTDM_RX_DM_EN_BMSK; | ||
1431 | msm_hs_write(uport, UARTDM_DMEN_ADDR, data); | ||
1432 | |||
1433 | /* Reset TX */ | ||
1434 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX); | ||
1435 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_RX); | ||
1436 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_ERROR_STATUS); | ||
1437 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_BREAK_INT); | ||
1438 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_STALE_INT); | ||
1439 | msm_hs_write(uport, UARTDM_CR_ADDR, RESET_CTS); | ||
1440 | msm_hs_write(uport, UARTDM_CR_ADDR, RFR_LOW); | ||
1441 | /* Turn on Uart Receiver */ | ||
1442 | msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_EN_BMSK); | ||
1443 | |||
1444 | /* Turn on Uart Transmitter */ | ||
1445 | msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_EN_BMSK); | ||
1446 | |||
1447 | /* Initialize the tx */ | ||
1448 | tx->tx_ready_int_en = 0; | ||
1449 | tx->dma_in_flight = 0; | ||
1450 | |||
1451 | tx->xfer.complete_func = msm_hs_dmov_tx_callback; | ||
1452 | tx->xfer.execute_func = NULL; | ||
1453 | |||
1454 | tx->command_ptr->cmd = CMD_LC | | ||
1455 | CMD_DST_CRCI(msm_uport->dma_tx_crci) | CMD_MODE_BOX; | ||
1456 | |||
1457 | tx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) | ||
1458 | | (MSM_UARTDM_BURST_SIZE); | ||
1459 | |||
1460 | tx->command_ptr->row_offset = (MSM_UARTDM_BURST_SIZE << 16); | ||
1461 | |||
1462 | tx->command_ptr->dst_row_addr = | ||
1463 | msm_uport->uport.mapbase + UARTDM_TF_ADDR; | ||
1464 | |||
1465 | |||
1466 | /* Turn on Uart Receive */ | ||
1467 | rx->xfer.complete_func = msm_hs_dmov_rx_callback; | ||
1468 | rx->xfer.execute_func = NULL; | ||
1469 | |||
1470 | rx->command_ptr->cmd = CMD_LC | | ||
1471 | CMD_SRC_CRCI(msm_uport->dma_rx_crci) | CMD_MODE_BOX; | ||
1472 | |||
1473 | rx->command_ptr->src_dst_len = (MSM_UARTDM_BURST_SIZE << 16) | ||
1474 | | (MSM_UARTDM_BURST_SIZE); | ||
1475 | rx->command_ptr->row_offset = MSM_UARTDM_BURST_SIZE; | ||
1476 | rx->command_ptr->src_row_addr = uport->mapbase + UARTDM_RF_ADDR; | ||
1477 | |||
1478 | |||
1479 | msm_uport->imr_reg |= UARTDM_ISR_RXSTALE_BMSK; | ||
1480 | /* Enable reading the current CTS, no harm even if CTS is ignored */ | ||
1481 | msm_uport->imr_reg |= UARTDM_ISR_CURRENT_CTS_BMSK; | ||
1482 | |||
1483 | msm_hs_write(uport, UARTDM_TFWR_ADDR, 0); /* TXLEV on empty TX fifo */ | ||
1484 | |||
1485 | |||
1486 | ret = request_irq(uport->irq, msm_hs_isr, IRQF_TRIGGER_HIGH, | ||
1487 | "msm_hs_uart", msm_uport); | ||
1488 | if (unlikely(ret)) { | ||
1489 | printk(KERN_ERR "Request msm_hs_uart IRQ failed!\n"); | ||
1490 | goto err_request_irq; | ||
1491 | } | ||
1492 | if (use_low_power_rx_wakeup(msm_uport)) { | ||
1493 | ret = request_irq(msm_uport->rx_wakeup.irq, | ||
1494 | msm_hs_rx_wakeup_isr, | ||
1495 | IRQF_TRIGGER_FALLING, | ||
1496 | "msm_hs_rx_wakeup", msm_uport); | ||
1497 | if (unlikely(ret)) { | ||
1498 | printk(KERN_ERR "Request msm_hs_rx_wakeup IRQ failed!\n"); | ||
1499 | free_irq(uport->irq, msm_uport); | ||
1500 | goto err_request_irq; | ||
1501 | } | ||
1502 | disable_irq(msm_uport->rx_wakeup.irq); | ||
1503 | } | ||
1504 | |||
1505 | spin_lock_irqsave(&uport->lock, flags); | ||
1506 | |||
1507 | msm_hs_write(uport, UARTDM_RFWR_ADDR, 0); | ||
1508 | msm_hs_start_rx_locked(uport); | ||
1509 | |||
1510 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1511 | ret = pm_runtime_set_active(uport->dev); | ||
1512 | if (ret) | ||
1513 | dev_err(uport->dev, "set active error:%d\n", ret); | ||
1514 | pm_runtime_enable(uport->dev); | ||
1515 | |||
1516 | return 0; | ||
1517 | |||
1518 | err_request_irq: | ||
1519 | err_msm_hs_init_clk: | ||
1520 | dma_unmap_single(uport->dev, tx->dma_base, | ||
1521 | UART_XMIT_SIZE, DMA_TO_DEVICE); | ||
1522 | return ret; | ||
1523 | } | ||
1524 | |||
1525 | /* Initialize tx and rx data structures */ | ||
1526 | static int __devinit uartdm_init_port(struct uart_port *uport) | ||
1527 | { | ||
1528 | int ret = 0; | ||
1529 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1530 | struct msm_hs_tx *tx = &msm_uport->tx; | ||
1531 | struct msm_hs_rx *rx = &msm_uport->rx; | ||
1532 | |||
1533 | /* Allocate the command pointer. Needs to be 64 bit aligned */ | ||
1534 | tx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); | ||
1535 | if (!tx->command_ptr) | ||
1536 | return -ENOMEM; | ||
1537 | |||
1538 | tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA); | ||
1539 | if (!tx->command_ptr_ptr) { | ||
1540 | ret = -ENOMEM; | ||
1541 | goto err_tx_command_ptr_ptr; | ||
1542 | } | ||
1543 | |||
1544 | tx->mapped_cmd_ptr = dma_map_single(uport->dev, tx->command_ptr, | ||
1545 | sizeof(dmov_box), DMA_TO_DEVICE); | ||
1546 | tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev, | ||
1547 | tx->command_ptr_ptr, | ||
1548 | sizeof(u32 *), DMA_TO_DEVICE); | ||
1549 | tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr); | ||
1550 | |||
1551 | init_waitqueue_head(&rx->wait); | ||
1552 | |||
1553 | rx->pool = dma_pool_create("rx_buffer_pool", uport->dev, | ||
1554 | UARTDM_RX_BUF_SIZE, 16, 0); | ||
1555 | if (!rx->pool) { | ||
1556 | pr_err("%s(): cannot allocate rx_buffer_pool", __func__); | ||
1557 | ret = -ENOMEM; | ||
1558 | goto err_dma_pool_create; | ||
1559 | } | ||
1560 | |||
1561 | rx->buffer = dma_pool_alloc(rx->pool, GFP_KERNEL, &rx->rbuffer); | ||
1562 | if (!rx->buffer) { | ||
1563 | pr_err("%s(): cannot allocate rx->buffer", __func__); | ||
1564 | ret = -ENOMEM; | ||
1565 | goto err_dma_pool_alloc; | ||
1566 | } | ||
1567 | |||
1568 | /* Allocate the command pointer. Needs to be 64 bit aligned */ | ||
1569 | rx->command_ptr = kmalloc(sizeof(dmov_box), GFP_KERNEL | __GFP_DMA); | ||
1570 | if (!rx->command_ptr) { | ||
1571 | pr_err("%s(): cannot allocate rx->command_ptr", __func__); | ||
1572 | ret = -ENOMEM; | ||
1573 | goto err_rx_command_ptr; | ||
1574 | } | ||
1575 | |||
1576 | rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA); | ||
1577 | if (!rx->command_ptr_ptr) { | ||
1578 | pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__); | ||
1579 | ret = -ENOMEM; | ||
1580 | goto err_rx_command_ptr_ptr; | ||
1581 | } | ||
1582 | |||
1583 | rx->command_ptr->num_rows = ((UARTDM_RX_BUF_SIZE >> 4) << 16) | | ||
1584 | (UARTDM_RX_BUF_SIZE >> 4); | ||
1585 | |||
1586 | rx->command_ptr->dst_row_addr = rx->rbuffer; | ||
1587 | |||
1588 | rx->mapped_cmd_ptr = dma_map_single(uport->dev, rx->command_ptr, | ||
1589 | sizeof(dmov_box), DMA_TO_DEVICE); | ||
1590 | |||
1591 | *rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr); | ||
1592 | |||
1593 | rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr, | ||
1594 | sizeof(u32 *), DMA_TO_DEVICE); | ||
1595 | rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr); | ||
1596 | |||
1597 | INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work); | ||
1598 | |||
1599 | return ret; | ||
1600 | |||
1601 | err_rx_command_ptr_ptr: | ||
1602 | kfree(rx->command_ptr); | ||
1603 | err_rx_command_ptr: | ||
1604 | dma_pool_free(msm_uport->rx.pool, msm_uport->rx.buffer, | ||
1605 | msm_uport->rx.rbuffer); | ||
1606 | err_dma_pool_alloc: | ||
1607 | dma_pool_destroy(msm_uport->rx.pool); | ||
1608 | err_dma_pool_create: | ||
1609 | dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr, | ||
1610 | sizeof(u32 *), DMA_TO_DEVICE); | ||
1611 | dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr, | ||
1612 | sizeof(dmov_box), DMA_TO_DEVICE); | ||
1613 | kfree(msm_uport->tx.command_ptr_ptr); | ||
1614 | err_tx_command_ptr_ptr: | ||
1615 | kfree(msm_uport->tx.command_ptr); | ||
1616 | return ret; | ||
1617 | } | ||
1618 | |||
1619 | static int __devinit msm_hs_probe(struct platform_device *pdev) | ||
1620 | { | ||
1621 | int ret; | ||
1622 | struct uart_port *uport; | ||
1623 | struct msm_hs_port *msm_uport; | ||
1624 | struct resource *resource; | ||
1625 | const struct msm_serial_hs_platform_data *pdata = | ||
1626 | pdev->dev.platform_data; | ||
1627 | |||
1628 | if (pdev->id < 0 || pdev->id >= UARTDM_NR) { | ||
1629 | printk(KERN_ERR "Invalid plaform device ID = %d\n", pdev->id); | ||
1630 | return -EINVAL; | ||
1631 | } | ||
1632 | |||
1633 | msm_uport = &q_uart_port[pdev->id]; | ||
1634 | uport = &msm_uport->uport; | ||
1635 | |||
1636 | uport->dev = &pdev->dev; | ||
1637 | |||
1638 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1639 | if (unlikely(!resource)) | ||
1640 | return -ENXIO; | ||
1641 | |||
1642 | uport->mapbase = resource->start; | ||
1643 | uport->irq = platform_get_irq(pdev, 0); | ||
1644 | if (unlikely(uport->irq < 0)) | ||
1645 | return -ENXIO; | ||
1646 | |||
1647 | if (unlikely(set_irq_wake(uport->irq, 1))) | ||
1648 | return -ENXIO; | ||
1649 | |||
1650 | if (pdata == NULL || pdata->rx_wakeup_irq < 0) | ||
1651 | msm_uport->rx_wakeup.irq = -1; | ||
1652 | else { | ||
1653 | msm_uport->rx_wakeup.irq = pdata->rx_wakeup_irq; | ||
1654 | msm_uport->rx_wakeup.ignore = 1; | ||
1655 | msm_uport->rx_wakeup.inject_rx = pdata->inject_rx_on_wakeup; | ||
1656 | msm_uport->rx_wakeup.rx_to_inject = pdata->rx_to_inject; | ||
1657 | |||
1658 | if (unlikely(msm_uport->rx_wakeup.irq < 0)) | ||
1659 | return -ENXIO; | ||
1660 | |||
1661 | if (unlikely(set_irq_wake(msm_uport->rx_wakeup.irq, 1))) | ||
1662 | return -ENXIO; | ||
1663 | } | ||
1664 | |||
1665 | if (pdata == NULL) | ||
1666 | msm_uport->exit_lpm_cb = NULL; | ||
1667 | else | ||
1668 | msm_uport->exit_lpm_cb = pdata->exit_lpm_cb; | ||
1669 | |||
1670 | resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, | ||
1671 | "uartdm_channels"); | ||
1672 | if (unlikely(!resource)) | ||
1673 | return -ENXIO; | ||
1674 | |||
1675 | msm_uport->dma_tx_channel = resource->start; | ||
1676 | msm_uport->dma_rx_channel = resource->end; | ||
1677 | |||
1678 | resource = platform_get_resource_byname(pdev, IORESOURCE_DMA, | ||
1679 | "uartdm_crci"); | ||
1680 | if (unlikely(!resource)) | ||
1681 | return -ENXIO; | ||
1682 | |||
1683 | msm_uport->dma_tx_crci = resource->start; | ||
1684 | msm_uport->dma_rx_crci = resource->end; | ||
1685 | |||
1686 | uport->iotype = UPIO_MEM; | ||
1687 | uport->fifosize = UART_FIFOSIZE; | ||
1688 | uport->ops = &msm_hs_ops; | ||
1689 | uport->flags = UPF_BOOT_AUTOCONF; | ||
1690 | uport->uartclk = UARTCLK; | ||
1691 | msm_uport->imr_reg = 0x0; | ||
1692 | msm_uport->clk = clk_get(&pdev->dev, "uartdm_clk"); | ||
1693 | if (IS_ERR(msm_uport->clk)) | ||
1694 | return PTR_ERR(msm_uport->clk); | ||
1695 | |||
1696 | ret = uartdm_init_port(uport); | ||
1697 | if (unlikely(ret)) | ||
1698 | return ret; | ||
1699 | |||
1700 | msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; | ||
1701 | hrtimer_init(&msm_uport->clk_off_timer, CLOCK_MONOTONIC, | ||
1702 | HRTIMER_MODE_REL); | ||
1703 | msm_uport->clk_off_timer.function = msm_hs_clk_off_retry; | ||
1704 | msm_uport->clk_off_delay = ktime_set(0, 1000000); /* 1ms */ | ||
1705 | |||
1706 | uport->line = pdev->id; | ||
1707 | return uart_add_one_port(&msm_hs_driver, uport); | ||
1708 | } | ||
1709 | |||
1710 | static int __init msm_serial_hs_init(void) | ||
1711 | { | ||
1712 | int ret, i; | ||
1713 | |||
1714 | /* Init all UARTS as non-configured */ | ||
1715 | for (i = 0; i < UARTDM_NR; i++) | ||
1716 | q_uart_port[i].uport.type = PORT_UNKNOWN; | ||
1717 | |||
1718 | msm_hs_workqueue = create_singlethread_workqueue("msm_serial_hs"); | ||
1719 | if (unlikely(!msm_hs_workqueue)) | ||
1720 | return -ENOMEM; | ||
1721 | |||
1722 | ret = uart_register_driver(&msm_hs_driver); | ||
1723 | if (unlikely(ret)) { | ||
1724 | printk(KERN_ERR "%s failed to load\n", __func__); | ||
1725 | goto err_uart_register_driver; | ||
1726 | } | ||
1727 | |||
1728 | ret = platform_driver_register(&msm_serial_hs_platform_driver); | ||
1729 | if (ret) { | ||
1730 | printk(KERN_ERR "%s failed to load\n", __func__); | ||
1731 | goto err_platform_driver_register; | ||
1732 | } | ||
1733 | |||
1734 | return ret; | ||
1735 | |||
1736 | err_platform_driver_register: | ||
1737 | uart_unregister_driver(&msm_hs_driver); | ||
1738 | err_uart_register_driver: | ||
1739 | destroy_workqueue(msm_hs_workqueue); | ||
1740 | return ret; | ||
1741 | } | ||
1742 | module_init(msm_serial_hs_init); | ||
1743 | |||
1744 | /* | ||
1745 | * Called by the upper layer when port is closed. | ||
1746 | * - Disables the port | ||
1747 | * - Unhook the ISR | ||
1748 | */ | ||
1749 | static void msm_hs_shutdown(struct uart_port *uport) | ||
1750 | { | ||
1751 | unsigned long flags; | ||
1752 | struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport); | ||
1753 | |||
1754 | BUG_ON(msm_uport->rx.flush < FLUSH_STOP); | ||
1755 | |||
1756 | spin_lock_irqsave(&uport->lock, flags); | ||
1757 | clk_enable(msm_uport->clk); | ||
1758 | |||
1759 | /* Disable the transmitter */ | ||
1760 | msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK); | ||
1761 | /* Disable the receiver */ | ||
1762 | msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_RX_DISABLE_BMSK); | ||
1763 | |||
1764 | pm_runtime_disable(uport->dev); | ||
1765 | pm_runtime_set_suspended(uport->dev); | ||
1766 | |||
1767 | /* Free the interrupt */ | ||
1768 | free_irq(uport->irq, msm_uport); | ||
1769 | if (use_low_power_rx_wakeup(msm_uport)) | ||
1770 | free_irq(msm_uport->rx_wakeup.irq, msm_uport); | ||
1771 | |||
1772 | msm_uport->imr_reg = 0; | ||
1773 | msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg); | ||
1774 | |||
1775 | wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN); | ||
1776 | |||
1777 | clk_disable(msm_uport->clk); /* to balance local clk_enable() */ | ||
1778 | if (msm_uport->clk_state != MSM_HS_CLK_OFF) | ||
1779 | clk_disable(msm_uport->clk); /* to balance clk_state */ | ||
1780 | msm_uport->clk_state = MSM_HS_CLK_PORT_OFF; | ||
1781 | |||
1782 | dma_unmap_single(uport->dev, msm_uport->tx.dma_base, | ||
1783 | UART_XMIT_SIZE, DMA_TO_DEVICE); | ||
1784 | |||
1785 | spin_unlock_irqrestore(&uport->lock, flags); | ||
1786 | |||
1787 | if (cancel_work_sync(&msm_uport->rx.tty_work)) | ||
1788 | msm_hs_tty_flip_buffer_work(&msm_uport->rx.tty_work); | ||
1789 | } | ||
1790 | |||
1791 | static void __exit msm_serial_hs_exit(void) | ||
1792 | { | ||
1793 | flush_workqueue(msm_hs_workqueue); | ||
1794 | destroy_workqueue(msm_hs_workqueue); | ||
1795 | platform_driver_unregister(&msm_serial_hs_platform_driver); | ||
1796 | uart_unregister_driver(&msm_hs_driver); | ||
1797 | } | ||
1798 | module_exit(msm_serial_hs_exit); | ||
1799 | |||
1800 | #ifdef CONFIG_PM_RUNTIME | ||
1801 | static int msm_hs_runtime_idle(struct device *dev) | ||
1802 | { | ||
1803 | /* | ||
1804 | * returning success from idle results in runtime suspend to be | ||
1805 | * called | ||
1806 | */ | ||
1807 | return 0; | ||
1808 | } | ||
1809 | |||
1810 | static int msm_hs_runtime_resume(struct device *dev) | ||
1811 | { | ||
1812 | struct platform_device *pdev = container_of(dev, struct | ||
1813 | platform_device, dev); | ||
1814 | struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; | ||
1815 | |||
1816 | msm_hs_request_clock_on(&msm_uport->uport); | ||
1817 | return 0; | ||
1818 | } | ||
1819 | |||
1820 | static int msm_hs_runtime_suspend(struct device *dev) | ||
1821 | { | ||
1822 | struct platform_device *pdev = container_of(dev, struct | ||
1823 | platform_device, dev); | ||
1824 | struct msm_hs_port *msm_uport = &q_uart_port[pdev->id]; | ||
1825 | |||
1826 | msm_hs_request_clock_off(&msm_uport->uport); | ||
1827 | return 0; | ||
1828 | } | ||
1829 | #else | ||
1830 | #define msm_hs_runtime_idle NULL | ||
1831 | #define msm_hs_runtime_resume NULL | ||
1832 | #define msm_hs_runtime_suspend NULL | ||
1833 | #endif | ||
1834 | |||
1835 | static const struct dev_pm_ops msm_hs_dev_pm_ops = { | ||
1836 | .runtime_suspend = msm_hs_runtime_suspend, | ||
1837 | .runtime_resume = msm_hs_runtime_resume, | ||
1838 | .runtime_idle = msm_hs_runtime_idle, | ||
1839 | }; | ||
1840 | |||
1841 | static struct platform_driver msm_serial_hs_platform_driver = { | ||
1842 | .probe = msm_hs_probe, | ||
1843 | .remove = __devexit_p(msm_hs_remove), | ||
1844 | .driver = { | ||
1845 | .name = "msm_serial_hs", | ||
1846 | .owner = THIS_MODULE, | ||
1847 | .pm = &msm_hs_dev_pm_ops, | ||
1848 | }, | ||
1849 | }; | ||
1850 | |||
1851 | static struct uart_driver msm_hs_driver = { | ||
1852 | .owner = THIS_MODULE, | ||
1853 | .driver_name = "msm_serial_hs", | ||
1854 | .dev_name = "ttyHS", | ||
1855 | .nr = UARTDM_NR, | ||
1856 | .cons = 0, | ||
1857 | }; | ||
1858 | |||
1859 | static struct uart_ops msm_hs_ops = { | ||
1860 | .tx_empty = msm_hs_tx_empty, | ||
1861 | .set_mctrl = msm_hs_set_mctrl_locked, | ||
1862 | .get_mctrl = msm_hs_get_mctrl_locked, | ||
1863 | .stop_tx = msm_hs_stop_tx_locked, | ||
1864 | .start_tx = msm_hs_start_tx_locked, | ||
1865 | .stop_rx = msm_hs_stop_rx_locked, | ||
1866 | .enable_ms = msm_hs_enable_ms_locked, | ||
1867 | .break_ctl = msm_hs_break_ctl, | ||
1868 | .startup = msm_hs_startup, | ||
1869 | .shutdown = msm_hs_shutdown, | ||
1870 | .set_termios = msm_hs_set_termios, | ||
1871 | .pm = msm_hs_pm, | ||
1872 | .type = msm_hs_type, | ||
1873 | .config_port = msm_hs_config_port, | ||
1874 | .release_port = msm_hs_release_port, | ||
1875 | .request_port = msm_hs_request_port, | ||
1876 | }; | ||
1877 | |||
1878 | MODULE_DESCRIPTION("High Speed UART Driver for the MSM chipset"); | ||
1879 | MODULE_VERSION("1.2"); | ||
1880 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c new file mode 100644 index 000000000000..beeff1e86093 --- /dev/null +++ b/drivers/tty/serial/msm_smd_tty.c | |||
@@ -0,0 +1,236 @@ | |||
1 | /* drivers/tty/serial/msm_smd_tty.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | ||
5 | * Author: Brian Swetland <swetland@google.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/cdev.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/wait.h> | ||
23 | |||
24 | #include <linux/tty.h> | ||
25 | #include <linux/tty_driver.h> | ||
26 | #include <linux/tty_flip.h> | ||
27 | |||
28 | #include <mach/msm_smd.h> | ||
29 | |||
30 | #define MAX_SMD_TTYS 32 | ||
31 | |||
32 | struct smd_tty_info { | ||
33 | struct tty_port port; | ||
34 | smd_channel_t *ch; | ||
35 | }; | ||
36 | |||
37 | struct smd_tty_channel_desc { | ||
38 | int id; | ||
39 | const char *name; | ||
40 | }; | ||
41 | |||
42 | static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; | ||
43 | |||
44 | static const struct smd_tty_channel_desc smd_default_tty_channels[] = { | ||
45 | { .id = 0, .name = "SMD_DS" }, | ||
46 | { .id = 27, .name = "SMD_GPSNMEA" }, | ||
47 | }; | ||
48 | |||
49 | static const struct smd_tty_channel_desc *smd_tty_channels = | ||
50 | smd_default_tty_channels; | ||
51 | static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels); | ||
52 | |||
53 | static void smd_tty_notify(void *priv, unsigned event) | ||
54 | { | ||
55 | unsigned char *ptr; | ||
56 | int avail; | ||
57 | struct smd_tty_info *info = priv; | ||
58 | struct tty_struct *tty; | ||
59 | |||
60 | if (event != SMD_EVENT_DATA) | ||
61 | return; | ||
62 | |||
63 | tty = tty_port_tty_get(&info->port); | ||
64 | if (!tty) | ||
65 | return; | ||
66 | |||
67 | for (;;) { | ||
68 | if (test_bit(TTY_THROTTLED, &tty->flags)) | ||
69 | break; | ||
70 | avail = smd_read_avail(info->ch); | ||
71 | if (avail == 0) | ||
72 | break; | ||
73 | |||
74 | avail = tty_prepare_flip_string(tty, &ptr, avail); | ||
75 | |||
76 | if (smd_read(info->ch, ptr, avail) != avail) { | ||
77 | /* shouldn't be possible since we're in interrupt | ||
78 | ** context here and nobody else could 'steal' our | ||
79 | ** characters. | ||
80 | */ | ||
81 | pr_err("OOPS - smd_tty_buffer mismatch?!"); | ||
82 | } | ||
83 | |||
84 | tty_flip_buffer_push(tty); | ||
85 | } | ||
86 | |||
87 | /* XXX only when writable and necessary */ | ||
88 | tty_wakeup(tty); | ||
89 | tty_kref_put(tty); | ||
90 | } | ||
91 | |||
92 | static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty) | ||
93 | { | ||
94 | int i, res = 0; | ||
95 | int n = tty->index; | ||
96 | const char *name = NULL; | ||
97 | struct smd_tty_info *info = smd_tty + n; | ||
98 | |||
99 | for (i = 0; i < smd_tty_channels_len; i++) { | ||
100 | if (smd_tty_channels[i].id == n) { | ||
101 | name = smd_tty_channels[i].name; | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | if (!name) | ||
106 | return -ENODEV; | ||
107 | |||
108 | if (info->ch) | ||
109 | smd_kick(info->ch); | ||
110 | else | ||
111 | res = smd_open(name, &info->ch, info, smd_tty_notify); | ||
112 | |||
113 | if (!res) | ||
114 | tty->driver_data = info; | ||
115 | |||
116 | return res; | ||
117 | } | ||
118 | |||
119 | static void smd_tty_port_shutdown(struct tty_port *tport) | ||
120 | { | ||
121 | struct smd_tty_info *info; | ||
122 | struct tty_struct *tty = tty_port_tty_get(tport); | ||
123 | |||
124 | info = tty->driver_data; | ||
125 | if (info->ch) { | ||
126 | smd_close(info->ch); | ||
127 | info->ch = 0; | ||
128 | } | ||
129 | |||
130 | tty->driver_data = 0; | ||
131 | tty_kref_put(tty); | ||
132 | } | ||
133 | |||
134 | static int smd_tty_open(struct tty_struct *tty, struct file *f) | ||
135 | { | ||
136 | struct smd_tty_info *info = smd_tty + tty->index; | ||
137 | |||
138 | return tty_port_open(&info->port, tty, f); | ||
139 | } | ||
140 | |||
141 | static void smd_tty_close(struct tty_struct *tty, struct file *f) | ||
142 | { | ||
143 | struct smd_tty_info *info = tty->driver_data; | ||
144 | |||
145 | tty_port_close(&info->port, tty, f); | ||
146 | } | ||
147 | |||
148 | static int smd_tty_write(struct tty_struct *tty, | ||
149 | const unsigned char *buf, int len) | ||
150 | { | ||
151 | struct smd_tty_info *info = tty->driver_data; | ||
152 | int avail; | ||
153 | |||
154 | /* if we're writing to a packet channel we will | ||
155 | ** never be able to write more data than there | ||
156 | ** is currently space for | ||
157 | */ | ||
158 | avail = smd_write_avail(info->ch); | ||
159 | if (len > avail) | ||
160 | len = avail; | ||
161 | |||
162 | return smd_write(info->ch, buf, len); | ||
163 | } | ||
164 | |||
165 | static int smd_tty_write_room(struct tty_struct *tty) | ||
166 | { | ||
167 | struct smd_tty_info *info = tty->driver_data; | ||
168 | return smd_write_avail(info->ch); | ||
169 | } | ||
170 | |||
171 | static int smd_tty_chars_in_buffer(struct tty_struct *tty) | ||
172 | { | ||
173 | struct smd_tty_info *info = tty->driver_data; | ||
174 | return smd_read_avail(info->ch); | ||
175 | } | ||
176 | |||
177 | static void smd_tty_unthrottle(struct tty_struct *tty) | ||
178 | { | ||
179 | struct smd_tty_info *info = tty->driver_data; | ||
180 | smd_kick(info->ch); | ||
181 | } | ||
182 | |||
183 | static const struct tty_port_operations smd_tty_port_ops = { | ||
184 | .shutdown = smd_tty_port_shutdown, | ||
185 | .activate = smd_tty_port_activate, | ||
186 | }; | ||
187 | |||
188 | static const struct tty_operations smd_tty_ops = { | ||
189 | .open = smd_tty_open, | ||
190 | .close = smd_tty_close, | ||
191 | .write = smd_tty_write, | ||
192 | .write_room = smd_tty_write_room, | ||
193 | .chars_in_buffer = smd_tty_chars_in_buffer, | ||
194 | .unthrottle = smd_tty_unthrottle, | ||
195 | }; | ||
196 | |||
197 | static struct tty_driver *smd_tty_driver; | ||
198 | |||
199 | static int __init smd_tty_init(void) | ||
200 | { | ||
201 | int ret, i; | ||
202 | |||
203 | smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); | ||
204 | if (smd_tty_driver == 0) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | smd_tty_driver->owner = THIS_MODULE; | ||
208 | smd_tty_driver->driver_name = "smd_tty_driver"; | ||
209 | smd_tty_driver->name = "smd"; | ||
210 | smd_tty_driver->major = 0; | ||
211 | smd_tty_driver->minor_start = 0; | ||
212 | smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
213 | smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; | ||
214 | smd_tty_driver->init_termios = tty_std_termios; | ||
215 | smd_tty_driver->init_termios.c_iflag = 0; | ||
216 | smd_tty_driver->init_termios.c_oflag = 0; | ||
217 | smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; | ||
218 | smd_tty_driver->init_termios.c_lflag = 0; | ||
219 | smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | | ||
220 | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
221 | tty_set_operations(smd_tty_driver, &smd_tty_ops); | ||
222 | |||
223 | ret = tty_register_driver(smd_tty_driver); | ||
224 | if (ret) | ||
225 | return ret; | ||
226 | |||
227 | for (i = 0; i < smd_tty_channels_len; i++) { | ||
228 | tty_port_init(&smd_tty[smd_tty_channels[i].id].port); | ||
229 | smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops; | ||
230 | tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0); | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | module_init(smd_tty_init); | ||
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 5c7abe4c94dd..0e8eec516df4 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c | |||
@@ -80,14 +80,16 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | |||
80 | /* | 80 | /* |
81 | * Try to register a serial port | 81 | * Try to register a serial port |
82 | */ | 82 | */ |
83 | static int __devinit of_platform_serial_probe(struct platform_device *ofdev, | 83 | static int __devinit of_platform_serial_probe(struct platform_device *ofdev) |
84 | const struct of_device_id *id) | ||
85 | { | 84 | { |
86 | struct of_serial_info *info; | 85 | struct of_serial_info *info; |
87 | struct uart_port port; | 86 | struct uart_port port; |
88 | int port_type; | 87 | int port_type; |
89 | int ret; | 88 | int ret; |
90 | 89 | ||
90 | if (!ofdev->dev.of_match) | ||
91 | return -EINVAL; | ||
92 | |||
91 | if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) | 93 | if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) |
92 | return -EBUSY; | 94 | return -EBUSY; |
93 | 95 | ||
@@ -95,7 +97,7 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev, | |||
95 | if (info == NULL) | 97 | if (info == NULL) |
96 | return -ENOMEM; | 98 | return -ENOMEM; |
97 | 99 | ||
98 | port_type = (unsigned long)id->data; | 100 | port_type = (unsigned long)ofdev->dev.of_match->data; |
99 | ret = of_platform_serial_setup(ofdev, port_type, &port); | 101 | ret = of_platform_serial_setup(ofdev, port_type, &port); |
100 | if (ret) | 102 | if (ret) |
101 | goto out; | 103 | goto out; |
@@ -160,21 +162,21 @@ static int of_platform_serial_remove(struct platform_device *ofdev) | |||
160 | * A few common types, add more as needed. | 162 | * A few common types, add more as needed. |
161 | */ | 163 | */ |
162 | static struct of_device_id __devinitdata of_platform_serial_table[] = { | 164 | static struct of_device_id __devinitdata of_platform_serial_table[] = { |
163 | { .type = "serial", .compatible = "ns8250", .data = (void *)PORT_8250, }, | 165 | { .compatible = "ns8250", .data = (void *)PORT_8250, }, |
164 | { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, | 166 | { .compatible = "ns16450", .data = (void *)PORT_16450, }, |
165 | { .type = "serial", .compatible = "ns16550a", .data = (void *)PORT_16550A, }, | 167 | { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, |
166 | { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, | 168 | { .compatible = "ns16550", .data = (void *)PORT_16550, }, |
167 | { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, | 169 | { .compatible = "ns16750", .data = (void *)PORT_16750, }, |
168 | { .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, }, | 170 | { .compatible = "ns16850", .data = (void *)PORT_16850, }, |
169 | #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL | 171 | #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL |
170 | { .type = "serial", .compatible = "ibm,qpace-nwp-serial", | 172 | { .compatible = "ibm,qpace-nwp-serial", |
171 | .data = (void *)PORT_NWPSERIAL, }, | 173 | .data = (void *)PORT_NWPSERIAL, }, |
172 | #endif | 174 | #endif |
173 | { .type = "serial", .data = (void *)PORT_UNKNOWN, }, | 175 | { .type = "serial", .data = (void *)PORT_UNKNOWN, }, |
174 | { /* end of list */ }, | 176 | { /* end of list */ }, |
175 | }; | 177 | }; |
176 | 178 | ||
177 | static struct of_platform_driver of_platform_serial_driver = { | 179 | static struct platform_driver of_platform_serial_driver = { |
178 | .driver = { | 180 | .driver = { |
179 | .name = "of_serial", | 181 | .name = "of_serial", |
180 | .owner = THIS_MODULE, | 182 | .owner = THIS_MODULE, |
@@ -186,13 +188,13 @@ static struct of_platform_driver of_platform_serial_driver = { | |||
186 | 188 | ||
187 | static int __init of_platform_serial_init(void) | 189 | static int __init of_platform_serial_init(void) |
188 | { | 190 | { |
189 | return of_register_platform_driver(&of_platform_serial_driver); | 191 | return platform_driver_register(&of_platform_serial_driver); |
190 | } | 192 | } |
191 | module_init(of_platform_serial_init); | 193 | module_init(of_platform_serial_init); |
192 | 194 | ||
193 | static void __exit of_platform_serial_exit(void) | 195 | static void __exit of_platform_serial_exit(void) |
194 | { | 196 | { |
195 | return of_unregister_platform_driver(&of_platform_serial_driver); | 197 | return platform_driver_unregister(&of_platform_serial_driver); |
196 | }; | 198 | }; |
197 | module_exit(of_platform_serial_exit); | 199 | module_exit(of_platform_serial_exit); |
198 | 200 | ||
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 7f2f01058789..763537943a53 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c | |||
@@ -20,6 +20,10 @@ | |||
20 | * this driver as required for the omap-platform. | 20 | * this driver as required for the omap-platform. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #if defined(CONFIG_SERIAL_OMAP_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | ||
24 | #define SUPPORT_SYSRQ | ||
25 | #endif | ||
26 | |||
23 | #include <linux/module.h> | 27 | #include <linux/module.h> |
24 | #include <linux/init.h> | 28 | #include <linux/init.h> |
25 | #include <linux/console.h> | 29 | #include <linux/console.h> |
@@ -190,7 +194,6 @@ static inline void receive_chars(struct uart_omap_port *up, int *status) | |||
190 | if (up->port.line == up->port.cons->index) { | 194 | if (up->port.line == up->port.cons->index) { |
191 | /* Recover the break flag from console xmit */ | 195 | /* Recover the break flag from console xmit */ |
192 | lsr |= up->lsr_break_flag; | 196 | lsr |= up->lsr_break_flag; |
193 | up->lsr_break_flag = 0; | ||
194 | } | 197 | } |
195 | #endif | 198 | #endif |
196 | if (lsr & UART_LSR_BI) | 199 | if (lsr & UART_LSR_BI) |
@@ -517,6 +520,9 @@ static int serial_omap_startup(struct uart_port *port) | |||
517 | up->ier = UART_IER_RLSI | UART_IER_RDI; | 520 | up->ier = UART_IER_RLSI | UART_IER_RDI; |
518 | serial_out(up, UART_IER, up->ier); | 521 | serial_out(up, UART_IER, up->ier); |
519 | 522 | ||
523 | /* Enable module level wake up */ | ||
524 | serial_out(up, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); | ||
525 | |||
520 | up->port_activity = jiffies; | 526 | up->port_activity = jiffies; |
521 | return 0; | 527 | return 0; |
522 | } | 528 | } |
@@ -824,9 +830,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, | |||
824 | serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); | 830 | serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); |
825 | serial_out(up, UART_EFR, efr); | 831 | serial_out(up, UART_EFR, efr); |
826 | serial_out(up, UART_LCR, 0); | 832 | serial_out(up, UART_LCR, 0); |
827 | /* Enable module level wake up */ | ||
828 | serial_out(up, UART_OMAP_WER, | ||
829 | (state != 0) ? OMAP_UART_WER_MOD_WKUP : 0); | ||
830 | } | 833 | } |
831 | 834 | ||
832 | static void serial_omap_release_port(struct uart_port *port) | 835 | static void serial_omap_release_port(struct uart_port *port) |
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 70a61458ec42..a9ad7f33526d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/serial_core.h> | 21 | #include <linux/serial_core.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/dmi.h> | ||
24 | 25 | ||
25 | #include <linux/dmaengine.h> | 26 | #include <linux/dmaengine.h> |
26 | #include <linux/pch_dma.h> | 27 | #include <linux/pch_dma.h> |
@@ -40,10 +41,11 @@ enum { | |||
40 | 41 | ||
41 | #define PCH_UART_DRIVER_DEVICE "ttyPCH" | 42 | #define PCH_UART_DRIVER_DEVICE "ttyPCH" |
42 | 43 | ||
43 | #define PCH_UART_NR_GE_256FIFO 1 | 44 | /* Set the max number of UART port |
44 | #define PCH_UART_NR_GE_64FIFO 3 | 45 | * Intel EG20T PCH: 4 port |
45 | #define PCH_UART_NR_GE (PCH_UART_NR_GE_256FIFO+PCH_UART_NR_GE_64FIFO) | 46 | * OKI SEMICONDUCTOR ML7213 IOH: 3 port |
46 | #define PCH_UART_NR PCH_UART_NR_GE | 47 | */ |
48 | #define PCH_UART_NR 4 | ||
47 | 49 | ||
48 | #define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1)) | 50 | #define PCH_UART_HANDLED_RX_INT (1<<((PCH_UART_HANDLED_RX_INT_SHIFT)<<1)) |
49 | #define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1)) | 51 | #define PCH_UART_HANDLED_TX_INT (1<<((PCH_UART_HANDLED_TX_INT_SHIFT)<<1)) |
@@ -192,6 +194,8 @@ enum { | |||
192 | #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) | 194 | #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) |
193 | #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) | 195 | #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) |
194 | 196 | ||
197 | #define PCI_VENDOR_ID_ROHM 0x10DB | ||
198 | |||
195 | struct pch_uart_buffer { | 199 | struct pch_uart_buffer { |
196 | unsigned char *buf; | 200 | unsigned char *buf; |
197 | int size; | 201 | int size; |
@@ -215,6 +219,7 @@ struct eg20t_port { | |||
215 | struct pch_uart_buffer rxbuf; | 219 | struct pch_uart_buffer rxbuf; |
216 | unsigned int dmsr; | 220 | unsigned int dmsr; |
217 | unsigned int fcr; | 221 | unsigned int fcr; |
222 | unsigned int mcr; | ||
218 | unsigned int use_dma; | 223 | unsigned int use_dma; |
219 | unsigned int use_dma_flag; | 224 | unsigned int use_dma_flag; |
220 | struct dma_async_tx_descriptor *desc_tx; | 225 | struct dma_async_tx_descriptor *desc_tx; |
@@ -223,13 +228,44 @@ struct eg20t_port { | |||
223 | struct pch_dma_slave param_rx; | 228 | struct pch_dma_slave param_rx; |
224 | struct dma_chan *chan_tx; | 229 | struct dma_chan *chan_tx; |
225 | struct dma_chan *chan_rx; | 230 | struct dma_chan *chan_rx; |
226 | struct scatterlist sg_tx; | 231 | struct scatterlist *sg_tx_p; |
232 | int nent; | ||
227 | struct scatterlist sg_rx; | 233 | struct scatterlist sg_rx; |
228 | int tx_dma_use; | 234 | int tx_dma_use; |
229 | void *rx_buf_virt; | 235 | void *rx_buf_virt; |
230 | dma_addr_t rx_buf_dma; | 236 | dma_addr_t rx_buf_dma; |
231 | }; | 237 | }; |
232 | 238 | ||
239 | /** | ||
240 | * struct pch_uart_driver_data - private data structure for UART-DMA | ||
241 | * @port_type: The number of DMA channel | ||
242 | * @line_no: UART port line number (0, 1, 2...) | ||
243 | */ | ||
244 | struct pch_uart_driver_data { | ||
245 | int port_type; | ||
246 | int line_no; | ||
247 | }; | ||
248 | |||
249 | enum pch_uart_num_t { | ||
250 | pch_et20t_uart0 = 0, | ||
251 | pch_et20t_uart1, | ||
252 | pch_et20t_uart2, | ||
253 | pch_et20t_uart3, | ||
254 | pch_ml7213_uart0, | ||
255 | pch_ml7213_uart1, | ||
256 | pch_ml7213_uart2, | ||
257 | }; | ||
258 | |||
259 | static struct pch_uart_driver_data drv_dat[] = { | ||
260 | [pch_et20t_uart0] = {PCH_UART_8LINE, 0}, | ||
261 | [pch_et20t_uart1] = {PCH_UART_2LINE, 1}, | ||
262 | [pch_et20t_uart2] = {PCH_UART_2LINE, 2}, | ||
263 | [pch_et20t_uart3] = {PCH_UART_2LINE, 3}, | ||
264 | [pch_ml7213_uart0] = {PCH_UART_8LINE, 0}, | ||
265 | [pch_ml7213_uart1] = {PCH_UART_2LINE, 1}, | ||
266 | [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, | ||
267 | }; | ||
268 | |||
233 | static unsigned int default_baud = 9600; | 269 | static unsigned int default_baud = 9600; |
234 | static const int trigger_level_256[4] = { 1, 64, 128, 224 }; | 270 | static const int trigger_level_256[4] = { 1, 64, 128, 224 }; |
235 | static const int trigger_level_64[4] = { 1, 16, 32, 56 }; | 271 | static const int trigger_level_64[4] = { 1, 16, 32, 56 }; |
@@ -278,7 +314,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, | |||
278 | 314 | ||
279 | div = DIV_ROUND(priv->base_baud / 16, baud); | 315 | div = DIV_ROUND(priv->base_baud / 16, baud); |
280 | if (div < 0 || USHRT_MAX <= div) { | 316 | if (div < 0 || USHRT_MAX <= div) { |
281 | pr_err("Invalid Baud(div=0x%x)\n", div); | 317 | dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div); |
282 | return -EINVAL; | 318 | return -EINVAL; |
283 | } | 319 | } |
284 | 320 | ||
@@ -286,17 +322,17 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, | |||
286 | dlm = ((unsigned int)div >> 8) & 0x00FFU; | 322 | dlm = ((unsigned int)div >> 8) & 0x00FFU; |
287 | 323 | ||
288 | if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { | 324 | if (parity & ~(PCH_UART_LCR_PEN | PCH_UART_LCR_EPS | PCH_UART_LCR_SP)) { |
289 | pr_err("Invalid parity(0x%x)\n", parity); | 325 | dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity); |
290 | return -EINVAL; | 326 | return -EINVAL; |
291 | } | 327 | } |
292 | 328 | ||
293 | if (bits & ~PCH_UART_LCR_WLS) { | 329 | if (bits & ~PCH_UART_LCR_WLS) { |
294 | pr_err("Invalid bits(0x%x)\n", bits); | 330 | dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits); |
295 | return -EINVAL; | 331 | return -EINVAL; |
296 | } | 332 | } |
297 | 333 | ||
298 | if (stb & ~PCH_UART_LCR_STB) { | 334 | if (stb & ~PCH_UART_LCR_STB) { |
299 | pr_err("Invalid STB(0x%x)\n", stb); | 335 | dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb); |
300 | return -EINVAL; | 336 | return -EINVAL; |
301 | } | 337 | } |
302 | 338 | ||
@@ -304,7 +340,7 @@ static int pch_uart_hal_set_line(struct eg20t_port *priv, int baud, | |||
304 | lcr |= bits; | 340 | lcr |= bits; |
305 | lcr |= stb; | 341 | lcr |= stb; |
306 | 342 | ||
307 | pr_debug("%s:baud = %d, div = %04x, lcr = %02x (%lu)\n", | 343 | dev_dbg(priv->port.dev, "%s:baud = %d, div = %04x, lcr = %02x (%lu)\n", |
308 | __func__, baud, div, lcr, jiffies); | 344 | __func__, baud, div, lcr, jiffies); |
309 | iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); | 345 | iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR); |
310 | iowrite8(dll, priv->membase + PCH_UART_DLL); | 346 | iowrite8(dll, priv->membase + PCH_UART_DLL); |
@@ -318,7 +354,8 @@ static int pch_uart_hal_fifo_reset(struct eg20t_port *priv, | |||
318 | unsigned int flag) | 354 | unsigned int flag) |
319 | { | 355 | { |
320 | if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { | 356 | if (flag & ~(PCH_UART_FCR_TFR | PCH_UART_FCR_RFR)) { |
321 | pr_err("%s:Invalid flag(0x%x)\n", __func__, flag); | 357 | dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n", |
358 | __func__, flag); | ||
322 | return -EINVAL; | 359 | return -EINVAL; |
323 | } | 360 | } |
324 | 361 | ||
@@ -337,17 +374,20 @@ static int pch_uart_hal_set_fifo(struct eg20t_port *priv, | |||
337 | u8 fcr; | 374 | u8 fcr; |
338 | 375 | ||
339 | if (dmamode & ~PCH_UART_FCR_DMS) { | 376 | if (dmamode & ~PCH_UART_FCR_DMS) { |
340 | pr_err("%s:Invalid DMA Mode(0x%x)\n", __func__, dmamode); | 377 | dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n", |
378 | __func__, dmamode); | ||
341 | return -EINVAL; | 379 | return -EINVAL; |
342 | } | 380 | } |
343 | 381 | ||
344 | if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) { | 382 | if (fifo_size & ~(PCH_UART_FCR_FIFOE | PCH_UART_FCR_FIFO256)) { |
345 | pr_err("%s:Invalid FIFO SIZE(0x%x)\n", __func__, fifo_size); | 383 | dev_err(priv->port.dev, "%s:Invalid FIFO SIZE(0x%x)\n", |
384 | __func__, fifo_size); | ||
346 | return -EINVAL; | 385 | return -EINVAL; |
347 | } | 386 | } |
348 | 387 | ||
349 | if (trigger & ~PCH_UART_FCR_RFTL) { | 388 | if (trigger & ~PCH_UART_FCR_RFTL) { |
350 | pr_err("%s:Invalid TRIGGER(0x%x)\n", __func__, trigger); | 389 | dev_err(priv->port.dev, "%s:Invalid TRIGGER(0x%x)\n", |
390 | __func__, trigger); | ||
351 | return -EINVAL; | 391 | return -EINVAL; |
352 | } | 392 | } |
353 | 393 | ||
@@ -386,7 +426,7 @@ static u8 pch_uart_hal_get_modem(struct eg20t_port *priv) | |||
386 | return get_msr(priv, priv->membase); | 426 | return get_msr(priv, priv->membase); |
387 | } | 427 | } |
388 | 428 | ||
389 | static int pch_uart_hal_write(struct eg20t_port *priv, | 429 | static void pch_uart_hal_write(struct eg20t_port *priv, |
390 | const unsigned char *buf, int tx_size) | 430 | const unsigned char *buf, int tx_size) |
391 | { | 431 | { |
392 | int i; | 432 | int i; |
@@ -396,7 +436,6 @@ static int pch_uart_hal_write(struct eg20t_port *priv, | |||
396 | thr = buf[i++]; | 436 | thr = buf[i++]; |
397 | iowrite8(thr, priv->membase + PCH_UART_THR); | 437 | iowrite8(thr, priv->membase + PCH_UART_THR); |
398 | } | 438 | } |
399 | return i; | ||
400 | } | 439 | } |
401 | 440 | ||
402 | static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, | 441 | static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, |
@@ -452,7 +491,7 @@ static int push_rx(struct eg20t_port *priv, const unsigned char *buf, | |||
452 | port = &priv->port; | 491 | port = &priv->port; |
453 | tty = tty_port_tty_get(&port->state->port); | 492 | tty = tty_port_tty_get(&port->state->port); |
454 | if (!tty) { | 493 | if (!tty) { |
455 | pr_debug("%s:tty is busy now", __func__); | 494 | dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); |
456 | return -EBUSY; | 495 | return -EBUSY; |
457 | } | 496 | } |
458 | 497 | ||
@@ -469,8 +508,8 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) | |||
469 | struct uart_port *port = &priv->port; | 508 | struct uart_port *port = &priv->port; |
470 | 509 | ||
471 | if (port->x_char) { | 510 | if (port->x_char) { |
472 | pr_debug("%s:X character send %02x (%lu)\n", __func__, | 511 | dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n", |
473 | port->x_char, jiffies); | 512 | __func__, port->x_char, jiffies); |
474 | buf[0] = port->x_char; | 513 | buf[0] = port->x_char; |
475 | port->x_char = 0; | 514 | port->x_char = 0; |
476 | ret = 1; | 515 | ret = 1; |
@@ -490,7 +529,7 @@ static int dma_push_rx(struct eg20t_port *priv, int size) | |||
490 | port = &priv->port; | 529 | port = &priv->port; |
491 | tty = tty_port_tty_get(&port->state->port); | 530 | tty = tty_port_tty_get(&port->state->port); |
492 | if (!tty) { | 531 | if (!tty) { |
493 | pr_debug("%s:tty is busy now", __func__); | 532 | dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); |
494 | return 0; | 533 | return 0; |
495 | } | 534 | } |
496 | 535 | ||
@@ -560,11 +599,13 @@ static void pch_request_dma(struct uart_port *port) | |||
560 | /* Set Tx DMA */ | 599 | /* Set Tx DMA */ |
561 | param = &priv->param_tx; | 600 | param = &priv->param_tx; |
562 | param->dma_dev = &dma_dev->dev; | 601 | param->dma_dev = &dma_dev->dev; |
563 | param->chan_id = priv->port.line; | 602 | param->chan_id = priv->port.line * 2; /* Tx = 0, 2, 4, ... */ |
603 | |||
564 | param->tx_reg = port->mapbase + UART_TX; | 604 | param->tx_reg = port->mapbase + UART_TX; |
565 | chan = dma_request_channel(mask, filter, param); | 605 | chan = dma_request_channel(mask, filter, param); |
566 | if (!chan) { | 606 | if (!chan) { |
567 | pr_err("%s:dma_request_channel FAILS(Tx)\n", __func__); | 607 | dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n", |
608 | __func__); | ||
568 | return; | 609 | return; |
569 | } | 610 | } |
570 | priv->chan_tx = chan; | 611 | priv->chan_tx = chan; |
@@ -572,11 +613,13 @@ static void pch_request_dma(struct uart_port *port) | |||
572 | /* Set Rx DMA */ | 613 | /* Set Rx DMA */ |
573 | param = &priv->param_rx; | 614 | param = &priv->param_rx; |
574 | param->dma_dev = &dma_dev->dev; | 615 | param->dma_dev = &dma_dev->dev; |
575 | param->chan_id = priv->port.line + 1; /* Rx = Tx + 1 */ | 616 | param->chan_id = priv->port.line * 2 + 1; /* Rx = Tx + 1 */ |
617 | |||
576 | param->rx_reg = port->mapbase + UART_RX; | 618 | param->rx_reg = port->mapbase + UART_RX; |
577 | chan = dma_request_channel(mask, filter, param); | 619 | chan = dma_request_channel(mask, filter, param); |
578 | if (!chan) { | 620 | if (!chan) { |
579 | pr_err("%s:dma_request_channel FAILS(Rx)\n", __func__); | 621 | dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", |
622 | __func__); | ||
580 | dma_release_channel(priv->chan_tx); | 623 | dma_release_channel(priv->chan_tx); |
581 | return; | 624 | return; |
582 | } | 625 | } |
@@ -592,16 +635,20 @@ static void pch_dma_rx_complete(void *arg) | |||
592 | struct eg20t_port *priv = arg; | 635 | struct eg20t_port *priv = arg; |
593 | struct uart_port *port = &priv->port; | 636 | struct uart_port *port = &priv->port; |
594 | struct tty_struct *tty = tty_port_tty_get(&port->state->port); | 637 | struct tty_struct *tty = tty_port_tty_get(&port->state->port); |
638 | int count; | ||
595 | 639 | ||
596 | if (!tty) { | 640 | if (!tty) { |
597 | pr_debug("%s:tty is busy now", __func__); | 641 | dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); |
598 | return; | 642 | return; |
599 | } | 643 | } |
600 | 644 | ||
601 | if (dma_push_rx(priv, priv->trigger_level)) | 645 | dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE); |
646 | count = dma_push_rx(priv, priv->trigger_level); | ||
647 | if (count) | ||
602 | tty_flip_buffer_push(tty); | 648 | tty_flip_buffer_push(tty); |
603 | |||
604 | tty_kref_put(tty); | 649 | tty_kref_put(tty); |
650 | async_tx_ack(priv->desc_rx); | ||
651 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT); | ||
605 | } | 652 | } |
606 | 653 | ||
607 | static void pch_dma_tx_complete(void *arg) | 654 | static void pch_dma_tx_complete(void *arg) |
@@ -609,16 +656,23 @@ static void pch_dma_tx_complete(void *arg) | |||
609 | struct eg20t_port *priv = arg; | 656 | struct eg20t_port *priv = arg; |
610 | struct uart_port *port = &priv->port; | 657 | struct uart_port *port = &priv->port; |
611 | struct circ_buf *xmit = &port->state->xmit; | 658 | struct circ_buf *xmit = &port->state->xmit; |
659 | struct scatterlist *sg = priv->sg_tx_p; | ||
660 | int i; | ||
612 | 661 | ||
613 | xmit->tail += sg_dma_len(&priv->sg_tx); | 662 | for (i = 0; i < priv->nent; i++, sg++) { |
663 | xmit->tail += sg_dma_len(sg); | ||
664 | port->icount.tx += sg_dma_len(sg); | ||
665 | } | ||
614 | xmit->tail &= UART_XMIT_SIZE - 1; | 666 | xmit->tail &= UART_XMIT_SIZE - 1; |
615 | port->icount.tx += sg_dma_len(&priv->sg_tx); | ||
616 | |||
617 | async_tx_ack(priv->desc_tx); | 667 | async_tx_ack(priv->desc_tx); |
668 | dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE); | ||
618 | priv->tx_dma_use = 0; | 669 | priv->tx_dma_use = 0; |
670 | priv->nent = 0; | ||
671 | kfree(priv->sg_tx_p); | ||
672 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); | ||
619 | } | 673 | } |
620 | 674 | ||
621 | static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size) | 675 | static int pop_tx(struct eg20t_port *priv, int size) |
622 | { | 676 | { |
623 | int count = 0; | 677 | int count = 0; |
624 | struct uart_port *port = &priv->port; | 678 | struct uart_port *port = &priv->port; |
@@ -631,13 +685,13 @@ static int pop_tx(struct eg20t_port *priv, unsigned char *buf, int size) | |||
631 | int cnt_to_end = | 685 | int cnt_to_end = |
632 | CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); | 686 | CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); |
633 | int sz = min(size - count, cnt_to_end); | 687 | int sz = min(size - count, cnt_to_end); |
634 | memcpy(&buf[count], &xmit->buf[xmit->tail], sz); | 688 | pch_uart_hal_write(priv, &xmit->buf[xmit->tail], sz); |
635 | xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1); | 689 | xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1); |
636 | count += sz; | 690 | count += sz; |
637 | } while (!uart_circ_empty(xmit) && count < size); | 691 | } while (!uart_circ_empty(xmit) && count < size); |
638 | 692 | ||
639 | pop_tx_end: | 693 | pop_tx_end: |
640 | pr_debug("%d characters. Remained %d characters. (%lu)\n", | 694 | dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n", |
641 | count, size - count, jiffies); | 695 | count, size - count, jiffies); |
642 | 696 | ||
643 | return count; | 697 | return count; |
@@ -679,7 +733,7 @@ static int dma_handle_rx(struct eg20t_port *priv) | |||
679 | 733 | ||
680 | sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */ | 734 | sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */ |
681 | 735 | ||
682 | sg_dma_len(sg) = priv->fifo_size; | 736 | sg_dma_len(sg) = priv->trigger_level; |
683 | 737 | ||
684 | sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt), | 738 | sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt), |
685 | sg_dma_len(sg), (unsigned long)priv->rx_buf_virt & | 739 | sg_dma_len(sg), (unsigned long)priv->rx_buf_virt & |
@@ -689,7 +743,8 @@ static int dma_handle_rx(struct eg20t_port *priv) | |||
689 | 743 | ||
690 | desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx, | 744 | desc = priv->chan_rx->device->device_prep_slave_sg(priv->chan_rx, |
691 | sg, 1, DMA_FROM_DEVICE, | 745 | sg, 1, DMA_FROM_DEVICE, |
692 | DMA_PREP_INTERRUPT); | 746 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
747 | |||
693 | if (!desc) | 748 | if (!desc) |
694 | return 0; | 749 | return 0; |
695 | 750 | ||
@@ -706,14 +761,14 @@ static unsigned int handle_tx(struct eg20t_port *priv) | |||
706 | { | 761 | { |
707 | struct uart_port *port = &priv->port; | 762 | struct uart_port *port = &priv->port; |
708 | struct circ_buf *xmit = &port->state->xmit; | 763 | struct circ_buf *xmit = &port->state->xmit; |
709 | int ret; | ||
710 | int fifo_size; | 764 | int fifo_size; |
711 | int tx_size; | 765 | int tx_size; |
712 | int size; | 766 | int size; |
713 | int tx_empty; | 767 | int tx_empty; |
714 | 768 | ||
715 | if (!priv->start_tx) { | 769 | if (!priv->start_tx) { |
716 | pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); | 770 | dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n", |
771 | __func__, jiffies); | ||
717 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | 772 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); |
718 | priv->tx_empty = 1; | 773 | priv->tx_empty = 1; |
719 | return 0; | 774 | return 0; |
@@ -728,17 +783,21 @@ static unsigned int handle_tx(struct eg20t_port *priv) | |||
728 | fifo_size--; | 783 | fifo_size--; |
729 | } | 784 | } |
730 | size = min(xmit->head - xmit->tail, fifo_size); | 785 | size = min(xmit->head - xmit->tail, fifo_size); |
731 | tx_size = pop_tx(priv, xmit->buf, size); | 786 | if (size < 0) |
787 | size = fifo_size; | ||
788 | |||
789 | tx_size = pop_tx(priv, size); | ||
732 | if (tx_size > 0) { | 790 | if (tx_size > 0) { |
733 | ret = pch_uart_hal_write(priv, xmit->buf, tx_size); | 791 | port->icount.tx += tx_size; |
734 | port->icount.tx += ret; | ||
735 | tx_empty = 0; | 792 | tx_empty = 0; |
736 | } | 793 | } |
737 | 794 | ||
738 | priv->tx_empty = tx_empty; | 795 | priv->tx_empty = tx_empty; |
739 | 796 | ||
740 | if (tx_empty) | 797 | if (tx_empty) { |
741 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | 798 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); |
799 | uart_write_wakeup(port); | ||
800 | } | ||
742 | 801 | ||
743 | return PCH_UART_HANDLED_TX_INT; | 802 | return PCH_UART_HANDLED_TX_INT; |
744 | } | 803 | } |
@@ -747,14 +806,28 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) | |||
747 | { | 806 | { |
748 | struct uart_port *port = &priv->port; | 807 | struct uart_port *port = &priv->port; |
749 | struct circ_buf *xmit = &port->state->xmit; | 808 | struct circ_buf *xmit = &port->state->xmit; |
750 | struct scatterlist *sg = &priv->sg_tx; | 809 | struct scatterlist *sg; |
751 | int nent; | 810 | int nent; |
752 | int fifo_size; | 811 | int fifo_size; |
753 | int tx_empty; | 812 | int tx_empty; |
754 | struct dma_async_tx_descriptor *desc; | 813 | struct dma_async_tx_descriptor *desc; |
814 | int num; | ||
815 | int i; | ||
816 | int bytes; | ||
817 | int size; | ||
818 | int rem; | ||
755 | 819 | ||
756 | if (!priv->start_tx) { | 820 | if (!priv->start_tx) { |
757 | pr_info("%s:Tx isn't started. (%lu)\n", __func__, jiffies); | 821 | dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n", |
822 | __func__, jiffies); | ||
823 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | ||
824 | priv->tx_empty = 1; | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | if (priv->tx_dma_use) { | ||
829 | dev_dbg(priv->port.dev, "%s:Tx is not completed. (%lu)\n", | ||
830 | __func__, jiffies); | ||
758 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | 831 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); |
759 | priv->tx_empty = 1; | 832 | priv->tx_empty = 1; |
760 | return 0; | 833 | return 0; |
@@ -769,37 +842,73 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) | |||
769 | fifo_size--; | 842 | fifo_size--; |
770 | } | 843 | } |
771 | 844 | ||
772 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | 845 | bytes = min((int)CIRC_CNT(xmit->head, xmit->tail, |
846 | UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, | ||
847 | xmit->tail, UART_XMIT_SIZE)); | ||
848 | if (!bytes) { | ||
849 | dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__); | ||
850 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT); | ||
851 | uart_write_wakeup(port); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | if (bytes > fifo_size) { | ||
856 | num = bytes / fifo_size + 1; | ||
857 | size = fifo_size; | ||
858 | rem = bytes % fifo_size; | ||
859 | } else { | ||
860 | num = 1; | ||
861 | size = bytes; | ||
862 | rem = bytes; | ||
863 | } | ||
864 | |||
865 | dev_dbg(priv->port.dev, "%s num=%d size=%d rem=%d\n", | ||
866 | __func__, num, size, rem); | ||
773 | 867 | ||
774 | priv->tx_dma_use = 1; | 868 | priv->tx_dma_use = 1; |
775 | 869 | ||
776 | sg_init_table(&priv->sg_tx, 1); /* Initialize SG table */ | 870 | priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); |
777 | 871 | ||
778 | sg_set_page(&priv->sg_tx, virt_to_page(xmit->buf), | 872 | sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */ |
779 | UART_XMIT_SIZE, (int)xmit->buf & ~PAGE_MASK); | 873 | sg = priv->sg_tx_p; |
780 | 874 | ||
781 | nent = dma_map_sg(port->dev, &priv->sg_tx, 1, DMA_TO_DEVICE); | 875 | for (i = 0; i < num; i++, sg++) { |
876 | if (i == (num - 1)) | ||
877 | sg_set_page(sg, virt_to_page(xmit->buf), | ||
878 | rem, fifo_size * i); | ||
879 | else | ||
880 | sg_set_page(sg, virt_to_page(xmit->buf), | ||
881 | size, fifo_size * i); | ||
882 | } | ||
883 | |||
884 | sg = priv->sg_tx_p; | ||
885 | nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE); | ||
782 | if (!nent) { | 886 | if (!nent) { |
783 | pr_err("%s:dma_map_sg Failed\n", __func__); | 887 | dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__); |
784 | return 0; | 888 | return 0; |
785 | } | 889 | } |
786 | 890 | priv->nent = nent; | |
787 | sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); | 891 | |
788 | sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + | 892 | for (i = 0; i < nent; i++, sg++) { |
789 | sg->offset; | 893 | sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) + |
790 | sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, | 894 | fifo_size * i; |
791 | UART_XMIT_SIZE), CIRC_CNT_TO_END(xmit->head, | 895 | sg_dma_address(sg) = (sg_dma_address(sg) & |
792 | xmit->tail, UART_XMIT_SIZE)); | 896 | ~(UART_XMIT_SIZE - 1)) + sg->offset; |
897 | if (i == (nent - 1)) | ||
898 | sg_dma_len(sg) = rem; | ||
899 | else | ||
900 | sg_dma_len(sg) = size; | ||
901 | } | ||
793 | 902 | ||
794 | desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx, | 903 | desc = priv->chan_tx->device->device_prep_slave_sg(priv->chan_tx, |
795 | sg, nent, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | 904 | priv->sg_tx_p, nent, DMA_TO_DEVICE, |
905 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
796 | if (!desc) { | 906 | if (!desc) { |
797 | pr_err("%s:device_prep_slave_sg Failed\n", __func__); | 907 | dev_err(priv->port.dev, "%s:device_prep_slave_sg Failed\n", |
908 | __func__); | ||
798 | return 0; | 909 | return 0; |
799 | } | 910 | } |
800 | 911 | dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE); | |
801 | dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); | ||
802 | |||
803 | priv->desc_tx = desc; | 912 | priv->desc_tx = desc; |
804 | desc->callback = pch_dma_tx_complete; | 913 | desc->callback = pch_dma_tx_complete; |
805 | desc->callback_param = priv; | 914 | desc->callback_param = priv; |
@@ -854,10 +963,16 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
854 | } | 963 | } |
855 | break; | 964 | break; |
856 | case PCH_UART_IID_RDR: /* Received Data Ready */ | 965 | case PCH_UART_IID_RDR: /* Received Data Ready */ |
857 | if (priv->use_dma) | 966 | if (priv->use_dma) { |
967 | pch_uart_hal_disable_interrupt(priv, | ||
968 | PCH_UART_HAL_RX_INT); | ||
858 | ret = dma_handle_rx(priv); | 969 | ret = dma_handle_rx(priv); |
859 | else | 970 | if (!ret) |
971 | pch_uart_hal_enable_interrupt(priv, | ||
972 | PCH_UART_HAL_RX_INT); | ||
973 | } else { | ||
860 | ret = handle_rx(priv); | 974 | ret = handle_rx(priv); |
975 | } | ||
861 | break; | 976 | break; |
862 | case PCH_UART_IID_RDR_TO: /* Received Data Ready | 977 | case PCH_UART_IID_RDR_TO: /* Received Data Ready |
863 | (FIFO Timeout) */ | 978 | (FIFO Timeout) */ |
@@ -874,7 +989,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) | |||
874 | ret = PCH_UART_HANDLED_MS_INT; | 989 | ret = PCH_UART_HANDLED_MS_INT; |
875 | break; | 990 | break; |
876 | default: /* Never junp to this label */ | 991 | default: /* Never junp to this label */ |
877 | pr_err("%s:iid=%d (%lu)\n", __func__, iid, jiffies); | 992 | dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, |
993 | iid, jiffies); | ||
878 | ret = -1; | 994 | ret = -1; |
879 | break; | 995 | break; |
880 | } | 996 | } |
@@ -932,7 +1048,6 @@ static unsigned int pch_uart_get_mctrl(struct uart_port *port) | |||
932 | static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) | 1048 | static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) |
933 | { | 1049 | { |
934 | u32 mcr = 0; | 1050 | u32 mcr = 0; |
935 | unsigned int dat; | ||
936 | struct eg20t_port *priv = container_of(port, struct eg20t_port, port); | 1051 | struct eg20t_port *priv = container_of(port, struct eg20t_port, port); |
937 | 1052 | ||
938 | if (mctrl & TIOCM_DTR) | 1053 | if (mctrl & TIOCM_DTR) |
@@ -942,11 +1057,11 @@ static void pch_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
942 | if (mctrl & TIOCM_LOOP) | 1057 | if (mctrl & TIOCM_LOOP) |
943 | mcr |= UART_MCR_LOOP; | 1058 | mcr |= UART_MCR_LOOP; |
944 | 1059 | ||
945 | if (mctrl) { | 1060 | if (priv->mcr & UART_MCR_AFE) |
946 | dat = pch_uart_get_mctrl(port); | 1061 | mcr |= UART_MCR_AFE; |
947 | dat |= mcr; | 1062 | |
948 | iowrite8(dat, priv->membase + UART_MCR); | 1063 | if (mctrl) |
949 | } | 1064 | iowrite8(mcr, priv->membase + UART_MCR); |
950 | } | 1065 | } |
951 | 1066 | ||
952 | static void pch_uart_stop_tx(struct uart_port *port) | 1067 | static void pch_uart_stop_tx(struct uart_port *port) |
@@ -963,9 +1078,13 @@ static void pch_uart_start_tx(struct uart_port *port) | |||
963 | 1078 | ||
964 | priv = container_of(port, struct eg20t_port, port); | 1079 | priv = container_of(port, struct eg20t_port, port); |
965 | 1080 | ||
966 | if (priv->use_dma) | 1081 | if (priv->use_dma) { |
967 | if (priv->tx_dma_use) | 1082 | if (priv->tx_dma_use) { |
1083 | dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n", | ||
1084 | __func__); | ||
968 | return; | 1085 | return; |
1086 | } | ||
1087 | } | ||
969 | 1088 | ||
970 | priv->start_tx = 1; | 1089 | priv->start_tx = 1; |
971 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); | 1090 | pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); |
@@ -1010,7 +1129,12 @@ static int pch_uart_startup(struct uart_port *port) | |||
1010 | 1129 | ||
1011 | priv = container_of(port, struct eg20t_port, port); | 1130 | priv = container_of(port, struct eg20t_port, port); |
1012 | priv->tx_empty = 1; | 1131 | priv->tx_empty = 1; |
1013 | port->uartclk = priv->base_baud; | 1132 | |
1133 | if (port->uartclk) | ||
1134 | priv->base_baud = port->uartclk; | ||
1135 | else | ||
1136 | port->uartclk = priv->base_baud; | ||
1137 | |||
1014 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); | 1138 | pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT); |
1015 | ret = pch_uart_hal_set_line(priv, default_baud, | 1139 | ret = pch_uart_hal_set_line(priv, default_baud, |
1016 | PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT, | 1140 | PCH_UART_HAL_PARITY_NONE, PCH_UART_HAL_8BIT, |
@@ -1081,7 +1205,8 @@ static void pch_uart_shutdown(struct uart_port *port) | |||
1081 | ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, | 1205 | ret = pch_uart_hal_set_fifo(priv, PCH_UART_HAL_DMA_MODE0, |
1082 | PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1); | 1206 | PCH_UART_HAL_FIFO_DIS, PCH_UART_HAL_TRIGGER1); |
1083 | if (ret) | 1207 | if (ret) |
1084 | pr_err("pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); | 1208 | dev_err(priv->port.dev, |
1209 | "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); | ||
1085 | 1210 | ||
1086 | if (priv->use_dma_flag) | 1211 | if (priv->use_dma_flag) |
1087 | pch_free_dma(port); | 1212 | pch_free_dma(port); |
@@ -1130,6 +1255,13 @@ static void pch_uart_set_termios(struct uart_port *port, | |||
1130 | } else { | 1255 | } else { |
1131 | parity = PCH_UART_HAL_PARITY_NONE; | 1256 | parity = PCH_UART_HAL_PARITY_NONE; |
1132 | } | 1257 | } |
1258 | |||
1259 | /* Only UART0 has auto hardware flow function */ | ||
1260 | if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256)) | ||
1261 | priv->mcr |= UART_MCR_AFE; | ||
1262 | else | ||
1263 | priv->mcr &= ~UART_MCR_AFE; | ||
1264 | |||
1133 | termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ | 1265 | termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ |
1134 | 1266 | ||
1135 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | 1267 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); |
@@ -1202,17 +1334,19 @@ static int pch_uart_verify_port(struct uart_port *port, | |||
1202 | 1334 | ||
1203 | priv = container_of(port, struct eg20t_port, port); | 1335 | priv = container_of(port, struct eg20t_port, port); |
1204 | if (serinfo->flags & UPF_LOW_LATENCY) { | 1336 | if (serinfo->flags & UPF_LOW_LATENCY) { |
1205 | pr_info("PCH UART : Use PIO Mode (without DMA)\n"); | 1337 | dev_info(priv->port.dev, |
1338 | "PCH UART : Use PIO Mode (without DMA)\n"); | ||
1206 | priv->use_dma = 0; | 1339 | priv->use_dma = 0; |
1207 | serinfo->flags &= ~UPF_LOW_LATENCY; | 1340 | serinfo->flags &= ~UPF_LOW_LATENCY; |
1208 | } else { | 1341 | } else { |
1209 | #ifndef CONFIG_PCH_DMA | 1342 | #ifndef CONFIG_PCH_DMA |
1210 | pr_err("%s : PCH DMA is not Loaded.\n", __func__); | 1343 | dev_err(priv->port.dev, "%s : PCH DMA is not Loaded.\n", |
1344 | __func__); | ||
1211 | return -EOPNOTSUPP; | 1345 | return -EOPNOTSUPP; |
1212 | #endif | 1346 | #endif |
1213 | priv->use_dma = 1; | 1347 | priv->use_dma = 1; |
1214 | priv->use_dma_flag = 1; | 1348 | priv->use_dma_flag = 1; |
1215 | pr_info("PCH UART : Use DMA Mode\n"); | 1349 | dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); |
1216 | } | 1350 | } |
1217 | 1351 | ||
1218 | return 0; | 1352 | return 0; |
@@ -1249,7 +1383,7 @@ static struct uart_driver pch_uart_driver = { | |||
1249 | }; | 1383 | }; |
1250 | 1384 | ||
1251 | static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | 1385 | static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, |
1252 | int port_type) | 1386 | const struct pci_device_id *id) |
1253 | { | 1387 | { |
1254 | struct eg20t_port *priv; | 1388 | struct eg20t_port *priv; |
1255 | int ret; | 1389 | int ret; |
@@ -1257,7 +1391,11 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | |||
1257 | unsigned int mapbase; | 1391 | unsigned int mapbase; |
1258 | unsigned char *rxbuf; | 1392 | unsigned char *rxbuf; |
1259 | int fifosize, base_baud; | 1393 | int fifosize, base_baud; |
1260 | static int num; | 1394 | int port_type; |
1395 | struct pch_uart_driver_data *board; | ||
1396 | |||
1397 | board = &drv_dat[id->driver_data]; | ||
1398 | port_type = board->port_type; | ||
1261 | 1399 | ||
1262 | priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL); | 1400 | priv = kzalloc(sizeof(struct eg20t_port), GFP_KERNEL); |
1263 | if (priv == NULL) | 1401 | if (priv == NULL) |
@@ -1267,14 +1405,18 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | |||
1267 | if (!rxbuf) | 1405 | if (!rxbuf) |
1268 | goto init_port_free_txbuf; | 1406 | goto init_port_free_txbuf; |
1269 | 1407 | ||
1408 | base_baud = 1843200; /* 1.8432MHz */ | ||
1409 | |||
1410 | /* quirk for CM-iTC board */ | ||
1411 | if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC")) | ||
1412 | base_baud = 192000000; /* 192.0MHz */ | ||
1413 | |||
1270 | switch (port_type) { | 1414 | switch (port_type) { |
1271 | case PORT_UNKNOWN: | 1415 | case PORT_UNKNOWN: |
1272 | fifosize = 256; /* UART0 */ | 1416 | fifosize = 256; /* EG20T/ML7213: UART0 */ |
1273 | base_baud = 1843200; /* 1.8432MHz */ | ||
1274 | break; | 1417 | break; |
1275 | case PORT_8250: | 1418 | case PORT_8250: |
1276 | fifosize = 64; /* UART1~3 */ | 1419 | fifosize = 64; /* EG20T:UART1~3 ML7213: UART1~2*/ |
1277 | base_baud = 1843200; /* 1.8432MHz */ | ||
1278 | break; | 1420 | break; |
1279 | default: | 1421 | default: |
1280 | dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type); | 1422 | dev_err(&pdev->dev, "Invalid Port Type(=%d)\n", port_type); |
@@ -1302,11 +1444,14 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, | |||
1302 | priv->port.ops = &pch_uart_ops; | 1444 | priv->port.ops = &pch_uart_ops; |
1303 | priv->port.flags = UPF_BOOT_AUTOCONF; | 1445 | priv->port.flags = UPF_BOOT_AUTOCONF; |
1304 | priv->port.fifosize = fifosize; | 1446 | priv->port.fifosize = fifosize; |
1305 | priv->port.line = num++; | 1447 | priv->port.line = board->line_no; |
1306 | priv->trigger = PCH_UART_HAL_TRIGGER_M; | 1448 | priv->trigger = PCH_UART_HAL_TRIGGER_M; |
1307 | 1449 | ||
1450 | spin_lock_init(&priv->port.lock); | ||
1451 | |||
1308 | pci_set_drvdata(pdev, priv); | 1452 | pci_set_drvdata(pdev, priv); |
1309 | pch_uart_hal_request(pdev, fifosize, base_baud); | 1453 | pch_uart_hal_request(pdev, fifosize, base_baud); |
1454 | |||
1310 | ret = uart_add_one_port(&pch_uart_driver, &priv->port); | 1455 | ret = uart_add_one_port(&pch_uart_driver, &priv->port); |
1311 | if (ret < 0) | 1456 | if (ret < 0) |
1312 | goto init_port_hal_free; | 1457 | goto init_port_hal_free; |
@@ -1377,13 +1522,19 @@ static int pch_uart_pci_resume(struct pci_dev *pdev) | |||
1377 | 1522 | ||
1378 | static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { | 1523 | static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { |
1379 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), | 1524 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811), |
1380 | .driver_data = PCH_UART_8LINE}, | 1525 | .driver_data = pch_et20t_uart0}, |
1381 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), | 1526 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812), |
1382 | .driver_data = PCH_UART_2LINE}, | 1527 | .driver_data = pch_et20t_uart1}, |
1383 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813), | 1528 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8813), |
1384 | .driver_data = PCH_UART_2LINE}, | 1529 | .driver_data = pch_et20t_uart2}, |
1385 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814), | 1530 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8814), |
1386 | .driver_data = PCH_UART_2LINE}, | 1531 | .driver_data = pch_et20t_uart3}, |
1532 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8027), | ||
1533 | .driver_data = pch_ml7213_uart0}, | ||
1534 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8028), | ||
1535 | .driver_data = pch_ml7213_uart1}, | ||
1536 | {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8029), | ||
1537 | .driver_data = pch_ml7213_uart2}, | ||
1387 | {0,}, | 1538 | {0,}, |
1388 | }; | 1539 | }; |
1389 | 1540 | ||
@@ -1397,7 +1548,7 @@ static int __devinit pch_uart_pci_probe(struct pci_dev *pdev, | |||
1397 | if (ret < 0) | 1548 | if (ret < 0) |
1398 | goto probe_error; | 1549 | goto probe_error; |
1399 | 1550 | ||
1400 | priv = pch_uart_init_port(pdev, id->driver_data); | 1551 | priv = pch_uart_init_port(pdev, id); |
1401 | if (!priv) { | 1552 | if (!priv) { |
1402 | ret = -EBUSY; | 1553 | ret = -EBUSY; |
1403 | goto probe_disable_device; | 1554 | goto probe_disable_device; |
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 460a72d91bb7..733fe8e73f0f 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c | |||
@@ -905,7 +905,7 @@ static int uart_get_lsr_info(struct tty_struct *tty, | |||
905 | return put_user(result, value); | 905 | return put_user(result, value); |
906 | } | 906 | } |
907 | 907 | ||
908 | static int uart_tiocmget(struct tty_struct *tty, struct file *file) | 908 | static int uart_tiocmget(struct tty_struct *tty) |
909 | { | 909 | { |
910 | struct uart_state *state = tty->driver_data; | 910 | struct uart_state *state = tty->driver_data; |
911 | struct tty_port *port = &state->port; | 911 | struct tty_port *port = &state->port; |
@@ -913,10 +913,8 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file) | |||
913 | int result = -EIO; | 913 | int result = -EIO; |
914 | 914 | ||
915 | mutex_lock(&port->mutex); | 915 | mutex_lock(&port->mutex); |
916 | if ((!file || !tty_hung_up_p(file)) && | 916 | if (!(tty->flags & (1 << TTY_IO_ERROR))) { |
917 | !(tty->flags & (1 << TTY_IO_ERROR))) { | ||
918 | result = uport->mctrl; | 917 | result = uport->mctrl; |
919 | |||
920 | spin_lock_irq(&uport->lock); | 918 | spin_lock_irq(&uport->lock); |
921 | result |= uport->ops->get_mctrl(uport); | 919 | result |= uport->ops->get_mctrl(uport); |
922 | spin_unlock_irq(&uport->lock); | 920 | spin_unlock_irq(&uport->lock); |
@@ -927,8 +925,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file) | |||
927 | } | 925 | } |
928 | 926 | ||
929 | static int | 927 | static int |
930 | uart_tiocmset(struct tty_struct *tty, struct file *file, | 928 | uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) |
931 | unsigned int set, unsigned int clear) | ||
932 | { | 929 | { |
933 | struct uart_state *state = tty->driver_data; | 930 | struct uart_state *state = tty->driver_data; |
934 | struct uart_port *uport = state->uart_port; | 931 | struct uart_port *uport = state->uart_port; |
@@ -936,8 +933,7 @@ uart_tiocmset(struct tty_struct *tty, struct file *file, | |||
936 | int ret = -EIO; | 933 | int ret = -EIO; |
937 | 934 | ||
938 | mutex_lock(&port->mutex); | 935 | mutex_lock(&port->mutex); |
939 | if ((!file || !tty_hung_up_p(file)) && | 936 | if (!(tty->flags & (1 << TTY_IO_ERROR))) { |
940 | !(tty->flags & (1 << TTY_IO_ERROR))) { | ||
941 | uart_update_mctrl(uport, set, clear); | 937 | uart_update_mctrl(uport, set, clear); |
942 | ret = 0; | 938 | ret = 0; |
943 | } | 939 | } |
@@ -1103,7 +1099,7 @@ static int uart_get_icount(struct tty_struct *tty, | |||
1103 | * Called via sys_ioctl. We can use spin_lock_irq() here. | 1099 | * Called via sys_ioctl. We can use spin_lock_irq() here. |
1104 | */ | 1100 | */ |
1105 | static int | 1101 | static int |
1106 | uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, | 1102 | uart_ioctl(struct tty_struct *tty, unsigned int cmd, |
1107 | unsigned long arg) | 1103 | unsigned long arg) |
1108 | { | 1104 | { |
1109 | struct uart_state *state = tty->driver_data; | 1105 | struct uart_state *state = tty->driver_data; |
@@ -1156,7 +1152,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, | |||
1156 | 1152 | ||
1157 | mutex_lock(&port->mutex); | 1153 | mutex_lock(&port->mutex); |
1158 | 1154 | ||
1159 | if (tty_hung_up_p(filp)) { | 1155 | if (tty->flags & (1 << TTY_IO_ERROR)) { |
1160 | ret = -EIO; | 1156 | ret = -EIO; |
1161 | goto out_up; | 1157 | goto out_up; |
1162 | } | 1158 | } |
@@ -2064,7 +2060,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) | |||
2064 | /* | 2060 | /* |
2065 | * Re-enable the console device after suspending. | 2061 | * Re-enable the console device after suspending. |
2066 | */ | 2062 | */ |
2067 | if (console_suspend_enabled && uart_console(uport)) { | 2063 | if (uart_console(uport)) { |
2068 | /* | 2064 | /* |
2069 | * First try to use the console cflag setting. | 2065 | * First try to use the console cflag setting. |
2070 | */ | 2066 | */ |
@@ -2077,9 +2073,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) | |||
2077 | if (port->tty && port->tty->termios && termios.c_cflag == 0) | 2073 | if (port->tty && port->tty->termios && termios.c_cflag == 0) |
2078 | termios = *(port->tty->termios); | 2074 | termios = *(port->tty->termios); |
2079 | 2075 | ||
2080 | uart_change_pm(state, 0); | ||
2081 | uport->ops->set_termios(uport, &termios, NULL); | 2076 | uport->ops->set_termios(uport, &termios, NULL); |
2082 | console_start(uport->cons); | 2077 | if (console_suspend_enabled) |
2078 | console_start(uport->cons); | ||
2083 | } | 2079 | } |
2084 | 2080 | ||
2085 | if (port->flags & ASYNC_SUSPENDED) { | 2081 | if (port->flags & ASYNC_SUSPENDED) { |
diff --git a/drivers/tty/serial/serial_cs.c b/drivers/tty/serial/serial_cs.c index 93760b2ea172..1ef4df9bf7e4 100644 --- a/drivers/tty/serial/serial_cs.c +++ b/drivers/tty/serial/serial_cs.c | |||
@@ -712,6 +712,7 @@ static struct pcmcia_device_id serial_ids[] = { | |||
712 | PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf), | 712 | PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf), |
713 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01), | 713 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01), |
714 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05), | 714 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05), |
715 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0b05), | ||
715 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101), | 716 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101), |
716 | PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070), | 717 | PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070), |
717 | PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562), | 718 | PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562), |
diff --git a/drivers/tty/serial/serial_lh7a40x.c b/drivers/tty/serial/serial_lh7a40x.c deleted file mode 100644 index ea744707c4d6..000000000000 --- a/drivers/tty/serial/serial_lh7a40x.c +++ /dev/null | |||
@@ -1,682 +0,0 @@ | |||
1 | /* drivers/serial/serial_lh7a40x.c | ||
2 | * | ||
3 | * Copyright (C) 2004 Coastal Environmental Systems | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | /* Driver for Sharp LH7A40X embedded serial ports | ||
12 | * | ||
13 | * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. | ||
14 | * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. | ||
15 | * | ||
16 | * --- | ||
17 | * | ||
18 | * This driver supports the embedded UARTs of the Sharp LH7A40X series | ||
19 | * CPUs. While similar to the 16550 and other UART chips, there is | ||
20 | * nothing close to register compatibility. Moreover, some of the | ||
21 | * modem control lines are not available, either in the chip or they | ||
22 | * are lacking in the board-level implementation. | ||
23 | * | ||
24 | * - Use of SIRDIS | ||
25 | * For simplicity, we disable the IR functions of any UART whenever | ||
26 | * we enable it. | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | |||
31 | #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) | ||
32 | #define SUPPORT_SYSRQ | ||
33 | #endif | ||
34 | |||
35 | #include <linux/module.h> | ||
36 | #include <linux/ioport.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/console.h> | ||
39 | #include <linux/sysrq.h> | ||
40 | #include <linux/tty.h> | ||
41 | #include <linux/tty_flip.h> | ||
42 | #include <linux/serial_core.h> | ||
43 | #include <linux/serial.h> | ||
44 | #include <linux/io.h> | ||
45 | |||
46 | #include <asm/irq.h> | ||
47 | #include <mach/hardware.h> | ||
48 | |||
49 | #define DEV_MAJOR 204 | ||
50 | #define DEV_MINOR 16 | ||
51 | #define DEV_NR 3 | ||
52 | |||
53 | #define ISR_LOOP_LIMIT 256 | ||
54 | |||
55 | #define UR(p,o) _UR ((p)->membase, o) | ||
56 | #define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) | ||
57 | #define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) | ||
58 | #define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) | ||
59 | |||
60 | #define UART_REG_SIZE 32 | ||
61 | |||
62 | #define UART_R_DATA (0x00) | ||
63 | #define UART_R_FCON (0x04) | ||
64 | #define UART_R_BRCON (0x08) | ||
65 | #define UART_R_CON (0x0c) | ||
66 | #define UART_R_STATUS (0x10) | ||
67 | #define UART_R_RAWISR (0x14) | ||
68 | #define UART_R_INTEN (0x18) | ||
69 | #define UART_R_ISR (0x1c) | ||
70 | |||
71 | #define UARTEN (0x01) /* UART enable */ | ||
72 | #define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ | ||
73 | |||
74 | #define RxEmpty (0x10) | ||
75 | #define TxEmpty (0x80) | ||
76 | #define TxFull (0x20) | ||
77 | #define nRxRdy RxEmpty | ||
78 | #define nTxRdy TxFull | ||
79 | #define TxBusy (0x08) | ||
80 | |||
81 | #define RxBreak (0x0800) | ||
82 | #define RxOverrunError (0x0400) | ||
83 | #define RxParityError (0x0200) | ||
84 | #define RxFramingError (0x0100) | ||
85 | #define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) | ||
86 | |||
87 | #define DCD (0x04) | ||
88 | #define DSR (0x02) | ||
89 | #define CTS (0x01) | ||
90 | |||
91 | #define RxInt (0x01) | ||
92 | #define TxInt (0x02) | ||
93 | #define ModemInt (0x04) | ||
94 | #define RxTimeoutInt (0x08) | ||
95 | |||
96 | #define MSEOI (0x10) | ||
97 | |||
98 | #define WLEN_8 (0x60) | ||
99 | #define WLEN_7 (0x40) | ||
100 | #define WLEN_6 (0x20) | ||
101 | #define WLEN_5 (0x00) | ||
102 | #define WLEN (0x60) /* Mask for all word-length bits */ | ||
103 | #define STP2 (0x08) | ||
104 | #define PEN (0x02) /* Parity Enable */ | ||
105 | #define EPS (0x04) /* Even Parity Set */ | ||
106 | #define FEN (0x10) /* FIFO Enable */ | ||
107 | #define BRK (0x01) /* Send Break */ | ||
108 | |||
109 | |||
110 | struct uart_port_lh7a40x { | ||
111 | struct uart_port port; | ||
112 | unsigned int statusPrev; /* Most recently read modem status */ | ||
113 | }; | ||
114 | |||
115 | static void lh7a40xuart_stop_tx (struct uart_port* port) | ||
116 | { | ||
117 | BIT_CLR (port, UART_R_INTEN, TxInt); | ||
118 | } | ||
119 | |||
120 | static void lh7a40xuart_start_tx (struct uart_port* port) | ||
121 | { | ||
122 | BIT_SET (port, UART_R_INTEN, TxInt); | ||
123 | |||
124 | /* *** FIXME: do I need to check for startup of the | ||
125 | transmitter? The old driver did, but AMBA | ||
126 | doesn't . */ | ||
127 | } | ||
128 | |||
129 | static void lh7a40xuart_stop_rx (struct uart_port* port) | ||
130 | { | ||
131 | BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); | ||
132 | } | ||
133 | |||
134 | static void lh7a40xuart_enable_ms (struct uart_port* port) | ||
135 | { | ||
136 | BIT_SET (port, UART_R_INTEN, ModemInt); | ||
137 | } | ||
138 | |||
139 | static void lh7a40xuart_rx_chars (struct uart_port* port) | ||
140 | { | ||
141 | struct tty_struct* tty = port->state->port.tty; | ||
142 | int cbRxMax = 256; /* (Gross) limit on receive */ | ||
143 | unsigned int data; /* Received data and status */ | ||
144 | unsigned int flag; | ||
145 | |||
146 | while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { | ||
147 | data = UR (port, UART_R_DATA); | ||
148 | flag = TTY_NORMAL; | ||
149 | ++port->icount.rx; | ||
150 | |||
151 | if (unlikely(data & RxError)) { | ||
152 | if (data & RxBreak) { | ||
153 | data &= ~(RxFramingError | RxParityError); | ||
154 | ++port->icount.brk; | ||
155 | if (uart_handle_break (port)) | ||
156 | continue; | ||
157 | } | ||
158 | else if (data & RxParityError) | ||
159 | ++port->icount.parity; | ||
160 | else if (data & RxFramingError) | ||
161 | ++port->icount.frame; | ||
162 | if (data & RxOverrunError) | ||
163 | ++port->icount.overrun; | ||
164 | |||
165 | /* Mask by termios, leave Rx'd byte */ | ||
166 | data &= port->read_status_mask | 0xff; | ||
167 | |||
168 | if (data & RxBreak) | ||
169 | flag = TTY_BREAK; | ||
170 | else if (data & RxParityError) | ||
171 | flag = TTY_PARITY; | ||
172 | else if (data & RxFramingError) | ||
173 | flag = TTY_FRAME; | ||
174 | } | ||
175 | |||
176 | if (uart_handle_sysrq_char (port, (unsigned char) data)) | ||
177 | continue; | ||
178 | |||
179 | uart_insert_char(port, data, RxOverrunError, data, flag); | ||
180 | } | ||
181 | tty_flip_buffer_push (tty); | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | static void lh7a40xuart_tx_chars (struct uart_port* port) | ||
186 | { | ||
187 | struct circ_buf* xmit = &port->state->xmit; | ||
188 | int cbTxMax = port->fifosize; | ||
189 | |||
190 | if (port->x_char) { | ||
191 | UR (port, UART_R_DATA) = port->x_char; | ||
192 | ++port->icount.tx; | ||
193 | port->x_char = 0; | ||
194 | return; | ||
195 | } | ||
196 | if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { | ||
197 | lh7a40xuart_stop_tx (port); | ||
198 | return; | ||
199 | } | ||
200 | |||
201 | /* Unlike the AMBA UART, the lh7a40x UART does not guarantee | ||
202 | that at least half of the FIFO is empty. Instead, we check | ||
203 | status for every character. Using the AMBA method causes | ||
204 | the transmitter to drop characters. */ | ||
205 | |||
206 | do { | ||
207 | UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; | ||
208 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
209 | ++port->icount.tx; | ||
210 | if (uart_circ_empty(xmit)) | ||
211 | break; | ||
212 | } while (!(UR (port, UART_R_STATUS) & nTxRdy) | ||
213 | && cbTxMax--); | ||
214 | |||
215 | if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) | ||
216 | uart_write_wakeup (port); | ||
217 | |||
218 | if (uart_circ_empty (xmit)) | ||
219 | lh7a40xuart_stop_tx (port); | ||
220 | } | ||
221 | |||
222 | static void lh7a40xuart_modem_status (struct uart_port* port) | ||
223 | { | ||
224 | unsigned int status = UR (port, UART_R_STATUS); | ||
225 | unsigned int delta | ||
226 | = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; | ||
227 | |||
228 | BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ | ||
229 | |||
230 | if (!delta) /* Only happens if we missed 2 transitions */ | ||
231 | return; | ||
232 | |||
233 | ((struct uart_port_lh7a40x*) port)->statusPrev = status; | ||
234 | |||
235 | if (delta & DCD) | ||
236 | uart_handle_dcd_change (port, status & DCD); | ||
237 | |||
238 | if (delta & DSR) | ||
239 | ++port->icount.dsr; | ||
240 | |||
241 | if (delta & CTS) | ||
242 | uart_handle_cts_change (port, status & CTS); | ||
243 | |||
244 | wake_up_interruptible (&port->state->port.delta_msr_wait); | ||
245 | } | ||
246 | |||
247 | static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) | ||
248 | { | ||
249 | struct uart_port* port = dev_id; | ||
250 | unsigned int cLoopLimit = ISR_LOOP_LIMIT; | ||
251 | unsigned int isr = UR (port, UART_R_ISR); | ||
252 | |||
253 | |||
254 | do { | ||
255 | if (isr & (RxInt | RxTimeoutInt)) | ||
256 | lh7a40xuart_rx_chars(port); | ||
257 | if (isr & ModemInt) | ||
258 | lh7a40xuart_modem_status (port); | ||
259 | if (isr & TxInt) | ||
260 | lh7a40xuart_tx_chars (port); | ||
261 | |||
262 | if (--cLoopLimit == 0) | ||
263 | break; | ||
264 | |||
265 | isr = UR (port, UART_R_ISR); | ||
266 | } while (isr & (RxInt | TxInt | RxTimeoutInt)); | ||
267 | |||
268 | return IRQ_HANDLED; | ||
269 | } | ||
270 | |||
271 | static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) | ||
272 | { | ||
273 | return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; | ||
274 | } | ||
275 | |||
276 | static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) | ||
277 | { | ||
278 | unsigned int result = 0; | ||
279 | unsigned int status = UR (port, UART_R_STATUS); | ||
280 | |||
281 | if (status & DCD) | ||
282 | result |= TIOCM_CAR; | ||
283 | if (status & DSR) | ||
284 | result |= TIOCM_DSR; | ||
285 | if (status & CTS) | ||
286 | result |= TIOCM_CTS; | ||
287 | |||
288 | return result; | ||
289 | } | ||
290 | |||
291 | static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) | ||
292 | { | ||
293 | /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ | ||
294 | /* Note, kernel appears to be setting DTR and RTS on console. */ | ||
295 | |||
296 | /* *** FIXME: this deserves more work. There's some work in | ||
297 | tracing all of the IO pins. */ | ||
298 | #if 0 | ||
299 | if( port->mapbase == UART1_PHYS) { | ||
300 | gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); | ||
301 | |||
302 | if (mctrl & TIOCM_RTS) | ||
303 | gpio->pbdr &= ~GPIOB_UART1_RTS; | ||
304 | else | ||
305 | gpio->pbdr |= GPIOB_UART1_RTS; | ||
306 | } | ||
307 | #endif | ||
308 | } | ||
309 | |||
310 | static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) | ||
311 | { | ||
312 | unsigned long flags; | ||
313 | |||
314 | spin_lock_irqsave(&port->lock, flags); | ||
315 | if (break_state == -1) | ||
316 | BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ | ||
317 | else | ||
318 | BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ | ||
319 | spin_unlock_irqrestore(&port->lock, flags); | ||
320 | } | ||
321 | |||
322 | static int lh7a40xuart_startup (struct uart_port* port) | ||
323 | { | ||
324 | int retval; | ||
325 | |||
326 | retval = request_irq (port->irq, lh7a40xuart_int, 0, | ||
327 | "serial_lh7a40x", port); | ||
328 | if (retval) | ||
329 | return retval; | ||
330 | |||
331 | /* Initial modem control-line settings */ | ||
332 | ((struct uart_port_lh7a40x*) port)->statusPrev | ||
333 | = UR (port, UART_R_STATUS); | ||
334 | |||
335 | /* There is presently no configuration option to enable IR. | ||
336 | Thus, we always disable it. */ | ||
337 | |||
338 | BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); | ||
339 | BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static void lh7a40xuart_shutdown (struct uart_port* port) | ||
345 | { | ||
346 | free_irq (port->irq, port); | ||
347 | BIT_CLR (port, UART_R_FCON, BRK | FEN); | ||
348 | BIT_CLR (port, UART_R_CON, UARTEN); | ||
349 | } | ||
350 | |||
351 | static void lh7a40xuart_set_termios (struct uart_port* port, | ||
352 | struct ktermios* termios, | ||
353 | struct ktermios* old) | ||
354 | { | ||
355 | unsigned int con; | ||
356 | unsigned int inten; | ||
357 | unsigned int fcon; | ||
358 | unsigned long flags; | ||
359 | unsigned int baud; | ||
360 | unsigned int quot; | ||
361 | |||
362 | baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); | ||
363 | quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ | ||
364 | |||
365 | switch (termios->c_cflag & CSIZE) { | ||
366 | case CS5: | ||
367 | fcon = WLEN_5; | ||
368 | break; | ||
369 | case CS6: | ||
370 | fcon = WLEN_6; | ||
371 | break; | ||
372 | case CS7: | ||
373 | fcon = WLEN_7; | ||
374 | break; | ||
375 | case CS8: | ||
376 | default: | ||
377 | fcon = WLEN_8; | ||
378 | break; | ||
379 | } | ||
380 | if (termios->c_cflag & CSTOPB) | ||
381 | fcon |= STP2; | ||
382 | if (termios->c_cflag & PARENB) { | ||
383 | fcon |= PEN; | ||
384 | if (!(termios->c_cflag & PARODD)) | ||
385 | fcon |= EPS; | ||
386 | } | ||
387 | if (port->fifosize > 1) | ||
388 | fcon |= FEN; | ||
389 | |||
390 | spin_lock_irqsave (&port->lock, flags); | ||
391 | |||
392 | uart_update_timeout (port, termios->c_cflag, baud); | ||
393 | |||
394 | port->read_status_mask = RxOverrunError; | ||
395 | if (termios->c_iflag & INPCK) | ||
396 | port->read_status_mask |= RxFramingError | RxParityError; | ||
397 | if (termios->c_iflag & (BRKINT | PARMRK)) | ||
398 | port->read_status_mask |= RxBreak; | ||
399 | |||
400 | /* Figure mask for status we ignore */ | ||
401 | port->ignore_status_mask = 0; | ||
402 | if (termios->c_iflag & IGNPAR) | ||
403 | port->ignore_status_mask |= RxFramingError | RxParityError; | ||
404 | if (termios->c_iflag & IGNBRK) { | ||
405 | port->ignore_status_mask |= RxBreak; | ||
406 | /* Ignore overrun when ignorning parity */ | ||
407 | /* *** FIXME: is this in the right place? */ | ||
408 | if (termios->c_iflag & IGNPAR) | ||
409 | port->ignore_status_mask |= RxOverrunError; | ||
410 | } | ||
411 | |||
412 | /* Ignore all receive errors when receive disabled */ | ||
413 | if ((termios->c_cflag & CREAD) == 0) | ||
414 | port->ignore_status_mask |= RxError; | ||
415 | |||
416 | con = UR (port, UART_R_CON); | ||
417 | inten = (UR (port, UART_R_INTEN) & ~ModemInt); | ||
418 | |||
419 | if (UART_ENABLE_MS (port, termios->c_cflag)) | ||
420 | inten |= ModemInt; | ||
421 | |||
422 | BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ | ||
423 | UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ | ||
424 | UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ | ||
425 | UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ | ||
426 | UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ | ||
427 | UR (port, UART_R_CON) = con; /* Restore UART mode */ | ||
428 | |||
429 | spin_unlock_irqrestore(&port->lock, flags); | ||
430 | } | ||
431 | |||
432 | static const char* lh7a40xuart_type (struct uart_port* port) | ||
433 | { | ||
434 | return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; | ||
435 | } | ||
436 | |||
437 | static void lh7a40xuart_release_port (struct uart_port* port) | ||
438 | { | ||
439 | release_mem_region (port->mapbase, UART_REG_SIZE); | ||
440 | } | ||
441 | |||
442 | static int lh7a40xuart_request_port (struct uart_port* port) | ||
443 | { | ||
444 | return request_mem_region (port->mapbase, UART_REG_SIZE, | ||
445 | "serial_lh7a40x") != NULL | ||
446 | ? 0 : -EBUSY; | ||
447 | } | ||
448 | |||
449 | static void lh7a40xuart_config_port (struct uart_port* port, int flags) | ||
450 | { | ||
451 | if (flags & UART_CONFIG_TYPE) { | ||
452 | port->type = PORT_LH7A40X; | ||
453 | lh7a40xuart_request_port (port); | ||
454 | } | ||
455 | } | ||
456 | |||
457 | static int lh7a40xuart_verify_port (struct uart_port* port, | ||
458 | struct serial_struct* ser) | ||
459 | { | ||
460 | int ret = 0; | ||
461 | |||
462 | if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) | ||
463 | ret = -EINVAL; | ||
464 | if (ser->irq < 0 || ser->irq >= nr_irqs) | ||
465 | ret = -EINVAL; | ||
466 | if (ser->baud_base < 9600) /* *** FIXME: is this true? */ | ||
467 | ret = -EINVAL; | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static struct uart_ops lh7a40x_uart_ops = { | ||
472 | .tx_empty = lh7a40xuart_tx_empty, | ||
473 | .set_mctrl = lh7a40xuart_set_mctrl, | ||
474 | .get_mctrl = lh7a40xuart_get_mctrl, | ||
475 | .stop_tx = lh7a40xuart_stop_tx, | ||
476 | .start_tx = lh7a40xuart_start_tx, | ||
477 | .stop_rx = lh7a40xuart_stop_rx, | ||
478 | .enable_ms = lh7a40xuart_enable_ms, | ||
479 | .break_ctl = lh7a40xuart_break_ctl, | ||
480 | .startup = lh7a40xuart_startup, | ||
481 | .shutdown = lh7a40xuart_shutdown, | ||
482 | .set_termios = lh7a40xuart_set_termios, | ||
483 | .type = lh7a40xuart_type, | ||
484 | .release_port = lh7a40xuart_release_port, | ||
485 | .request_port = lh7a40xuart_request_port, | ||
486 | .config_port = lh7a40xuart_config_port, | ||
487 | .verify_port = lh7a40xuart_verify_port, | ||
488 | }; | ||
489 | |||
490 | static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { | ||
491 | { | ||
492 | .port = { | ||
493 | .membase = (void*) io_p2v (UART1_PHYS), | ||
494 | .mapbase = UART1_PHYS, | ||
495 | .iotype = UPIO_MEM, | ||
496 | .irq = IRQ_UART1INTR, | ||
497 | .uartclk = 14745600/2, | ||
498 | .fifosize = 16, | ||
499 | .ops = &lh7a40x_uart_ops, | ||
500 | .flags = UPF_BOOT_AUTOCONF, | ||
501 | .line = 0, | ||
502 | }, | ||
503 | }, | ||
504 | { | ||
505 | .port = { | ||
506 | .membase = (void*) io_p2v (UART2_PHYS), | ||
507 | .mapbase = UART2_PHYS, | ||
508 | .iotype = UPIO_MEM, | ||
509 | .irq = IRQ_UART2INTR, | ||
510 | .uartclk = 14745600/2, | ||
511 | .fifosize = 16, | ||
512 | .ops = &lh7a40x_uart_ops, | ||
513 | .flags = UPF_BOOT_AUTOCONF, | ||
514 | .line = 1, | ||
515 | }, | ||
516 | }, | ||
517 | { | ||
518 | .port = { | ||
519 | .membase = (void*) io_p2v (UART3_PHYS), | ||
520 | .mapbase = UART3_PHYS, | ||
521 | .iotype = UPIO_MEM, | ||
522 | .irq = IRQ_UART3INTR, | ||
523 | .uartclk = 14745600/2, | ||
524 | .fifosize = 16, | ||
525 | .ops = &lh7a40x_uart_ops, | ||
526 | .flags = UPF_BOOT_AUTOCONF, | ||
527 | .line = 2, | ||
528 | }, | ||
529 | }, | ||
530 | }; | ||
531 | |||
532 | #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE | ||
533 | # define LH7A40X_CONSOLE NULL | ||
534 | #else | ||
535 | # define LH7A40X_CONSOLE &lh7a40x_console | ||
536 | |||
537 | static void lh7a40xuart_console_putchar(struct uart_port *port, int ch) | ||
538 | { | ||
539 | while (UR(port, UART_R_STATUS) & nTxRdy) | ||
540 | ; | ||
541 | UR(port, UART_R_DATA) = ch; | ||
542 | } | ||
543 | |||
544 | static void lh7a40xuart_console_write (struct console* co, | ||
545 | const char* s, | ||
546 | unsigned int count) | ||
547 | { | ||
548 | struct uart_port* port = &lh7a40x_ports[co->index].port; | ||
549 | unsigned int con = UR (port, UART_R_CON); | ||
550 | unsigned int inten = UR (port, UART_R_INTEN); | ||
551 | |||
552 | |||
553 | UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ | ||
554 | BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ | ||
555 | |||
556 | uart_console_write(port, s, count, lh7a40xuart_console_putchar); | ||
557 | |||
558 | /* Wait until all characters are sent */ | ||
559 | while (UR (port, UART_R_STATUS) & TxBusy) | ||
560 | ; | ||
561 | |||
562 | /* Restore control and interrupt mask */ | ||
563 | UR (port, UART_R_CON) = con; | ||
564 | UR (port, UART_R_INTEN) = inten; | ||
565 | } | ||
566 | |||
567 | static void __init lh7a40xuart_console_get_options (struct uart_port* port, | ||
568 | int* baud, | ||
569 | int* parity, | ||
570 | int* bits) | ||
571 | { | ||
572 | if (UR (port, UART_R_CON) & UARTEN) { | ||
573 | unsigned int fcon = UR (port, UART_R_FCON); | ||
574 | unsigned int quot = UR (port, UART_R_BRCON) + 1; | ||
575 | |||
576 | switch (fcon & (PEN | EPS)) { | ||
577 | default: *parity = 'n'; break; | ||
578 | case PEN: *parity = 'o'; break; | ||
579 | case PEN | EPS: *parity = 'e'; break; | ||
580 | } | ||
581 | |||
582 | switch (fcon & WLEN) { | ||
583 | default: | ||
584 | case WLEN_8: *bits = 8; break; | ||
585 | case WLEN_7: *bits = 7; break; | ||
586 | case WLEN_6: *bits = 6; break; | ||
587 | case WLEN_5: *bits = 5; break; | ||
588 | } | ||
589 | |||
590 | *baud = port->uartclk/(16*quot); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | static int __init lh7a40xuart_console_setup (struct console* co, char* options) | ||
595 | { | ||
596 | struct uart_port* port; | ||
597 | int baud = 38400; | ||
598 | int bits = 8; | ||
599 | int parity = 'n'; | ||
600 | int flow = 'n'; | ||
601 | |||
602 | if (co->index >= DEV_NR) /* Bounds check on device number */ | ||
603 | co->index = 0; | ||
604 | port = &lh7a40x_ports[co->index].port; | ||
605 | |||
606 | if (options) | ||
607 | uart_parse_options (options, &baud, &parity, &bits, &flow); | ||
608 | else | ||
609 | lh7a40xuart_console_get_options (port, &baud, &parity, &bits); | ||
610 | |||
611 | return uart_set_options (port, co, baud, parity, bits, flow); | ||
612 | } | ||
613 | |||
614 | static struct uart_driver lh7a40x_reg; | ||
615 | static struct console lh7a40x_console = { | ||
616 | .name = "ttyAM", | ||
617 | .write = lh7a40xuart_console_write, | ||
618 | .device = uart_console_device, | ||
619 | .setup = lh7a40xuart_console_setup, | ||
620 | .flags = CON_PRINTBUFFER, | ||
621 | .index = -1, | ||
622 | .data = &lh7a40x_reg, | ||
623 | }; | ||
624 | |||
625 | static int __init lh7a40xuart_console_init(void) | ||
626 | { | ||
627 | register_console (&lh7a40x_console); | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | console_initcall (lh7a40xuart_console_init); | ||
632 | |||
633 | #endif | ||
634 | |||
635 | static struct uart_driver lh7a40x_reg = { | ||
636 | .owner = THIS_MODULE, | ||
637 | .driver_name = "ttyAM", | ||
638 | .dev_name = "ttyAM", | ||
639 | .major = DEV_MAJOR, | ||
640 | .minor = DEV_MINOR, | ||
641 | .nr = DEV_NR, | ||
642 | .cons = LH7A40X_CONSOLE, | ||
643 | }; | ||
644 | |||
645 | static int __init lh7a40xuart_init(void) | ||
646 | { | ||
647 | int ret; | ||
648 | |||
649 | printk (KERN_INFO "serial: LH7A40X serial driver\n"); | ||
650 | |||
651 | ret = uart_register_driver (&lh7a40x_reg); | ||
652 | |||
653 | if (ret == 0) { | ||
654 | int i; | ||
655 | |||
656 | for (i = 0; i < DEV_NR; i++) { | ||
657 | /* UART3, when used, requires GPIO pin reallocation */ | ||
658 | if (lh7a40x_ports[i].port.mapbase == UART3_PHYS) | ||
659 | GPIO_PINMUX |= 1<<3; | ||
660 | uart_add_one_port (&lh7a40x_reg, | ||
661 | &lh7a40x_ports[i].port); | ||
662 | } | ||
663 | } | ||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | static void __exit lh7a40xuart_exit(void) | ||
668 | { | ||
669 | int i; | ||
670 | |||
671 | for (i = 0; i < DEV_NR; i++) | ||
672 | uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); | ||
673 | |||
674 | uart_unregister_driver (&lh7a40x_reg); | ||
675 | } | ||
676 | |||
677 | module_init (lh7a40xuart_init); | ||
678 | module_exit (lh7a40xuart_exit); | ||
679 | |||
680 | MODULE_AUTHOR ("Marc Singer"); | ||
681 | MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); | ||
682 | MODULE_LICENSE ("GPL"); | ||
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index c9014868297d..c0b7246d7339 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c | |||
@@ -519,7 +519,7 @@ static struct console sunhv_console = { | |||
519 | .data = &sunhv_reg, | 519 | .data = &sunhv_reg, |
520 | }; | 520 | }; |
521 | 521 | ||
522 | static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match) | 522 | static int __devinit hv_probe(struct platform_device *op) |
523 | { | 523 | { |
524 | struct uart_port *port; | 524 | struct uart_port *port; |
525 | unsigned long minor; | 525 | unsigned long minor; |
@@ -629,7 +629,7 @@ static const struct of_device_id hv_match[] = { | |||
629 | }; | 629 | }; |
630 | MODULE_DEVICE_TABLE(of, hv_match); | 630 | MODULE_DEVICE_TABLE(of, hv_match); |
631 | 631 | ||
632 | static struct of_platform_driver hv_driver = { | 632 | static struct platform_driver hv_driver = { |
633 | .driver = { | 633 | .driver = { |
634 | .name = "hv", | 634 | .name = "hv", |
635 | .owner = THIS_MODULE, | 635 | .owner = THIS_MODULE, |
@@ -644,12 +644,12 @@ static int __init sunhv_init(void) | |||
644 | if (tlb_type != hypervisor) | 644 | if (tlb_type != hypervisor) |
645 | return -ENODEV; | 645 | return -ENODEV; |
646 | 646 | ||
647 | return of_register_platform_driver(&hv_driver); | 647 | return platform_driver_register(&hv_driver); |
648 | } | 648 | } |
649 | 649 | ||
650 | static void __exit sunhv_exit(void) | 650 | static void __exit sunhv_exit(void) |
651 | { | 651 | { |
652 | of_unregister_platform_driver(&hv_driver); | 652 | platform_driver_unregister(&hv_driver); |
653 | } | 653 | } |
654 | 654 | ||
655 | module_init(sunhv_init); | 655 | module_init(sunhv_init); |
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 5b246b18f42f..b5fa2a57b9da 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c | |||
@@ -1006,7 +1006,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, | |||
1006 | return 0; | 1006 | return 0; |
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match) | 1009 | static int __devinit sab_probe(struct platform_device *op) |
1010 | { | 1010 | { |
1011 | static int inst; | 1011 | static int inst; |
1012 | struct uart_sunsab_port *up; | 1012 | struct uart_sunsab_port *up; |
@@ -1092,7 +1092,7 @@ static const struct of_device_id sab_match[] = { | |||
1092 | }; | 1092 | }; |
1093 | MODULE_DEVICE_TABLE(of, sab_match); | 1093 | MODULE_DEVICE_TABLE(of, sab_match); |
1094 | 1094 | ||
1095 | static struct of_platform_driver sab_driver = { | 1095 | static struct platform_driver sab_driver = { |
1096 | .driver = { | 1096 | .driver = { |
1097 | .name = "sab", | 1097 | .name = "sab", |
1098 | .owner = THIS_MODULE, | 1098 | .owner = THIS_MODULE, |
@@ -1130,12 +1130,12 @@ static int __init sunsab_init(void) | |||
1130 | } | 1130 | } |
1131 | } | 1131 | } |
1132 | 1132 | ||
1133 | return of_register_platform_driver(&sab_driver); | 1133 | return platform_driver_register(&sab_driver); |
1134 | } | 1134 | } |
1135 | 1135 | ||
1136 | static void __exit sunsab_exit(void) | 1136 | static void __exit sunsab_exit(void) |
1137 | { | 1137 | { |
1138 | of_unregister_platform_driver(&sab_driver); | 1138 | platform_driver_unregister(&sab_driver); |
1139 | if (sunsab_reg.nr) { | 1139 | if (sunsab_reg.nr) { |
1140 | sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); | 1140 | sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); |
1141 | } | 1141 | } |
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 551ebfe3ccbb..92aa54550e84 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c | |||
@@ -1406,7 +1406,7 @@ static enum su_type __devinit su_get_type(struct device_node *dp) | |||
1406 | return SU_PORT_PORT; | 1406 | return SU_PORT_PORT; |
1407 | } | 1407 | } |
1408 | 1408 | ||
1409 | static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match) | 1409 | static int __devinit su_probe(struct platform_device *op) |
1410 | { | 1410 | { |
1411 | static int inst; | 1411 | static int inst; |
1412 | struct device_node *dp = op->dev.of_node; | 1412 | struct device_node *dp = op->dev.of_node; |
@@ -1543,7 +1543,7 @@ static const struct of_device_id su_match[] = { | |||
1543 | }; | 1543 | }; |
1544 | MODULE_DEVICE_TABLE(of, su_match); | 1544 | MODULE_DEVICE_TABLE(of, su_match); |
1545 | 1545 | ||
1546 | static struct of_platform_driver su_driver = { | 1546 | static struct platform_driver su_driver = { |
1547 | .driver = { | 1547 | .driver = { |
1548 | .name = "su", | 1548 | .name = "su", |
1549 | .owner = THIS_MODULE, | 1549 | .owner = THIS_MODULE, |
@@ -1586,7 +1586,7 @@ static int __init sunsu_init(void) | |||
1586 | return err; | 1586 | return err; |
1587 | } | 1587 | } |
1588 | 1588 | ||
1589 | err = of_register_platform_driver(&su_driver); | 1589 | err = platform_driver_register(&su_driver); |
1590 | if (err && num_uart) | 1590 | if (err && num_uart) |
1591 | sunserial_unregister_minors(&sunsu_reg, num_uart); | 1591 | sunserial_unregister_minors(&sunsu_reg, num_uart); |
1592 | 1592 | ||
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index c1967ac1c07f..99ff9abf57ce 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c | |||
@@ -1399,7 +1399,7 @@ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) | |||
1399 | 1399 | ||
1400 | static int zilog_irq = -1; | 1400 | static int zilog_irq = -1; |
1401 | 1401 | ||
1402 | static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match) | 1402 | static int __devinit zs_probe(struct platform_device *op) |
1403 | { | 1403 | { |
1404 | static int kbm_inst, uart_inst; | 1404 | static int kbm_inst, uart_inst; |
1405 | int inst; | 1405 | int inst; |
@@ -1540,7 +1540,7 @@ static const struct of_device_id zs_match[] = { | |||
1540 | }; | 1540 | }; |
1541 | MODULE_DEVICE_TABLE(of, zs_match); | 1541 | MODULE_DEVICE_TABLE(of, zs_match); |
1542 | 1542 | ||
1543 | static struct of_platform_driver zs_driver = { | 1543 | static struct platform_driver zs_driver = { |
1544 | .driver = { | 1544 | .driver = { |
1545 | .name = "zs", | 1545 | .name = "zs", |
1546 | .owner = THIS_MODULE, | 1546 | .owner = THIS_MODULE, |
@@ -1576,7 +1576,7 @@ static int __init sunzilog_init(void) | |||
1576 | goto out_free_tables; | 1576 | goto out_free_tables; |
1577 | } | 1577 | } |
1578 | 1578 | ||
1579 | err = of_register_platform_driver(&zs_driver); | 1579 | err = platform_driver_register(&zs_driver); |
1580 | if (err) | 1580 | if (err) |
1581 | goto out_unregister_uart; | 1581 | goto out_unregister_uart; |
1582 | 1582 | ||
@@ -1604,7 +1604,7 @@ out: | |||
1604 | return err; | 1604 | return err; |
1605 | 1605 | ||
1606 | out_unregister_driver: | 1606 | out_unregister_driver: |
1607 | of_unregister_platform_driver(&zs_driver); | 1607 | platform_driver_unregister(&zs_driver); |
1608 | 1608 | ||
1609 | out_unregister_uart: | 1609 | out_unregister_uart: |
1610 | if (num_sunzilog) { | 1610 | if (num_sunzilog) { |
@@ -1619,7 +1619,7 @@ out_free_tables: | |||
1619 | 1619 | ||
1620 | static void __exit sunzilog_exit(void) | 1620 | static void __exit sunzilog_exit(void) |
1621 | { | 1621 | { |
1622 | of_unregister_platform_driver(&zs_driver); | 1622 | platform_driver_unregister(&zs_driver); |
1623 | 1623 | ||
1624 | if (zilog_irq != -1) { | 1624 | if (zilog_irq != -1) { |
1625 | struct uart_sunzilog_port *up = sunzilog_irq_chain; | 1625 | struct uart_sunzilog_port *up = sunzilog_irq_chain; |
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index d2fce865b731..8af1ed83a4c0 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c | |||
@@ -19,22 +19,11 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <asm/io.h> | 21 | #include <asm/io.h> |
22 | #if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) | ||
23 | #include <linux/of.h> | 22 | #include <linux/of.h> |
24 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
25 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
26 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
27 | 26 | ||
28 | /* Match table for of_platform binding */ | ||
29 | static struct of_device_id ulite_of_match[] __devinitdata = { | ||
30 | { .compatible = "xlnx,opb-uartlite-1.00.b", }, | ||
31 | { .compatible = "xlnx,xps-uartlite-1.00.a", }, | ||
32 | {} | ||
33 | }; | ||
34 | MODULE_DEVICE_TABLE(of, ulite_of_match); | ||
35 | |||
36 | #endif | ||
37 | |||
38 | #define ULITE_NAME "ttyUL" | 27 | #define ULITE_NAME "ttyUL" |
39 | #define ULITE_MAJOR 204 | 28 | #define ULITE_MAJOR 204 |
40 | #define ULITE_MINOR 187 | 29 | #define ULITE_MINOR 187 |
@@ -571,9 +560,29 @@ static int __devexit ulite_release(struct device *dev) | |||
571 | * Platform bus binding | 560 | * Platform bus binding |
572 | */ | 561 | */ |
573 | 562 | ||
563 | #if defined(CONFIG_OF) | ||
564 | /* Match table for of_platform binding */ | ||
565 | static struct of_device_id ulite_of_match[] __devinitdata = { | ||
566 | { .compatible = "xlnx,opb-uartlite-1.00.b", }, | ||
567 | { .compatible = "xlnx,xps-uartlite-1.00.a", }, | ||
568 | {} | ||
569 | }; | ||
570 | MODULE_DEVICE_TABLE(of, ulite_of_match); | ||
571 | #else /* CONFIG_OF */ | ||
572 | #define ulite_of_match NULL | ||
573 | #endif /* CONFIG_OF */ | ||
574 | |||
574 | static int __devinit ulite_probe(struct platform_device *pdev) | 575 | static int __devinit ulite_probe(struct platform_device *pdev) |
575 | { | 576 | { |
576 | struct resource *res, *res2; | 577 | struct resource *res, *res2; |
578 | int id = pdev->id; | ||
579 | #ifdef CONFIG_OF | ||
580 | const __be32 *prop; | ||
581 | |||
582 | prop = of_get_property(pdev->dev.of_node, "port-number", NULL); | ||
583 | if (prop) | ||
584 | id = be32_to_cpup(prop); | ||
585 | #endif | ||
577 | 586 | ||
578 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 587 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
579 | if (!res) | 588 | if (!res) |
@@ -583,7 +592,7 @@ static int __devinit ulite_probe(struct platform_device *pdev) | |||
583 | if (!res2) | 592 | if (!res2) |
584 | return -ENODEV; | 593 | return -ENODEV; |
585 | 594 | ||
586 | return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start); | 595 | return ulite_assign(&pdev->dev, id, res->start, res2->start); |
587 | } | 596 | } |
588 | 597 | ||
589 | static int __devexit ulite_remove(struct platform_device *pdev) | 598 | static int __devexit ulite_remove(struct platform_device *pdev) |
@@ -595,72 +604,15 @@ static int __devexit ulite_remove(struct platform_device *pdev) | |||
595 | MODULE_ALIAS("platform:uartlite"); | 604 | MODULE_ALIAS("platform:uartlite"); |
596 | 605 | ||
597 | static struct platform_driver ulite_platform_driver = { | 606 | static struct platform_driver ulite_platform_driver = { |
598 | .probe = ulite_probe, | 607 | .probe = ulite_probe, |
599 | .remove = __devexit_p(ulite_remove), | 608 | .remove = __devexit_p(ulite_remove), |
600 | .driver = { | ||
601 | .owner = THIS_MODULE, | ||
602 | .name = "uartlite", | ||
603 | }, | ||
604 | }; | ||
605 | |||
606 | /* --------------------------------------------------------------------- | ||
607 | * OF bus bindings | ||
608 | */ | ||
609 | #if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) | ||
610 | static int __devinit | ||
611 | ulite_of_probe(struct platform_device *op, const struct of_device_id *match) | ||
612 | { | ||
613 | struct resource res; | ||
614 | const unsigned int *id; | ||
615 | int irq, rc; | ||
616 | |||
617 | dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match); | ||
618 | |||
619 | rc = of_address_to_resource(op->dev.of_node, 0, &res); | ||
620 | if (rc) { | ||
621 | dev_err(&op->dev, "invalid address\n"); | ||
622 | return rc; | ||
623 | } | ||
624 | |||
625 | irq = irq_of_parse_and_map(op->dev.of_node, 0); | ||
626 | |||
627 | id = of_get_property(op->dev.of_node, "port-number", NULL); | ||
628 | |||
629 | return ulite_assign(&op->dev, id ? *id : -1, res.start, irq); | ||
630 | } | ||
631 | |||
632 | static int __devexit ulite_of_remove(struct platform_device *op) | ||
633 | { | ||
634 | return ulite_release(&op->dev); | ||
635 | } | ||
636 | |||
637 | static struct of_platform_driver ulite_of_driver = { | ||
638 | .probe = ulite_of_probe, | ||
639 | .remove = __devexit_p(ulite_of_remove), | ||
640 | .driver = { | 609 | .driver = { |
641 | .name = "uartlite", | ||
642 | .owner = THIS_MODULE, | 610 | .owner = THIS_MODULE, |
611 | .name = "uartlite", | ||
643 | .of_match_table = ulite_of_match, | 612 | .of_match_table = ulite_of_match, |
644 | }, | 613 | }, |
645 | }; | 614 | }; |
646 | 615 | ||
647 | /* Registration helpers to keep the number of #ifdefs to a minimum */ | ||
648 | static inline int __init ulite_of_register(void) | ||
649 | { | ||
650 | pr_debug("uartlite: calling of_register_platform_driver()\n"); | ||
651 | return of_register_platform_driver(&ulite_of_driver); | ||
652 | } | ||
653 | |||
654 | static inline void __exit ulite_of_unregister(void) | ||
655 | { | ||
656 | of_unregister_platform_driver(&ulite_of_driver); | ||
657 | } | ||
658 | #else /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ | ||
659 | /* Appropriate config not enabled; do nothing helpers */ | ||
660 | static inline int __init ulite_of_register(void) { return 0; } | ||
661 | static inline void __exit ulite_of_unregister(void) { } | ||
662 | #endif /* CONFIG_OF && (CONFIG_PPC32 || CONFIG_MICROBLAZE) */ | ||
663 | |||
664 | /* --------------------------------------------------------------------- | 616 | /* --------------------------------------------------------------------- |
665 | * Module setup/teardown | 617 | * Module setup/teardown |
666 | */ | 618 | */ |
@@ -674,10 +626,6 @@ int __init ulite_init(void) | |||
674 | if (ret) | 626 | if (ret) |
675 | goto err_uart; | 627 | goto err_uart; |
676 | 628 | ||
677 | ret = ulite_of_register(); | ||
678 | if (ret) | ||
679 | goto err_of; | ||
680 | |||
681 | pr_debug("uartlite: calling platform_driver_register()\n"); | 629 | pr_debug("uartlite: calling platform_driver_register()\n"); |
682 | ret = platform_driver_register(&ulite_platform_driver); | 630 | ret = platform_driver_register(&ulite_platform_driver); |
683 | if (ret) | 631 | if (ret) |
@@ -686,8 +634,6 @@ int __init ulite_init(void) | |||
686 | return 0; | 634 | return 0; |
687 | 635 | ||
688 | err_plat: | 636 | err_plat: |
689 | ulite_of_unregister(); | ||
690 | err_of: | ||
691 | uart_unregister_driver(&ulite_uart_driver); | 637 | uart_unregister_driver(&ulite_uart_driver); |
692 | err_uart: | 638 | err_uart: |
693 | printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); | 639 | printk(KERN_ERR "registering uartlite driver failed: err=%i", ret); |
@@ -697,7 +643,6 @@ err_uart: | |||
697 | void __exit ulite_exit(void) | 643 | void __exit ulite_exit(void) |
698 | { | 644 | { |
699 | platform_driver_unregister(&ulite_platform_driver); | 645 | platform_driver_unregister(&ulite_platform_driver); |
700 | ulite_of_unregister(); | ||
701 | uart_unregister_driver(&ulite_uart_driver); | 646 | uart_unregister_driver(&ulite_uart_driver); |
702 | } | 647 | } |
703 | 648 | ||
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 3f4848e2174a..ff51dae1df0c 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c | |||
@@ -1194,8 +1194,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context) | |||
1194 | release_firmware(fw); | 1194 | release_firmware(fw); |
1195 | } | 1195 | } |
1196 | 1196 | ||
1197 | static int ucc_uart_probe(struct platform_device *ofdev, | 1197 | static int ucc_uart_probe(struct platform_device *ofdev) |
1198 | const struct of_device_id *match) | ||
1199 | { | 1198 | { |
1200 | struct device_node *np = ofdev->dev.of_node; | 1199 | struct device_node *np = ofdev->dev.of_node; |
1201 | const unsigned int *iprop; /* Integer OF properties */ | 1200 | const unsigned int *iprop; /* Integer OF properties */ |
@@ -1485,7 +1484,7 @@ static struct of_device_id ucc_uart_match[] = { | |||
1485 | }; | 1484 | }; |
1486 | MODULE_DEVICE_TABLE(of, ucc_uart_match); | 1485 | MODULE_DEVICE_TABLE(of, ucc_uart_match); |
1487 | 1486 | ||
1488 | static struct of_platform_driver ucc_uart_of_driver = { | 1487 | static struct platform_driver ucc_uart_of_driver = { |
1489 | .driver = { | 1488 | .driver = { |
1490 | .name = "ucc_uart", | 1489 | .name = "ucc_uart", |
1491 | .owner = THIS_MODULE, | 1490 | .owner = THIS_MODULE, |
@@ -1510,7 +1509,7 @@ static int __init ucc_uart_init(void) | |||
1510 | return ret; | 1509 | return ret; |
1511 | } | 1510 | } |
1512 | 1511 | ||
1513 | ret = of_register_platform_driver(&ucc_uart_of_driver); | 1512 | ret = platform_driver_register(&ucc_uart_of_driver); |
1514 | if (ret) | 1513 | if (ret) |
1515 | printk(KERN_ERR | 1514 | printk(KERN_ERR |
1516 | "ucc-uart: could not register platform driver\n"); | 1515 | "ucc-uart: could not register platform driver\n"); |
@@ -1523,7 +1522,7 @@ static void __exit ucc_uart_exit(void) | |||
1523 | printk(KERN_INFO | 1522 | printk(KERN_INFO |
1524 | "Freescale QUICC Engine UART device driver unloading\n"); | 1523 | "Freescale QUICC Engine UART device driver unloading\n"); |
1525 | 1524 | ||
1526 | of_unregister_platform_driver(&ucc_uart_of_driver); | 1525 | platform_driver_unregister(&ucc_uart_of_driver); |
1527 | uart_unregister_driver(&ucc_uart_driver); | 1526 | uart_unregister_driver(&ucc_uart_driver); |
1528 | } | 1527 | } |
1529 | 1528 | ||
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c new file mode 100644 index 000000000000..18888d005a0a --- /dev/null +++ b/drivers/tty/synclink.c | |||
@@ -0,0 +1,8119 @@ | |||
1 | /* | ||
2 | * linux/drivers/char/synclink.c | ||
3 | * | ||
4 | * $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $ | ||
5 | * | ||
6 | * Device driver for Microgate SyncLink ISA and PCI | ||
7 | * high speed multiprotocol serial adapters. | ||
8 | * | ||
9 | * written by Paul Fulghum for Microgate Corporation | ||
10 | * paulkf@microgate.com | ||
11 | * | ||
12 | * Microgate and SyncLink are trademarks of Microgate Corporation | ||
13 | * | ||
14 | * Derived from serial.c written by Theodore Ts'o and Linus Torvalds | ||
15 | * | ||
16 | * Original release 01/11/99 | ||
17 | * | ||
18 | * This code is released under the GNU General Public License (GPL) | ||
19 | * | ||
20 | * This driver is primarily intended for use in synchronous | ||
21 | * HDLC mode. Asynchronous mode is also provided. | ||
22 | * | ||
23 | * When operating in synchronous mode, each call to mgsl_write() | ||
24 | * contains exactly one complete HDLC frame. Calling mgsl_put_char | ||
25 | * will start assembling an HDLC frame that will not be sent until | ||
26 | * mgsl_flush_chars or mgsl_write is called. | ||
27 | * | ||
28 | * Synchronous receive data is reported as complete frames. To accomplish | ||
29 | * this, the TTY flip buffer is bypassed (too small to hold largest | ||
30 | * frame and may fragment frames) and the line discipline | ||
31 | * receive entry point is called directly. | ||
32 | * | ||
33 | * This driver has been tested with a slightly modified ppp.c driver | ||
34 | * for synchronous PPP. | ||
35 | * | ||
36 | * 2000/02/16 | ||
37 | * Added interface for syncppp.c driver (an alternate synchronous PPP | ||
38 | * implementation that also supports Cisco HDLC). Each device instance | ||
39 | * registers as a tty device AND a network device (if dosyncppp option | ||
40 | * is set for the device). The functionality is determined by which | ||
41 | * device interface is opened. | ||
42 | * | ||
43 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
44 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
45 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
46 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
47 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
48 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
49 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
50 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
51 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
52 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
53 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
54 | */ | ||
55 | |||
56 | #if defined(__i386__) | ||
57 | # define BREAKPOINT() asm(" int $3"); | ||
58 | #else | ||
59 | # define BREAKPOINT() { } | ||
60 | #endif | ||
61 | |||
62 | #define MAX_ISA_DEVICES 10 | ||
63 | #define MAX_PCI_DEVICES 10 | ||
64 | #define MAX_TOTAL_DEVICES 20 | ||
65 | |||
66 | #include <linux/module.h> | ||
67 | #include <linux/errno.h> | ||
68 | #include <linux/signal.h> | ||
69 | #include <linux/sched.h> | ||
70 | #include <linux/timer.h> | ||
71 | #include <linux/interrupt.h> | ||
72 | #include <linux/pci.h> | ||
73 | #include <linux/tty.h> | ||
74 | #include <linux/tty_flip.h> | ||
75 | #include <linux/serial.h> | ||
76 | #include <linux/major.h> | ||
77 | #include <linux/string.h> | ||
78 | #include <linux/fcntl.h> | ||
79 | #include <linux/ptrace.h> | ||
80 | #include <linux/ioport.h> | ||
81 | #include <linux/mm.h> | ||
82 | #include <linux/seq_file.h> | ||
83 | #include <linux/slab.h> | ||
84 | #include <linux/delay.h> | ||
85 | #include <linux/netdevice.h> | ||
86 | #include <linux/vmalloc.h> | ||
87 | #include <linux/init.h> | ||
88 | #include <linux/ioctl.h> | ||
89 | #include <linux/synclink.h> | ||
90 | |||
91 | #include <asm/system.h> | ||
92 | #include <asm/io.h> | ||
93 | #include <asm/irq.h> | ||
94 | #include <asm/dma.h> | ||
95 | #include <linux/bitops.h> | ||
96 | #include <asm/types.h> | ||
97 | #include <linux/termios.h> | ||
98 | #include <linux/workqueue.h> | ||
99 | #include <linux/hdlc.h> | ||
100 | #include <linux/dma-mapping.h> | ||
101 | |||
102 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_MODULE)) | ||
103 | #define SYNCLINK_GENERIC_HDLC 1 | ||
104 | #else | ||
105 | #define SYNCLINK_GENERIC_HDLC 0 | ||
106 | #endif | ||
107 | |||
108 | #define GET_USER(error,value,addr) error = get_user(value,addr) | ||
109 | #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 | ||
110 | #define PUT_USER(error,value,addr) error = put_user(value,addr) | ||
111 | #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 | ||
112 | |||
113 | #include <asm/uaccess.h> | ||
114 | |||
115 | #define RCLRVALUE 0xffff | ||
116 | |||
117 | static MGSL_PARAMS default_params = { | ||
118 | MGSL_MODE_HDLC, /* unsigned long mode */ | ||
119 | 0, /* unsigned char loopback; */ | ||
120 | HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ | ||
121 | HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ | ||
122 | 0, /* unsigned long clock_speed; */ | ||
123 | 0xff, /* unsigned char addr_filter; */ | ||
124 | HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ | ||
125 | HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ | ||
126 | HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ | ||
127 | 9600, /* unsigned long data_rate; */ | ||
128 | 8, /* unsigned char data_bits; */ | ||
129 | 1, /* unsigned char stop_bits; */ | ||
130 | ASYNC_PARITY_NONE /* unsigned char parity; */ | ||
131 | }; | ||
132 | |||
133 | #define SHARED_MEM_ADDRESS_SIZE 0x40000 | ||
134 | #define BUFFERLISTSIZE 4096 | ||
135 | #define DMABUFFERSIZE 4096 | ||
136 | #define MAXRXFRAMES 7 | ||
137 | |||
138 | typedef struct _DMABUFFERENTRY | ||
139 | { | ||
140 | u32 phys_addr; /* 32-bit flat physical address of data buffer */ | ||
141 | volatile u16 count; /* buffer size/data count */ | ||
142 | volatile u16 status; /* Control/status field */ | ||
143 | volatile u16 rcc; /* character count field */ | ||
144 | u16 reserved; /* padding required by 16C32 */ | ||
145 | u32 link; /* 32-bit flat link to next buffer entry */ | ||
146 | char *virt_addr; /* virtual address of data buffer */ | ||
147 | u32 phys_entry; /* physical address of this buffer entry */ | ||
148 | dma_addr_t dma_addr; | ||
149 | } DMABUFFERENTRY, *DMAPBUFFERENTRY; | ||
150 | |||
151 | /* The queue of BH actions to be performed */ | ||
152 | |||
153 | #define BH_RECEIVE 1 | ||
154 | #define BH_TRANSMIT 2 | ||
155 | #define BH_STATUS 4 | ||
156 | |||
157 | #define IO_PIN_SHUTDOWN_LIMIT 100 | ||
158 | |||
159 | struct _input_signal_events { | ||
160 | int ri_up; | ||
161 | int ri_down; | ||
162 | int dsr_up; | ||
163 | int dsr_down; | ||
164 | int dcd_up; | ||
165 | int dcd_down; | ||
166 | int cts_up; | ||
167 | int cts_down; | ||
168 | }; | ||
169 | |||
170 | /* transmit holding buffer definitions*/ | ||
171 | #define MAX_TX_HOLDING_BUFFERS 5 | ||
172 | struct tx_holding_buffer { | ||
173 | int buffer_size; | ||
174 | unsigned char * buffer; | ||
175 | }; | ||
176 | |||
177 | |||
178 | /* | ||
179 | * Device instance data structure | ||
180 | */ | ||
181 | |||
182 | struct mgsl_struct { | ||
183 | int magic; | ||
184 | struct tty_port port; | ||
185 | int line; | ||
186 | int hw_version; | ||
187 | |||
188 | struct mgsl_icount icount; | ||
189 | |||
190 | int timeout; | ||
191 | int x_char; /* xon/xoff character */ | ||
192 | u16 read_status_mask; | ||
193 | u16 ignore_status_mask; | ||
194 | unsigned char *xmit_buf; | ||
195 | int xmit_head; | ||
196 | int xmit_tail; | ||
197 | int xmit_cnt; | ||
198 | |||
199 | wait_queue_head_t status_event_wait_q; | ||
200 | wait_queue_head_t event_wait_q; | ||
201 | struct timer_list tx_timer; /* HDLC transmit timeout timer */ | ||
202 | struct mgsl_struct *next_device; /* device list link */ | ||
203 | |||
204 | spinlock_t irq_spinlock; /* spinlock for synchronizing with ISR */ | ||
205 | struct work_struct task; /* task structure for scheduling bh */ | ||
206 | |||
207 | u32 EventMask; /* event trigger mask */ | ||
208 | u32 RecordedEvents; /* pending events */ | ||
209 | |||
210 | u32 max_frame_size; /* as set by device config */ | ||
211 | |||
212 | u32 pending_bh; | ||
213 | |||
214 | bool bh_running; /* Protection from multiple */ | ||
215 | int isr_overflow; | ||
216 | bool bh_requested; | ||
217 | |||
218 | int dcd_chkcount; /* check counts to prevent */ | ||
219 | int cts_chkcount; /* too many IRQs if a signal */ | ||
220 | int dsr_chkcount; /* is floating */ | ||
221 | int ri_chkcount; | ||
222 | |||
223 | char *buffer_list; /* virtual address of Rx & Tx buffer lists */ | ||
224 | u32 buffer_list_phys; | ||
225 | dma_addr_t buffer_list_dma_addr; | ||
226 | |||
227 | unsigned int rx_buffer_count; /* count of total allocated Rx buffers */ | ||
228 | DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */ | ||
229 | unsigned int current_rx_buffer; | ||
230 | |||
231 | int num_tx_dma_buffers; /* number of tx dma frames required */ | ||
232 | int tx_dma_buffers_used; | ||
233 | unsigned int tx_buffer_count; /* count of total allocated Tx buffers */ | ||
234 | DMABUFFERENTRY *tx_buffer_list; /* list of transmit buffer entries */ | ||
235 | int start_tx_dma_buffer; /* tx dma buffer to start tx dma operation */ | ||
236 | int current_tx_buffer; /* next tx dma buffer to be loaded */ | ||
237 | |||
238 | unsigned char *intermediate_rxbuffer; | ||
239 | |||
240 | int num_tx_holding_buffers; /* number of tx holding buffer allocated */ | ||
241 | int get_tx_holding_index; /* next tx holding buffer for adapter to load */ | ||
242 | int put_tx_holding_index; /* next tx holding buffer to store user request */ | ||
243 | int tx_holding_count; /* number of tx holding buffers waiting */ | ||
244 | struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS]; | ||
245 | |||
246 | bool rx_enabled; | ||
247 | bool rx_overflow; | ||
248 | bool rx_rcc_underrun; | ||
249 | |||
250 | bool tx_enabled; | ||
251 | bool tx_active; | ||
252 | u32 idle_mode; | ||
253 | |||
254 | u16 cmr_value; | ||
255 | u16 tcsr_value; | ||
256 | |||
257 | char device_name[25]; /* device instance name */ | ||
258 | |||
259 | unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ | ||
260 | unsigned char bus; /* expansion bus number (zero based) */ | ||
261 | unsigned char function; /* PCI device number */ | ||
262 | |||
263 | unsigned int io_base; /* base I/O address of adapter */ | ||
264 | unsigned int io_addr_size; /* size of the I/O address range */ | ||
265 | bool io_addr_requested; /* true if I/O address requested */ | ||
266 | |||
267 | unsigned int irq_level; /* interrupt level */ | ||
268 | unsigned long irq_flags; | ||
269 | bool irq_requested; /* true if IRQ requested */ | ||
270 | |||
271 | unsigned int dma_level; /* DMA channel */ | ||
272 | bool dma_requested; /* true if dma channel requested */ | ||
273 | |||
274 | u16 mbre_bit; | ||
275 | u16 loopback_bits; | ||
276 | u16 usc_idle_mode; | ||
277 | |||
278 | MGSL_PARAMS params; /* communications parameters */ | ||
279 | |||
280 | unsigned char serial_signals; /* current serial signal states */ | ||
281 | |||
282 | bool irq_occurred; /* for diagnostics use */ | ||
283 | unsigned int init_error; /* Initialization startup error (DIAGS) */ | ||
284 | int fDiagnosticsmode; /* Driver in Diagnostic mode? (DIAGS) */ | ||
285 | |||
286 | u32 last_mem_alloc; | ||
287 | unsigned char* memory_base; /* shared memory address (PCI only) */ | ||
288 | u32 phys_memory_base; | ||
289 | bool shared_mem_requested; | ||
290 | |||
291 | unsigned char* lcr_base; /* local config registers (PCI only) */ | ||
292 | u32 phys_lcr_base; | ||
293 | u32 lcr_offset; | ||
294 | bool lcr_mem_requested; | ||
295 | |||
296 | u32 misc_ctrl_value; | ||
297 | char flag_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
298 | char char_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
299 | bool drop_rts_on_tx_done; | ||
300 | |||
301 | bool loopmode_insert_requested; | ||
302 | bool loopmode_send_done_requested; | ||
303 | |||
304 | struct _input_signal_events input_signal_events; | ||
305 | |||
306 | /* generic HDLC device parts */ | ||
307 | int netcount; | ||
308 | spinlock_t netlock; | ||
309 | |||
310 | #if SYNCLINK_GENERIC_HDLC | ||
311 | struct net_device *netdev; | ||
312 | #endif | ||
313 | }; | ||
314 | |||
315 | #define MGSL_MAGIC 0x5401 | ||
316 | |||
317 | /* | ||
318 | * The size of the serial xmit buffer is 1 page, or 4096 bytes | ||
319 | */ | ||
320 | #ifndef SERIAL_XMIT_SIZE | ||
321 | #define SERIAL_XMIT_SIZE 4096 | ||
322 | #endif | ||
323 | |||
324 | /* | ||
325 | * These macros define the offsets used in calculating the | ||
326 | * I/O address of the specified USC registers. | ||
327 | */ | ||
328 | |||
329 | |||
330 | #define DCPIN 2 /* Bit 1 of I/O address */ | ||
331 | #define SDPIN 4 /* Bit 2 of I/O address */ | ||
332 | |||
333 | #define DCAR 0 /* DMA command/address register */ | ||
334 | #define CCAR SDPIN /* channel command/address register */ | ||
335 | #define DATAREG DCPIN + SDPIN /* serial data register */ | ||
336 | #define MSBONLY 0x41 | ||
337 | #define LSBONLY 0x40 | ||
338 | |||
339 | /* | ||
340 | * These macros define the register address (ordinal number) | ||
341 | * used for writing address/value pairs to the USC. | ||
342 | */ | ||
343 | |||
344 | #define CMR 0x02 /* Channel mode Register */ | ||
345 | #define CCSR 0x04 /* Channel Command/status Register */ | ||
346 | #define CCR 0x06 /* Channel Control Register */ | ||
347 | #define PSR 0x08 /* Port status Register */ | ||
348 | #define PCR 0x0a /* Port Control Register */ | ||
349 | #define TMDR 0x0c /* Test mode Data Register */ | ||
350 | #define TMCR 0x0e /* Test mode Control Register */ | ||
351 | #define CMCR 0x10 /* Clock mode Control Register */ | ||
352 | #define HCR 0x12 /* Hardware Configuration Register */ | ||
353 | #define IVR 0x14 /* Interrupt Vector Register */ | ||
354 | #define IOCR 0x16 /* Input/Output Control Register */ | ||
355 | #define ICR 0x18 /* Interrupt Control Register */ | ||
356 | #define DCCR 0x1a /* Daisy Chain Control Register */ | ||
357 | #define MISR 0x1c /* Misc Interrupt status Register */ | ||
358 | #define SICR 0x1e /* status Interrupt Control Register */ | ||
359 | #define RDR 0x20 /* Receive Data Register */ | ||
360 | #define RMR 0x22 /* Receive mode Register */ | ||
361 | #define RCSR 0x24 /* Receive Command/status Register */ | ||
362 | #define RICR 0x26 /* Receive Interrupt Control Register */ | ||
363 | #define RSR 0x28 /* Receive Sync Register */ | ||
364 | #define RCLR 0x2a /* Receive count Limit Register */ | ||
365 | #define RCCR 0x2c /* Receive Character count Register */ | ||
366 | #define TC0R 0x2e /* Time Constant 0 Register */ | ||
367 | #define TDR 0x30 /* Transmit Data Register */ | ||
368 | #define TMR 0x32 /* Transmit mode Register */ | ||
369 | #define TCSR 0x34 /* Transmit Command/status Register */ | ||
370 | #define TICR 0x36 /* Transmit Interrupt Control Register */ | ||
371 | #define TSR 0x38 /* Transmit Sync Register */ | ||
372 | #define TCLR 0x3a /* Transmit count Limit Register */ | ||
373 | #define TCCR 0x3c /* Transmit Character count Register */ | ||
374 | #define TC1R 0x3e /* Time Constant 1 Register */ | ||
375 | |||
376 | |||
377 | /* | ||
378 | * MACRO DEFINITIONS FOR DMA REGISTERS | ||
379 | */ | ||
380 | |||
381 | #define DCR 0x06 /* DMA Control Register (shared) */ | ||
382 | #define DACR 0x08 /* DMA Array count Register (shared) */ | ||
383 | #define BDCR 0x12 /* Burst/Dwell Control Register (shared) */ | ||
384 | #define DIVR 0x14 /* DMA Interrupt Vector Register (shared) */ | ||
385 | #define DICR 0x18 /* DMA Interrupt Control Register (shared) */ | ||
386 | #define CDIR 0x1a /* Clear DMA Interrupt Register (shared) */ | ||
387 | #define SDIR 0x1c /* Set DMA Interrupt Register (shared) */ | ||
388 | |||
389 | #define TDMR 0x02 /* Transmit DMA mode Register */ | ||
390 | #define TDIAR 0x1e /* Transmit DMA Interrupt Arm Register */ | ||
391 | #define TBCR 0x2a /* Transmit Byte count Register */ | ||
392 | #define TARL 0x2c /* Transmit Address Register (low) */ | ||
393 | #define TARU 0x2e /* Transmit Address Register (high) */ | ||
394 | #define NTBCR 0x3a /* Next Transmit Byte count Register */ | ||
395 | #define NTARL 0x3c /* Next Transmit Address Register (low) */ | ||
396 | #define NTARU 0x3e /* Next Transmit Address Register (high) */ | ||
397 | |||
398 | #define RDMR 0x82 /* Receive DMA mode Register (non-shared) */ | ||
399 | #define RDIAR 0x9e /* Receive DMA Interrupt Arm Register */ | ||
400 | #define RBCR 0xaa /* Receive Byte count Register */ | ||
401 | #define RARL 0xac /* Receive Address Register (low) */ | ||
402 | #define RARU 0xae /* Receive Address Register (high) */ | ||
403 | #define NRBCR 0xba /* Next Receive Byte count Register */ | ||
404 | #define NRARL 0xbc /* Next Receive Address Register (low) */ | ||
405 | #define NRARU 0xbe /* Next Receive Address Register (high) */ | ||
406 | |||
407 | |||
408 | /* | ||
409 | * MACRO DEFINITIONS FOR MODEM STATUS BITS | ||
410 | */ | ||
411 | |||
412 | #define MODEMSTATUS_DTR 0x80 | ||
413 | #define MODEMSTATUS_DSR 0x40 | ||
414 | #define MODEMSTATUS_RTS 0x20 | ||
415 | #define MODEMSTATUS_CTS 0x10 | ||
416 | #define MODEMSTATUS_RI 0x04 | ||
417 | #define MODEMSTATUS_DCD 0x01 | ||
418 | |||
419 | |||
420 | /* | ||
421 | * Channel Command/Address Register (CCAR) Command Codes | ||
422 | */ | ||
423 | |||
424 | #define RTCmd_Null 0x0000 | ||
425 | #define RTCmd_ResetHighestIus 0x1000 | ||
426 | #define RTCmd_TriggerChannelLoadDma 0x2000 | ||
427 | #define RTCmd_TriggerRxDma 0x2800 | ||
428 | #define RTCmd_TriggerTxDma 0x3000 | ||
429 | #define RTCmd_TriggerRxAndTxDma 0x3800 | ||
430 | #define RTCmd_PurgeRxFifo 0x4800 | ||
431 | #define RTCmd_PurgeTxFifo 0x5000 | ||
432 | #define RTCmd_PurgeRxAndTxFifo 0x5800 | ||
433 | #define RTCmd_LoadRcc 0x6800 | ||
434 | #define RTCmd_LoadTcc 0x7000 | ||
435 | #define RTCmd_LoadRccAndTcc 0x7800 | ||
436 | #define RTCmd_LoadTC0 0x8800 | ||
437 | #define RTCmd_LoadTC1 0x9000 | ||
438 | #define RTCmd_LoadTC0AndTC1 0x9800 | ||
439 | #define RTCmd_SerialDataLSBFirst 0xa000 | ||
440 | #define RTCmd_SerialDataMSBFirst 0xa800 | ||
441 | #define RTCmd_SelectBigEndian 0xb000 | ||
442 | #define RTCmd_SelectLittleEndian 0xb800 | ||
443 | |||
444 | |||
445 | /* | ||
446 | * DMA Command/Address Register (DCAR) Command Codes | ||
447 | */ | ||
448 | |||
449 | #define DmaCmd_Null 0x0000 | ||
450 | #define DmaCmd_ResetTxChannel 0x1000 | ||
451 | #define DmaCmd_ResetRxChannel 0x1200 | ||
452 | #define DmaCmd_StartTxChannel 0x2000 | ||
453 | #define DmaCmd_StartRxChannel 0x2200 | ||
454 | #define DmaCmd_ContinueTxChannel 0x3000 | ||
455 | #define DmaCmd_ContinueRxChannel 0x3200 | ||
456 | #define DmaCmd_PauseTxChannel 0x4000 | ||
457 | #define DmaCmd_PauseRxChannel 0x4200 | ||
458 | #define DmaCmd_AbortTxChannel 0x5000 | ||
459 | #define DmaCmd_AbortRxChannel 0x5200 | ||
460 | #define DmaCmd_InitTxChannel 0x7000 | ||
461 | #define DmaCmd_InitRxChannel 0x7200 | ||
462 | #define DmaCmd_ResetHighestDmaIus 0x8000 | ||
463 | #define DmaCmd_ResetAllChannels 0x9000 | ||
464 | #define DmaCmd_StartAllChannels 0xa000 | ||
465 | #define DmaCmd_ContinueAllChannels 0xb000 | ||
466 | #define DmaCmd_PauseAllChannels 0xc000 | ||
467 | #define DmaCmd_AbortAllChannels 0xd000 | ||
468 | #define DmaCmd_InitAllChannels 0xf000 | ||
469 | |||
470 | #define TCmd_Null 0x0000 | ||
471 | #define TCmd_ClearTxCRC 0x2000 | ||
472 | #define TCmd_SelectTicrTtsaData 0x4000 | ||
473 | #define TCmd_SelectTicrTxFifostatus 0x5000 | ||
474 | #define TCmd_SelectTicrIntLevel 0x6000 | ||
475 | #define TCmd_SelectTicrdma_level 0x7000 | ||
476 | #define TCmd_SendFrame 0x8000 | ||
477 | #define TCmd_SendAbort 0x9000 | ||
478 | #define TCmd_EnableDleInsertion 0xc000 | ||
479 | #define TCmd_DisableDleInsertion 0xd000 | ||
480 | #define TCmd_ClearEofEom 0xe000 | ||
481 | #define TCmd_SetEofEom 0xf000 | ||
482 | |||
483 | #define RCmd_Null 0x0000 | ||
484 | #define RCmd_ClearRxCRC 0x2000 | ||
485 | #define RCmd_EnterHuntmode 0x3000 | ||
486 | #define RCmd_SelectRicrRtsaData 0x4000 | ||
487 | #define RCmd_SelectRicrRxFifostatus 0x5000 | ||
488 | #define RCmd_SelectRicrIntLevel 0x6000 | ||
489 | #define RCmd_SelectRicrdma_level 0x7000 | ||
490 | |||
491 | /* | ||
492 | * Bits for enabling and disabling IRQs in Interrupt Control Register (ICR) | ||
493 | */ | ||
494 | |||
495 | #define RECEIVE_STATUS BIT5 | ||
496 | #define RECEIVE_DATA BIT4 | ||
497 | #define TRANSMIT_STATUS BIT3 | ||
498 | #define TRANSMIT_DATA BIT2 | ||
499 | #define IO_PIN BIT1 | ||
500 | #define MISC BIT0 | ||
501 | |||
502 | |||
503 | /* | ||
504 | * Receive status Bits in Receive Command/status Register RCSR | ||
505 | */ | ||
506 | |||
507 | #define RXSTATUS_SHORT_FRAME BIT8 | ||
508 | #define RXSTATUS_CODE_VIOLATION BIT8 | ||
509 | #define RXSTATUS_EXITED_HUNT BIT7 | ||
510 | #define RXSTATUS_IDLE_RECEIVED BIT6 | ||
511 | #define RXSTATUS_BREAK_RECEIVED BIT5 | ||
512 | #define RXSTATUS_ABORT_RECEIVED BIT5 | ||
513 | #define RXSTATUS_RXBOUND BIT4 | ||
514 | #define RXSTATUS_CRC_ERROR BIT3 | ||
515 | #define RXSTATUS_FRAMING_ERROR BIT3 | ||
516 | #define RXSTATUS_ABORT BIT2 | ||
517 | #define RXSTATUS_PARITY_ERROR BIT2 | ||
518 | #define RXSTATUS_OVERRUN BIT1 | ||
519 | #define RXSTATUS_DATA_AVAILABLE BIT0 | ||
520 | #define RXSTATUS_ALL 0x01f6 | ||
521 | #define usc_UnlatchRxstatusBits(a,b) usc_OutReg( (a), RCSR, (u16)((b) & RXSTATUS_ALL) ) | ||
522 | |||
523 | /* | ||
524 | * Values for setting transmit idle mode in | ||
525 | * Transmit Control/status Register (TCSR) | ||
526 | */ | ||
527 | #define IDLEMODE_FLAGS 0x0000 | ||
528 | #define IDLEMODE_ALT_ONE_ZERO 0x0100 | ||
529 | #define IDLEMODE_ZERO 0x0200 | ||
530 | #define IDLEMODE_ONE 0x0300 | ||
531 | #define IDLEMODE_ALT_MARK_SPACE 0x0500 | ||
532 | #define IDLEMODE_SPACE 0x0600 | ||
533 | #define IDLEMODE_MARK 0x0700 | ||
534 | #define IDLEMODE_MASK 0x0700 | ||
535 | |||
536 | /* | ||
537 | * IUSC revision identifiers | ||
538 | */ | ||
539 | #define IUSC_SL1660 0x4d44 | ||
540 | #define IUSC_PRE_SL1660 0x4553 | ||
541 | |||
542 | /* | ||
543 | * Transmit status Bits in Transmit Command/status Register (TCSR) | ||
544 | */ | ||
545 | |||
546 | #define TCSR_PRESERVE 0x0F00 | ||
547 | |||
548 | #define TCSR_UNDERWAIT BIT11 | ||
549 | #define TXSTATUS_PREAMBLE_SENT BIT7 | ||
550 | #define TXSTATUS_IDLE_SENT BIT6 | ||
551 | #define TXSTATUS_ABORT_SENT BIT5 | ||
552 | #define TXSTATUS_EOF_SENT BIT4 | ||
553 | #define TXSTATUS_EOM_SENT BIT4 | ||
554 | #define TXSTATUS_CRC_SENT BIT3 | ||
555 | #define TXSTATUS_ALL_SENT BIT2 | ||
556 | #define TXSTATUS_UNDERRUN BIT1 | ||
557 | #define TXSTATUS_FIFO_EMPTY BIT0 | ||
558 | #define TXSTATUS_ALL 0x00fa | ||
559 | #define usc_UnlatchTxstatusBits(a,b) usc_OutReg( (a), TCSR, (u16)((a)->tcsr_value + ((b) & 0x00FF)) ) | ||
560 | |||
561 | |||
562 | #define MISCSTATUS_RXC_LATCHED BIT15 | ||
563 | #define MISCSTATUS_RXC BIT14 | ||
564 | #define MISCSTATUS_TXC_LATCHED BIT13 | ||
565 | #define MISCSTATUS_TXC BIT12 | ||
566 | #define MISCSTATUS_RI_LATCHED BIT11 | ||
567 | #define MISCSTATUS_RI BIT10 | ||
568 | #define MISCSTATUS_DSR_LATCHED BIT9 | ||
569 | #define MISCSTATUS_DSR BIT8 | ||
570 | #define MISCSTATUS_DCD_LATCHED BIT7 | ||
571 | #define MISCSTATUS_DCD BIT6 | ||
572 | #define MISCSTATUS_CTS_LATCHED BIT5 | ||
573 | #define MISCSTATUS_CTS BIT4 | ||
574 | #define MISCSTATUS_RCC_UNDERRUN BIT3 | ||
575 | #define MISCSTATUS_DPLL_NO_SYNC BIT2 | ||
576 | #define MISCSTATUS_BRG1_ZERO BIT1 | ||
577 | #define MISCSTATUS_BRG0_ZERO BIT0 | ||
578 | |||
579 | #define usc_UnlatchIostatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0xaaa0)) | ||
580 | #define usc_UnlatchMiscstatusBits(a,b) usc_OutReg((a),MISR,(u16)((b) & 0x000f)) | ||
581 | |||
582 | #define SICR_RXC_ACTIVE BIT15 | ||
583 | #define SICR_RXC_INACTIVE BIT14 | ||
584 | #define SICR_RXC (BIT15+BIT14) | ||
585 | #define SICR_TXC_ACTIVE BIT13 | ||
586 | #define SICR_TXC_INACTIVE BIT12 | ||
587 | #define SICR_TXC (BIT13+BIT12) | ||
588 | #define SICR_RI_ACTIVE BIT11 | ||
589 | #define SICR_RI_INACTIVE BIT10 | ||
590 | #define SICR_RI (BIT11+BIT10) | ||
591 | #define SICR_DSR_ACTIVE BIT9 | ||
592 | #define SICR_DSR_INACTIVE BIT8 | ||
593 | #define SICR_DSR (BIT9+BIT8) | ||
594 | #define SICR_DCD_ACTIVE BIT7 | ||
595 | #define SICR_DCD_INACTIVE BIT6 | ||
596 | #define SICR_DCD (BIT7+BIT6) | ||
597 | #define SICR_CTS_ACTIVE BIT5 | ||
598 | #define SICR_CTS_INACTIVE BIT4 | ||
599 | #define SICR_CTS (BIT5+BIT4) | ||
600 | #define SICR_RCC_UNDERFLOW BIT3 | ||
601 | #define SICR_DPLL_NO_SYNC BIT2 | ||
602 | #define SICR_BRG1_ZERO BIT1 | ||
603 | #define SICR_BRG0_ZERO BIT0 | ||
604 | |||
605 | void usc_DisableMasterIrqBit( struct mgsl_struct *info ); | ||
606 | void usc_EnableMasterIrqBit( struct mgsl_struct *info ); | ||
607 | void usc_EnableInterrupts( struct mgsl_struct *info, u16 IrqMask ); | ||
608 | void usc_DisableInterrupts( struct mgsl_struct *info, u16 IrqMask ); | ||
609 | void usc_ClearIrqPendingBits( struct mgsl_struct *info, u16 IrqMask ); | ||
610 | |||
611 | #define usc_EnableInterrupts( a, b ) \ | ||
612 | usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0xc0 + (b)) ) | ||
613 | |||
614 | #define usc_DisableInterrupts( a, b ) \ | ||
615 | usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0xff00) + 0x80 + (b)) ) | ||
616 | |||
617 | #define usc_EnableMasterIrqBit(a) \ | ||
618 | usc_OutReg( (a), ICR, (u16)((usc_InReg((a),ICR) & 0x0f00) + 0xb000) ) | ||
619 | |||
620 | #define usc_DisableMasterIrqBit(a) \ | ||
621 | usc_OutReg( (a), ICR, (u16)(usc_InReg((a),ICR) & 0x7f00) ) | ||
622 | |||
623 | #define usc_ClearIrqPendingBits( a, b ) usc_OutReg( (a), DCCR, 0x40 + (b) ) | ||
624 | |||
625 | /* | ||
626 | * Transmit status Bits in Transmit Control status Register (TCSR) | ||
627 | * and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) | ||
628 | */ | ||
629 | |||
630 | #define TXSTATUS_PREAMBLE_SENT BIT7 | ||
631 | #define TXSTATUS_IDLE_SENT BIT6 | ||
632 | #define TXSTATUS_ABORT_SENT BIT5 | ||
633 | #define TXSTATUS_EOF BIT4 | ||
634 | #define TXSTATUS_CRC_SENT BIT3 | ||
635 | #define TXSTATUS_ALL_SENT BIT2 | ||
636 | #define TXSTATUS_UNDERRUN BIT1 | ||
637 | #define TXSTATUS_FIFO_EMPTY BIT0 | ||
638 | |||
639 | #define DICR_MASTER BIT15 | ||
640 | #define DICR_TRANSMIT BIT0 | ||
641 | #define DICR_RECEIVE BIT1 | ||
642 | |||
643 | #define usc_EnableDmaInterrupts(a,b) \ | ||
644 | usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) | (b)) ) | ||
645 | |||
646 | #define usc_DisableDmaInterrupts(a,b) \ | ||
647 | usc_OutDmaReg( (a), DICR, (u16)(usc_InDmaReg((a),DICR) & ~(b)) ) | ||
648 | |||
649 | #define usc_EnableStatusIrqs(a,b) \ | ||
650 | usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) | (b)) ) | ||
651 | |||
652 | #define usc_DisablestatusIrqs(a,b) \ | ||
653 | usc_OutReg( (a), SICR, (u16)(usc_InReg((a),SICR) & ~(b)) ) | ||
654 | |||
655 | /* Transmit status Bits in Transmit Control status Register (TCSR) */ | ||
656 | /* and Transmit Interrupt Control Register (TICR) (except BIT2, BIT0) */ | ||
657 | |||
658 | |||
659 | #define DISABLE_UNCONDITIONAL 0 | ||
660 | #define DISABLE_END_OF_FRAME 1 | ||
661 | #define ENABLE_UNCONDITIONAL 2 | ||
662 | #define ENABLE_AUTO_CTS 3 | ||
663 | #define ENABLE_AUTO_DCD 3 | ||
664 | #define usc_EnableTransmitter(a,b) \ | ||
665 | usc_OutReg( (a), TMR, (u16)((usc_InReg((a),TMR) & 0xfffc) | (b)) ) | ||
666 | #define usc_EnableReceiver(a,b) \ | ||
667 | usc_OutReg( (a), RMR, (u16)((usc_InReg((a),RMR) & 0xfffc) | (b)) ) | ||
668 | |||
669 | static u16 usc_InDmaReg( struct mgsl_struct *info, u16 Port ); | ||
670 | static void usc_OutDmaReg( struct mgsl_struct *info, u16 Port, u16 Value ); | ||
671 | static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ); | ||
672 | |||
673 | static u16 usc_InReg( struct mgsl_struct *info, u16 Port ); | ||
674 | static void usc_OutReg( struct mgsl_struct *info, u16 Port, u16 Value ); | ||
675 | static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ); | ||
676 | void usc_RCmd( struct mgsl_struct *info, u16 Cmd ); | ||
677 | void usc_TCmd( struct mgsl_struct *info, u16 Cmd ); | ||
678 | |||
679 | #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b))) | ||
680 | #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b)) | ||
681 | |||
682 | #define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1)) | ||
683 | |||
684 | static void usc_process_rxoverrun_sync( struct mgsl_struct *info ); | ||
685 | static void usc_start_receiver( struct mgsl_struct *info ); | ||
686 | static void usc_stop_receiver( struct mgsl_struct *info ); | ||
687 | |||
688 | static void usc_start_transmitter( struct mgsl_struct *info ); | ||
689 | static void usc_stop_transmitter( struct mgsl_struct *info ); | ||
690 | static void usc_set_txidle( struct mgsl_struct *info ); | ||
691 | static void usc_load_txfifo( struct mgsl_struct *info ); | ||
692 | |||
693 | static void usc_enable_aux_clock( struct mgsl_struct *info, u32 DataRate ); | ||
694 | static void usc_enable_loopback( struct mgsl_struct *info, int enable ); | ||
695 | |||
696 | static void usc_get_serial_signals( struct mgsl_struct *info ); | ||
697 | static void usc_set_serial_signals( struct mgsl_struct *info ); | ||
698 | |||
699 | static void usc_reset( struct mgsl_struct *info ); | ||
700 | |||
701 | static void usc_set_sync_mode( struct mgsl_struct *info ); | ||
702 | static void usc_set_sdlc_mode( struct mgsl_struct *info ); | ||
703 | static void usc_set_async_mode( struct mgsl_struct *info ); | ||
704 | static void usc_enable_async_clock( struct mgsl_struct *info, u32 DataRate ); | ||
705 | |||
706 | static void usc_loopback_frame( struct mgsl_struct *info ); | ||
707 | |||
708 | static void mgsl_tx_timeout(unsigned long context); | ||
709 | |||
710 | |||
711 | static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ); | ||
712 | static void usc_loopmode_insert_request( struct mgsl_struct * info ); | ||
713 | static int usc_loopmode_active( struct mgsl_struct * info); | ||
714 | static void usc_loopmode_send_done( struct mgsl_struct * info ); | ||
715 | |||
716 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg); | ||
717 | |||
718 | #if SYNCLINK_GENERIC_HDLC | ||
719 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | ||
720 | static void hdlcdev_tx_done(struct mgsl_struct *info); | ||
721 | static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size); | ||
722 | static int hdlcdev_init(struct mgsl_struct *info); | ||
723 | static void hdlcdev_exit(struct mgsl_struct *info); | ||
724 | #endif | ||
725 | |||
726 | /* | ||
727 | * Defines a BUS descriptor value for the PCI adapter | ||
728 | * local bus address ranges. | ||
729 | */ | ||
730 | |||
731 | #define BUS_DESCRIPTOR( WrHold, WrDly, RdDly, Nwdd, Nwad, Nxda, Nrdd, Nrad ) \ | ||
732 | (0x00400020 + \ | ||
733 | ((WrHold) << 30) + \ | ||
734 | ((WrDly) << 28) + \ | ||
735 | ((RdDly) << 26) + \ | ||
736 | ((Nwdd) << 20) + \ | ||
737 | ((Nwad) << 15) + \ | ||
738 | ((Nxda) << 13) + \ | ||
739 | ((Nrdd) << 11) + \ | ||
740 | ((Nrad) << 6) ) | ||
741 | |||
742 | static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit); | ||
743 | |||
744 | /* | ||
745 | * Adapter diagnostic routines | ||
746 | */ | ||
747 | static bool mgsl_register_test( struct mgsl_struct *info ); | ||
748 | static bool mgsl_irq_test( struct mgsl_struct *info ); | ||
749 | static bool mgsl_dma_test( struct mgsl_struct *info ); | ||
750 | static bool mgsl_memory_test( struct mgsl_struct *info ); | ||
751 | static int mgsl_adapter_test( struct mgsl_struct *info ); | ||
752 | |||
753 | /* | ||
754 | * device and resource management routines | ||
755 | */ | ||
756 | static int mgsl_claim_resources(struct mgsl_struct *info); | ||
757 | static void mgsl_release_resources(struct mgsl_struct *info); | ||
758 | static void mgsl_add_device(struct mgsl_struct *info); | ||
759 | static struct mgsl_struct* mgsl_allocate_device(void); | ||
760 | |||
761 | /* | ||
762 | * DMA buffer manupulation functions. | ||
763 | */ | ||
764 | static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ); | ||
765 | static bool mgsl_get_rx_frame( struct mgsl_struct *info ); | ||
766 | static bool mgsl_get_raw_rx_frame( struct mgsl_struct *info ); | ||
767 | static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ); | ||
768 | static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ); | ||
769 | static int num_free_tx_dma_buffers(struct mgsl_struct *info); | ||
770 | static void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize); | ||
771 | static void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count); | ||
772 | |||
773 | /* | ||
774 | * DMA and Shared Memory buffer allocation and formatting | ||
775 | */ | ||
776 | static int mgsl_allocate_dma_buffers(struct mgsl_struct *info); | ||
777 | static void mgsl_free_dma_buffers(struct mgsl_struct *info); | ||
778 | static int mgsl_alloc_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); | ||
779 | static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList,int Buffercount); | ||
780 | static int mgsl_alloc_buffer_list_memory(struct mgsl_struct *info); | ||
781 | static void mgsl_free_buffer_list_memory(struct mgsl_struct *info); | ||
782 | static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info); | ||
783 | static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info); | ||
784 | static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info); | ||
785 | static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info); | ||
786 | static bool load_next_tx_holding_buffer(struct mgsl_struct *info); | ||
787 | static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize); | ||
788 | |||
789 | /* | ||
790 | * Bottom half interrupt handlers | ||
791 | */ | ||
792 | static void mgsl_bh_handler(struct work_struct *work); | ||
793 | static void mgsl_bh_receive(struct mgsl_struct *info); | ||
794 | static void mgsl_bh_transmit(struct mgsl_struct *info); | ||
795 | static void mgsl_bh_status(struct mgsl_struct *info); | ||
796 | |||
797 | /* | ||
798 | * Interrupt handler routines and dispatch table. | ||
799 | */ | ||
800 | static void mgsl_isr_null( struct mgsl_struct *info ); | ||
801 | static void mgsl_isr_transmit_data( struct mgsl_struct *info ); | ||
802 | static void mgsl_isr_receive_data( struct mgsl_struct *info ); | ||
803 | static void mgsl_isr_receive_status( struct mgsl_struct *info ); | ||
804 | static void mgsl_isr_transmit_status( struct mgsl_struct *info ); | ||
805 | static void mgsl_isr_io_pin( struct mgsl_struct *info ); | ||
806 | static void mgsl_isr_misc( struct mgsl_struct *info ); | ||
807 | static void mgsl_isr_receive_dma( struct mgsl_struct *info ); | ||
808 | static void mgsl_isr_transmit_dma( struct mgsl_struct *info ); | ||
809 | |||
810 | typedef void (*isr_dispatch_func)(struct mgsl_struct *); | ||
811 | |||
812 | static isr_dispatch_func UscIsrTable[7] = | ||
813 | { | ||
814 | mgsl_isr_null, | ||
815 | mgsl_isr_misc, | ||
816 | mgsl_isr_io_pin, | ||
817 | mgsl_isr_transmit_data, | ||
818 | mgsl_isr_transmit_status, | ||
819 | mgsl_isr_receive_data, | ||
820 | mgsl_isr_receive_status | ||
821 | }; | ||
822 | |||
823 | /* | ||
824 | * ioctl call handlers | ||
825 | */ | ||
826 | static int tiocmget(struct tty_struct *tty); | ||
827 | static int tiocmset(struct tty_struct *tty, | ||
828 | unsigned int set, unsigned int clear); | ||
829 | static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount | ||
830 | __user *user_icount); | ||
831 | static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params); | ||
832 | static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params); | ||
833 | static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode); | ||
834 | static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode); | ||
835 | static int mgsl_txenable(struct mgsl_struct * info, int enable); | ||
836 | static int mgsl_txabort(struct mgsl_struct * info); | ||
837 | static int mgsl_rxenable(struct mgsl_struct * info, int enable); | ||
838 | static int mgsl_wait_event(struct mgsl_struct * info, int __user *mask); | ||
839 | static int mgsl_loopmode_send_done( struct mgsl_struct * info ); | ||
840 | |||
841 | /* set non-zero on successful registration with PCI subsystem */ | ||
842 | static bool pci_registered; | ||
843 | |||
844 | /* | ||
845 | * Global linked list of SyncLink devices | ||
846 | */ | ||
847 | static struct mgsl_struct *mgsl_device_list; | ||
848 | static int mgsl_device_count; | ||
849 | |||
850 | /* | ||
851 | * Set this param to non-zero to load eax with the | ||
852 | * .text section address and breakpoint on module load. | ||
853 | * This is useful for use with gdb and add-symbol-file command. | ||
854 | */ | ||
855 | static int break_on_load; | ||
856 | |||
857 | /* | ||
858 | * Driver major number, defaults to zero to get auto | ||
859 | * assigned major number. May be forced as module parameter. | ||
860 | */ | ||
861 | static int ttymajor; | ||
862 | |||
863 | /* | ||
864 | * Array of user specified options for ISA adapters. | ||
865 | */ | ||
866 | static int io[MAX_ISA_DEVICES]; | ||
867 | static int irq[MAX_ISA_DEVICES]; | ||
868 | static int dma[MAX_ISA_DEVICES]; | ||
869 | static int debug_level; | ||
870 | static int maxframe[MAX_TOTAL_DEVICES]; | ||
871 | static int txdmabufs[MAX_TOTAL_DEVICES]; | ||
872 | static int txholdbufs[MAX_TOTAL_DEVICES]; | ||
873 | |||
874 | module_param(break_on_load, bool, 0); | ||
875 | module_param(ttymajor, int, 0); | ||
876 | module_param_array(io, int, NULL, 0); | ||
877 | module_param_array(irq, int, NULL, 0); | ||
878 | module_param_array(dma, int, NULL, 0); | ||
879 | module_param(debug_level, int, 0); | ||
880 | module_param_array(maxframe, int, NULL, 0); | ||
881 | module_param_array(txdmabufs, int, NULL, 0); | ||
882 | module_param_array(txholdbufs, int, NULL, 0); | ||
883 | |||
884 | static char *driver_name = "SyncLink serial driver"; | ||
885 | static char *driver_version = "$Revision: 4.38 $"; | ||
886 | |||
887 | static int synclink_init_one (struct pci_dev *dev, | ||
888 | const struct pci_device_id *ent); | ||
889 | static void synclink_remove_one (struct pci_dev *dev); | ||
890 | |||
891 | static struct pci_device_id synclink_pci_tbl[] = { | ||
892 | { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, | ||
893 | { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, | ||
894 | { 0, }, /* terminate list */ | ||
895 | }; | ||
896 | MODULE_DEVICE_TABLE(pci, synclink_pci_tbl); | ||
897 | |||
898 | MODULE_LICENSE("GPL"); | ||
899 | |||
900 | static struct pci_driver synclink_pci_driver = { | ||
901 | .name = "synclink", | ||
902 | .id_table = synclink_pci_tbl, | ||
903 | .probe = synclink_init_one, | ||
904 | .remove = __devexit_p(synclink_remove_one), | ||
905 | }; | ||
906 | |||
907 | static struct tty_driver *serial_driver; | ||
908 | |||
909 | /* number of characters left in xmit buffer before we ask for more */ | ||
910 | #define WAKEUP_CHARS 256 | ||
911 | |||
912 | |||
913 | static void mgsl_change_params(struct mgsl_struct *info); | ||
914 | static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout); | ||
915 | |||
916 | /* | ||
917 | * 1st function defined in .text section. Calling this function in | ||
918 | * init_module() followed by a breakpoint allows a remote debugger | ||
919 | * (gdb) to get the .text address for the add-symbol-file command. | ||
920 | * This allows remote debugging of dynamically loadable modules. | ||
921 | */ | ||
922 | static void* mgsl_get_text_ptr(void) | ||
923 | { | ||
924 | return mgsl_get_text_ptr; | ||
925 | } | ||
926 | |||
927 | static inline int mgsl_paranoia_check(struct mgsl_struct *info, | ||
928 | char *name, const char *routine) | ||
929 | { | ||
930 | #ifdef MGSL_PARANOIA_CHECK | ||
931 | static const char *badmagic = | ||
932 | "Warning: bad magic number for mgsl struct (%s) in %s\n"; | ||
933 | static const char *badinfo = | ||
934 | "Warning: null mgsl_struct for (%s) in %s\n"; | ||
935 | |||
936 | if (!info) { | ||
937 | printk(badinfo, name, routine); | ||
938 | return 1; | ||
939 | } | ||
940 | if (info->magic != MGSL_MAGIC) { | ||
941 | printk(badmagic, name, routine); | ||
942 | return 1; | ||
943 | } | ||
944 | #else | ||
945 | if (!info) | ||
946 | return 1; | ||
947 | #endif | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | /** | ||
952 | * line discipline callback wrappers | ||
953 | * | ||
954 | * The wrappers maintain line discipline references | ||
955 | * while calling into the line discipline. | ||
956 | * | ||
957 | * ldisc_receive_buf - pass receive data to line discipline | ||
958 | */ | ||
959 | |||
960 | static void ldisc_receive_buf(struct tty_struct *tty, | ||
961 | const __u8 *data, char *flags, int count) | ||
962 | { | ||
963 | struct tty_ldisc *ld; | ||
964 | if (!tty) | ||
965 | return; | ||
966 | ld = tty_ldisc_ref(tty); | ||
967 | if (ld) { | ||
968 | if (ld->ops->receive_buf) | ||
969 | ld->ops->receive_buf(tty, data, flags, count); | ||
970 | tty_ldisc_deref(ld); | ||
971 | } | ||
972 | } | ||
973 | |||
974 | /* mgsl_stop() throttle (stop) transmitter | ||
975 | * | ||
976 | * Arguments: tty pointer to tty info structure | ||
977 | * Return Value: None | ||
978 | */ | ||
979 | static void mgsl_stop(struct tty_struct *tty) | ||
980 | { | ||
981 | struct mgsl_struct *info = tty->driver_data; | ||
982 | unsigned long flags; | ||
983 | |||
984 | if (mgsl_paranoia_check(info, tty->name, "mgsl_stop")) | ||
985 | return; | ||
986 | |||
987 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
988 | printk("mgsl_stop(%s)\n",info->device_name); | ||
989 | |||
990 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
991 | if (info->tx_enabled) | ||
992 | usc_stop_transmitter(info); | ||
993 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
994 | |||
995 | } /* end of mgsl_stop() */ | ||
996 | |||
997 | /* mgsl_start() release (start) transmitter | ||
998 | * | ||
999 | * Arguments: tty pointer to tty info structure | ||
1000 | * Return Value: None | ||
1001 | */ | ||
1002 | static void mgsl_start(struct tty_struct *tty) | ||
1003 | { | ||
1004 | struct mgsl_struct *info = tty->driver_data; | ||
1005 | unsigned long flags; | ||
1006 | |||
1007 | if (mgsl_paranoia_check(info, tty->name, "mgsl_start")) | ||
1008 | return; | ||
1009 | |||
1010 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1011 | printk("mgsl_start(%s)\n",info->device_name); | ||
1012 | |||
1013 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1014 | if (!info->tx_enabled) | ||
1015 | usc_start_transmitter(info); | ||
1016 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1017 | |||
1018 | } /* end of mgsl_start() */ | ||
1019 | |||
1020 | /* | ||
1021 | * Bottom half work queue access functions | ||
1022 | */ | ||
1023 | |||
1024 | /* mgsl_bh_action() Return next bottom half action to perform. | ||
1025 | * Return Value: BH action code or 0 if nothing to do. | ||
1026 | */ | ||
1027 | static int mgsl_bh_action(struct mgsl_struct *info) | ||
1028 | { | ||
1029 | unsigned long flags; | ||
1030 | int rc = 0; | ||
1031 | |||
1032 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1033 | |||
1034 | if (info->pending_bh & BH_RECEIVE) { | ||
1035 | info->pending_bh &= ~BH_RECEIVE; | ||
1036 | rc = BH_RECEIVE; | ||
1037 | } else if (info->pending_bh & BH_TRANSMIT) { | ||
1038 | info->pending_bh &= ~BH_TRANSMIT; | ||
1039 | rc = BH_TRANSMIT; | ||
1040 | } else if (info->pending_bh & BH_STATUS) { | ||
1041 | info->pending_bh &= ~BH_STATUS; | ||
1042 | rc = BH_STATUS; | ||
1043 | } | ||
1044 | |||
1045 | if (!rc) { | ||
1046 | /* Mark BH routine as complete */ | ||
1047 | info->bh_running = false; | ||
1048 | info->bh_requested = false; | ||
1049 | } | ||
1050 | |||
1051 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1052 | |||
1053 | return rc; | ||
1054 | } | ||
1055 | |||
1056 | /* | ||
1057 | * Perform bottom half processing of work items queued by ISR. | ||
1058 | */ | ||
1059 | static void mgsl_bh_handler(struct work_struct *work) | ||
1060 | { | ||
1061 | struct mgsl_struct *info = | ||
1062 | container_of(work, struct mgsl_struct, task); | ||
1063 | int action; | ||
1064 | |||
1065 | if (!info) | ||
1066 | return; | ||
1067 | |||
1068 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1069 | printk( "%s(%d):mgsl_bh_handler(%s) entry\n", | ||
1070 | __FILE__,__LINE__,info->device_name); | ||
1071 | |||
1072 | info->bh_running = true; | ||
1073 | |||
1074 | while((action = mgsl_bh_action(info)) != 0) { | ||
1075 | |||
1076 | /* Process work item */ | ||
1077 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1078 | printk( "%s(%d):mgsl_bh_handler() work item action=%d\n", | ||
1079 | __FILE__,__LINE__,action); | ||
1080 | |||
1081 | switch (action) { | ||
1082 | |||
1083 | case BH_RECEIVE: | ||
1084 | mgsl_bh_receive(info); | ||
1085 | break; | ||
1086 | case BH_TRANSMIT: | ||
1087 | mgsl_bh_transmit(info); | ||
1088 | break; | ||
1089 | case BH_STATUS: | ||
1090 | mgsl_bh_status(info); | ||
1091 | break; | ||
1092 | default: | ||
1093 | /* unknown work item ID */ | ||
1094 | printk("Unknown work item ID=%08X!\n", action); | ||
1095 | break; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1100 | printk( "%s(%d):mgsl_bh_handler(%s) exit\n", | ||
1101 | __FILE__,__LINE__,info->device_name); | ||
1102 | } | ||
1103 | |||
1104 | static void mgsl_bh_receive(struct mgsl_struct *info) | ||
1105 | { | ||
1106 | bool (*get_rx_frame)(struct mgsl_struct *info) = | ||
1107 | (info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame); | ||
1108 | |||
1109 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1110 | printk( "%s(%d):mgsl_bh_receive(%s)\n", | ||
1111 | __FILE__,__LINE__,info->device_name); | ||
1112 | |||
1113 | do | ||
1114 | { | ||
1115 | if (info->rx_rcc_underrun) { | ||
1116 | unsigned long flags; | ||
1117 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1118 | usc_start_receiver(info); | ||
1119 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1120 | return; | ||
1121 | } | ||
1122 | } while(get_rx_frame(info)); | ||
1123 | } | ||
1124 | |||
1125 | static void mgsl_bh_transmit(struct mgsl_struct *info) | ||
1126 | { | ||
1127 | struct tty_struct *tty = info->port.tty; | ||
1128 | unsigned long flags; | ||
1129 | |||
1130 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1131 | printk( "%s(%d):mgsl_bh_transmit() entry on %s\n", | ||
1132 | __FILE__,__LINE__,info->device_name); | ||
1133 | |||
1134 | if (tty) | ||
1135 | tty_wakeup(tty); | ||
1136 | |||
1137 | /* if transmitter idle and loopmode_send_done_requested | ||
1138 | * then start echoing RxD to TxD | ||
1139 | */ | ||
1140 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1141 | if ( !info->tx_active && info->loopmode_send_done_requested ) | ||
1142 | usc_loopmode_send_done( info ); | ||
1143 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1144 | } | ||
1145 | |||
1146 | static void mgsl_bh_status(struct mgsl_struct *info) | ||
1147 | { | ||
1148 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
1149 | printk( "%s(%d):mgsl_bh_status() entry on %s\n", | ||
1150 | __FILE__,__LINE__,info->device_name); | ||
1151 | |||
1152 | info->ri_chkcount = 0; | ||
1153 | info->dsr_chkcount = 0; | ||
1154 | info->dcd_chkcount = 0; | ||
1155 | info->cts_chkcount = 0; | ||
1156 | } | ||
1157 | |||
1158 | /* mgsl_isr_receive_status() | ||
1159 | * | ||
1160 | * Service a receive status interrupt. The type of status | ||
1161 | * interrupt is indicated by the state of the RCSR. | ||
1162 | * This is only used for HDLC mode. | ||
1163 | * | ||
1164 | * Arguments: info pointer to device instance data | ||
1165 | * Return Value: None | ||
1166 | */ | ||
1167 | static void mgsl_isr_receive_status( struct mgsl_struct *info ) | ||
1168 | { | ||
1169 | u16 status = usc_InReg( info, RCSR ); | ||
1170 | |||
1171 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1172 | printk("%s(%d):mgsl_isr_receive_status status=%04X\n", | ||
1173 | __FILE__,__LINE__,status); | ||
1174 | |||
1175 | if ( (status & RXSTATUS_ABORT_RECEIVED) && | ||
1176 | info->loopmode_insert_requested && | ||
1177 | usc_loopmode_active(info) ) | ||
1178 | { | ||
1179 | ++info->icount.rxabort; | ||
1180 | info->loopmode_insert_requested = false; | ||
1181 | |||
1182 | /* clear CMR:13 to start echoing RxD to TxD */ | ||
1183 | info->cmr_value &= ~BIT13; | ||
1184 | usc_OutReg(info, CMR, info->cmr_value); | ||
1185 | |||
1186 | /* disable received abort irq (no longer required) */ | ||
1187 | usc_OutReg(info, RICR, | ||
1188 | (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED)); | ||
1189 | } | ||
1190 | |||
1191 | if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) { | ||
1192 | if (status & RXSTATUS_EXITED_HUNT) | ||
1193 | info->icount.exithunt++; | ||
1194 | if (status & RXSTATUS_IDLE_RECEIVED) | ||
1195 | info->icount.rxidle++; | ||
1196 | wake_up_interruptible(&info->event_wait_q); | ||
1197 | } | ||
1198 | |||
1199 | if (status & RXSTATUS_OVERRUN){ | ||
1200 | info->icount.rxover++; | ||
1201 | usc_process_rxoverrun_sync( info ); | ||
1202 | } | ||
1203 | |||
1204 | usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); | ||
1205 | usc_UnlatchRxstatusBits( info, status ); | ||
1206 | |||
1207 | } /* end of mgsl_isr_receive_status() */ | ||
1208 | |||
1209 | /* mgsl_isr_transmit_status() | ||
1210 | * | ||
1211 | * Service a transmit status interrupt | ||
1212 | * HDLC mode :end of transmit frame | ||
1213 | * Async mode:all data is sent | ||
1214 | * transmit status is indicated by bits in the TCSR. | ||
1215 | * | ||
1216 | * Arguments: info pointer to device instance data | ||
1217 | * Return Value: None | ||
1218 | */ | ||
1219 | static void mgsl_isr_transmit_status( struct mgsl_struct *info ) | ||
1220 | { | ||
1221 | u16 status = usc_InReg( info, TCSR ); | ||
1222 | |||
1223 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1224 | printk("%s(%d):mgsl_isr_transmit_status status=%04X\n", | ||
1225 | __FILE__,__LINE__,status); | ||
1226 | |||
1227 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); | ||
1228 | usc_UnlatchTxstatusBits( info, status ); | ||
1229 | |||
1230 | if ( status & (TXSTATUS_UNDERRUN | TXSTATUS_ABORT_SENT) ) | ||
1231 | { | ||
1232 | /* finished sending HDLC abort. This may leave */ | ||
1233 | /* the TxFifo with data from the aborted frame */ | ||
1234 | /* so purge the TxFifo. Also shutdown the DMA */ | ||
1235 | /* channel in case there is data remaining in */ | ||
1236 | /* the DMA buffer */ | ||
1237 | usc_DmaCmd( info, DmaCmd_ResetTxChannel ); | ||
1238 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
1239 | } | ||
1240 | |||
1241 | if ( status & TXSTATUS_EOF_SENT ) | ||
1242 | info->icount.txok++; | ||
1243 | else if ( status & TXSTATUS_UNDERRUN ) | ||
1244 | info->icount.txunder++; | ||
1245 | else if ( status & TXSTATUS_ABORT_SENT ) | ||
1246 | info->icount.txabort++; | ||
1247 | else | ||
1248 | info->icount.txunder++; | ||
1249 | |||
1250 | info->tx_active = false; | ||
1251 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1252 | del_timer(&info->tx_timer); | ||
1253 | |||
1254 | if ( info->drop_rts_on_tx_done ) { | ||
1255 | usc_get_serial_signals( info ); | ||
1256 | if ( info->serial_signals & SerialSignal_RTS ) { | ||
1257 | info->serial_signals &= ~SerialSignal_RTS; | ||
1258 | usc_set_serial_signals( info ); | ||
1259 | } | ||
1260 | info->drop_rts_on_tx_done = false; | ||
1261 | } | ||
1262 | |||
1263 | #if SYNCLINK_GENERIC_HDLC | ||
1264 | if (info->netcount) | ||
1265 | hdlcdev_tx_done(info); | ||
1266 | else | ||
1267 | #endif | ||
1268 | { | ||
1269 | if (info->port.tty->stopped || info->port.tty->hw_stopped) { | ||
1270 | usc_stop_transmitter(info); | ||
1271 | return; | ||
1272 | } | ||
1273 | info->pending_bh |= BH_TRANSMIT; | ||
1274 | } | ||
1275 | |||
1276 | } /* end of mgsl_isr_transmit_status() */ | ||
1277 | |||
1278 | /* mgsl_isr_io_pin() | ||
1279 | * | ||
1280 | * Service an Input/Output pin interrupt. The type of | ||
1281 | * interrupt is indicated by bits in the MISR | ||
1282 | * | ||
1283 | * Arguments: info pointer to device instance data | ||
1284 | * Return Value: None | ||
1285 | */ | ||
1286 | static void mgsl_isr_io_pin( struct mgsl_struct *info ) | ||
1287 | { | ||
1288 | struct mgsl_icount *icount; | ||
1289 | u16 status = usc_InReg( info, MISR ); | ||
1290 | |||
1291 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1292 | printk("%s(%d):mgsl_isr_io_pin status=%04X\n", | ||
1293 | __FILE__,__LINE__,status); | ||
1294 | |||
1295 | usc_ClearIrqPendingBits( info, IO_PIN ); | ||
1296 | usc_UnlatchIostatusBits( info, status ); | ||
1297 | |||
1298 | if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | | ||
1299 | MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { | ||
1300 | icount = &info->icount; | ||
1301 | /* update input line counters */ | ||
1302 | if (status & MISCSTATUS_RI_LATCHED) { | ||
1303 | if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) | ||
1304 | usc_DisablestatusIrqs(info,SICR_RI); | ||
1305 | icount->rng++; | ||
1306 | if ( status & MISCSTATUS_RI ) | ||
1307 | info->input_signal_events.ri_up++; | ||
1308 | else | ||
1309 | info->input_signal_events.ri_down++; | ||
1310 | } | ||
1311 | if (status & MISCSTATUS_DSR_LATCHED) { | ||
1312 | if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) | ||
1313 | usc_DisablestatusIrqs(info,SICR_DSR); | ||
1314 | icount->dsr++; | ||
1315 | if ( status & MISCSTATUS_DSR ) | ||
1316 | info->input_signal_events.dsr_up++; | ||
1317 | else | ||
1318 | info->input_signal_events.dsr_down++; | ||
1319 | } | ||
1320 | if (status & MISCSTATUS_DCD_LATCHED) { | ||
1321 | if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) | ||
1322 | usc_DisablestatusIrqs(info,SICR_DCD); | ||
1323 | icount->dcd++; | ||
1324 | if (status & MISCSTATUS_DCD) { | ||
1325 | info->input_signal_events.dcd_up++; | ||
1326 | } else | ||
1327 | info->input_signal_events.dcd_down++; | ||
1328 | #if SYNCLINK_GENERIC_HDLC | ||
1329 | if (info->netcount) { | ||
1330 | if (status & MISCSTATUS_DCD) | ||
1331 | netif_carrier_on(info->netdev); | ||
1332 | else | ||
1333 | netif_carrier_off(info->netdev); | ||
1334 | } | ||
1335 | #endif | ||
1336 | } | ||
1337 | if (status & MISCSTATUS_CTS_LATCHED) | ||
1338 | { | ||
1339 | if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) | ||
1340 | usc_DisablestatusIrqs(info,SICR_CTS); | ||
1341 | icount->cts++; | ||
1342 | if ( status & MISCSTATUS_CTS ) | ||
1343 | info->input_signal_events.cts_up++; | ||
1344 | else | ||
1345 | info->input_signal_events.cts_down++; | ||
1346 | } | ||
1347 | wake_up_interruptible(&info->status_event_wait_q); | ||
1348 | wake_up_interruptible(&info->event_wait_q); | ||
1349 | |||
1350 | if ( (info->port.flags & ASYNC_CHECK_CD) && | ||
1351 | (status & MISCSTATUS_DCD_LATCHED) ) { | ||
1352 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1353 | printk("%s CD now %s...", info->device_name, | ||
1354 | (status & MISCSTATUS_DCD) ? "on" : "off"); | ||
1355 | if (status & MISCSTATUS_DCD) | ||
1356 | wake_up_interruptible(&info->port.open_wait); | ||
1357 | else { | ||
1358 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1359 | printk("doing serial hangup..."); | ||
1360 | if (info->port.tty) | ||
1361 | tty_hangup(info->port.tty); | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1365 | if ( (info->port.flags & ASYNC_CTS_FLOW) && | ||
1366 | (status & MISCSTATUS_CTS_LATCHED) ) { | ||
1367 | if (info->port.tty->hw_stopped) { | ||
1368 | if (status & MISCSTATUS_CTS) { | ||
1369 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1370 | printk("CTS tx start..."); | ||
1371 | if (info->port.tty) | ||
1372 | info->port.tty->hw_stopped = 0; | ||
1373 | usc_start_transmitter(info); | ||
1374 | info->pending_bh |= BH_TRANSMIT; | ||
1375 | return; | ||
1376 | } | ||
1377 | } else { | ||
1378 | if (!(status & MISCSTATUS_CTS)) { | ||
1379 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1380 | printk("CTS tx stop..."); | ||
1381 | if (info->port.tty) | ||
1382 | info->port.tty->hw_stopped = 1; | ||
1383 | usc_stop_transmitter(info); | ||
1384 | } | ||
1385 | } | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | info->pending_bh |= BH_STATUS; | ||
1390 | |||
1391 | /* for diagnostics set IRQ flag */ | ||
1392 | if ( status & MISCSTATUS_TXC_LATCHED ){ | ||
1393 | usc_OutReg( info, SICR, | ||
1394 | (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); | ||
1395 | usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); | ||
1396 | info->irq_occurred = true; | ||
1397 | } | ||
1398 | |||
1399 | } /* end of mgsl_isr_io_pin() */ | ||
1400 | |||
1401 | /* mgsl_isr_transmit_data() | ||
1402 | * | ||
1403 | * Service a transmit data interrupt (async mode only). | ||
1404 | * | ||
1405 | * Arguments: info pointer to device instance data | ||
1406 | * Return Value: None | ||
1407 | */ | ||
1408 | static void mgsl_isr_transmit_data( struct mgsl_struct *info ) | ||
1409 | { | ||
1410 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1411 | printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n", | ||
1412 | __FILE__,__LINE__,info->xmit_cnt); | ||
1413 | |||
1414 | usc_ClearIrqPendingBits( info, TRANSMIT_DATA ); | ||
1415 | |||
1416 | if (info->port.tty->stopped || info->port.tty->hw_stopped) { | ||
1417 | usc_stop_transmitter(info); | ||
1418 | return; | ||
1419 | } | ||
1420 | |||
1421 | if ( info->xmit_cnt ) | ||
1422 | usc_load_txfifo( info ); | ||
1423 | else | ||
1424 | info->tx_active = false; | ||
1425 | |||
1426 | if (info->xmit_cnt < WAKEUP_CHARS) | ||
1427 | info->pending_bh |= BH_TRANSMIT; | ||
1428 | |||
1429 | } /* end of mgsl_isr_transmit_data() */ | ||
1430 | |||
1431 | /* mgsl_isr_receive_data() | ||
1432 | * | ||
1433 | * Service a receive data interrupt. This occurs | ||
1434 | * when operating in asynchronous interrupt transfer mode. | ||
1435 | * The receive data FIFO is flushed to the receive data buffers. | ||
1436 | * | ||
1437 | * Arguments: info pointer to device instance data | ||
1438 | * Return Value: None | ||
1439 | */ | ||
1440 | static void mgsl_isr_receive_data( struct mgsl_struct *info ) | ||
1441 | { | ||
1442 | int Fifocount; | ||
1443 | u16 status; | ||
1444 | int work = 0; | ||
1445 | unsigned char DataByte; | ||
1446 | struct tty_struct *tty = info->port.tty; | ||
1447 | struct mgsl_icount *icount = &info->icount; | ||
1448 | |||
1449 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1450 | printk("%s(%d):mgsl_isr_receive_data\n", | ||
1451 | __FILE__,__LINE__); | ||
1452 | |||
1453 | usc_ClearIrqPendingBits( info, RECEIVE_DATA ); | ||
1454 | |||
1455 | /* select FIFO status for RICR readback */ | ||
1456 | usc_RCmd( info, RCmd_SelectRicrRxFifostatus ); | ||
1457 | |||
1458 | /* clear the Wordstatus bit so that status readback */ | ||
1459 | /* only reflects the status of this byte */ | ||
1460 | usc_OutReg( info, RICR+LSBONLY, (u16)(usc_InReg(info, RICR+LSBONLY) & ~BIT3 )); | ||
1461 | |||
1462 | /* flush the receive FIFO */ | ||
1463 | |||
1464 | while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) { | ||
1465 | int flag; | ||
1466 | |||
1467 | /* read one byte from RxFIFO */ | ||
1468 | outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY), | ||
1469 | info->io_base + CCAR ); | ||
1470 | DataByte = inb( info->io_base + CCAR ); | ||
1471 | |||
1472 | /* get the status of the received byte */ | ||
1473 | status = usc_InReg(info, RCSR); | ||
1474 | if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + | ||
1475 | RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) | ||
1476 | usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); | ||
1477 | |||
1478 | icount->rx++; | ||
1479 | |||
1480 | flag = 0; | ||
1481 | if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + | ||
1482 | RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) { | ||
1483 | printk("rxerr=%04X\n",status); | ||
1484 | /* update error statistics */ | ||
1485 | if ( status & RXSTATUS_BREAK_RECEIVED ) { | ||
1486 | status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR); | ||
1487 | icount->brk++; | ||
1488 | } else if (status & RXSTATUS_PARITY_ERROR) | ||
1489 | icount->parity++; | ||
1490 | else if (status & RXSTATUS_FRAMING_ERROR) | ||
1491 | icount->frame++; | ||
1492 | else if (status & RXSTATUS_OVERRUN) { | ||
1493 | /* must issue purge fifo cmd before */ | ||
1494 | /* 16C32 accepts more receive chars */ | ||
1495 | usc_RTCmd(info,RTCmd_PurgeRxFifo); | ||
1496 | icount->overrun++; | ||
1497 | } | ||
1498 | |||
1499 | /* discard char if tty control flags say so */ | ||
1500 | if (status & info->ignore_status_mask) | ||
1501 | continue; | ||
1502 | |||
1503 | status &= info->read_status_mask; | ||
1504 | |||
1505 | if (status & RXSTATUS_BREAK_RECEIVED) { | ||
1506 | flag = TTY_BREAK; | ||
1507 | if (info->port.flags & ASYNC_SAK) | ||
1508 | do_SAK(tty); | ||
1509 | } else if (status & RXSTATUS_PARITY_ERROR) | ||
1510 | flag = TTY_PARITY; | ||
1511 | else if (status & RXSTATUS_FRAMING_ERROR) | ||
1512 | flag = TTY_FRAME; | ||
1513 | } /* end of if (error) */ | ||
1514 | tty_insert_flip_char(tty, DataByte, flag); | ||
1515 | if (status & RXSTATUS_OVERRUN) { | ||
1516 | /* Overrun is special, since it's | ||
1517 | * reported immediately, and doesn't | ||
1518 | * affect the current character | ||
1519 | */ | ||
1520 | work += tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
1521 | } | ||
1522 | } | ||
1523 | |||
1524 | if ( debug_level >= DEBUG_LEVEL_ISR ) { | ||
1525 | printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", | ||
1526 | __FILE__,__LINE__,icount->rx,icount->brk, | ||
1527 | icount->parity,icount->frame,icount->overrun); | ||
1528 | } | ||
1529 | |||
1530 | if(work) | ||
1531 | tty_flip_buffer_push(tty); | ||
1532 | } | ||
1533 | |||
1534 | /* mgsl_isr_misc() | ||
1535 | * | ||
1536 | * Service a miscellaneous interrupt source. | ||
1537 | * | ||
1538 | * Arguments: info pointer to device extension (instance data) | ||
1539 | * Return Value: None | ||
1540 | */ | ||
1541 | static void mgsl_isr_misc( struct mgsl_struct *info ) | ||
1542 | { | ||
1543 | u16 status = usc_InReg( info, MISR ); | ||
1544 | |||
1545 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1546 | printk("%s(%d):mgsl_isr_misc status=%04X\n", | ||
1547 | __FILE__,__LINE__,status); | ||
1548 | |||
1549 | if ((status & MISCSTATUS_RCC_UNDERRUN) && | ||
1550 | (info->params.mode == MGSL_MODE_HDLC)) { | ||
1551 | |||
1552 | /* turn off receiver and rx DMA */ | ||
1553 | usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); | ||
1554 | usc_DmaCmd(info, DmaCmd_ResetRxChannel); | ||
1555 | usc_UnlatchRxstatusBits(info, RXSTATUS_ALL); | ||
1556 | usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS); | ||
1557 | usc_DisableInterrupts(info, RECEIVE_DATA + RECEIVE_STATUS); | ||
1558 | |||
1559 | /* schedule BH handler to restart receiver */ | ||
1560 | info->pending_bh |= BH_RECEIVE; | ||
1561 | info->rx_rcc_underrun = true; | ||
1562 | } | ||
1563 | |||
1564 | usc_ClearIrqPendingBits( info, MISC ); | ||
1565 | usc_UnlatchMiscstatusBits( info, status ); | ||
1566 | |||
1567 | } /* end of mgsl_isr_misc() */ | ||
1568 | |||
1569 | /* mgsl_isr_null() | ||
1570 | * | ||
1571 | * Services undefined interrupt vectors from the | ||
1572 | * USC. (hence this function SHOULD never be called) | ||
1573 | * | ||
1574 | * Arguments: info pointer to device extension (instance data) | ||
1575 | * Return Value: None | ||
1576 | */ | ||
1577 | static void mgsl_isr_null( struct mgsl_struct *info ) | ||
1578 | { | ||
1579 | |||
1580 | } /* end of mgsl_isr_null() */ | ||
1581 | |||
1582 | /* mgsl_isr_receive_dma() | ||
1583 | * | ||
1584 | * Service a receive DMA channel interrupt. | ||
1585 | * For this driver there are two sources of receive DMA interrupts | ||
1586 | * as identified in the Receive DMA mode Register (RDMR): | ||
1587 | * | ||
1588 | * BIT3 EOA/EOL End of List, all receive buffers in receive | ||
1589 | * buffer list have been filled (no more free buffers | ||
1590 | * available). The DMA controller has shut down. | ||
1591 | * | ||
1592 | * BIT2 EOB End of Buffer. This interrupt occurs when a receive | ||
1593 | * DMA buffer is terminated in response to completion | ||
1594 | * of a good frame or a frame with errors. The status | ||
1595 | * of the frame is stored in the buffer entry in the | ||
1596 | * list of receive buffer entries. | ||
1597 | * | ||
1598 | * Arguments: info pointer to device instance data | ||
1599 | * Return Value: None | ||
1600 | */ | ||
1601 | static void mgsl_isr_receive_dma( struct mgsl_struct *info ) | ||
1602 | { | ||
1603 | u16 status; | ||
1604 | |||
1605 | /* clear interrupt pending and IUS bit for Rx DMA IRQ */ | ||
1606 | usc_OutDmaReg( info, CDIR, BIT9+BIT1 ); | ||
1607 | |||
1608 | /* Read the receive DMA status to identify interrupt type. */ | ||
1609 | /* This also clears the status bits. */ | ||
1610 | status = usc_InDmaReg( info, RDMR ); | ||
1611 | |||
1612 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1613 | printk("%s(%d):mgsl_isr_receive_dma(%s) status=%04X\n", | ||
1614 | __FILE__,__LINE__,info->device_name,status); | ||
1615 | |||
1616 | info->pending_bh |= BH_RECEIVE; | ||
1617 | |||
1618 | if ( status & BIT3 ) { | ||
1619 | info->rx_overflow = true; | ||
1620 | info->icount.buf_overrun++; | ||
1621 | } | ||
1622 | |||
1623 | } /* end of mgsl_isr_receive_dma() */ | ||
1624 | |||
1625 | /* mgsl_isr_transmit_dma() | ||
1626 | * | ||
1627 | * This function services a transmit DMA channel interrupt. | ||
1628 | * | ||
1629 | * For this driver there is one source of transmit DMA interrupts | ||
1630 | * as identified in the Transmit DMA Mode Register (TDMR): | ||
1631 | * | ||
1632 | * BIT2 EOB End of Buffer. This interrupt occurs when a | ||
1633 | * transmit DMA buffer has been emptied. | ||
1634 | * | ||
1635 | * The driver maintains enough transmit DMA buffers to hold at least | ||
1636 | * one max frame size transmit frame. When operating in a buffered | ||
1637 | * transmit mode, there may be enough transmit DMA buffers to hold at | ||
1638 | * least two or more max frame size frames. On an EOB condition, | ||
1639 | * determine if there are any queued transmit buffers and copy into | ||
1640 | * transmit DMA buffers if we have room. | ||
1641 | * | ||
1642 | * Arguments: info pointer to device instance data | ||
1643 | * Return Value: None | ||
1644 | */ | ||
1645 | static void mgsl_isr_transmit_dma( struct mgsl_struct *info ) | ||
1646 | { | ||
1647 | u16 status; | ||
1648 | |||
1649 | /* clear interrupt pending and IUS bit for Tx DMA IRQ */ | ||
1650 | usc_OutDmaReg(info, CDIR, BIT8+BIT0 ); | ||
1651 | |||
1652 | /* Read the transmit DMA status to identify interrupt type. */ | ||
1653 | /* This also clears the status bits. */ | ||
1654 | |||
1655 | status = usc_InDmaReg( info, TDMR ); | ||
1656 | |||
1657 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1658 | printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n", | ||
1659 | __FILE__,__LINE__,info->device_name,status); | ||
1660 | |||
1661 | if ( status & BIT2 ) { | ||
1662 | --info->tx_dma_buffers_used; | ||
1663 | |||
1664 | /* if there are transmit frames queued, | ||
1665 | * try to load the next one | ||
1666 | */ | ||
1667 | if ( load_next_tx_holding_buffer(info) ) { | ||
1668 | /* if call returns non-zero value, we have | ||
1669 | * at least one free tx holding buffer | ||
1670 | */ | ||
1671 | info->pending_bh |= BH_TRANSMIT; | ||
1672 | } | ||
1673 | } | ||
1674 | |||
1675 | } /* end of mgsl_isr_transmit_dma() */ | ||
1676 | |||
1677 | /* mgsl_interrupt() | ||
1678 | * | ||
1679 | * Interrupt service routine entry point. | ||
1680 | * | ||
1681 | * Arguments: | ||
1682 | * | ||
1683 | * irq interrupt number that caused interrupt | ||
1684 | * dev_id device ID supplied during interrupt registration | ||
1685 | * | ||
1686 | * Return Value: None | ||
1687 | */ | ||
1688 | static irqreturn_t mgsl_interrupt(int dummy, void *dev_id) | ||
1689 | { | ||
1690 | struct mgsl_struct *info = dev_id; | ||
1691 | u16 UscVector; | ||
1692 | u16 DmaVector; | ||
1693 | |||
1694 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1695 | printk(KERN_DEBUG "%s(%d):mgsl_interrupt(%d)entry.\n", | ||
1696 | __FILE__, __LINE__, info->irq_level); | ||
1697 | |||
1698 | spin_lock(&info->irq_spinlock); | ||
1699 | |||
1700 | for(;;) { | ||
1701 | /* Read the interrupt vectors from hardware. */ | ||
1702 | UscVector = usc_InReg(info, IVR) >> 9; | ||
1703 | DmaVector = usc_InDmaReg(info, DIVR); | ||
1704 | |||
1705 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1706 | printk("%s(%d):%s UscVector=%08X DmaVector=%08X\n", | ||
1707 | __FILE__,__LINE__,info->device_name,UscVector,DmaVector); | ||
1708 | |||
1709 | if ( !UscVector && !DmaVector ) | ||
1710 | break; | ||
1711 | |||
1712 | /* Dispatch interrupt vector */ | ||
1713 | if ( UscVector ) | ||
1714 | (*UscIsrTable[UscVector])(info); | ||
1715 | else if ( (DmaVector&(BIT10|BIT9)) == BIT10) | ||
1716 | mgsl_isr_transmit_dma(info); | ||
1717 | else | ||
1718 | mgsl_isr_receive_dma(info); | ||
1719 | |||
1720 | if ( info->isr_overflow ) { | ||
1721 | printk(KERN_ERR "%s(%d):%s isr overflow irq=%d\n", | ||
1722 | __FILE__, __LINE__, info->device_name, info->irq_level); | ||
1723 | usc_DisableMasterIrqBit(info); | ||
1724 | usc_DisableDmaInterrupts(info,DICR_MASTER); | ||
1725 | break; | ||
1726 | } | ||
1727 | } | ||
1728 | |||
1729 | /* Request bottom half processing if there's something | ||
1730 | * for it to do and the bh is not already running | ||
1731 | */ | ||
1732 | |||
1733 | if ( info->pending_bh && !info->bh_running && !info->bh_requested ) { | ||
1734 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1735 | printk("%s(%d):%s queueing bh task.\n", | ||
1736 | __FILE__,__LINE__,info->device_name); | ||
1737 | schedule_work(&info->task); | ||
1738 | info->bh_requested = true; | ||
1739 | } | ||
1740 | |||
1741 | spin_unlock(&info->irq_spinlock); | ||
1742 | |||
1743 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
1744 | printk(KERN_DEBUG "%s(%d):mgsl_interrupt(%d)exit.\n", | ||
1745 | __FILE__, __LINE__, info->irq_level); | ||
1746 | |||
1747 | return IRQ_HANDLED; | ||
1748 | } /* end of mgsl_interrupt() */ | ||
1749 | |||
1750 | /* startup() | ||
1751 | * | ||
1752 | * Initialize and start device. | ||
1753 | * | ||
1754 | * Arguments: info pointer to device instance data | ||
1755 | * Return Value: 0 if success, otherwise error code | ||
1756 | */ | ||
1757 | static int startup(struct mgsl_struct * info) | ||
1758 | { | ||
1759 | int retval = 0; | ||
1760 | |||
1761 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1762 | printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); | ||
1763 | |||
1764 | if (info->port.flags & ASYNC_INITIALIZED) | ||
1765 | return 0; | ||
1766 | |||
1767 | if (!info->xmit_buf) { | ||
1768 | /* allocate a page of memory for a transmit buffer */ | ||
1769 | info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); | ||
1770 | if (!info->xmit_buf) { | ||
1771 | printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", | ||
1772 | __FILE__,__LINE__,info->device_name); | ||
1773 | return -ENOMEM; | ||
1774 | } | ||
1775 | } | ||
1776 | |||
1777 | info->pending_bh = 0; | ||
1778 | |||
1779 | memset(&info->icount, 0, sizeof(info->icount)); | ||
1780 | |||
1781 | setup_timer(&info->tx_timer, mgsl_tx_timeout, (unsigned long)info); | ||
1782 | |||
1783 | /* Allocate and claim adapter resources */ | ||
1784 | retval = mgsl_claim_resources(info); | ||
1785 | |||
1786 | /* perform existence check and diagnostics */ | ||
1787 | if ( !retval ) | ||
1788 | retval = mgsl_adapter_test(info); | ||
1789 | |||
1790 | if ( retval ) { | ||
1791 | if (capable(CAP_SYS_ADMIN) && info->port.tty) | ||
1792 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1793 | mgsl_release_resources(info); | ||
1794 | return retval; | ||
1795 | } | ||
1796 | |||
1797 | /* program hardware for current parameters */ | ||
1798 | mgsl_change_params(info); | ||
1799 | |||
1800 | if (info->port.tty) | ||
1801 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1802 | |||
1803 | info->port.flags |= ASYNC_INITIALIZED; | ||
1804 | |||
1805 | return 0; | ||
1806 | |||
1807 | } /* end of startup() */ | ||
1808 | |||
1809 | /* shutdown() | ||
1810 | * | ||
1811 | * Called by mgsl_close() and mgsl_hangup() to shutdown hardware | ||
1812 | * | ||
1813 | * Arguments: info pointer to device instance data | ||
1814 | * Return Value: None | ||
1815 | */ | ||
1816 | static void shutdown(struct mgsl_struct * info) | ||
1817 | { | ||
1818 | unsigned long flags; | ||
1819 | |||
1820 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
1821 | return; | ||
1822 | |||
1823 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1824 | printk("%s(%d):mgsl_shutdown(%s)\n", | ||
1825 | __FILE__,__LINE__, info->device_name ); | ||
1826 | |||
1827 | /* clear status wait queue because status changes */ | ||
1828 | /* can't happen after shutting down the hardware */ | ||
1829 | wake_up_interruptible(&info->status_event_wait_q); | ||
1830 | wake_up_interruptible(&info->event_wait_q); | ||
1831 | |||
1832 | del_timer_sync(&info->tx_timer); | ||
1833 | |||
1834 | if (info->xmit_buf) { | ||
1835 | free_page((unsigned long) info->xmit_buf); | ||
1836 | info->xmit_buf = NULL; | ||
1837 | } | ||
1838 | |||
1839 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1840 | usc_DisableMasterIrqBit(info); | ||
1841 | usc_stop_receiver(info); | ||
1842 | usc_stop_transmitter(info); | ||
1843 | usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS + | ||
1844 | TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC ); | ||
1845 | usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); | ||
1846 | |||
1847 | /* Disable DMAEN (Port 7, Bit 14) */ | ||
1848 | /* This disconnects the DMA request signal from the ISA bus */ | ||
1849 | /* on the ISA adapter. This has no effect for the PCI adapter */ | ||
1850 | usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); | ||
1851 | |||
1852 | /* Disable INTEN (Port 6, Bit12) */ | ||
1853 | /* This disconnects the IRQ request signal to the ISA bus */ | ||
1854 | /* on the ISA adapter. This has no effect for the PCI adapter */ | ||
1855 | usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); | ||
1856 | |||
1857 | if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { | ||
1858 | info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | ||
1859 | usc_set_serial_signals(info); | ||
1860 | } | ||
1861 | |||
1862 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1863 | |||
1864 | mgsl_release_resources(info); | ||
1865 | |||
1866 | if (info->port.tty) | ||
1867 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
1868 | |||
1869 | info->port.flags &= ~ASYNC_INITIALIZED; | ||
1870 | |||
1871 | } /* end of shutdown() */ | ||
1872 | |||
1873 | static void mgsl_program_hw(struct mgsl_struct *info) | ||
1874 | { | ||
1875 | unsigned long flags; | ||
1876 | |||
1877 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
1878 | |||
1879 | usc_stop_receiver(info); | ||
1880 | usc_stop_transmitter(info); | ||
1881 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
1882 | |||
1883 | if (info->params.mode == MGSL_MODE_HDLC || | ||
1884 | info->params.mode == MGSL_MODE_RAW || | ||
1885 | info->netcount) | ||
1886 | usc_set_sync_mode(info); | ||
1887 | else | ||
1888 | usc_set_async_mode(info); | ||
1889 | |||
1890 | usc_set_serial_signals(info); | ||
1891 | |||
1892 | info->dcd_chkcount = 0; | ||
1893 | info->cts_chkcount = 0; | ||
1894 | info->ri_chkcount = 0; | ||
1895 | info->dsr_chkcount = 0; | ||
1896 | |||
1897 | usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI); | ||
1898 | usc_EnableInterrupts(info, IO_PIN); | ||
1899 | usc_get_serial_signals(info); | ||
1900 | |||
1901 | if (info->netcount || info->port.tty->termios->c_cflag & CREAD) | ||
1902 | usc_start_receiver(info); | ||
1903 | |||
1904 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
1905 | } | ||
1906 | |||
1907 | /* Reconfigure adapter based on new parameters | ||
1908 | */ | ||
1909 | static void mgsl_change_params(struct mgsl_struct *info) | ||
1910 | { | ||
1911 | unsigned cflag; | ||
1912 | int bits_per_char; | ||
1913 | |||
1914 | if (!info->port.tty || !info->port.tty->termios) | ||
1915 | return; | ||
1916 | |||
1917 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1918 | printk("%s(%d):mgsl_change_params(%s)\n", | ||
1919 | __FILE__,__LINE__, info->device_name ); | ||
1920 | |||
1921 | cflag = info->port.tty->termios->c_cflag; | ||
1922 | |||
1923 | /* if B0 rate (hangup) specified then negate DTR and RTS */ | ||
1924 | /* otherwise assert DTR and RTS */ | ||
1925 | if (cflag & CBAUD) | ||
1926 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
1927 | else | ||
1928 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
1929 | |||
1930 | /* byte size and parity */ | ||
1931 | |||
1932 | switch (cflag & CSIZE) { | ||
1933 | case CS5: info->params.data_bits = 5; break; | ||
1934 | case CS6: info->params.data_bits = 6; break; | ||
1935 | case CS7: info->params.data_bits = 7; break; | ||
1936 | case CS8: info->params.data_bits = 8; break; | ||
1937 | /* Never happens, but GCC is too dumb to figure it out */ | ||
1938 | default: info->params.data_bits = 7; break; | ||
1939 | } | ||
1940 | |||
1941 | if (cflag & CSTOPB) | ||
1942 | info->params.stop_bits = 2; | ||
1943 | else | ||
1944 | info->params.stop_bits = 1; | ||
1945 | |||
1946 | info->params.parity = ASYNC_PARITY_NONE; | ||
1947 | if (cflag & PARENB) { | ||
1948 | if (cflag & PARODD) | ||
1949 | info->params.parity = ASYNC_PARITY_ODD; | ||
1950 | else | ||
1951 | info->params.parity = ASYNC_PARITY_EVEN; | ||
1952 | #ifdef CMSPAR | ||
1953 | if (cflag & CMSPAR) | ||
1954 | info->params.parity = ASYNC_PARITY_SPACE; | ||
1955 | #endif | ||
1956 | } | ||
1957 | |||
1958 | /* calculate number of jiffies to transmit a full | ||
1959 | * FIFO (32 bytes) at specified data rate | ||
1960 | */ | ||
1961 | bits_per_char = info->params.data_bits + | ||
1962 | info->params.stop_bits + 1; | ||
1963 | |||
1964 | /* if port data rate is set to 460800 or less then | ||
1965 | * allow tty settings to override, otherwise keep the | ||
1966 | * current data rate. | ||
1967 | */ | ||
1968 | if (info->params.data_rate <= 460800) | ||
1969 | info->params.data_rate = tty_get_baud_rate(info->port.tty); | ||
1970 | |||
1971 | if ( info->params.data_rate ) { | ||
1972 | info->timeout = (32*HZ*bits_per_char) / | ||
1973 | info->params.data_rate; | ||
1974 | } | ||
1975 | info->timeout += HZ/50; /* Add .02 seconds of slop */ | ||
1976 | |||
1977 | if (cflag & CRTSCTS) | ||
1978 | info->port.flags |= ASYNC_CTS_FLOW; | ||
1979 | else | ||
1980 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
1981 | |||
1982 | if (cflag & CLOCAL) | ||
1983 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
1984 | else | ||
1985 | info->port.flags |= ASYNC_CHECK_CD; | ||
1986 | |||
1987 | /* process tty input control flags */ | ||
1988 | |||
1989 | info->read_status_mask = RXSTATUS_OVERRUN; | ||
1990 | if (I_INPCK(info->port.tty)) | ||
1991 | info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; | ||
1992 | if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) | ||
1993 | info->read_status_mask |= RXSTATUS_BREAK_RECEIVED; | ||
1994 | |||
1995 | if (I_IGNPAR(info->port.tty)) | ||
1996 | info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; | ||
1997 | if (I_IGNBRK(info->port.tty)) { | ||
1998 | info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED; | ||
1999 | /* If ignoring parity and break indicators, ignore | ||
2000 | * overruns too. (For real raw support). | ||
2001 | */ | ||
2002 | if (I_IGNPAR(info->port.tty)) | ||
2003 | info->ignore_status_mask |= RXSTATUS_OVERRUN; | ||
2004 | } | ||
2005 | |||
2006 | mgsl_program_hw(info); | ||
2007 | |||
2008 | } /* end of mgsl_change_params() */ | ||
2009 | |||
2010 | /* mgsl_put_char() | ||
2011 | * | ||
2012 | * Add a character to the transmit buffer. | ||
2013 | * | ||
2014 | * Arguments: tty pointer to tty information structure | ||
2015 | * ch character to add to transmit buffer | ||
2016 | * | ||
2017 | * Return Value: None | ||
2018 | */ | ||
2019 | static int mgsl_put_char(struct tty_struct *tty, unsigned char ch) | ||
2020 | { | ||
2021 | struct mgsl_struct *info = tty->driver_data; | ||
2022 | unsigned long flags; | ||
2023 | int ret = 0; | ||
2024 | |||
2025 | if (debug_level >= DEBUG_LEVEL_INFO) { | ||
2026 | printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n", | ||
2027 | __FILE__, __LINE__, ch, info->device_name); | ||
2028 | } | ||
2029 | |||
2030 | if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char")) | ||
2031 | return 0; | ||
2032 | |||
2033 | if (!info->xmit_buf) | ||
2034 | return 0; | ||
2035 | |||
2036 | spin_lock_irqsave(&info->irq_spinlock, flags); | ||
2037 | |||
2038 | if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) { | ||
2039 | if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { | ||
2040 | info->xmit_buf[info->xmit_head++] = ch; | ||
2041 | info->xmit_head &= SERIAL_XMIT_SIZE-1; | ||
2042 | info->xmit_cnt++; | ||
2043 | ret = 1; | ||
2044 | } | ||
2045 | } | ||
2046 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | ||
2047 | return ret; | ||
2048 | |||
2049 | } /* end of mgsl_put_char() */ | ||
2050 | |||
2051 | /* mgsl_flush_chars() | ||
2052 | * | ||
2053 | * Enable transmitter so remaining characters in the | ||
2054 | * transmit buffer are sent. | ||
2055 | * | ||
2056 | * Arguments: tty pointer to tty information structure | ||
2057 | * Return Value: None | ||
2058 | */ | ||
2059 | static void mgsl_flush_chars(struct tty_struct *tty) | ||
2060 | { | ||
2061 | struct mgsl_struct *info = tty->driver_data; | ||
2062 | unsigned long flags; | ||
2063 | |||
2064 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2065 | printk( "%s(%d):mgsl_flush_chars() entry on %s xmit_cnt=%d\n", | ||
2066 | __FILE__,__LINE__,info->device_name,info->xmit_cnt); | ||
2067 | |||
2068 | if (mgsl_paranoia_check(info, tty->name, "mgsl_flush_chars")) | ||
2069 | return; | ||
2070 | |||
2071 | if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || | ||
2072 | !info->xmit_buf) | ||
2073 | return; | ||
2074 | |||
2075 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2076 | printk( "%s(%d):mgsl_flush_chars() entry on %s starting transmitter\n", | ||
2077 | __FILE__,__LINE__,info->device_name ); | ||
2078 | |||
2079 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2080 | |||
2081 | if (!info->tx_active) { | ||
2082 | if ( (info->params.mode == MGSL_MODE_HDLC || | ||
2083 | info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) { | ||
2084 | /* operating in synchronous (frame oriented) mode */ | ||
2085 | /* copy data from circular xmit_buf to */ | ||
2086 | /* transmit DMA buffer. */ | ||
2087 | mgsl_load_tx_dma_buffer(info, | ||
2088 | info->xmit_buf,info->xmit_cnt); | ||
2089 | } | ||
2090 | usc_start_transmitter(info); | ||
2091 | } | ||
2092 | |||
2093 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2094 | |||
2095 | } /* end of mgsl_flush_chars() */ | ||
2096 | |||
2097 | /* mgsl_write() | ||
2098 | * | ||
2099 | * Send a block of data | ||
2100 | * | ||
2101 | * Arguments: | ||
2102 | * | ||
2103 | * tty pointer to tty information structure | ||
2104 | * buf pointer to buffer containing send data | ||
2105 | * count size of send data in bytes | ||
2106 | * | ||
2107 | * Return Value: number of characters written | ||
2108 | */ | ||
2109 | static int mgsl_write(struct tty_struct * tty, | ||
2110 | const unsigned char *buf, int count) | ||
2111 | { | ||
2112 | int c, ret = 0; | ||
2113 | struct mgsl_struct *info = tty->driver_data; | ||
2114 | unsigned long flags; | ||
2115 | |||
2116 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2117 | printk( "%s(%d):mgsl_write(%s) count=%d\n", | ||
2118 | __FILE__,__LINE__,info->device_name,count); | ||
2119 | |||
2120 | if (mgsl_paranoia_check(info, tty->name, "mgsl_write")) | ||
2121 | goto cleanup; | ||
2122 | |||
2123 | if (!info->xmit_buf) | ||
2124 | goto cleanup; | ||
2125 | |||
2126 | if ( info->params.mode == MGSL_MODE_HDLC || | ||
2127 | info->params.mode == MGSL_MODE_RAW ) { | ||
2128 | /* operating in synchronous (frame oriented) mode */ | ||
2129 | /* operating in synchronous (frame oriented) mode */ | ||
2130 | if (info->tx_active) { | ||
2131 | |||
2132 | if ( info->params.mode == MGSL_MODE_HDLC ) { | ||
2133 | ret = 0; | ||
2134 | goto cleanup; | ||
2135 | } | ||
2136 | /* transmitter is actively sending data - | ||
2137 | * if we have multiple transmit dma and | ||
2138 | * holding buffers, attempt to queue this | ||
2139 | * frame for transmission at a later time. | ||
2140 | */ | ||
2141 | if (info->tx_holding_count >= info->num_tx_holding_buffers ) { | ||
2142 | /* no tx holding buffers available */ | ||
2143 | ret = 0; | ||
2144 | goto cleanup; | ||
2145 | } | ||
2146 | |||
2147 | /* queue transmit frame request */ | ||
2148 | ret = count; | ||
2149 | save_tx_buffer_request(info,buf,count); | ||
2150 | |||
2151 | /* if we have sufficient tx dma buffers, | ||
2152 | * load the next buffered tx request | ||
2153 | */ | ||
2154 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2155 | load_next_tx_holding_buffer(info); | ||
2156 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2157 | goto cleanup; | ||
2158 | } | ||
2159 | |||
2160 | /* if operating in HDLC LoopMode and the adapter */ | ||
2161 | /* has yet to be inserted into the loop, we can't */ | ||
2162 | /* transmit */ | ||
2163 | |||
2164 | if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) && | ||
2165 | !usc_loopmode_active(info) ) | ||
2166 | { | ||
2167 | ret = 0; | ||
2168 | goto cleanup; | ||
2169 | } | ||
2170 | |||
2171 | if ( info->xmit_cnt ) { | ||
2172 | /* Send accumulated from send_char() calls */ | ||
2173 | /* as frame and wait before accepting more data. */ | ||
2174 | ret = 0; | ||
2175 | |||
2176 | /* copy data from circular xmit_buf to */ | ||
2177 | /* transmit DMA buffer. */ | ||
2178 | mgsl_load_tx_dma_buffer(info, | ||
2179 | info->xmit_buf,info->xmit_cnt); | ||
2180 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2181 | printk( "%s(%d):mgsl_write(%s) sync xmit_cnt flushing\n", | ||
2182 | __FILE__,__LINE__,info->device_name); | ||
2183 | } else { | ||
2184 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2185 | printk( "%s(%d):mgsl_write(%s) sync transmit accepted\n", | ||
2186 | __FILE__,__LINE__,info->device_name); | ||
2187 | ret = count; | ||
2188 | info->xmit_cnt = count; | ||
2189 | mgsl_load_tx_dma_buffer(info,buf,count); | ||
2190 | } | ||
2191 | } else { | ||
2192 | while (1) { | ||
2193 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2194 | c = min_t(int, count, | ||
2195 | min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, | ||
2196 | SERIAL_XMIT_SIZE - info->xmit_head)); | ||
2197 | if (c <= 0) { | ||
2198 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2199 | break; | ||
2200 | } | ||
2201 | memcpy(info->xmit_buf + info->xmit_head, buf, c); | ||
2202 | info->xmit_head = ((info->xmit_head + c) & | ||
2203 | (SERIAL_XMIT_SIZE-1)); | ||
2204 | info->xmit_cnt += c; | ||
2205 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2206 | buf += c; | ||
2207 | count -= c; | ||
2208 | ret += c; | ||
2209 | } | ||
2210 | } | ||
2211 | |||
2212 | if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { | ||
2213 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2214 | if (!info->tx_active) | ||
2215 | usc_start_transmitter(info); | ||
2216 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2217 | } | ||
2218 | cleanup: | ||
2219 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2220 | printk( "%s(%d):mgsl_write(%s) returning=%d\n", | ||
2221 | __FILE__,__LINE__,info->device_name,ret); | ||
2222 | |||
2223 | return ret; | ||
2224 | |||
2225 | } /* end of mgsl_write() */ | ||
2226 | |||
2227 | /* mgsl_write_room() | ||
2228 | * | ||
2229 | * Return the count of free bytes in transmit buffer | ||
2230 | * | ||
2231 | * Arguments: tty pointer to tty info structure | ||
2232 | * Return Value: None | ||
2233 | */ | ||
2234 | static int mgsl_write_room(struct tty_struct *tty) | ||
2235 | { | ||
2236 | struct mgsl_struct *info = tty->driver_data; | ||
2237 | int ret; | ||
2238 | |||
2239 | if (mgsl_paranoia_check(info, tty->name, "mgsl_write_room")) | ||
2240 | return 0; | ||
2241 | ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; | ||
2242 | if (ret < 0) | ||
2243 | ret = 0; | ||
2244 | |||
2245 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2246 | printk("%s(%d):mgsl_write_room(%s)=%d\n", | ||
2247 | __FILE__,__LINE__, info->device_name,ret ); | ||
2248 | |||
2249 | if ( info->params.mode == MGSL_MODE_HDLC || | ||
2250 | info->params.mode == MGSL_MODE_RAW ) { | ||
2251 | /* operating in synchronous (frame oriented) mode */ | ||
2252 | if ( info->tx_active ) | ||
2253 | return 0; | ||
2254 | else | ||
2255 | return HDLC_MAX_FRAME_SIZE; | ||
2256 | } | ||
2257 | |||
2258 | return ret; | ||
2259 | |||
2260 | } /* end of mgsl_write_room() */ | ||
2261 | |||
2262 | /* mgsl_chars_in_buffer() | ||
2263 | * | ||
2264 | * Return the count of bytes in transmit buffer | ||
2265 | * | ||
2266 | * Arguments: tty pointer to tty info structure | ||
2267 | * Return Value: None | ||
2268 | */ | ||
2269 | static int mgsl_chars_in_buffer(struct tty_struct *tty) | ||
2270 | { | ||
2271 | struct mgsl_struct *info = tty->driver_data; | ||
2272 | |||
2273 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2274 | printk("%s(%d):mgsl_chars_in_buffer(%s)\n", | ||
2275 | __FILE__,__LINE__, info->device_name ); | ||
2276 | |||
2277 | if (mgsl_paranoia_check(info, tty->name, "mgsl_chars_in_buffer")) | ||
2278 | return 0; | ||
2279 | |||
2280 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2281 | printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n", | ||
2282 | __FILE__,__LINE__, info->device_name,info->xmit_cnt ); | ||
2283 | |||
2284 | if ( info->params.mode == MGSL_MODE_HDLC || | ||
2285 | info->params.mode == MGSL_MODE_RAW ) { | ||
2286 | /* operating in synchronous (frame oriented) mode */ | ||
2287 | if ( info->tx_active ) | ||
2288 | return info->max_frame_size; | ||
2289 | else | ||
2290 | return 0; | ||
2291 | } | ||
2292 | |||
2293 | return info->xmit_cnt; | ||
2294 | } /* end of mgsl_chars_in_buffer() */ | ||
2295 | |||
2296 | /* mgsl_flush_buffer() | ||
2297 | * | ||
2298 | * Discard all data in the send buffer | ||
2299 | * | ||
2300 | * Arguments: tty pointer to tty info structure | ||
2301 | * Return Value: None | ||
2302 | */ | ||
2303 | static void mgsl_flush_buffer(struct tty_struct *tty) | ||
2304 | { | ||
2305 | struct mgsl_struct *info = tty->driver_data; | ||
2306 | unsigned long flags; | ||
2307 | |||
2308 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2309 | printk("%s(%d):mgsl_flush_buffer(%s) entry\n", | ||
2310 | __FILE__,__LINE__, info->device_name ); | ||
2311 | |||
2312 | if (mgsl_paranoia_check(info, tty->name, "mgsl_flush_buffer")) | ||
2313 | return; | ||
2314 | |||
2315 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2316 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
2317 | del_timer(&info->tx_timer); | ||
2318 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2319 | |||
2320 | tty_wakeup(tty); | ||
2321 | } | ||
2322 | |||
2323 | /* mgsl_send_xchar() | ||
2324 | * | ||
2325 | * Send a high-priority XON/XOFF character | ||
2326 | * | ||
2327 | * Arguments: tty pointer to tty info structure | ||
2328 | * ch character to send | ||
2329 | * Return Value: None | ||
2330 | */ | ||
2331 | static void mgsl_send_xchar(struct tty_struct *tty, char ch) | ||
2332 | { | ||
2333 | struct mgsl_struct *info = tty->driver_data; | ||
2334 | unsigned long flags; | ||
2335 | |||
2336 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2337 | printk("%s(%d):mgsl_send_xchar(%s,%d)\n", | ||
2338 | __FILE__,__LINE__, info->device_name, ch ); | ||
2339 | |||
2340 | if (mgsl_paranoia_check(info, tty->name, "mgsl_send_xchar")) | ||
2341 | return; | ||
2342 | |||
2343 | info->x_char = ch; | ||
2344 | if (ch) { | ||
2345 | /* Make sure transmit interrupts are on */ | ||
2346 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2347 | if (!info->tx_enabled) | ||
2348 | usc_start_transmitter(info); | ||
2349 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2350 | } | ||
2351 | } /* end of mgsl_send_xchar() */ | ||
2352 | |||
2353 | /* mgsl_throttle() | ||
2354 | * | ||
2355 | * Signal remote device to throttle send data (our receive data) | ||
2356 | * | ||
2357 | * Arguments: tty pointer to tty info structure | ||
2358 | * Return Value: None | ||
2359 | */ | ||
2360 | static void mgsl_throttle(struct tty_struct * tty) | ||
2361 | { | ||
2362 | struct mgsl_struct *info = tty->driver_data; | ||
2363 | unsigned long flags; | ||
2364 | |||
2365 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2366 | printk("%s(%d):mgsl_throttle(%s) entry\n", | ||
2367 | __FILE__,__LINE__, info->device_name ); | ||
2368 | |||
2369 | if (mgsl_paranoia_check(info, tty->name, "mgsl_throttle")) | ||
2370 | return; | ||
2371 | |||
2372 | if (I_IXOFF(tty)) | ||
2373 | mgsl_send_xchar(tty, STOP_CHAR(tty)); | ||
2374 | |||
2375 | if (tty->termios->c_cflag & CRTSCTS) { | ||
2376 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2377 | info->serial_signals &= ~SerialSignal_RTS; | ||
2378 | usc_set_serial_signals(info); | ||
2379 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2380 | } | ||
2381 | } /* end of mgsl_throttle() */ | ||
2382 | |||
2383 | /* mgsl_unthrottle() | ||
2384 | * | ||
2385 | * Signal remote device to stop throttling send data (our receive data) | ||
2386 | * | ||
2387 | * Arguments: tty pointer to tty info structure | ||
2388 | * Return Value: None | ||
2389 | */ | ||
2390 | static void mgsl_unthrottle(struct tty_struct * tty) | ||
2391 | { | ||
2392 | struct mgsl_struct *info = tty->driver_data; | ||
2393 | unsigned long flags; | ||
2394 | |||
2395 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2396 | printk("%s(%d):mgsl_unthrottle(%s) entry\n", | ||
2397 | __FILE__,__LINE__, info->device_name ); | ||
2398 | |||
2399 | if (mgsl_paranoia_check(info, tty->name, "mgsl_unthrottle")) | ||
2400 | return; | ||
2401 | |||
2402 | if (I_IXOFF(tty)) { | ||
2403 | if (info->x_char) | ||
2404 | info->x_char = 0; | ||
2405 | else | ||
2406 | mgsl_send_xchar(tty, START_CHAR(tty)); | ||
2407 | } | ||
2408 | |||
2409 | if (tty->termios->c_cflag & CRTSCTS) { | ||
2410 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2411 | info->serial_signals |= SerialSignal_RTS; | ||
2412 | usc_set_serial_signals(info); | ||
2413 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2414 | } | ||
2415 | |||
2416 | } /* end of mgsl_unthrottle() */ | ||
2417 | |||
2418 | /* mgsl_get_stats() | ||
2419 | * | ||
2420 | * get the current serial parameters information | ||
2421 | * | ||
2422 | * Arguments: info pointer to device instance data | ||
2423 | * user_icount pointer to buffer to hold returned stats | ||
2424 | * | ||
2425 | * Return Value: 0 if success, otherwise error code | ||
2426 | */ | ||
2427 | static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user *user_icount) | ||
2428 | { | ||
2429 | int err; | ||
2430 | |||
2431 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2432 | printk("%s(%d):mgsl_get_params(%s)\n", | ||
2433 | __FILE__,__LINE__, info->device_name); | ||
2434 | |||
2435 | if (!user_icount) { | ||
2436 | memset(&info->icount, 0, sizeof(info->icount)); | ||
2437 | } else { | ||
2438 | mutex_lock(&info->port.mutex); | ||
2439 | COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); | ||
2440 | mutex_unlock(&info->port.mutex); | ||
2441 | if (err) | ||
2442 | return -EFAULT; | ||
2443 | } | ||
2444 | |||
2445 | return 0; | ||
2446 | |||
2447 | } /* end of mgsl_get_stats() */ | ||
2448 | |||
2449 | /* mgsl_get_params() | ||
2450 | * | ||
2451 | * get the current serial parameters information | ||
2452 | * | ||
2453 | * Arguments: info pointer to device instance data | ||
2454 | * user_params pointer to buffer to hold returned params | ||
2455 | * | ||
2456 | * Return Value: 0 if success, otherwise error code | ||
2457 | */ | ||
2458 | static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_params) | ||
2459 | { | ||
2460 | int err; | ||
2461 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2462 | printk("%s(%d):mgsl_get_params(%s)\n", | ||
2463 | __FILE__,__LINE__, info->device_name); | ||
2464 | |||
2465 | mutex_lock(&info->port.mutex); | ||
2466 | COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); | ||
2467 | mutex_unlock(&info->port.mutex); | ||
2468 | if (err) { | ||
2469 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2470 | printk( "%s(%d):mgsl_get_params(%s) user buffer copy failed\n", | ||
2471 | __FILE__,__LINE__,info->device_name); | ||
2472 | return -EFAULT; | ||
2473 | } | ||
2474 | |||
2475 | return 0; | ||
2476 | |||
2477 | } /* end of mgsl_get_params() */ | ||
2478 | |||
2479 | /* mgsl_set_params() | ||
2480 | * | ||
2481 | * set the serial parameters | ||
2482 | * | ||
2483 | * Arguments: | ||
2484 | * | ||
2485 | * info pointer to device instance data | ||
2486 | * new_params user buffer containing new serial params | ||
2487 | * | ||
2488 | * Return Value: 0 if success, otherwise error code | ||
2489 | */ | ||
2490 | static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_params) | ||
2491 | { | ||
2492 | unsigned long flags; | ||
2493 | MGSL_PARAMS tmp_params; | ||
2494 | int err; | ||
2495 | |||
2496 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2497 | printk("%s(%d):mgsl_set_params %s\n", __FILE__,__LINE__, | ||
2498 | info->device_name ); | ||
2499 | COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); | ||
2500 | if (err) { | ||
2501 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2502 | printk( "%s(%d):mgsl_set_params(%s) user buffer copy failed\n", | ||
2503 | __FILE__,__LINE__,info->device_name); | ||
2504 | return -EFAULT; | ||
2505 | } | ||
2506 | |||
2507 | mutex_lock(&info->port.mutex); | ||
2508 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2509 | memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); | ||
2510 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2511 | |||
2512 | mgsl_change_params(info); | ||
2513 | mutex_unlock(&info->port.mutex); | ||
2514 | |||
2515 | return 0; | ||
2516 | |||
2517 | } /* end of mgsl_set_params() */ | ||
2518 | |||
2519 | /* mgsl_get_txidle() | ||
2520 | * | ||
2521 | * get the current transmit idle mode | ||
2522 | * | ||
2523 | * Arguments: info pointer to device instance data | ||
2524 | * idle_mode pointer to buffer to hold returned idle mode | ||
2525 | * | ||
2526 | * Return Value: 0 if success, otherwise error code | ||
2527 | */ | ||
2528 | static int mgsl_get_txidle(struct mgsl_struct * info, int __user *idle_mode) | ||
2529 | { | ||
2530 | int err; | ||
2531 | |||
2532 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2533 | printk("%s(%d):mgsl_get_txidle(%s)=%d\n", | ||
2534 | __FILE__,__LINE__, info->device_name, info->idle_mode); | ||
2535 | |||
2536 | COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); | ||
2537 | if (err) { | ||
2538 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2539 | printk( "%s(%d):mgsl_get_txidle(%s) user buffer copy failed\n", | ||
2540 | __FILE__,__LINE__,info->device_name); | ||
2541 | return -EFAULT; | ||
2542 | } | ||
2543 | |||
2544 | return 0; | ||
2545 | |||
2546 | } /* end of mgsl_get_txidle() */ | ||
2547 | |||
2548 | /* mgsl_set_txidle() service ioctl to set transmit idle mode | ||
2549 | * | ||
2550 | * Arguments: info pointer to device instance data | ||
2551 | * idle_mode new idle mode | ||
2552 | * | ||
2553 | * Return Value: 0 if success, otherwise error code | ||
2554 | */ | ||
2555 | static int mgsl_set_txidle(struct mgsl_struct * info, int idle_mode) | ||
2556 | { | ||
2557 | unsigned long flags; | ||
2558 | |||
2559 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2560 | printk("%s(%d):mgsl_set_txidle(%s,%d)\n", __FILE__,__LINE__, | ||
2561 | info->device_name, idle_mode ); | ||
2562 | |||
2563 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2564 | info->idle_mode = idle_mode; | ||
2565 | usc_set_txidle( info ); | ||
2566 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2567 | return 0; | ||
2568 | |||
2569 | } /* end of mgsl_set_txidle() */ | ||
2570 | |||
2571 | /* mgsl_txenable() | ||
2572 | * | ||
2573 | * enable or disable the transmitter | ||
2574 | * | ||
2575 | * Arguments: | ||
2576 | * | ||
2577 | * info pointer to device instance data | ||
2578 | * enable 1 = enable, 0 = disable | ||
2579 | * | ||
2580 | * Return Value: 0 if success, otherwise error code | ||
2581 | */ | ||
2582 | static int mgsl_txenable(struct mgsl_struct * info, int enable) | ||
2583 | { | ||
2584 | unsigned long flags; | ||
2585 | |||
2586 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2587 | printk("%s(%d):mgsl_txenable(%s,%d)\n", __FILE__,__LINE__, | ||
2588 | info->device_name, enable); | ||
2589 | |||
2590 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2591 | if ( enable ) { | ||
2592 | if ( !info->tx_enabled ) { | ||
2593 | |||
2594 | usc_start_transmitter(info); | ||
2595 | /*-------------------------------------------------- | ||
2596 | * if HDLC/SDLC Loop mode, attempt to insert the | ||
2597 | * station in the 'loop' by setting CMR:13. Upon | ||
2598 | * receipt of the next GoAhead (RxAbort) sequence, | ||
2599 | * the OnLoop indicator (CCSR:7) should go active | ||
2600 | * to indicate that we are on the loop | ||
2601 | *--------------------------------------------------*/ | ||
2602 | if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) | ||
2603 | usc_loopmode_insert_request( info ); | ||
2604 | } | ||
2605 | } else { | ||
2606 | if ( info->tx_enabled ) | ||
2607 | usc_stop_transmitter(info); | ||
2608 | } | ||
2609 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2610 | return 0; | ||
2611 | |||
2612 | } /* end of mgsl_txenable() */ | ||
2613 | |||
2614 | /* mgsl_txabort() abort send HDLC frame | ||
2615 | * | ||
2616 | * Arguments: info pointer to device instance data | ||
2617 | * Return Value: 0 if success, otherwise error code | ||
2618 | */ | ||
2619 | static int mgsl_txabort(struct mgsl_struct * info) | ||
2620 | { | ||
2621 | unsigned long flags; | ||
2622 | |||
2623 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2624 | printk("%s(%d):mgsl_txabort(%s)\n", __FILE__,__LINE__, | ||
2625 | info->device_name); | ||
2626 | |||
2627 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2628 | if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) | ||
2629 | { | ||
2630 | if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) | ||
2631 | usc_loopmode_cancel_transmit( info ); | ||
2632 | else | ||
2633 | usc_TCmd(info,TCmd_SendAbort); | ||
2634 | } | ||
2635 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2636 | return 0; | ||
2637 | |||
2638 | } /* end of mgsl_txabort() */ | ||
2639 | |||
2640 | /* mgsl_rxenable() enable or disable the receiver | ||
2641 | * | ||
2642 | * Arguments: info pointer to device instance data | ||
2643 | * enable 1 = enable, 0 = disable | ||
2644 | * Return Value: 0 if success, otherwise error code | ||
2645 | */ | ||
2646 | static int mgsl_rxenable(struct mgsl_struct * info, int enable) | ||
2647 | { | ||
2648 | unsigned long flags; | ||
2649 | |||
2650 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2651 | printk("%s(%d):mgsl_rxenable(%s,%d)\n", __FILE__,__LINE__, | ||
2652 | info->device_name, enable); | ||
2653 | |||
2654 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2655 | if ( enable ) { | ||
2656 | if ( !info->rx_enabled ) | ||
2657 | usc_start_receiver(info); | ||
2658 | } else { | ||
2659 | if ( info->rx_enabled ) | ||
2660 | usc_stop_receiver(info); | ||
2661 | } | ||
2662 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2663 | return 0; | ||
2664 | |||
2665 | } /* end of mgsl_rxenable() */ | ||
2666 | |||
2667 | /* mgsl_wait_event() wait for specified event to occur | ||
2668 | * | ||
2669 | * Arguments: info pointer to device instance data | ||
2670 | * mask pointer to bitmask of events to wait for | ||
2671 | * Return Value: 0 if successful and bit mask updated with | ||
2672 | * of events triggerred, | ||
2673 | * otherwise error code | ||
2674 | */ | ||
2675 | static int mgsl_wait_event(struct mgsl_struct * info, int __user * mask_ptr) | ||
2676 | { | ||
2677 | unsigned long flags; | ||
2678 | int s; | ||
2679 | int rc=0; | ||
2680 | struct mgsl_icount cprev, cnow; | ||
2681 | int events; | ||
2682 | int mask; | ||
2683 | struct _input_signal_events oldsigs, newsigs; | ||
2684 | DECLARE_WAITQUEUE(wait, current); | ||
2685 | |||
2686 | COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); | ||
2687 | if (rc) { | ||
2688 | return -EFAULT; | ||
2689 | } | ||
2690 | |||
2691 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2692 | printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__, | ||
2693 | info->device_name, mask); | ||
2694 | |||
2695 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2696 | |||
2697 | /* return immediately if state matches requested events */ | ||
2698 | usc_get_serial_signals(info); | ||
2699 | s = info->serial_signals; | ||
2700 | events = mask & | ||
2701 | ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + | ||
2702 | ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + | ||
2703 | ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + | ||
2704 | ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); | ||
2705 | if (events) { | ||
2706 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2707 | goto exit; | ||
2708 | } | ||
2709 | |||
2710 | /* save current irq counts */ | ||
2711 | cprev = info->icount; | ||
2712 | oldsigs = info->input_signal_events; | ||
2713 | |||
2714 | /* enable hunt and idle irqs if needed */ | ||
2715 | if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { | ||
2716 | u16 oldreg = usc_InReg(info,RICR); | ||
2717 | u16 newreg = oldreg + | ||
2718 | (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) + | ||
2719 | (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0); | ||
2720 | if (oldreg != newreg) | ||
2721 | usc_OutReg(info, RICR, newreg); | ||
2722 | } | ||
2723 | |||
2724 | set_current_state(TASK_INTERRUPTIBLE); | ||
2725 | add_wait_queue(&info->event_wait_q, &wait); | ||
2726 | |||
2727 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2728 | |||
2729 | |||
2730 | for(;;) { | ||
2731 | schedule(); | ||
2732 | if (signal_pending(current)) { | ||
2733 | rc = -ERESTARTSYS; | ||
2734 | break; | ||
2735 | } | ||
2736 | |||
2737 | /* get current irq counts */ | ||
2738 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2739 | cnow = info->icount; | ||
2740 | newsigs = info->input_signal_events; | ||
2741 | set_current_state(TASK_INTERRUPTIBLE); | ||
2742 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2743 | |||
2744 | /* if no change, wait aborted for some reason */ | ||
2745 | if (newsigs.dsr_up == oldsigs.dsr_up && | ||
2746 | newsigs.dsr_down == oldsigs.dsr_down && | ||
2747 | newsigs.dcd_up == oldsigs.dcd_up && | ||
2748 | newsigs.dcd_down == oldsigs.dcd_down && | ||
2749 | newsigs.cts_up == oldsigs.cts_up && | ||
2750 | newsigs.cts_down == oldsigs.cts_down && | ||
2751 | newsigs.ri_up == oldsigs.ri_up && | ||
2752 | newsigs.ri_down == oldsigs.ri_down && | ||
2753 | cnow.exithunt == cprev.exithunt && | ||
2754 | cnow.rxidle == cprev.rxidle) { | ||
2755 | rc = -EIO; | ||
2756 | break; | ||
2757 | } | ||
2758 | |||
2759 | events = mask & | ||
2760 | ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + | ||
2761 | (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + | ||
2762 | (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + | ||
2763 | (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + | ||
2764 | (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + | ||
2765 | (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + | ||
2766 | (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + | ||
2767 | (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + | ||
2768 | (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + | ||
2769 | (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); | ||
2770 | if (events) | ||
2771 | break; | ||
2772 | |||
2773 | cprev = cnow; | ||
2774 | oldsigs = newsigs; | ||
2775 | } | ||
2776 | |||
2777 | remove_wait_queue(&info->event_wait_q, &wait); | ||
2778 | set_current_state(TASK_RUNNING); | ||
2779 | |||
2780 | if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { | ||
2781 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2782 | if (!waitqueue_active(&info->event_wait_q)) { | ||
2783 | /* disable enable exit hunt mode/idle rcvd IRQs */ | ||
2784 | usc_OutReg(info, RICR, usc_InReg(info,RICR) & | ||
2785 | ~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)); | ||
2786 | } | ||
2787 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2788 | } | ||
2789 | exit: | ||
2790 | if ( rc == 0 ) | ||
2791 | PUT_USER(rc, events, mask_ptr); | ||
2792 | |||
2793 | return rc; | ||
2794 | |||
2795 | } /* end of mgsl_wait_event() */ | ||
2796 | |||
2797 | static int modem_input_wait(struct mgsl_struct *info,int arg) | ||
2798 | { | ||
2799 | unsigned long flags; | ||
2800 | int rc; | ||
2801 | struct mgsl_icount cprev, cnow; | ||
2802 | DECLARE_WAITQUEUE(wait, current); | ||
2803 | |||
2804 | /* save current irq counts */ | ||
2805 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2806 | cprev = info->icount; | ||
2807 | add_wait_queue(&info->status_event_wait_q, &wait); | ||
2808 | set_current_state(TASK_INTERRUPTIBLE); | ||
2809 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2810 | |||
2811 | for(;;) { | ||
2812 | schedule(); | ||
2813 | if (signal_pending(current)) { | ||
2814 | rc = -ERESTARTSYS; | ||
2815 | break; | ||
2816 | } | ||
2817 | |||
2818 | /* get new irq counts */ | ||
2819 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2820 | cnow = info->icount; | ||
2821 | set_current_state(TASK_INTERRUPTIBLE); | ||
2822 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2823 | |||
2824 | /* if no change, wait aborted for some reason */ | ||
2825 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
2826 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { | ||
2827 | rc = -EIO; | ||
2828 | break; | ||
2829 | } | ||
2830 | |||
2831 | /* check for change in caller specified modem input */ | ||
2832 | if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || | ||
2833 | (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || | ||
2834 | (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || | ||
2835 | (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { | ||
2836 | rc = 0; | ||
2837 | break; | ||
2838 | } | ||
2839 | |||
2840 | cprev = cnow; | ||
2841 | } | ||
2842 | remove_wait_queue(&info->status_event_wait_q, &wait); | ||
2843 | set_current_state(TASK_RUNNING); | ||
2844 | return rc; | ||
2845 | } | ||
2846 | |||
2847 | /* return the state of the serial control and status signals | ||
2848 | */ | ||
2849 | static int tiocmget(struct tty_struct *tty) | ||
2850 | { | ||
2851 | struct mgsl_struct *info = tty->driver_data; | ||
2852 | unsigned int result; | ||
2853 | unsigned long flags; | ||
2854 | |||
2855 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2856 | usc_get_serial_signals(info); | ||
2857 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2858 | |||
2859 | result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + | ||
2860 | ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + | ||
2861 | ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + | ||
2862 | ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + | ||
2863 | ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + | ||
2864 | ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); | ||
2865 | |||
2866 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2867 | printk("%s(%d):%s tiocmget() value=%08X\n", | ||
2868 | __FILE__,__LINE__, info->device_name, result ); | ||
2869 | return result; | ||
2870 | } | ||
2871 | |||
2872 | /* set modem control signals (DTR/RTS) | ||
2873 | */ | ||
2874 | static int tiocmset(struct tty_struct *tty, | ||
2875 | unsigned int set, unsigned int clear) | ||
2876 | { | ||
2877 | struct mgsl_struct *info = tty->driver_data; | ||
2878 | unsigned long flags; | ||
2879 | |||
2880 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2881 | printk("%s(%d):%s tiocmset(%x,%x)\n", | ||
2882 | __FILE__,__LINE__,info->device_name, set, clear); | ||
2883 | |||
2884 | if (set & TIOCM_RTS) | ||
2885 | info->serial_signals |= SerialSignal_RTS; | ||
2886 | if (set & TIOCM_DTR) | ||
2887 | info->serial_signals |= SerialSignal_DTR; | ||
2888 | if (clear & TIOCM_RTS) | ||
2889 | info->serial_signals &= ~SerialSignal_RTS; | ||
2890 | if (clear & TIOCM_DTR) | ||
2891 | info->serial_signals &= ~SerialSignal_DTR; | ||
2892 | |||
2893 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2894 | usc_set_serial_signals(info); | ||
2895 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2896 | |||
2897 | return 0; | ||
2898 | } | ||
2899 | |||
2900 | /* mgsl_break() Set or clear transmit break condition | ||
2901 | * | ||
2902 | * Arguments: tty pointer to tty instance data | ||
2903 | * break_state -1=set break condition, 0=clear | ||
2904 | * Return Value: error code | ||
2905 | */ | ||
2906 | static int mgsl_break(struct tty_struct *tty, int break_state) | ||
2907 | { | ||
2908 | struct mgsl_struct * info = tty->driver_data; | ||
2909 | unsigned long flags; | ||
2910 | |||
2911 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2912 | printk("%s(%d):mgsl_break(%s,%d)\n", | ||
2913 | __FILE__,__LINE__, info->device_name, break_state); | ||
2914 | |||
2915 | if (mgsl_paranoia_check(info, tty->name, "mgsl_break")) | ||
2916 | return -EINVAL; | ||
2917 | |||
2918 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2919 | if (break_state == -1) | ||
2920 | usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) | BIT7)); | ||
2921 | else | ||
2922 | usc_OutReg(info,IOCR,(u16)(usc_InReg(info,IOCR) & ~BIT7)); | ||
2923 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2924 | return 0; | ||
2925 | |||
2926 | } /* end of mgsl_break() */ | ||
2927 | |||
2928 | /* | ||
2929 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
2930 | * Return: write counters to the user passed counter struct | ||
2931 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
2932 | * RI where only 0->1 is counted. | ||
2933 | */ | ||
2934 | static int msgl_get_icount(struct tty_struct *tty, | ||
2935 | struct serial_icounter_struct *icount) | ||
2936 | |||
2937 | { | ||
2938 | struct mgsl_struct * info = tty->driver_data; | ||
2939 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
2940 | unsigned long flags; | ||
2941 | |||
2942 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
2943 | cnow = info->icount; | ||
2944 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
2945 | |||
2946 | icount->cts = cnow.cts; | ||
2947 | icount->dsr = cnow.dsr; | ||
2948 | icount->rng = cnow.rng; | ||
2949 | icount->dcd = cnow.dcd; | ||
2950 | icount->rx = cnow.rx; | ||
2951 | icount->tx = cnow.tx; | ||
2952 | icount->frame = cnow.frame; | ||
2953 | icount->overrun = cnow.overrun; | ||
2954 | icount->parity = cnow.parity; | ||
2955 | icount->brk = cnow.brk; | ||
2956 | icount->buf_overrun = cnow.buf_overrun; | ||
2957 | return 0; | ||
2958 | } | ||
2959 | |||
2960 | /* mgsl_ioctl() Service an IOCTL request | ||
2961 | * | ||
2962 | * Arguments: | ||
2963 | * | ||
2964 | * tty pointer to tty instance data | ||
2965 | * cmd IOCTL command code | ||
2966 | * arg command argument/context | ||
2967 | * | ||
2968 | * Return Value: 0 if success, otherwise error code | ||
2969 | */ | ||
2970 | static int mgsl_ioctl(struct tty_struct *tty, | ||
2971 | unsigned int cmd, unsigned long arg) | ||
2972 | { | ||
2973 | struct mgsl_struct * info = tty->driver_data; | ||
2974 | |||
2975 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2976 | printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, | ||
2977 | info->device_name, cmd ); | ||
2978 | |||
2979 | if (mgsl_paranoia_check(info, tty->name, "mgsl_ioctl")) | ||
2980 | return -ENODEV; | ||
2981 | |||
2982 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||
2983 | (cmd != TIOCMIWAIT)) { | ||
2984 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
2985 | return -EIO; | ||
2986 | } | ||
2987 | |||
2988 | return mgsl_ioctl_common(info, cmd, arg); | ||
2989 | } | ||
2990 | |||
2991 | static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) | ||
2992 | { | ||
2993 | void __user *argp = (void __user *)arg; | ||
2994 | |||
2995 | switch (cmd) { | ||
2996 | case MGSL_IOCGPARAMS: | ||
2997 | return mgsl_get_params(info, argp); | ||
2998 | case MGSL_IOCSPARAMS: | ||
2999 | return mgsl_set_params(info, argp); | ||
3000 | case MGSL_IOCGTXIDLE: | ||
3001 | return mgsl_get_txidle(info, argp); | ||
3002 | case MGSL_IOCSTXIDLE: | ||
3003 | return mgsl_set_txidle(info,(int)arg); | ||
3004 | case MGSL_IOCTXENABLE: | ||
3005 | return mgsl_txenable(info,(int)arg); | ||
3006 | case MGSL_IOCRXENABLE: | ||
3007 | return mgsl_rxenable(info,(int)arg); | ||
3008 | case MGSL_IOCTXABORT: | ||
3009 | return mgsl_txabort(info); | ||
3010 | case MGSL_IOCGSTATS: | ||
3011 | return mgsl_get_stats(info, argp); | ||
3012 | case MGSL_IOCWAITEVENT: | ||
3013 | return mgsl_wait_event(info, argp); | ||
3014 | case MGSL_IOCLOOPTXDONE: | ||
3015 | return mgsl_loopmode_send_done(info); | ||
3016 | /* Wait for modem input (DCD,RI,DSR,CTS) change | ||
3017 | * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) | ||
3018 | */ | ||
3019 | case TIOCMIWAIT: | ||
3020 | return modem_input_wait(info,(int)arg); | ||
3021 | |||
3022 | default: | ||
3023 | return -ENOIOCTLCMD; | ||
3024 | } | ||
3025 | return 0; | ||
3026 | } | ||
3027 | |||
3028 | /* mgsl_set_termios() | ||
3029 | * | ||
3030 | * Set new termios settings | ||
3031 | * | ||
3032 | * Arguments: | ||
3033 | * | ||
3034 | * tty pointer to tty structure | ||
3035 | * termios pointer to buffer to hold returned old termios | ||
3036 | * | ||
3037 | * Return Value: None | ||
3038 | */ | ||
3039 | static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
3040 | { | ||
3041 | struct mgsl_struct *info = tty->driver_data; | ||
3042 | unsigned long flags; | ||
3043 | |||
3044 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3045 | printk("%s(%d):mgsl_set_termios %s\n", __FILE__,__LINE__, | ||
3046 | tty->driver->name ); | ||
3047 | |||
3048 | mgsl_change_params(info); | ||
3049 | |||
3050 | /* Handle transition to B0 status */ | ||
3051 | if (old_termios->c_cflag & CBAUD && | ||
3052 | !(tty->termios->c_cflag & CBAUD)) { | ||
3053 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
3054 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3055 | usc_set_serial_signals(info); | ||
3056 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3057 | } | ||
3058 | |||
3059 | /* Handle transition away from B0 status */ | ||
3060 | if (!(old_termios->c_cflag & CBAUD) && | ||
3061 | tty->termios->c_cflag & CBAUD) { | ||
3062 | info->serial_signals |= SerialSignal_DTR; | ||
3063 | if (!(tty->termios->c_cflag & CRTSCTS) || | ||
3064 | !test_bit(TTY_THROTTLED, &tty->flags)) { | ||
3065 | info->serial_signals |= SerialSignal_RTS; | ||
3066 | } | ||
3067 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3068 | usc_set_serial_signals(info); | ||
3069 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3070 | } | ||
3071 | |||
3072 | /* Handle turning off CRTSCTS */ | ||
3073 | if (old_termios->c_cflag & CRTSCTS && | ||
3074 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
3075 | tty->hw_stopped = 0; | ||
3076 | mgsl_start(tty); | ||
3077 | } | ||
3078 | |||
3079 | } /* end of mgsl_set_termios() */ | ||
3080 | |||
3081 | /* mgsl_close() | ||
3082 | * | ||
3083 | * Called when port is closed. Wait for remaining data to be | ||
3084 | * sent. Disable port and free resources. | ||
3085 | * | ||
3086 | * Arguments: | ||
3087 | * | ||
3088 | * tty pointer to open tty structure | ||
3089 | * filp pointer to open file object | ||
3090 | * | ||
3091 | * Return Value: None | ||
3092 | */ | ||
3093 | static void mgsl_close(struct tty_struct *tty, struct file * filp) | ||
3094 | { | ||
3095 | struct mgsl_struct * info = tty->driver_data; | ||
3096 | |||
3097 | if (mgsl_paranoia_check(info, tty->name, "mgsl_close")) | ||
3098 | return; | ||
3099 | |||
3100 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3101 | printk("%s(%d):mgsl_close(%s) entry, count=%d\n", | ||
3102 | __FILE__,__LINE__, info->device_name, info->port.count); | ||
3103 | |||
3104 | if (tty_port_close_start(&info->port, tty, filp) == 0) | ||
3105 | goto cleanup; | ||
3106 | |||
3107 | mutex_lock(&info->port.mutex); | ||
3108 | if (info->port.flags & ASYNC_INITIALIZED) | ||
3109 | mgsl_wait_until_sent(tty, info->timeout); | ||
3110 | mgsl_flush_buffer(tty); | ||
3111 | tty_ldisc_flush(tty); | ||
3112 | shutdown(info); | ||
3113 | mutex_unlock(&info->port.mutex); | ||
3114 | |||
3115 | tty_port_close_end(&info->port, tty); | ||
3116 | info->port.tty = NULL; | ||
3117 | cleanup: | ||
3118 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3119 | printk("%s(%d):mgsl_close(%s) exit, count=%d\n", __FILE__,__LINE__, | ||
3120 | tty->driver->name, info->port.count); | ||
3121 | |||
3122 | } /* end of mgsl_close() */ | ||
3123 | |||
3124 | /* mgsl_wait_until_sent() | ||
3125 | * | ||
3126 | * Wait until the transmitter is empty. | ||
3127 | * | ||
3128 | * Arguments: | ||
3129 | * | ||
3130 | * tty pointer to tty info structure | ||
3131 | * timeout time to wait for send completion | ||
3132 | * | ||
3133 | * Return Value: None | ||
3134 | */ | ||
3135 | static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) | ||
3136 | { | ||
3137 | struct mgsl_struct * info = tty->driver_data; | ||
3138 | unsigned long orig_jiffies, char_time; | ||
3139 | |||
3140 | if (!info ) | ||
3141 | return; | ||
3142 | |||
3143 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3144 | printk("%s(%d):mgsl_wait_until_sent(%s) entry\n", | ||
3145 | __FILE__,__LINE__, info->device_name ); | ||
3146 | |||
3147 | if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent")) | ||
3148 | return; | ||
3149 | |||
3150 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
3151 | goto exit; | ||
3152 | |||
3153 | orig_jiffies = jiffies; | ||
3154 | |||
3155 | /* Set check interval to 1/5 of estimated time to | ||
3156 | * send a character, and make it at least 1. The check | ||
3157 | * interval should also be less than the timeout. | ||
3158 | * Note: use tight timings here to satisfy the NIST-PCTS. | ||
3159 | */ | ||
3160 | |||
3161 | if ( info->params.data_rate ) { | ||
3162 | char_time = info->timeout/(32 * 5); | ||
3163 | if (!char_time) | ||
3164 | char_time++; | ||
3165 | } else | ||
3166 | char_time = 1; | ||
3167 | |||
3168 | if (timeout) | ||
3169 | char_time = min_t(unsigned long, char_time, timeout); | ||
3170 | |||
3171 | if ( info->params.mode == MGSL_MODE_HDLC || | ||
3172 | info->params.mode == MGSL_MODE_RAW ) { | ||
3173 | while (info->tx_active) { | ||
3174 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
3175 | if (signal_pending(current)) | ||
3176 | break; | ||
3177 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
3178 | break; | ||
3179 | } | ||
3180 | } else { | ||
3181 | while (!(usc_InReg(info,TCSR) & TXSTATUS_ALL_SENT) && | ||
3182 | info->tx_enabled) { | ||
3183 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
3184 | if (signal_pending(current)) | ||
3185 | break; | ||
3186 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
3187 | break; | ||
3188 | } | ||
3189 | } | ||
3190 | |||
3191 | exit: | ||
3192 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3193 | printk("%s(%d):mgsl_wait_until_sent(%s) exit\n", | ||
3194 | __FILE__,__LINE__, info->device_name ); | ||
3195 | |||
3196 | } /* end of mgsl_wait_until_sent() */ | ||
3197 | |||
3198 | /* mgsl_hangup() | ||
3199 | * | ||
3200 | * Called by tty_hangup() when a hangup is signaled. | ||
3201 | * This is the same as to closing all open files for the port. | ||
3202 | * | ||
3203 | * Arguments: tty pointer to associated tty object | ||
3204 | * Return Value: None | ||
3205 | */ | ||
3206 | static void mgsl_hangup(struct tty_struct *tty) | ||
3207 | { | ||
3208 | struct mgsl_struct * info = tty->driver_data; | ||
3209 | |||
3210 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3211 | printk("%s(%d):mgsl_hangup(%s)\n", | ||
3212 | __FILE__,__LINE__, info->device_name ); | ||
3213 | |||
3214 | if (mgsl_paranoia_check(info, tty->name, "mgsl_hangup")) | ||
3215 | return; | ||
3216 | |||
3217 | mgsl_flush_buffer(tty); | ||
3218 | shutdown(info); | ||
3219 | |||
3220 | info->port.count = 0; | ||
3221 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | ||
3222 | info->port.tty = NULL; | ||
3223 | |||
3224 | wake_up_interruptible(&info->port.open_wait); | ||
3225 | |||
3226 | } /* end of mgsl_hangup() */ | ||
3227 | |||
3228 | /* | ||
3229 | * carrier_raised() | ||
3230 | * | ||
3231 | * Return true if carrier is raised | ||
3232 | */ | ||
3233 | |||
3234 | static int carrier_raised(struct tty_port *port) | ||
3235 | { | ||
3236 | unsigned long flags; | ||
3237 | struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); | ||
3238 | |||
3239 | spin_lock_irqsave(&info->irq_spinlock, flags); | ||
3240 | usc_get_serial_signals(info); | ||
3241 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | ||
3242 | return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; | ||
3243 | } | ||
3244 | |||
3245 | static void dtr_rts(struct tty_port *port, int on) | ||
3246 | { | ||
3247 | struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); | ||
3248 | unsigned long flags; | ||
3249 | |||
3250 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3251 | if (on) | ||
3252 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
3253 | else | ||
3254 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
3255 | usc_set_serial_signals(info); | ||
3256 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3257 | } | ||
3258 | |||
3259 | |||
3260 | /* block_til_ready() | ||
3261 | * | ||
3262 | * Block the current process until the specified port | ||
3263 | * is ready to be opened. | ||
3264 | * | ||
3265 | * Arguments: | ||
3266 | * | ||
3267 | * tty pointer to tty info structure | ||
3268 | * filp pointer to open file object | ||
3269 | * info pointer to device instance data | ||
3270 | * | ||
3271 | * Return Value: 0 if success, otherwise error code | ||
3272 | */ | ||
3273 | static int block_til_ready(struct tty_struct *tty, struct file * filp, | ||
3274 | struct mgsl_struct *info) | ||
3275 | { | ||
3276 | DECLARE_WAITQUEUE(wait, current); | ||
3277 | int retval; | ||
3278 | bool do_clocal = false; | ||
3279 | bool extra_count = false; | ||
3280 | unsigned long flags; | ||
3281 | int dcd; | ||
3282 | struct tty_port *port = &info->port; | ||
3283 | |||
3284 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3285 | printk("%s(%d):block_til_ready on %s\n", | ||
3286 | __FILE__,__LINE__, tty->driver->name ); | ||
3287 | |||
3288 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ | ||
3289 | /* nonblock mode is set or port is not enabled */ | ||
3290 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3291 | return 0; | ||
3292 | } | ||
3293 | |||
3294 | if (tty->termios->c_cflag & CLOCAL) | ||
3295 | do_clocal = true; | ||
3296 | |||
3297 | /* Wait for carrier detect and the line to become | ||
3298 | * free (i.e., not in use by the callout). While we are in | ||
3299 | * this loop, port->count is dropped by one, so that | ||
3300 | * mgsl_close() knows when to free things. We restore it upon | ||
3301 | * exit, either normal or abnormal. | ||
3302 | */ | ||
3303 | |||
3304 | retval = 0; | ||
3305 | add_wait_queue(&port->open_wait, &wait); | ||
3306 | |||
3307 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3308 | printk("%s(%d):block_til_ready before block on %s count=%d\n", | ||
3309 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3310 | |||
3311 | spin_lock_irqsave(&info->irq_spinlock, flags); | ||
3312 | if (!tty_hung_up_p(filp)) { | ||
3313 | extra_count = true; | ||
3314 | port->count--; | ||
3315 | } | ||
3316 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | ||
3317 | port->blocked_open++; | ||
3318 | |||
3319 | while (1) { | ||
3320 | if (tty->termios->c_cflag & CBAUD) | ||
3321 | tty_port_raise_dtr_rts(port); | ||
3322 | |||
3323 | set_current_state(TASK_INTERRUPTIBLE); | ||
3324 | |||
3325 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ | ||
3326 | retval = (port->flags & ASYNC_HUP_NOTIFY) ? | ||
3327 | -EAGAIN : -ERESTARTSYS; | ||
3328 | break; | ||
3329 | } | ||
3330 | |||
3331 | dcd = tty_port_carrier_raised(&info->port); | ||
3332 | |||
3333 | if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd)) | ||
3334 | break; | ||
3335 | |||
3336 | if (signal_pending(current)) { | ||
3337 | retval = -ERESTARTSYS; | ||
3338 | break; | ||
3339 | } | ||
3340 | |||
3341 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3342 | printk("%s(%d):block_til_ready blocking on %s count=%d\n", | ||
3343 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3344 | |||
3345 | tty_unlock(); | ||
3346 | schedule(); | ||
3347 | tty_lock(); | ||
3348 | } | ||
3349 | |||
3350 | set_current_state(TASK_RUNNING); | ||
3351 | remove_wait_queue(&port->open_wait, &wait); | ||
3352 | |||
3353 | /* FIXME: Racy on hangup during close wait */ | ||
3354 | if (extra_count) | ||
3355 | port->count++; | ||
3356 | port->blocked_open--; | ||
3357 | |||
3358 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3359 | printk("%s(%d):block_til_ready after blocking on %s count=%d\n", | ||
3360 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3361 | |||
3362 | if (!retval) | ||
3363 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3364 | |||
3365 | return retval; | ||
3366 | |||
3367 | } /* end of block_til_ready() */ | ||
3368 | |||
3369 | /* mgsl_open() | ||
3370 | * | ||
3371 | * Called when a port is opened. Init and enable port. | ||
3372 | * Perform serial-specific initialization for the tty structure. | ||
3373 | * | ||
3374 | * Arguments: tty pointer to tty info structure | ||
3375 | * filp associated file pointer | ||
3376 | * | ||
3377 | * Return Value: 0 if success, otherwise error code | ||
3378 | */ | ||
3379 | static int mgsl_open(struct tty_struct *tty, struct file * filp) | ||
3380 | { | ||
3381 | struct mgsl_struct *info; | ||
3382 | int retval, line; | ||
3383 | unsigned long flags; | ||
3384 | |||
3385 | /* verify range of specified line number */ | ||
3386 | line = tty->index; | ||
3387 | if ((line < 0) || (line >= mgsl_device_count)) { | ||
3388 | printk("%s(%d):mgsl_open with invalid line #%d.\n", | ||
3389 | __FILE__,__LINE__,line); | ||
3390 | return -ENODEV; | ||
3391 | } | ||
3392 | |||
3393 | /* find the info structure for the specified line */ | ||
3394 | info = mgsl_device_list; | ||
3395 | while(info && info->line != line) | ||
3396 | info = info->next_device; | ||
3397 | if (mgsl_paranoia_check(info, tty->name, "mgsl_open")) | ||
3398 | return -ENODEV; | ||
3399 | |||
3400 | tty->driver_data = info; | ||
3401 | info->port.tty = tty; | ||
3402 | |||
3403 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3404 | printk("%s(%d):mgsl_open(%s), old ref count = %d\n", | ||
3405 | __FILE__,__LINE__,tty->driver->name, info->port.count); | ||
3406 | |||
3407 | /* If port is closing, signal caller to try again */ | ||
3408 | if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ | ||
3409 | if (info->port.flags & ASYNC_CLOSING) | ||
3410 | interruptible_sleep_on(&info->port.close_wait); | ||
3411 | retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? | ||
3412 | -EAGAIN : -ERESTARTSYS); | ||
3413 | goto cleanup; | ||
3414 | } | ||
3415 | |||
3416 | info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
3417 | |||
3418 | spin_lock_irqsave(&info->netlock, flags); | ||
3419 | if (info->netcount) { | ||
3420 | retval = -EBUSY; | ||
3421 | spin_unlock_irqrestore(&info->netlock, flags); | ||
3422 | goto cleanup; | ||
3423 | } | ||
3424 | info->port.count++; | ||
3425 | spin_unlock_irqrestore(&info->netlock, flags); | ||
3426 | |||
3427 | if (info->port.count == 1) { | ||
3428 | /* 1st open on this device, init hardware */ | ||
3429 | retval = startup(info); | ||
3430 | if (retval < 0) | ||
3431 | goto cleanup; | ||
3432 | } | ||
3433 | |||
3434 | retval = block_til_ready(tty, filp, info); | ||
3435 | if (retval) { | ||
3436 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3437 | printk("%s(%d):block_til_ready(%s) returned %d\n", | ||
3438 | __FILE__,__LINE__, info->device_name, retval); | ||
3439 | goto cleanup; | ||
3440 | } | ||
3441 | |||
3442 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3443 | printk("%s(%d):mgsl_open(%s) success\n", | ||
3444 | __FILE__,__LINE__, info->device_name); | ||
3445 | retval = 0; | ||
3446 | |||
3447 | cleanup: | ||
3448 | if (retval) { | ||
3449 | if (tty->count == 1) | ||
3450 | info->port.tty = NULL; /* tty layer will release tty struct */ | ||
3451 | if(info->port.count) | ||
3452 | info->port.count--; | ||
3453 | } | ||
3454 | |||
3455 | return retval; | ||
3456 | |||
3457 | } /* end of mgsl_open() */ | ||
3458 | |||
3459 | /* | ||
3460 | * /proc fs routines.... | ||
3461 | */ | ||
3462 | |||
3463 | static inline void line_info(struct seq_file *m, struct mgsl_struct *info) | ||
3464 | { | ||
3465 | char stat_buf[30]; | ||
3466 | unsigned long flags; | ||
3467 | |||
3468 | if (info->bus_type == MGSL_BUS_TYPE_PCI) { | ||
3469 | seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X", | ||
3470 | info->device_name, info->io_base, info->irq_level, | ||
3471 | info->phys_memory_base, info->phys_lcr_base); | ||
3472 | } else { | ||
3473 | seq_printf(m, "%s:(E)ISA io:%04X irq:%d dma:%d", | ||
3474 | info->device_name, info->io_base, | ||
3475 | info->irq_level, info->dma_level); | ||
3476 | } | ||
3477 | |||
3478 | /* output current serial signal states */ | ||
3479 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3480 | usc_get_serial_signals(info); | ||
3481 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3482 | |||
3483 | stat_buf[0] = 0; | ||
3484 | stat_buf[1] = 0; | ||
3485 | if (info->serial_signals & SerialSignal_RTS) | ||
3486 | strcat(stat_buf, "|RTS"); | ||
3487 | if (info->serial_signals & SerialSignal_CTS) | ||
3488 | strcat(stat_buf, "|CTS"); | ||
3489 | if (info->serial_signals & SerialSignal_DTR) | ||
3490 | strcat(stat_buf, "|DTR"); | ||
3491 | if (info->serial_signals & SerialSignal_DSR) | ||
3492 | strcat(stat_buf, "|DSR"); | ||
3493 | if (info->serial_signals & SerialSignal_DCD) | ||
3494 | strcat(stat_buf, "|CD"); | ||
3495 | if (info->serial_signals & SerialSignal_RI) | ||
3496 | strcat(stat_buf, "|RI"); | ||
3497 | |||
3498 | if (info->params.mode == MGSL_MODE_HDLC || | ||
3499 | info->params.mode == MGSL_MODE_RAW ) { | ||
3500 | seq_printf(m, " HDLC txok:%d rxok:%d", | ||
3501 | info->icount.txok, info->icount.rxok); | ||
3502 | if (info->icount.txunder) | ||
3503 | seq_printf(m, " txunder:%d", info->icount.txunder); | ||
3504 | if (info->icount.txabort) | ||
3505 | seq_printf(m, " txabort:%d", info->icount.txabort); | ||
3506 | if (info->icount.rxshort) | ||
3507 | seq_printf(m, " rxshort:%d", info->icount.rxshort); | ||
3508 | if (info->icount.rxlong) | ||
3509 | seq_printf(m, " rxlong:%d", info->icount.rxlong); | ||
3510 | if (info->icount.rxover) | ||
3511 | seq_printf(m, " rxover:%d", info->icount.rxover); | ||
3512 | if (info->icount.rxcrc) | ||
3513 | seq_printf(m, " rxcrc:%d", info->icount.rxcrc); | ||
3514 | } else { | ||
3515 | seq_printf(m, " ASYNC tx:%d rx:%d", | ||
3516 | info->icount.tx, info->icount.rx); | ||
3517 | if (info->icount.frame) | ||
3518 | seq_printf(m, " fe:%d", info->icount.frame); | ||
3519 | if (info->icount.parity) | ||
3520 | seq_printf(m, " pe:%d", info->icount.parity); | ||
3521 | if (info->icount.brk) | ||
3522 | seq_printf(m, " brk:%d", info->icount.brk); | ||
3523 | if (info->icount.overrun) | ||
3524 | seq_printf(m, " oe:%d", info->icount.overrun); | ||
3525 | } | ||
3526 | |||
3527 | /* Append serial signal status to end */ | ||
3528 | seq_printf(m, " %s\n", stat_buf+1); | ||
3529 | |||
3530 | seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", | ||
3531 | info->tx_active,info->bh_requested,info->bh_running, | ||
3532 | info->pending_bh); | ||
3533 | |||
3534 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
3535 | { | ||
3536 | u16 Tcsr = usc_InReg( info, TCSR ); | ||
3537 | u16 Tdmr = usc_InDmaReg( info, TDMR ); | ||
3538 | u16 Ticr = usc_InReg( info, TICR ); | ||
3539 | u16 Rscr = usc_InReg( info, RCSR ); | ||
3540 | u16 Rdmr = usc_InDmaReg( info, RDMR ); | ||
3541 | u16 Ricr = usc_InReg( info, RICR ); | ||
3542 | u16 Icr = usc_InReg( info, ICR ); | ||
3543 | u16 Dccr = usc_InReg( info, DCCR ); | ||
3544 | u16 Tmr = usc_InReg( info, TMR ); | ||
3545 | u16 Tccr = usc_InReg( info, TCCR ); | ||
3546 | u16 Ccar = inw( info->io_base + CCAR ); | ||
3547 | seq_printf(m, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n" | ||
3548 | "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n", | ||
3549 | Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar ); | ||
3550 | } | ||
3551 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
3552 | } | ||
3553 | |||
3554 | /* Called to print information about devices */ | ||
3555 | static int mgsl_proc_show(struct seq_file *m, void *v) | ||
3556 | { | ||
3557 | struct mgsl_struct *info; | ||
3558 | |||
3559 | seq_printf(m, "synclink driver:%s\n", driver_version); | ||
3560 | |||
3561 | info = mgsl_device_list; | ||
3562 | while( info ) { | ||
3563 | line_info(m, info); | ||
3564 | info = info->next_device; | ||
3565 | } | ||
3566 | return 0; | ||
3567 | } | ||
3568 | |||
3569 | static int mgsl_proc_open(struct inode *inode, struct file *file) | ||
3570 | { | ||
3571 | return single_open(file, mgsl_proc_show, NULL); | ||
3572 | } | ||
3573 | |||
3574 | static const struct file_operations mgsl_proc_fops = { | ||
3575 | .owner = THIS_MODULE, | ||
3576 | .open = mgsl_proc_open, | ||
3577 | .read = seq_read, | ||
3578 | .llseek = seq_lseek, | ||
3579 | .release = single_release, | ||
3580 | }; | ||
3581 | |||
3582 | /* mgsl_allocate_dma_buffers() | ||
3583 | * | ||
3584 | * Allocate and format DMA buffers (ISA adapter) | ||
3585 | * or format shared memory buffers (PCI adapter). | ||
3586 | * | ||
3587 | * Arguments: info pointer to device instance data | ||
3588 | * Return Value: 0 if success, otherwise error | ||
3589 | */ | ||
3590 | static int mgsl_allocate_dma_buffers(struct mgsl_struct *info) | ||
3591 | { | ||
3592 | unsigned short BuffersPerFrame; | ||
3593 | |||
3594 | info->last_mem_alloc = 0; | ||
3595 | |||
3596 | /* Calculate the number of DMA buffers necessary to hold the */ | ||
3597 | /* largest allowable frame size. Note: If the max frame size is */ | ||
3598 | /* not an even multiple of the DMA buffer size then we need to */ | ||
3599 | /* round the buffer count per frame up one. */ | ||
3600 | |||
3601 | BuffersPerFrame = (unsigned short)(info->max_frame_size/DMABUFFERSIZE); | ||
3602 | if ( info->max_frame_size % DMABUFFERSIZE ) | ||
3603 | BuffersPerFrame++; | ||
3604 | |||
3605 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
3606 | /* | ||
3607 | * The PCI adapter has 256KBytes of shared memory to use. | ||
3608 | * This is 64 PAGE_SIZE buffers. | ||
3609 | * | ||
3610 | * The first page is used for padding at this time so the | ||
3611 | * buffer list does not begin at offset 0 of the PCI | ||
3612 | * adapter's shared memory. | ||
3613 | * | ||
3614 | * The 2nd page is used for the buffer list. A 4K buffer | ||
3615 | * list can hold 128 DMA_BUFFER structures at 32 bytes | ||
3616 | * each. | ||
3617 | * | ||
3618 | * This leaves 62 4K pages. | ||
3619 | * | ||
3620 | * The next N pages are used for transmit frame(s). We | ||
3621 | * reserve enough 4K page blocks to hold the required | ||
3622 | * number of transmit dma buffers (num_tx_dma_buffers), | ||
3623 | * each of MaxFrameSize size. | ||
3624 | * | ||
3625 | * Of the remaining pages (62-N), determine how many can | ||
3626 | * be used to receive full MaxFrameSize inbound frames | ||
3627 | */ | ||
3628 | info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; | ||
3629 | info->rx_buffer_count = 62 - info->tx_buffer_count; | ||
3630 | } else { | ||
3631 | /* Calculate the number of PAGE_SIZE buffers needed for */ | ||
3632 | /* receive and transmit DMA buffers. */ | ||
3633 | |||
3634 | |||
3635 | /* Calculate the number of DMA buffers necessary to */ | ||
3636 | /* hold 7 max size receive frames and one max size transmit frame. */ | ||
3637 | /* The receive buffer count is bumped by one so we avoid an */ | ||
3638 | /* End of List condition if all receive buffers are used when */ | ||
3639 | /* using linked list DMA buffers. */ | ||
3640 | |||
3641 | info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame; | ||
3642 | info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6; | ||
3643 | |||
3644 | /* | ||
3645 | * limit total TxBuffers & RxBuffers to 62 4K total | ||
3646 | * (ala PCI Allocation) | ||
3647 | */ | ||
3648 | |||
3649 | if ( (info->tx_buffer_count + info->rx_buffer_count) > 62 ) | ||
3650 | info->rx_buffer_count = 62 - info->tx_buffer_count; | ||
3651 | |||
3652 | } | ||
3653 | |||
3654 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
3655 | printk("%s(%d):Allocating %d TX and %d RX DMA buffers.\n", | ||
3656 | __FILE__,__LINE__, info->tx_buffer_count,info->rx_buffer_count); | ||
3657 | |||
3658 | if ( mgsl_alloc_buffer_list_memory( info ) < 0 || | ||
3659 | mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || | ||
3660 | mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || | ||
3661 | mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 || | ||
3662 | mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) { | ||
3663 | printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__); | ||
3664 | return -ENOMEM; | ||
3665 | } | ||
3666 | |||
3667 | mgsl_reset_rx_dma_buffers( info ); | ||
3668 | mgsl_reset_tx_dma_buffers( info ); | ||
3669 | |||
3670 | return 0; | ||
3671 | |||
3672 | } /* end of mgsl_allocate_dma_buffers() */ | ||
3673 | |||
3674 | /* | ||
3675 | * mgsl_alloc_buffer_list_memory() | ||
3676 | * | ||
3677 | * Allocate a common DMA buffer for use as the | ||
3678 | * receive and transmit buffer lists. | ||
3679 | * | ||
3680 | * A buffer list is a set of buffer entries where each entry contains | ||
3681 | * a pointer to an actual buffer and a pointer to the next buffer entry | ||
3682 | * (plus some other info about the buffer). | ||
3683 | * | ||
3684 | * The buffer entries for a list are built to form a circular list so | ||
3685 | * that when the entire list has been traversed you start back at the | ||
3686 | * beginning. | ||
3687 | * | ||
3688 | * This function allocates memory for just the buffer entries. | ||
3689 | * The links (pointer to next entry) are filled in with the physical | ||
3690 | * address of the next entry so the adapter can navigate the list | ||
3691 | * using bus master DMA. The pointers to the actual buffers are filled | ||
3692 | * out later when the actual buffers are allocated. | ||
3693 | * | ||
3694 | * Arguments: info pointer to device instance data | ||
3695 | * Return Value: 0 if success, otherwise error | ||
3696 | */ | ||
3697 | static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info ) | ||
3698 | { | ||
3699 | unsigned int i; | ||
3700 | |||
3701 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
3702 | /* PCI adapter uses shared memory. */ | ||
3703 | info->buffer_list = info->memory_base + info->last_mem_alloc; | ||
3704 | info->buffer_list_phys = info->last_mem_alloc; | ||
3705 | info->last_mem_alloc += BUFFERLISTSIZE; | ||
3706 | } else { | ||
3707 | /* ISA adapter uses system memory. */ | ||
3708 | /* The buffer lists are allocated as a common buffer that both */ | ||
3709 | /* the processor and adapter can access. This allows the driver to */ | ||
3710 | /* inspect portions of the buffer while other portions are being */ | ||
3711 | /* updated by the adapter using Bus Master DMA. */ | ||
3712 | |||
3713 | info->buffer_list = dma_alloc_coherent(NULL, BUFFERLISTSIZE, &info->buffer_list_dma_addr, GFP_KERNEL); | ||
3714 | if (info->buffer_list == NULL) | ||
3715 | return -ENOMEM; | ||
3716 | info->buffer_list_phys = (u32)(info->buffer_list_dma_addr); | ||
3717 | } | ||
3718 | |||
3719 | /* We got the memory for the buffer entry lists. */ | ||
3720 | /* Initialize the memory block to all zeros. */ | ||
3721 | memset( info->buffer_list, 0, BUFFERLISTSIZE ); | ||
3722 | |||
3723 | /* Save virtual address pointers to the receive and */ | ||
3724 | /* transmit buffer lists. (Receive 1st). These pointers will */ | ||
3725 | /* be used by the processor to access the lists. */ | ||
3726 | info->rx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; | ||
3727 | info->tx_buffer_list = (DMABUFFERENTRY *)info->buffer_list; | ||
3728 | info->tx_buffer_list += info->rx_buffer_count; | ||
3729 | |||
3730 | /* | ||
3731 | * Build the links for the buffer entry lists such that | ||
3732 | * two circular lists are built. (Transmit and Receive). | ||
3733 | * | ||
3734 | * Note: the links are physical addresses | ||
3735 | * which are read by the adapter to determine the next | ||
3736 | * buffer entry to use. | ||
3737 | */ | ||
3738 | |||
3739 | for ( i = 0; i < info->rx_buffer_count; i++ ) { | ||
3740 | /* calculate and store physical address of this buffer entry */ | ||
3741 | info->rx_buffer_list[i].phys_entry = | ||
3742 | info->buffer_list_phys + (i * sizeof(DMABUFFERENTRY)); | ||
3743 | |||
3744 | /* calculate and store physical address of */ | ||
3745 | /* next entry in cirular list of entries */ | ||
3746 | |||
3747 | info->rx_buffer_list[i].link = info->buffer_list_phys; | ||
3748 | |||
3749 | if ( i < info->rx_buffer_count - 1 ) | ||
3750 | info->rx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); | ||
3751 | } | ||
3752 | |||
3753 | for ( i = 0; i < info->tx_buffer_count; i++ ) { | ||
3754 | /* calculate and store physical address of this buffer entry */ | ||
3755 | info->tx_buffer_list[i].phys_entry = info->buffer_list_phys + | ||
3756 | ((info->rx_buffer_count + i) * sizeof(DMABUFFERENTRY)); | ||
3757 | |||
3758 | /* calculate and store physical address of */ | ||
3759 | /* next entry in cirular list of entries */ | ||
3760 | |||
3761 | info->tx_buffer_list[i].link = info->buffer_list_phys + | ||
3762 | info->rx_buffer_count * sizeof(DMABUFFERENTRY); | ||
3763 | |||
3764 | if ( i < info->tx_buffer_count - 1 ) | ||
3765 | info->tx_buffer_list[i].link += (i + 1) * sizeof(DMABUFFERENTRY); | ||
3766 | } | ||
3767 | |||
3768 | return 0; | ||
3769 | |||
3770 | } /* end of mgsl_alloc_buffer_list_memory() */ | ||
3771 | |||
3772 | /* Free DMA buffers allocated for use as the | ||
3773 | * receive and transmit buffer lists. | ||
3774 | * Warning: | ||
3775 | * | ||
3776 | * The data transfer buffers associated with the buffer list | ||
3777 | * MUST be freed before freeing the buffer list itself because | ||
3778 | * the buffer list contains the information necessary to free | ||
3779 | * the individual buffers! | ||
3780 | */ | ||
3781 | static void mgsl_free_buffer_list_memory( struct mgsl_struct *info ) | ||
3782 | { | ||
3783 | if (info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI) | ||
3784 | dma_free_coherent(NULL, BUFFERLISTSIZE, info->buffer_list, info->buffer_list_dma_addr); | ||
3785 | |||
3786 | info->buffer_list = NULL; | ||
3787 | info->rx_buffer_list = NULL; | ||
3788 | info->tx_buffer_list = NULL; | ||
3789 | |||
3790 | } /* end of mgsl_free_buffer_list_memory() */ | ||
3791 | |||
3792 | /* | ||
3793 | * mgsl_alloc_frame_memory() | ||
3794 | * | ||
3795 | * Allocate the frame DMA buffers used by the specified buffer list. | ||
3796 | * Each DMA buffer will be one memory page in size. This is necessary | ||
3797 | * because memory can fragment enough that it may be impossible | ||
3798 | * contiguous pages. | ||
3799 | * | ||
3800 | * Arguments: | ||
3801 | * | ||
3802 | * info pointer to device instance data | ||
3803 | * BufferList pointer to list of buffer entries | ||
3804 | * Buffercount count of buffer entries in buffer list | ||
3805 | * | ||
3806 | * Return Value: 0 if success, otherwise -ENOMEM | ||
3807 | */ | ||
3808 | static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount) | ||
3809 | { | ||
3810 | int i; | ||
3811 | u32 phys_addr; | ||
3812 | |||
3813 | /* Allocate page sized buffers for the receive buffer list */ | ||
3814 | |||
3815 | for ( i = 0; i < Buffercount; i++ ) { | ||
3816 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
3817 | /* PCI adapter uses shared memory buffers. */ | ||
3818 | BufferList[i].virt_addr = info->memory_base + info->last_mem_alloc; | ||
3819 | phys_addr = info->last_mem_alloc; | ||
3820 | info->last_mem_alloc += DMABUFFERSIZE; | ||
3821 | } else { | ||
3822 | /* ISA adapter uses system memory. */ | ||
3823 | BufferList[i].virt_addr = dma_alloc_coherent(NULL, DMABUFFERSIZE, &BufferList[i].dma_addr, GFP_KERNEL); | ||
3824 | if (BufferList[i].virt_addr == NULL) | ||
3825 | return -ENOMEM; | ||
3826 | phys_addr = (u32)(BufferList[i].dma_addr); | ||
3827 | } | ||
3828 | BufferList[i].phys_addr = phys_addr; | ||
3829 | } | ||
3830 | |||
3831 | return 0; | ||
3832 | |||
3833 | } /* end of mgsl_alloc_frame_memory() */ | ||
3834 | |||
3835 | /* | ||
3836 | * mgsl_free_frame_memory() | ||
3837 | * | ||
3838 | * Free the buffers associated with | ||
3839 | * each buffer entry of a buffer list. | ||
3840 | * | ||
3841 | * Arguments: | ||
3842 | * | ||
3843 | * info pointer to device instance data | ||
3844 | * BufferList pointer to list of buffer entries | ||
3845 | * Buffercount count of buffer entries in buffer list | ||
3846 | * | ||
3847 | * Return Value: None | ||
3848 | */ | ||
3849 | static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *BufferList, int Buffercount) | ||
3850 | { | ||
3851 | int i; | ||
3852 | |||
3853 | if ( BufferList ) { | ||
3854 | for ( i = 0 ; i < Buffercount ; i++ ) { | ||
3855 | if ( BufferList[i].virt_addr ) { | ||
3856 | if ( info->bus_type != MGSL_BUS_TYPE_PCI ) | ||
3857 | dma_free_coherent(NULL, DMABUFFERSIZE, BufferList[i].virt_addr, BufferList[i].dma_addr); | ||
3858 | BufferList[i].virt_addr = NULL; | ||
3859 | } | ||
3860 | } | ||
3861 | } | ||
3862 | |||
3863 | } /* end of mgsl_free_frame_memory() */ | ||
3864 | |||
3865 | /* mgsl_free_dma_buffers() | ||
3866 | * | ||
3867 | * Free DMA buffers | ||
3868 | * | ||
3869 | * Arguments: info pointer to device instance data | ||
3870 | * Return Value: None | ||
3871 | */ | ||
3872 | static void mgsl_free_dma_buffers( struct mgsl_struct *info ) | ||
3873 | { | ||
3874 | mgsl_free_frame_memory( info, info->rx_buffer_list, info->rx_buffer_count ); | ||
3875 | mgsl_free_frame_memory( info, info->tx_buffer_list, info->tx_buffer_count ); | ||
3876 | mgsl_free_buffer_list_memory( info ); | ||
3877 | |||
3878 | } /* end of mgsl_free_dma_buffers() */ | ||
3879 | |||
3880 | |||
3881 | /* | ||
3882 | * mgsl_alloc_intermediate_rxbuffer_memory() | ||
3883 | * | ||
3884 | * Allocate a buffer large enough to hold max_frame_size. This buffer | ||
3885 | * is used to pass an assembled frame to the line discipline. | ||
3886 | * | ||
3887 | * Arguments: | ||
3888 | * | ||
3889 | * info pointer to device instance data | ||
3890 | * | ||
3891 | * Return Value: 0 if success, otherwise -ENOMEM | ||
3892 | */ | ||
3893 | static int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info) | ||
3894 | { | ||
3895 | info->intermediate_rxbuffer = kmalloc(info->max_frame_size, GFP_KERNEL | GFP_DMA); | ||
3896 | if ( info->intermediate_rxbuffer == NULL ) | ||
3897 | return -ENOMEM; | ||
3898 | |||
3899 | return 0; | ||
3900 | |||
3901 | } /* end of mgsl_alloc_intermediate_rxbuffer_memory() */ | ||
3902 | |||
3903 | /* | ||
3904 | * mgsl_free_intermediate_rxbuffer_memory() | ||
3905 | * | ||
3906 | * | ||
3907 | * Arguments: | ||
3908 | * | ||
3909 | * info pointer to device instance data | ||
3910 | * | ||
3911 | * Return Value: None | ||
3912 | */ | ||
3913 | static void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info) | ||
3914 | { | ||
3915 | kfree(info->intermediate_rxbuffer); | ||
3916 | info->intermediate_rxbuffer = NULL; | ||
3917 | |||
3918 | } /* end of mgsl_free_intermediate_rxbuffer_memory() */ | ||
3919 | |||
3920 | /* | ||
3921 | * mgsl_alloc_intermediate_txbuffer_memory() | ||
3922 | * | ||
3923 | * Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size. | ||
3924 | * This buffer is used to load transmit frames into the adapter's dma transfer | ||
3925 | * buffers when there is sufficient space. | ||
3926 | * | ||
3927 | * Arguments: | ||
3928 | * | ||
3929 | * info pointer to device instance data | ||
3930 | * | ||
3931 | * Return Value: 0 if success, otherwise -ENOMEM | ||
3932 | */ | ||
3933 | static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info) | ||
3934 | { | ||
3935 | int i; | ||
3936 | |||
3937 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
3938 | printk("%s %s(%d) allocating %d tx holding buffers\n", | ||
3939 | info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers); | ||
3940 | |||
3941 | memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers)); | ||
3942 | |||
3943 | for ( i=0; i<info->num_tx_holding_buffers; ++i) { | ||
3944 | info->tx_holding_buffers[i].buffer = | ||
3945 | kmalloc(info->max_frame_size, GFP_KERNEL); | ||
3946 | if (info->tx_holding_buffers[i].buffer == NULL) { | ||
3947 | for (--i; i >= 0; i--) { | ||
3948 | kfree(info->tx_holding_buffers[i].buffer); | ||
3949 | info->tx_holding_buffers[i].buffer = NULL; | ||
3950 | } | ||
3951 | return -ENOMEM; | ||
3952 | } | ||
3953 | } | ||
3954 | |||
3955 | return 0; | ||
3956 | |||
3957 | } /* end of mgsl_alloc_intermediate_txbuffer_memory() */ | ||
3958 | |||
3959 | /* | ||
3960 | * mgsl_free_intermediate_txbuffer_memory() | ||
3961 | * | ||
3962 | * | ||
3963 | * Arguments: | ||
3964 | * | ||
3965 | * info pointer to device instance data | ||
3966 | * | ||
3967 | * Return Value: None | ||
3968 | */ | ||
3969 | static void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info) | ||
3970 | { | ||
3971 | int i; | ||
3972 | |||
3973 | for ( i=0; i<info->num_tx_holding_buffers; ++i ) { | ||
3974 | kfree(info->tx_holding_buffers[i].buffer); | ||
3975 | info->tx_holding_buffers[i].buffer = NULL; | ||
3976 | } | ||
3977 | |||
3978 | info->get_tx_holding_index = 0; | ||
3979 | info->put_tx_holding_index = 0; | ||
3980 | info->tx_holding_count = 0; | ||
3981 | |||
3982 | } /* end of mgsl_free_intermediate_txbuffer_memory() */ | ||
3983 | |||
3984 | |||
3985 | /* | ||
3986 | * load_next_tx_holding_buffer() | ||
3987 | * | ||
3988 | * attempts to load the next buffered tx request into the | ||
3989 | * tx dma buffers | ||
3990 | * | ||
3991 | * Arguments: | ||
3992 | * | ||
3993 | * info pointer to device instance data | ||
3994 | * | ||
3995 | * Return Value: true if next buffered tx request loaded | ||
3996 | * into adapter's tx dma buffer, | ||
3997 | * false otherwise | ||
3998 | */ | ||
3999 | static bool load_next_tx_holding_buffer(struct mgsl_struct *info) | ||
4000 | { | ||
4001 | bool ret = false; | ||
4002 | |||
4003 | if ( info->tx_holding_count ) { | ||
4004 | /* determine if we have enough tx dma buffers | ||
4005 | * to accommodate the next tx frame | ||
4006 | */ | ||
4007 | struct tx_holding_buffer *ptx = | ||
4008 | &info->tx_holding_buffers[info->get_tx_holding_index]; | ||
4009 | int num_free = num_free_tx_dma_buffers(info); | ||
4010 | int num_needed = ptx->buffer_size / DMABUFFERSIZE; | ||
4011 | if ( ptx->buffer_size % DMABUFFERSIZE ) | ||
4012 | ++num_needed; | ||
4013 | |||
4014 | if (num_needed <= num_free) { | ||
4015 | info->xmit_cnt = ptx->buffer_size; | ||
4016 | mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size); | ||
4017 | |||
4018 | --info->tx_holding_count; | ||
4019 | if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers) | ||
4020 | info->get_tx_holding_index=0; | ||
4021 | |||
4022 | /* restart transmit timer */ | ||
4023 | mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(5000)); | ||
4024 | |||
4025 | ret = true; | ||
4026 | } | ||
4027 | } | ||
4028 | |||
4029 | return ret; | ||
4030 | } | ||
4031 | |||
4032 | /* | ||
4033 | * save_tx_buffer_request() | ||
4034 | * | ||
4035 | * attempt to store transmit frame request for later transmission | ||
4036 | * | ||
4037 | * Arguments: | ||
4038 | * | ||
4039 | * info pointer to device instance data | ||
4040 | * Buffer pointer to buffer containing frame to load | ||
4041 | * BufferSize size in bytes of frame in Buffer | ||
4042 | * | ||
4043 | * Return Value: 1 if able to store, 0 otherwise | ||
4044 | */ | ||
4045 | static int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize) | ||
4046 | { | ||
4047 | struct tx_holding_buffer *ptx; | ||
4048 | |||
4049 | if ( info->tx_holding_count >= info->num_tx_holding_buffers ) { | ||
4050 | return 0; /* all buffers in use */ | ||
4051 | } | ||
4052 | |||
4053 | ptx = &info->tx_holding_buffers[info->put_tx_holding_index]; | ||
4054 | ptx->buffer_size = BufferSize; | ||
4055 | memcpy( ptx->buffer, Buffer, BufferSize); | ||
4056 | |||
4057 | ++info->tx_holding_count; | ||
4058 | if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers) | ||
4059 | info->put_tx_holding_index=0; | ||
4060 | |||
4061 | return 1; | ||
4062 | } | ||
4063 | |||
4064 | static int mgsl_claim_resources(struct mgsl_struct *info) | ||
4065 | { | ||
4066 | if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) { | ||
4067 | printk( "%s(%d):I/O address conflict on device %s Addr=%08X\n", | ||
4068 | __FILE__,__LINE__,info->device_name, info->io_base); | ||
4069 | return -ENODEV; | ||
4070 | } | ||
4071 | info->io_addr_requested = true; | ||
4072 | |||
4073 | if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, | ||
4074 | info->device_name, info ) < 0 ) { | ||
4075 | printk( "%s(%d):Cant request interrupt on device %s IRQ=%d\n", | ||
4076 | __FILE__,__LINE__,info->device_name, info->irq_level ); | ||
4077 | goto errout; | ||
4078 | } | ||
4079 | info->irq_requested = true; | ||
4080 | |||
4081 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
4082 | if (request_mem_region(info->phys_memory_base,0x40000,"synclink") == NULL) { | ||
4083 | printk( "%s(%d):mem addr conflict device %s Addr=%08X\n", | ||
4084 | __FILE__,__LINE__,info->device_name, info->phys_memory_base); | ||
4085 | goto errout; | ||
4086 | } | ||
4087 | info->shared_mem_requested = true; | ||
4088 | if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) { | ||
4089 | printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n", | ||
4090 | __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset); | ||
4091 | goto errout; | ||
4092 | } | ||
4093 | info->lcr_mem_requested = true; | ||
4094 | |||
4095 | info->memory_base = ioremap_nocache(info->phys_memory_base, | ||
4096 | 0x40000); | ||
4097 | if (!info->memory_base) { | ||
4098 | printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n", | ||
4099 | __FILE__,__LINE__,info->device_name, info->phys_memory_base ); | ||
4100 | goto errout; | ||
4101 | } | ||
4102 | |||
4103 | if ( !mgsl_memory_test(info) ) { | ||
4104 | printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n", | ||
4105 | __FILE__,__LINE__,info->device_name, info->phys_memory_base ); | ||
4106 | goto errout; | ||
4107 | } | ||
4108 | |||
4109 | info->lcr_base = ioremap_nocache(info->phys_lcr_base, | ||
4110 | PAGE_SIZE); | ||
4111 | if (!info->lcr_base) { | ||
4112 | printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n", | ||
4113 | __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); | ||
4114 | goto errout; | ||
4115 | } | ||
4116 | info->lcr_base += info->lcr_offset; | ||
4117 | |||
4118 | } else { | ||
4119 | /* claim DMA channel */ | ||
4120 | |||
4121 | if (request_dma(info->dma_level,info->device_name) < 0){ | ||
4122 | printk( "%s(%d):Cant request DMA channel on device %s DMA=%d\n", | ||
4123 | __FILE__,__LINE__,info->device_name, info->dma_level ); | ||
4124 | mgsl_release_resources( info ); | ||
4125 | return -ENODEV; | ||
4126 | } | ||
4127 | info->dma_requested = true; | ||
4128 | |||
4129 | /* ISA adapter uses bus master DMA */ | ||
4130 | set_dma_mode(info->dma_level,DMA_MODE_CASCADE); | ||
4131 | enable_dma(info->dma_level); | ||
4132 | } | ||
4133 | |||
4134 | if ( mgsl_allocate_dma_buffers(info) < 0 ) { | ||
4135 | printk( "%s(%d):Cant allocate DMA buffers on device %s DMA=%d\n", | ||
4136 | __FILE__,__LINE__,info->device_name, info->dma_level ); | ||
4137 | goto errout; | ||
4138 | } | ||
4139 | |||
4140 | return 0; | ||
4141 | errout: | ||
4142 | mgsl_release_resources(info); | ||
4143 | return -ENODEV; | ||
4144 | |||
4145 | } /* end of mgsl_claim_resources() */ | ||
4146 | |||
4147 | static void mgsl_release_resources(struct mgsl_struct *info) | ||
4148 | { | ||
4149 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
4150 | printk( "%s(%d):mgsl_release_resources(%s) entry\n", | ||
4151 | __FILE__,__LINE__,info->device_name ); | ||
4152 | |||
4153 | if ( info->irq_requested ) { | ||
4154 | free_irq(info->irq_level, info); | ||
4155 | info->irq_requested = false; | ||
4156 | } | ||
4157 | if ( info->dma_requested ) { | ||
4158 | disable_dma(info->dma_level); | ||
4159 | free_dma(info->dma_level); | ||
4160 | info->dma_requested = false; | ||
4161 | } | ||
4162 | mgsl_free_dma_buffers(info); | ||
4163 | mgsl_free_intermediate_rxbuffer_memory(info); | ||
4164 | mgsl_free_intermediate_txbuffer_memory(info); | ||
4165 | |||
4166 | if ( info->io_addr_requested ) { | ||
4167 | release_region(info->io_base,info->io_addr_size); | ||
4168 | info->io_addr_requested = false; | ||
4169 | } | ||
4170 | if ( info->shared_mem_requested ) { | ||
4171 | release_mem_region(info->phys_memory_base,0x40000); | ||
4172 | info->shared_mem_requested = false; | ||
4173 | } | ||
4174 | if ( info->lcr_mem_requested ) { | ||
4175 | release_mem_region(info->phys_lcr_base + info->lcr_offset,128); | ||
4176 | info->lcr_mem_requested = false; | ||
4177 | } | ||
4178 | if (info->memory_base){ | ||
4179 | iounmap(info->memory_base); | ||
4180 | info->memory_base = NULL; | ||
4181 | } | ||
4182 | if (info->lcr_base){ | ||
4183 | iounmap(info->lcr_base - info->lcr_offset); | ||
4184 | info->lcr_base = NULL; | ||
4185 | } | ||
4186 | |||
4187 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
4188 | printk( "%s(%d):mgsl_release_resources(%s) exit\n", | ||
4189 | __FILE__,__LINE__,info->device_name ); | ||
4190 | |||
4191 | } /* end of mgsl_release_resources() */ | ||
4192 | |||
4193 | /* mgsl_add_device() | ||
4194 | * | ||
4195 | * Add the specified device instance data structure to the | ||
4196 | * global linked list of devices and increment the device count. | ||
4197 | * | ||
4198 | * Arguments: info pointer to device instance data | ||
4199 | * Return Value: None | ||
4200 | */ | ||
4201 | static void mgsl_add_device( struct mgsl_struct *info ) | ||
4202 | { | ||
4203 | info->next_device = NULL; | ||
4204 | info->line = mgsl_device_count; | ||
4205 | sprintf(info->device_name,"ttySL%d",info->line); | ||
4206 | |||
4207 | if (info->line < MAX_TOTAL_DEVICES) { | ||
4208 | if (maxframe[info->line]) | ||
4209 | info->max_frame_size = maxframe[info->line]; | ||
4210 | |||
4211 | if (txdmabufs[info->line]) { | ||
4212 | info->num_tx_dma_buffers = txdmabufs[info->line]; | ||
4213 | if (info->num_tx_dma_buffers < 1) | ||
4214 | info->num_tx_dma_buffers = 1; | ||
4215 | } | ||
4216 | |||
4217 | if (txholdbufs[info->line]) { | ||
4218 | info->num_tx_holding_buffers = txholdbufs[info->line]; | ||
4219 | if (info->num_tx_holding_buffers < 1) | ||
4220 | info->num_tx_holding_buffers = 1; | ||
4221 | else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS) | ||
4222 | info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS; | ||
4223 | } | ||
4224 | } | ||
4225 | |||
4226 | mgsl_device_count++; | ||
4227 | |||
4228 | if ( !mgsl_device_list ) | ||
4229 | mgsl_device_list = info; | ||
4230 | else { | ||
4231 | struct mgsl_struct *current_dev = mgsl_device_list; | ||
4232 | while( current_dev->next_device ) | ||
4233 | current_dev = current_dev->next_device; | ||
4234 | current_dev->next_device = info; | ||
4235 | } | ||
4236 | |||
4237 | if ( info->max_frame_size < 4096 ) | ||
4238 | info->max_frame_size = 4096; | ||
4239 | else if ( info->max_frame_size > 65535 ) | ||
4240 | info->max_frame_size = 65535; | ||
4241 | |||
4242 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
4243 | printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n", | ||
4244 | info->hw_version + 1, info->device_name, info->io_base, info->irq_level, | ||
4245 | info->phys_memory_base, info->phys_lcr_base, | ||
4246 | info->max_frame_size ); | ||
4247 | } else { | ||
4248 | printk( "SyncLink ISA %s: IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n", | ||
4249 | info->device_name, info->io_base, info->irq_level, info->dma_level, | ||
4250 | info->max_frame_size ); | ||
4251 | } | ||
4252 | |||
4253 | #if SYNCLINK_GENERIC_HDLC | ||
4254 | hdlcdev_init(info); | ||
4255 | #endif | ||
4256 | |||
4257 | } /* end of mgsl_add_device() */ | ||
4258 | |||
4259 | static const struct tty_port_operations mgsl_port_ops = { | ||
4260 | .carrier_raised = carrier_raised, | ||
4261 | .dtr_rts = dtr_rts, | ||
4262 | }; | ||
4263 | |||
4264 | |||
4265 | /* mgsl_allocate_device() | ||
4266 | * | ||
4267 | * Allocate and initialize a device instance structure | ||
4268 | * | ||
4269 | * Arguments: none | ||
4270 | * Return Value: pointer to mgsl_struct if success, otherwise NULL | ||
4271 | */ | ||
4272 | static struct mgsl_struct* mgsl_allocate_device(void) | ||
4273 | { | ||
4274 | struct mgsl_struct *info; | ||
4275 | |||
4276 | info = kzalloc(sizeof(struct mgsl_struct), | ||
4277 | GFP_KERNEL); | ||
4278 | |||
4279 | if (!info) { | ||
4280 | printk("Error can't allocate device instance data\n"); | ||
4281 | } else { | ||
4282 | tty_port_init(&info->port); | ||
4283 | info->port.ops = &mgsl_port_ops; | ||
4284 | info->magic = MGSL_MAGIC; | ||
4285 | INIT_WORK(&info->task, mgsl_bh_handler); | ||
4286 | info->max_frame_size = 4096; | ||
4287 | info->port.close_delay = 5*HZ/10; | ||
4288 | info->port.closing_wait = 30*HZ; | ||
4289 | init_waitqueue_head(&info->status_event_wait_q); | ||
4290 | init_waitqueue_head(&info->event_wait_q); | ||
4291 | spin_lock_init(&info->irq_spinlock); | ||
4292 | spin_lock_init(&info->netlock); | ||
4293 | memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); | ||
4294 | info->idle_mode = HDLC_TXIDLE_FLAGS; | ||
4295 | info->num_tx_dma_buffers = 1; | ||
4296 | info->num_tx_holding_buffers = 0; | ||
4297 | } | ||
4298 | |||
4299 | return info; | ||
4300 | |||
4301 | } /* end of mgsl_allocate_device()*/ | ||
4302 | |||
4303 | static const struct tty_operations mgsl_ops = { | ||
4304 | .open = mgsl_open, | ||
4305 | .close = mgsl_close, | ||
4306 | .write = mgsl_write, | ||
4307 | .put_char = mgsl_put_char, | ||
4308 | .flush_chars = mgsl_flush_chars, | ||
4309 | .write_room = mgsl_write_room, | ||
4310 | .chars_in_buffer = mgsl_chars_in_buffer, | ||
4311 | .flush_buffer = mgsl_flush_buffer, | ||
4312 | .ioctl = mgsl_ioctl, | ||
4313 | .throttle = mgsl_throttle, | ||
4314 | .unthrottle = mgsl_unthrottle, | ||
4315 | .send_xchar = mgsl_send_xchar, | ||
4316 | .break_ctl = mgsl_break, | ||
4317 | .wait_until_sent = mgsl_wait_until_sent, | ||
4318 | .set_termios = mgsl_set_termios, | ||
4319 | .stop = mgsl_stop, | ||
4320 | .start = mgsl_start, | ||
4321 | .hangup = mgsl_hangup, | ||
4322 | .tiocmget = tiocmget, | ||
4323 | .tiocmset = tiocmset, | ||
4324 | .get_icount = msgl_get_icount, | ||
4325 | .proc_fops = &mgsl_proc_fops, | ||
4326 | }; | ||
4327 | |||
4328 | /* | ||
4329 | * perform tty device initialization | ||
4330 | */ | ||
4331 | static int mgsl_init_tty(void) | ||
4332 | { | ||
4333 | int rc; | ||
4334 | |||
4335 | serial_driver = alloc_tty_driver(128); | ||
4336 | if (!serial_driver) | ||
4337 | return -ENOMEM; | ||
4338 | |||
4339 | serial_driver->owner = THIS_MODULE; | ||
4340 | serial_driver->driver_name = "synclink"; | ||
4341 | serial_driver->name = "ttySL"; | ||
4342 | serial_driver->major = ttymajor; | ||
4343 | serial_driver->minor_start = 64; | ||
4344 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
4345 | serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
4346 | serial_driver->init_termios = tty_std_termios; | ||
4347 | serial_driver->init_termios.c_cflag = | ||
4348 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
4349 | serial_driver->init_termios.c_ispeed = 9600; | ||
4350 | serial_driver->init_termios.c_ospeed = 9600; | ||
4351 | serial_driver->flags = TTY_DRIVER_REAL_RAW; | ||
4352 | tty_set_operations(serial_driver, &mgsl_ops); | ||
4353 | if ((rc = tty_register_driver(serial_driver)) < 0) { | ||
4354 | printk("%s(%d):Couldn't register serial driver\n", | ||
4355 | __FILE__,__LINE__); | ||
4356 | put_tty_driver(serial_driver); | ||
4357 | serial_driver = NULL; | ||
4358 | return rc; | ||
4359 | } | ||
4360 | |||
4361 | printk("%s %s, tty major#%d\n", | ||
4362 | driver_name, driver_version, | ||
4363 | serial_driver->major); | ||
4364 | return 0; | ||
4365 | } | ||
4366 | |||
4367 | /* enumerate user specified ISA adapters | ||
4368 | */ | ||
4369 | static void mgsl_enum_isa_devices(void) | ||
4370 | { | ||
4371 | struct mgsl_struct *info; | ||
4372 | int i; | ||
4373 | |||
4374 | /* Check for user specified ISA devices */ | ||
4375 | |||
4376 | for (i=0 ;(i < MAX_ISA_DEVICES) && io[i] && irq[i]; i++){ | ||
4377 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
4378 | printk("ISA device specified io=%04X,irq=%d,dma=%d\n", | ||
4379 | io[i], irq[i], dma[i] ); | ||
4380 | |||
4381 | info = mgsl_allocate_device(); | ||
4382 | if ( !info ) { | ||
4383 | /* error allocating device instance data */ | ||
4384 | if ( debug_level >= DEBUG_LEVEL_ERROR ) | ||
4385 | printk( "can't allocate device instance data.\n"); | ||
4386 | continue; | ||
4387 | } | ||
4388 | |||
4389 | /* Copy user configuration info to device instance data */ | ||
4390 | info->io_base = (unsigned int)io[i]; | ||
4391 | info->irq_level = (unsigned int)irq[i]; | ||
4392 | info->irq_level = irq_canonicalize(info->irq_level); | ||
4393 | info->dma_level = (unsigned int)dma[i]; | ||
4394 | info->bus_type = MGSL_BUS_TYPE_ISA; | ||
4395 | info->io_addr_size = 16; | ||
4396 | info->irq_flags = 0; | ||
4397 | |||
4398 | mgsl_add_device( info ); | ||
4399 | } | ||
4400 | } | ||
4401 | |||
4402 | static void synclink_cleanup(void) | ||
4403 | { | ||
4404 | int rc; | ||
4405 | struct mgsl_struct *info; | ||
4406 | struct mgsl_struct *tmp; | ||
4407 | |||
4408 | printk("Unloading %s: %s\n", driver_name, driver_version); | ||
4409 | |||
4410 | if (serial_driver) { | ||
4411 | if ((rc = tty_unregister_driver(serial_driver))) | ||
4412 | printk("%s(%d) failed to unregister tty driver err=%d\n", | ||
4413 | __FILE__,__LINE__,rc); | ||
4414 | put_tty_driver(serial_driver); | ||
4415 | } | ||
4416 | |||
4417 | info = mgsl_device_list; | ||
4418 | while(info) { | ||
4419 | #if SYNCLINK_GENERIC_HDLC | ||
4420 | hdlcdev_exit(info); | ||
4421 | #endif | ||
4422 | mgsl_release_resources(info); | ||
4423 | tmp = info; | ||
4424 | info = info->next_device; | ||
4425 | kfree(tmp); | ||
4426 | } | ||
4427 | |||
4428 | if (pci_registered) | ||
4429 | pci_unregister_driver(&synclink_pci_driver); | ||
4430 | } | ||
4431 | |||
4432 | static int __init synclink_init(void) | ||
4433 | { | ||
4434 | int rc; | ||
4435 | |||
4436 | if (break_on_load) { | ||
4437 | mgsl_get_text_ptr(); | ||
4438 | BREAKPOINT(); | ||
4439 | } | ||
4440 | |||
4441 | printk("%s %s\n", driver_name, driver_version); | ||
4442 | |||
4443 | mgsl_enum_isa_devices(); | ||
4444 | if ((rc = pci_register_driver(&synclink_pci_driver)) < 0) | ||
4445 | printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); | ||
4446 | else | ||
4447 | pci_registered = true; | ||
4448 | |||
4449 | if ((rc = mgsl_init_tty()) < 0) | ||
4450 | goto error; | ||
4451 | |||
4452 | return 0; | ||
4453 | |||
4454 | error: | ||
4455 | synclink_cleanup(); | ||
4456 | return rc; | ||
4457 | } | ||
4458 | |||
4459 | static void __exit synclink_exit(void) | ||
4460 | { | ||
4461 | synclink_cleanup(); | ||
4462 | } | ||
4463 | |||
4464 | module_init(synclink_init); | ||
4465 | module_exit(synclink_exit); | ||
4466 | |||
4467 | /* | ||
4468 | * usc_RTCmd() | ||
4469 | * | ||
4470 | * Issue a USC Receive/Transmit command to the | ||
4471 | * Channel Command/Address Register (CCAR). | ||
4472 | * | ||
4473 | * Notes: | ||
4474 | * | ||
4475 | * The command is encoded in the most significant 5 bits <15..11> | ||
4476 | * of the CCAR value. Bits <10..7> of the CCAR must be preserved | ||
4477 | * and Bits <6..0> must be written as zeros. | ||
4478 | * | ||
4479 | * Arguments: | ||
4480 | * | ||
4481 | * info pointer to device information structure | ||
4482 | * Cmd command mask (use symbolic macros) | ||
4483 | * | ||
4484 | * Return Value: | ||
4485 | * | ||
4486 | * None | ||
4487 | */ | ||
4488 | static void usc_RTCmd( struct mgsl_struct *info, u16 Cmd ) | ||
4489 | { | ||
4490 | /* output command to CCAR in bits <15..11> */ | ||
4491 | /* preserve bits <10..7>, bits <6..0> must be zero */ | ||
4492 | |||
4493 | outw( Cmd + info->loopback_bits, info->io_base + CCAR ); | ||
4494 | |||
4495 | /* Read to flush write to CCAR */ | ||
4496 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4497 | inw( info->io_base + CCAR ); | ||
4498 | |||
4499 | } /* end of usc_RTCmd() */ | ||
4500 | |||
4501 | /* | ||
4502 | * usc_DmaCmd() | ||
4503 | * | ||
4504 | * Issue a DMA command to the DMA Command/Address Register (DCAR). | ||
4505 | * | ||
4506 | * Arguments: | ||
4507 | * | ||
4508 | * info pointer to device information structure | ||
4509 | * Cmd DMA command mask (usc_DmaCmd_XX Macros) | ||
4510 | * | ||
4511 | * Return Value: | ||
4512 | * | ||
4513 | * None | ||
4514 | */ | ||
4515 | static void usc_DmaCmd( struct mgsl_struct *info, u16 Cmd ) | ||
4516 | { | ||
4517 | /* write command mask to DCAR */ | ||
4518 | outw( Cmd + info->mbre_bit, info->io_base ); | ||
4519 | |||
4520 | /* Read to flush write to DCAR */ | ||
4521 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4522 | inw( info->io_base ); | ||
4523 | |||
4524 | } /* end of usc_DmaCmd() */ | ||
4525 | |||
4526 | /* | ||
4527 | * usc_OutDmaReg() | ||
4528 | * | ||
4529 | * Write a 16-bit value to a USC DMA register | ||
4530 | * | ||
4531 | * Arguments: | ||
4532 | * | ||
4533 | * info pointer to device info structure | ||
4534 | * RegAddr register address (number) for write | ||
4535 | * RegValue 16-bit value to write to register | ||
4536 | * | ||
4537 | * Return Value: | ||
4538 | * | ||
4539 | * None | ||
4540 | * | ||
4541 | */ | ||
4542 | static void usc_OutDmaReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) | ||
4543 | { | ||
4544 | /* Note: The DCAR is located at the adapter base address */ | ||
4545 | /* Note: must preserve state of BIT8 in DCAR */ | ||
4546 | |||
4547 | outw( RegAddr + info->mbre_bit, info->io_base ); | ||
4548 | outw( RegValue, info->io_base ); | ||
4549 | |||
4550 | /* Read to flush write to DCAR */ | ||
4551 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4552 | inw( info->io_base ); | ||
4553 | |||
4554 | } /* end of usc_OutDmaReg() */ | ||
4555 | |||
4556 | /* | ||
4557 | * usc_InDmaReg() | ||
4558 | * | ||
4559 | * Read a 16-bit value from a DMA register | ||
4560 | * | ||
4561 | * Arguments: | ||
4562 | * | ||
4563 | * info pointer to device info structure | ||
4564 | * RegAddr register address (number) to read from | ||
4565 | * | ||
4566 | * Return Value: | ||
4567 | * | ||
4568 | * The 16-bit value read from register | ||
4569 | * | ||
4570 | */ | ||
4571 | static u16 usc_InDmaReg( struct mgsl_struct *info, u16 RegAddr ) | ||
4572 | { | ||
4573 | /* Note: The DCAR is located at the adapter base address */ | ||
4574 | /* Note: must preserve state of BIT8 in DCAR */ | ||
4575 | |||
4576 | outw( RegAddr + info->mbre_bit, info->io_base ); | ||
4577 | return inw( info->io_base ); | ||
4578 | |||
4579 | } /* end of usc_InDmaReg() */ | ||
4580 | |||
4581 | /* | ||
4582 | * | ||
4583 | * usc_OutReg() | ||
4584 | * | ||
4585 | * Write a 16-bit value to a USC serial channel register | ||
4586 | * | ||
4587 | * Arguments: | ||
4588 | * | ||
4589 | * info pointer to device info structure | ||
4590 | * RegAddr register address (number) to write to | ||
4591 | * RegValue 16-bit value to write to register | ||
4592 | * | ||
4593 | * Return Value: | ||
4594 | * | ||
4595 | * None | ||
4596 | * | ||
4597 | */ | ||
4598 | static void usc_OutReg( struct mgsl_struct *info, u16 RegAddr, u16 RegValue ) | ||
4599 | { | ||
4600 | outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); | ||
4601 | outw( RegValue, info->io_base + CCAR ); | ||
4602 | |||
4603 | /* Read to flush write to CCAR */ | ||
4604 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4605 | inw( info->io_base + CCAR ); | ||
4606 | |||
4607 | } /* end of usc_OutReg() */ | ||
4608 | |||
4609 | /* | ||
4610 | * usc_InReg() | ||
4611 | * | ||
4612 | * Reads a 16-bit value from a USC serial channel register | ||
4613 | * | ||
4614 | * Arguments: | ||
4615 | * | ||
4616 | * info pointer to device extension | ||
4617 | * RegAddr register address (number) to read from | ||
4618 | * | ||
4619 | * Return Value: | ||
4620 | * | ||
4621 | * 16-bit value read from register | ||
4622 | */ | ||
4623 | static u16 usc_InReg( struct mgsl_struct *info, u16 RegAddr ) | ||
4624 | { | ||
4625 | outw( RegAddr + info->loopback_bits, info->io_base + CCAR ); | ||
4626 | return inw( info->io_base + CCAR ); | ||
4627 | |||
4628 | } /* end of usc_InReg() */ | ||
4629 | |||
4630 | /* usc_set_sdlc_mode() | ||
4631 | * | ||
4632 | * Set up the adapter for SDLC DMA communications. | ||
4633 | * | ||
4634 | * Arguments: info pointer to device instance data | ||
4635 | * Return Value: NONE | ||
4636 | */ | ||
4637 | static void usc_set_sdlc_mode( struct mgsl_struct *info ) | ||
4638 | { | ||
4639 | u16 RegValue; | ||
4640 | bool PreSL1660; | ||
4641 | |||
4642 | /* | ||
4643 | * determine if the IUSC on the adapter is pre-SL1660. If | ||
4644 | * not, take advantage of the UnderWait feature of more | ||
4645 | * modern chips. If an underrun occurs and this bit is set, | ||
4646 | * the transmitter will idle the programmed idle pattern | ||
4647 | * until the driver has time to service the underrun. Otherwise, | ||
4648 | * the dma controller may get the cycles previously requested | ||
4649 | * and begin transmitting queued tx data. | ||
4650 | */ | ||
4651 | usc_OutReg(info,TMCR,0x1f); | ||
4652 | RegValue=usc_InReg(info,TMDR); | ||
4653 | PreSL1660 = (RegValue == IUSC_PRE_SL1660); | ||
4654 | |||
4655 | if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) | ||
4656 | { | ||
4657 | /* | ||
4658 | ** Channel Mode Register (CMR) | ||
4659 | ** | ||
4660 | ** <15..14> 10 Tx Sub Modes, Send Flag on Underrun | ||
4661 | ** <13> 0 0 = Transmit Disabled (initially) | ||
4662 | ** <12> 0 1 = Consecutive Idles share common 0 | ||
4663 | ** <11..8> 1110 Transmitter Mode = HDLC/SDLC Loop | ||
4664 | ** <7..4> 0000 Rx Sub Modes, addr/ctrl field handling | ||
4665 | ** <3..0> 0110 Receiver Mode = HDLC/SDLC | ||
4666 | ** | ||
4667 | ** 1000 1110 0000 0110 = 0x8e06 | ||
4668 | */ | ||
4669 | RegValue = 0x8e06; | ||
4670 | |||
4671 | /*-------------------------------------------------- | ||
4672 | * ignore user options for UnderRun Actions and | ||
4673 | * preambles | ||
4674 | *--------------------------------------------------*/ | ||
4675 | } | ||
4676 | else | ||
4677 | { | ||
4678 | /* Channel mode Register (CMR) | ||
4679 | * | ||
4680 | * <15..14> 00 Tx Sub modes, Underrun Action | ||
4681 | * <13> 0 1 = Send Preamble before opening flag | ||
4682 | * <12> 0 1 = Consecutive Idles share common 0 | ||
4683 | * <11..8> 0110 Transmitter mode = HDLC/SDLC | ||
4684 | * <7..4> 0000 Rx Sub modes, addr/ctrl field handling | ||
4685 | * <3..0> 0110 Receiver mode = HDLC/SDLC | ||
4686 | * | ||
4687 | * 0000 0110 0000 0110 = 0x0606 | ||
4688 | */ | ||
4689 | if (info->params.mode == MGSL_MODE_RAW) { | ||
4690 | RegValue = 0x0001; /* Set Receive mode = external sync */ | ||
4691 | |||
4692 | usc_OutReg( info, IOCR, /* Set IOCR DCD is RxSync Detect Input */ | ||
4693 | (unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12)); | ||
4694 | |||
4695 | /* | ||
4696 | * TxSubMode: | ||
4697 | * CMR <15> 0 Don't send CRC on Tx Underrun | ||
4698 | * CMR <14> x undefined | ||
4699 | * CMR <13> 0 Send preamble before openning sync | ||
4700 | * CMR <12> 0 Send 8-bit syncs, 1=send Syncs per TxLength | ||
4701 | * | ||
4702 | * TxMode: | ||
4703 | * CMR <11-8) 0100 MonoSync | ||
4704 | * | ||
4705 | * 0x00 0100 xxxx xxxx 04xx | ||
4706 | */ | ||
4707 | RegValue |= 0x0400; | ||
4708 | } | ||
4709 | else { | ||
4710 | |||
4711 | RegValue = 0x0606; | ||
4712 | |||
4713 | if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 ) | ||
4714 | RegValue |= BIT14; | ||
4715 | else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG ) | ||
4716 | RegValue |= BIT15; | ||
4717 | else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC ) | ||
4718 | RegValue |= BIT15 + BIT14; | ||
4719 | } | ||
4720 | |||
4721 | if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE ) | ||
4722 | RegValue |= BIT13; | ||
4723 | } | ||
4724 | |||
4725 | if ( info->params.mode == MGSL_MODE_HDLC && | ||
4726 | (info->params.flags & HDLC_FLAG_SHARE_ZERO) ) | ||
4727 | RegValue |= BIT12; | ||
4728 | |||
4729 | if ( info->params.addr_filter != 0xff ) | ||
4730 | { | ||
4731 | /* set up receive address filtering */ | ||
4732 | usc_OutReg( info, RSR, info->params.addr_filter ); | ||
4733 | RegValue |= BIT4; | ||
4734 | } | ||
4735 | |||
4736 | usc_OutReg( info, CMR, RegValue ); | ||
4737 | info->cmr_value = RegValue; | ||
4738 | |||
4739 | /* Receiver mode Register (RMR) | ||
4740 | * | ||
4741 | * <15..13> 000 encoding | ||
4742 | * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) | ||
4743 | * <10> 1 1 = Set CRC to all 1s (use for SDLC/HDLC) | ||
4744 | * <9> 0 1 = Include Receive chars in CRC | ||
4745 | * <8> 1 1 = Use Abort/PE bit as abort indicator | ||
4746 | * <7..6> 00 Even parity | ||
4747 | * <5> 0 parity disabled | ||
4748 | * <4..2> 000 Receive Char Length = 8 bits | ||
4749 | * <1..0> 00 Disable Receiver | ||
4750 | * | ||
4751 | * 0000 0101 0000 0000 = 0x0500 | ||
4752 | */ | ||
4753 | |||
4754 | RegValue = 0x0500; | ||
4755 | |||
4756 | switch ( info->params.encoding ) { | ||
4757 | case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; | ||
4758 | case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; | ||
4759 | case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break; | ||
4760 | case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; | ||
4761 | case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break; | ||
4762 | case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break; | ||
4763 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; | ||
4764 | } | ||
4765 | |||
4766 | if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) | ||
4767 | RegValue |= BIT9; | ||
4768 | else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) | ||
4769 | RegValue |= ( BIT12 | BIT10 | BIT9 ); | ||
4770 | |||
4771 | usc_OutReg( info, RMR, RegValue ); | ||
4772 | |||
4773 | /* Set the Receive count Limit Register (RCLR) to 0xffff. */ | ||
4774 | /* When an opening flag of an SDLC frame is recognized the */ | ||
4775 | /* Receive Character count (RCC) is loaded with the value in */ | ||
4776 | /* RCLR. The RCC is decremented for each received byte. The */ | ||
4777 | /* value of RCC is stored after the closing flag of the frame */ | ||
4778 | /* allowing the frame size to be computed. */ | ||
4779 | |||
4780 | usc_OutReg( info, RCLR, RCLRVALUE ); | ||
4781 | |||
4782 | usc_RCmd( info, RCmd_SelectRicrdma_level ); | ||
4783 | |||
4784 | /* Receive Interrupt Control Register (RICR) | ||
4785 | * | ||
4786 | * <15..8> ? RxFIFO DMA Request Level | ||
4787 | * <7> 0 Exited Hunt IA (Interrupt Arm) | ||
4788 | * <6> 0 Idle Received IA | ||
4789 | * <5> 0 Break/Abort IA | ||
4790 | * <4> 0 Rx Bound IA | ||
4791 | * <3> 1 Queued status reflects oldest 2 bytes in FIFO | ||
4792 | * <2> 0 Abort/PE IA | ||
4793 | * <1> 1 Rx Overrun IA | ||
4794 | * <0> 0 Select TC0 value for readback | ||
4795 | * | ||
4796 | * 0000 0000 0000 1000 = 0x000a | ||
4797 | */ | ||
4798 | |||
4799 | /* Carry over the Exit Hunt and Idle Received bits */ | ||
4800 | /* in case they have been armed by usc_ArmEvents. */ | ||
4801 | |||
4802 | RegValue = usc_InReg( info, RICR ) & 0xc0; | ||
4803 | |||
4804 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4805 | usc_OutReg( info, RICR, (u16)(0x030a | RegValue) ); | ||
4806 | else | ||
4807 | usc_OutReg( info, RICR, (u16)(0x140a | RegValue) ); | ||
4808 | |||
4809 | /* Unlatch all Rx status bits and clear Rx status IRQ Pending */ | ||
4810 | |||
4811 | usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); | ||
4812 | usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); | ||
4813 | |||
4814 | /* Transmit mode Register (TMR) | ||
4815 | * | ||
4816 | * <15..13> 000 encoding | ||
4817 | * <12..11> 00 FCS = 16bit CRC CCITT (x15 + x12 + x5 + 1) | ||
4818 | * <10> 1 1 = Start CRC as all 1s (use for SDLC/HDLC) | ||
4819 | * <9> 0 1 = Tx CRC Enabled | ||
4820 | * <8> 0 1 = Append CRC to end of transmit frame | ||
4821 | * <7..6> 00 Transmit parity Even | ||
4822 | * <5> 0 Transmit parity Disabled | ||
4823 | * <4..2> 000 Tx Char Length = 8 bits | ||
4824 | * <1..0> 00 Disable Transmitter | ||
4825 | * | ||
4826 | * 0000 0100 0000 0000 = 0x0400 | ||
4827 | */ | ||
4828 | |||
4829 | RegValue = 0x0400; | ||
4830 | |||
4831 | switch ( info->params.encoding ) { | ||
4832 | case HDLC_ENCODING_NRZB: RegValue |= BIT13; break; | ||
4833 | case HDLC_ENCODING_NRZI_MARK: RegValue |= BIT14; break; | ||
4834 | case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT14 + BIT13; break; | ||
4835 | case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT15; break; | ||
4836 | case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT15 + BIT13; break; | ||
4837 | case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14; break; | ||
4838 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break; | ||
4839 | } | ||
4840 | |||
4841 | if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT ) | ||
4842 | RegValue |= BIT9 + BIT8; | ||
4843 | else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT ) | ||
4844 | RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8); | ||
4845 | |||
4846 | usc_OutReg( info, TMR, RegValue ); | ||
4847 | |||
4848 | usc_set_txidle( info ); | ||
4849 | |||
4850 | |||
4851 | usc_TCmd( info, TCmd_SelectTicrdma_level ); | ||
4852 | |||
4853 | /* Transmit Interrupt Control Register (TICR) | ||
4854 | * | ||
4855 | * <15..8> ? Transmit FIFO DMA Level | ||
4856 | * <7> 0 Present IA (Interrupt Arm) | ||
4857 | * <6> 0 Idle Sent IA | ||
4858 | * <5> 1 Abort Sent IA | ||
4859 | * <4> 1 EOF/EOM Sent IA | ||
4860 | * <3> 0 CRC Sent IA | ||
4861 | * <2> 1 1 = Wait for SW Trigger to Start Frame | ||
4862 | * <1> 1 Tx Underrun IA | ||
4863 | * <0> 0 TC0 constant on read back | ||
4864 | * | ||
4865 | * 0000 0000 0011 0110 = 0x0036 | ||
4866 | */ | ||
4867 | |||
4868 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4869 | usc_OutReg( info, TICR, 0x0736 ); | ||
4870 | else | ||
4871 | usc_OutReg( info, TICR, 0x1436 ); | ||
4872 | |||
4873 | usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); | ||
4874 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); | ||
4875 | |||
4876 | /* | ||
4877 | ** Transmit Command/Status Register (TCSR) | ||
4878 | ** | ||
4879 | ** <15..12> 0000 TCmd | ||
4880 | ** <11> 0/1 UnderWait | ||
4881 | ** <10..08> 000 TxIdle | ||
4882 | ** <7> x PreSent | ||
4883 | ** <6> x IdleSent | ||
4884 | ** <5> x AbortSent | ||
4885 | ** <4> x EOF/EOM Sent | ||
4886 | ** <3> x CRC Sent | ||
4887 | ** <2> x All Sent | ||
4888 | ** <1> x TxUnder | ||
4889 | ** <0> x TxEmpty | ||
4890 | ** | ||
4891 | ** 0000 0000 0000 0000 = 0x0000 | ||
4892 | */ | ||
4893 | info->tcsr_value = 0; | ||
4894 | |||
4895 | if ( !PreSL1660 ) | ||
4896 | info->tcsr_value |= TCSR_UNDERWAIT; | ||
4897 | |||
4898 | usc_OutReg( info, TCSR, info->tcsr_value ); | ||
4899 | |||
4900 | /* Clock mode Control Register (CMCR) | ||
4901 | * | ||
4902 | * <15..14> 00 counter 1 Source = Disabled | ||
4903 | * <13..12> 00 counter 0 Source = Disabled | ||
4904 | * <11..10> 11 BRG1 Input is TxC Pin | ||
4905 | * <9..8> 11 BRG0 Input is TxC Pin | ||
4906 | * <7..6> 01 DPLL Input is BRG1 Output | ||
4907 | * <5..3> XXX TxCLK comes from Port 0 | ||
4908 | * <2..0> XXX RxCLK comes from Port 1 | ||
4909 | * | ||
4910 | * 0000 1111 0111 0111 = 0x0f77 | ||
4911 | */ | ||
4912 | |||
4913 | RegValue = 0x0f40; | ||
4914 | |||
4915 | if ( info->params.flags & HDLC_FLAG_RXC_DPLL ) | ||
4916 | RegValue |= 0x0003; /* RxCLK from DPLL */ | ||
4917 | else if ( info->params.flags & HDLC_FLAG_RXC_BRG ) | ||
4918 | RegValue |= 0x0004; /* RxCLK from BRG0 */ | ||
4919 | else if ( info->params.flags & HDLC_FLAG_RXC_TXCPIN) | ||
4920 | RegValue |= 0x0006; /* RxCLK from TXC Input */ | ||
4921 | else | ||
4922 | RegValue |= 0x0007; /* RxCLK from Port1 */ | ||
4923 | |||
4924 | if ( info->params.flags & HDLC_FLAG_TXC_DPLL ) | ||
4925 | RegValue |= 0x0018; /* TxCLK from DPLL */ | ||
4926 | else if ( info->params.flags & HDLC_FLAG_TXC_BRG ) | ||
4927 | RegValue |= 0x0020; /* TxCLK from BRG0 */ | ||
4928 | else if ( info->params.flags & HDLC_FLAG_TXC_RXCPIN) | ||
4929 | RegValue |= 0x0038; /* RxCLK from TXC Input */ | ||
4930 | else | ||
4931 | RegValue |= 0x0030; /* TxCLK from Port0 */ | ||
4932 | |||
4933 | usc_OutReg( info, CMCR, RegValue ); | ||
4934 | |||
4935 | |||
4936 | /* Hardware Configuration Register (HCR) | ||
4937 | * | ||
4938 | * <15..14> 00 CTR0 Divisor:00=32,01=16,10=8,11=4 | ||
4939 | * <13> 0 CTR1DSel:0=CTR0Div determines CTR0Div | ||
4940 | * <12> 0 CVOK:0=report code violation in biphase | ||
4941 | * <11..10> 00 DPLL Divisor:00=32,01=16,10=8,11=4 | ||
4942 | * <9..8> XX DPLL mode:00=disable,01=NRZ,10=Biphase,11=Biphase Level | ||
4943 | * <7..6> 00 reserved | ||
4944 | * <5> 0 BRG1 mode:0=continuous,1=single cycle | ||
4945 | * <4> X BRG1 Enable | ||
4946 | * <3..2> 00 reserved | ||
4947 | * <1> 0 BRG0 mode:0=continuous,1=single cycle | ||
4948 | * <0> 0 BRG0 Enable | ||
4949 | */ | ||
4950 | |||
4951 | RegValue = 0x0000; | ||
4952 | |||
4953 | if ( info->params.flags & (HDLC_FLAG_RXC_DPLL + HDLC_FLAG_TXC_DPLL) ) { | ||
4954 | u32 XtalSpeed; | ||
4955 | u32 DpllDivisor; | ||
4956 | u16 Tc; | ||
4957 | |||
4958 | /* DPLL is enabled. Use BRG1 to provide continuous reference clock */ | ||
4959 | /* for DPLL. DPLL mode in HCR is dependent on the encoding used. */ | ||
4960 | |||
4961 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
4962 | XtalSpeed = 11059200; | ||
4963 | else | ||
4964 | XtalSpeed = 14745600; | ||
4965 | |||
4966 | if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { | ||
4967 | DpllDivisor = 16; | ||
4968 | RegValue |= BIT10; | ||
4969 | } | ||
4970 | else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { | ||
4971 | DpllDivisor = 8; | ||
4972 | RegValue |= BIT11; | ||
4973 | } | ||
4974 | else | ||
4975 | DpllDivisor = 32; | ||
4976 | |||
4977 | /* Tc = (Xtal/Speed) - 1 */ | ||
4978 | /* If twice the remainder of (Xtal/Speed) is greater than Speed */ | ||
4979 | /* then rounding up gives a more precise time constant. Instead */ | ||
4980 | /* of rounding up and then subtracting 1 we just don't subtract */ | ||
4981 | /* the one in this case. */ | ||
4982 | |||
4983 | /*-------------------------------------------------- | ||
4984 | * ejz: for DPLL mode, application should use the | ||
4985 | * same clock speed as the partner system, even | ||
4986 | * though clocking is derived from the input RxData. | ||
4987 | * In case the user uses a 0 for the clock speed, | ||
4988 | * default to 0xffffffff and don't try to divide by | ||
4989 | * zero | ||
4990 | *--------------------------------------------------*/ | ||
4991 | if ( info->params.clock_speed ) | ||
4992 | { | ||
4993 | Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed); | ||
4994 | if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2) | ||
4995 | / info->params.clock_speed) ) | ||
4996 | Tc--; | ||
4997 | } | ||
4998 | else | ||
4999 | Tc = -1; | ||
5000 | |||
5001 | |||
5002 | /* Write 16-bit Time Constant for BRG1 */ | ||
5003 | usc_OutReg( info, TC1R, Tc ); | ||
5004 | |||
5005 | RegValue |= BIT4; /* enable BRG1 */ | ||
5006 | |||
5007 | switch ( info->params.encoding ) { | ||
5008 | case HDLC_ENCODING_NRZ: | ||
5009 | case HDLC_ENCODING_NRZB: | ||
5010 | case HDLC_ENCODING_NRZI_MARK: | ||
5011 | case HDLC_ENCODING_NRZI_SPACE: RegValue |= BIT8; break; | ||
5012 | case HDLC_ENCODING_BIPHASE_MARK: | ||
5013 | case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT9; break; | ||
5014 | case HDLC_ENCODING_BIPHASE_LEVEL: | ||
5015 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT9 + BIT8; break; | ||
5016 | } | ||
5017 | } | ||
5018 | |||
5019 | usc_OutReg( info, HCR, RegValue ); | ||
5020 | |||
5021 | |||
5022 | /* Channel Control/status Register (CCSR) | ||
5023 | * | ||
5024 | * <15> X RCC FIFO Overflow status (RO) | ||
5025 | * <14> X RCC FIFO Not Empty status (RO) | ||
5026 | * <13> 0 1 = Clear RCC FIFO (WO) | ||
5027 | * <12> X DPLL Sync (RW) | ||
5028 | * <11> X DPLL 2 Missed Clocks status (RO) | ||
5029 | * <10> X DPLL 1 Missed Clock status (RO) | ||
5030 | * <9..8> 00 DPLL Resync on rising and falling edges (RW) | ||
5031 | * <7> X SDLC Loop On status (RO) | ||
5032 | * <6> X SDLC Loop Send status (RO) | ||
5033 | * <5> 1 Bypass counters for TxClk and RxClk (RW) | ||
5034 | * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) | ||
5035 | * <1..0> 00 reserved | ||
5036 | * | ||
5037 | * 0000 0000 0010 0000 = 0x0020 | ||
5038 | */ | ||
5039 | |||
5040 | usc_OutReg( info, CCSR, 0x1020 ); | ||
5041 | |||
5042 | |||
5043 | if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) { | ||
5044 | usc_OutReg( info, SICR, | ||
5045 | (u16)(usc_InReg(info,SICR) | SICR_CTS_INACTIVE) ); | ||
5046 | } | ||
5047 | |||
5048 | |||
5049 | /* enable Master Interrupt Enable bit (MIE) */ | ||
5050 | usc_EnableMasterIrqBit( info ); | ||
5051 | |||
5052 | usc_ClearIrqPendingBits( info, RECEIVE_STATUS + RECEIVE_DATA + | ||
5053 | TRANSMIT_STATUS + TRANSMIT_DATA + MISC); | ||
5054 | |||
5055 | /* arm RCC underflow interrupt */ | ||
5056 | usc_OutReg(info, SICR, (u16)(usc_InReg(info,SICR) | BIT3)); | ||
5057 | usc_EnableInterrupts(info, MISC); | ||
5058 | |||
5059 | info->mbre_bit = 0; | ||
5060 | outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ | ||
5061 | usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ | ||
5062 | info->mbre_bit = BIT8; | ||
5063 | outw( BIT8, info->io_base ); /* set Master Bus Enable (DCAR) */ | ||
5064 | |||
5065 | if (info->bus_type == MGSL_BUS_TYPE_ISA) { | ||
5066 | /* Enable DMAEN (Port 7, Bit 14) */ | ||
5067 | /* This connects the DMA request signal to the ISA bus */ | ||
5068 | usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14)); | ||
5069 | } | ||
5070 | |||
5071 | /* DMA Control Register (DCR) | ||
5072 | * | ||
5073 | * <15..14> 10 Priority mode = Alternating Tx/Rx | ||
5074 | * 01 Rx has priority | ||
5075 | * 00 Tx has priority | ||
5076 | * | ||
5077 | * <13> 1 Enable Priority Preempt per DCR<15..14> | ||
5078 | * (WARNING DCR<11..10> must be 00 when this is 1) | ||
5079 | * 0 Choose activate channel per DCR<11..10> | ||
5080 | * | ||
5081 | * <12> 0 Little Endian for Array/List | ||
5082 | * <11..10> 00 Both Channels can use each bus grant | ||
5083 | * <9..6> 0000 reserved | ||
5084 | * <5> 0 7 CLK - Minimum Bus Re-request Interval | ||
5085 | * <4> 0 1 = drive D/C and S/D pins | ||
5086 | * <3> 1 1 = Add one wait state to all DMA cycles. | ||
5087 | * <2> 0 1 = Strobe /UAS on every transfer. | ||
5088 | * <1..0> 11 Addr incrementing only affects LS24 bits | ||
5089 | * | ||
5090 | * 0110 0000 0000 1011 = 0x600b | ||
5091 | */ | ||
5092 | |||
5093 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
5094 | /* PCI adapter does not need DMA wait state */ | ||
5095 | usc_OutDmaReg( info, DCR, 0xa00b ); | ||
5096 | } | ||
5097 | else | ||
5098 | usc_OutDmaReg( info, DCR, 0x800b ); | ||
5099 | |||
5100 | |||
5101 | /* Receive DMA mode Register (RDMR) | ||
5102 | * | ||
5103 | * <15..14> 11 DMA mode = Linked List Buffer mode | ||
5104 | * <13> 1 RSBinA/L = store Rx status Block in Arrary/List entry | ||
5105 | * <12> 1 Clear count of List Entry after fetching | ||
5106 | * <11..10> 00 Address mode = Increment | ||
5107 | * <9> 1 Terminate Buffer on RxBound | ||
5108 | * <8> 0 Bus Width = 16bits | ||
5109 | * <7..0> ? status Bits (write as 0s) | ||
5110 | * | ||
5111 | * 1111 0010 0000 0000 = 0xf200 | ||
5112 | */ | ||
5113 | |||
5114 | usc_OutDmaReg( info, RDMR, 0xf200 ); | ||
5115 | |||
5116 | |||
5117 | /* Transmit DMA mode Register (TDMR) | ||
5118 | * | ||
5119 | * <15..14> 11 DMA mode = Linked List Buffer mode | ||
5120 | * <13> 1 TCBinA/L = fetch Tx Control Block from List entry | ||
5121 | * <12> 1 Clear count of List Entry after fetching | ||
5122 | * <11..10> 00 Address mode = Increment | ||
5123 | * <9> 1 Terminate Buffer on end of frame | ||
5124 | * <8> 0 Bus Width = 16bits | ||
5125 | * <7..0> ? status Bits (Read Only so write as 0) | ||
5126 | * | ||
5127 | * 1111 0010 0000 0000 = 0xf200 | ||
5128 | */ | ||
5129 | |||
5130 | usc_OutDmaReg( info, TDMR, 0xf200 ); | ||
5131 | |||
5132 | |||
5133 | /* DMA Interrupt Control Register (DICR) | ||
5134 | * | ||
5135 | * <15> 1 DMA Interrupt Enable | ||
5136 | * <14> 0 1 = Disable IEO from USC | ||
5137 | * <13> 0 1 = Don't provide vector during IntAck | ||
5138 | * <12> 1 1 = Include status in Vector | ||
5139 | * <10..2> 0 reserved, Must be 0s | ||
5140 | * <1> 0 1 = Rx DMA Interrupt Enabled | ||
5141 | * <0> 0 1 = Tx DMA Interrupt Enabled | ||
5142 | * | ||
5143 | * 1001 0000 0000 0000 = 0x9000 | ||
5144 | */ | ||
5145 | |||
5146 | usc_OutDmaReg( info, DICR, 0x9000 ); | ||
5147 | |||
5148 | usc_InDmaReg( info, RDMR ); /* clear pending receive DMA IRQ bits */ | ||
5149 | usc_InDmaReg( info, TDMR ); /* clear pending transmit DMA IRQ bits */ | ||
5150 | usc_OutDmaReg( info, CDIR, 0x0303 ); /* clear IUS and Pending for Tx and Rx */ | ||
5151 | |||
5152 | /* Channel Control Register (CCR) | ||
5153 | * | ||
5154 | * <15..14> 10 Use 32-bit Tx Control Blocks (TCBs) | ||
5155 | * <13> 0 Trigger Tx on SW Command Disabled | ||
5156 | * <12> 0 Flag Preamble Disabled | ||
5157 | * <11..10> 00 Preamble Length | ||
5158 | * <9..8> 00 Preamble Pattern | ||
5159 | * <7..6> 10 Use 32-bit Rx status Blocks (RSBs) | ||
5160 | * <5> 0 Trigger Rx on SW Command Disabled | ||
5161 | * <4..0> 0 reserved | ||
5162 | * | ||
5163 | * 1000 0000 1000 0000 = 0x8080 | ||
5164 | */ | ||
5165 | |||
5166 | RegValue = 0x8080; | ||
5167 | |||
5168 | switch ( info->params.preamble_length ) { | ||
5169 | case HDLC_PREAMBLE_LENGTH_16BITS: RegValue |= BIT10; break; | ||
5170 | case HDLC_PREAMBLE_LENGTH_32BITS: RegValue |= BIT11; break; | ||
5171 | case HDLC_PREAMBLE_LENGTH_64BITS: RegValue |= BIT11 + BIT10; break; | ||
5172 | } | ||
5173 | |||
5174 | switch ( info->params.preamble ) { | ||
5175 | case HDLC_PREAMBLE_PATTERN_FLAGS: RegValue |= BIT8 + BIT12; break; | ||
5176 | case HDLC_PREAMBLE_PATTERN_ONES: RegValue |= BIT8; break; | ||
5177 | case HDLC_PREAMBLE_PATTERN_10: RegValue |= BIT9; break; | ||
5178 | case HDLC_PREAMBLE_PATTERN_01: RegValue |= BIT9 + BIT8; break; | ||
5179 | } | ||
5180 | |||
5181 | usc_OutReg( info, CCR, RegValue ); | ||
5182 | |||
5183 | |||
5184 | /* | ||
5185 | * Burst/Dwell Control Register | ||
5186 | * | ||
5187 | * <15..8> 0x20 Maximum number of transfers per bus grant | ||
5188 | * <7..0> 0x00 Maximum number of clock cycles per bus grant | ||
5189 | */ | ||
5190 | |||
5191 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
5192 | /* don't limit bus occupancy on PCI adapter */ | ||
5193 | usc_OutDmaReg( info, BDCR, 0x0000 ); | ||
5194 | } | ||
5195 | else | ||
5196 | usc_OutDmaReg( info, BDCR, 0x2000 ); | ||
5197 | |||
5198 | usc_stop_transmitter(info); | ||
5199 | usc_stop_receiver(info); | ||
5200 | |||
5201 | } /* end of usc_set_sdlc_mode() */ | ||
5202 | |||
5203 | /* usc_enable_loopback() | ||
5204 | * | ||
5205 | * Set the 16C32 for internal loopback mode. | ||
5206 | * The TxCLK and RxCLK signals are generated from the BRG0 and | ||
5207 | * the TxD is looped back to the RxD internally. | ||
5208 | * | ||
5209 | * Arguments: info pointer to device instance data | ||
5210 | * enable 1 = enable loopback, 0 = disable | ||
5211 | * Return Value: None | ||
5212 | */ | ||
5213 | static void usc_enable_loopback(struct mgsl_struct *info, int enable) | ||
5214 | { | ||
5215 | if (enable) { | ||
5216 | /* blank external TXD output */ | ||
5217 | usc_OutReg(info,IOCR,usc_InReg(info,IOCR) | (BIT7+BIT6)); | ||
5218 | |||
5219 | /* Clock mode Control Register (CMCR) | ||
5220 | * | ||
5221 | * <15..14> 00 counter 1 Disabled | ||
5222 | * <13..12> 00 counter 0 Disabled | ||
5223 | * <11..10> 11 BRG1 Input is TxC Pin | ||
5224 | * <9..8> 11 BRG0 Input is TxC Pin | ||
5225 | * <7..6> 01 DPLL Input is BRG1 Output | ||
5226 | * <5..3> 100 TxCLK comes from BRG0 | ||
5227 | * <2..0> 100 RxCLK comes from BRG0 | ||
5228 | * | ||
5229 | * 0000 1111 0110 0100 = 0x0f64 | ||
5230 | */ | ||
5231 | |||
5232 | usc_OutReg( info, CMCR, 0x0f64 ); | ||
5233 | |||
5234 | /* Write 16-bit Time Constant for BRG0 */ | ||
5235 | /* use clock speed if available, otherwise use 8 for diagnostics */ | ||
5236 | if (info->params.clock_speed) { | ||
5237 | if (info->bus_type == MGSL_BUS_TYPE_PCI) | ||
5238 | usc_OutReg(info, TC0R, (u16)((11059200/info->params.clock_speed)-1)); | ||
5239 | else | ||
5240 | usc_OutReg(info, TC0R, (u16)((14745600/info->params.clock_speed)-1)); | ||
5241 | } else | ||
5242 | usc_OutReg(info, TC0R, (u16)8); | ||
5243 | |||
5244 | /* Hardware Configuration Register (HCR) Clear Bit 1, BRG0 | ||
5245 | mode = Continuous Set Bit 0 to enable BRG0. */ | ||
5246 | usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); | ||
5247 | |||
5248 | /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ | ||
5249 | usc_OutReg(info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004)); | ||
5250 | |||
5251 | /* set Internal Data loopback mode */ | ||
5252 | info->loopback_bits = 0x300; | ||
5253 | outw( 0x0300, info->io_base + CCAR ); | ||
5254 | } else { | ||
5255 | /* enable external TXD output */ | ||
5256 | usc_OutReg(info,IOCR,usc_InReg(info,IOCR) & ~(BIT7+BIT6)); | ||
5257 | |||
5258 | /* clear Internal Data loopback mode */ | ||
5259 | info->loopback_bits = 0; | ||
5260 | outw( 0,info->io_base + CCAR ); | ||
5261 | } | ||
5262 | |||
5263 | } /* end of usc_enable_loopback() */ | ||
5264 | |||
5265 | /* usc_enable_aux_clock() | ||
5266 | * | ||
5267 | * Enabled the AUX clock output at the specified frequency. | ||
5268 | * | ||
5269 | * Arguments: | ||
5270 | * | ||
5271 | * info pointer to device extension | ||
5272 | * data_rate data rate of clock in bits per second | ||
5273 | * A data rate of 0 disables the AUX clock. | ||
5274 | * | ||
5275 | * Return Value: None | ||
5276 | */ | ||
5277 | static void usc_enable_aux_clock( struct mgsl_struct *info, u32 data_rate ) | ||
5278 | { | ||
5279 | u32 XtalSpeed; | ||
5280 | u16 Tc; | ||
5281 | |||
5282 | if ( data_rate ) { | ||
5283 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
5284 | XtalSpeed = 11059200; | ||
5285 | else | ||
5286 | XtalSpeed = 14745600; | ||
5287 | |||
5288 | |||
5289 | /* Tc = (Xtal/Speed) - 1 */ | ||
5290 | /* If twice the remainder of (Xtal/Speed) is greater than Speed */ | ||
5291 | /* then rounding up gives a more precise time constant. Instead */ | ||
5292 | /* of rounding up and then subtracting 1 we just don't subtract */ | ||
5293 | /* the one in this case. */ | ||
5294 | |||
5295 | |||
5296 | Tc = (u16)(XtalSpeed/data_rate); | ||
5297 | if ( !(((XtalSpeed % data_rate) * 2) / data_rate) ) | ||
5298 | Tc--; | ||
5299 | |||
5300 | /* Write 16-bit Time Constant for BRG0 */ | ||
5301 | usc_OutReg( info, TC0R, Tc ); | ||
5302 | |||
5303 | /* | ||
5304 | * Hardware Configuration Register (HCR) | ||
5305 | * Clear Bit 1, BRG0 mode = Continuous | ||
5306 | * Set Bit 0 to enable BRG0. | ||
5307 | */ | ||
5308 | |||
5309 | usc_OutReg( info, HCR, (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); | ||
5310 | |||
5311 | /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ | ||
5312 | usc_OutReg( info, IOCR, (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); | ||
5313 | } else { | ||
5314 | /* data rate == 0 so turn off BRG0 */ | ||
5315 | usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); | ||
5316 | } | ||
5317 | |||
5318 | } /* end of usc_enable_aux_clock() */ | ||
5319 | |||
5320 | /* | ||
5321 | * | ||
5322 | * usc_process_rxoverrun_sync() | ||
5323 | * | ||
5324 | * This function processes a receive overrun by resetting the | ||
5325 | * receive DMA buffers and issuing a Purge Rx FIFO command | ||
5326 | * to allow the receiver to continue receiving. | ||
5327 | * | ||
5328 | * Arguments: | ||
5329 | * | ||
5330 | * info pointer to device extension | ||
5331 | * | ||
5332 | * Return Value: None | ||
5333 | */ | ||
5334 | static void usc_process_rxoverrun_sync( struct mgsl_struct *info ) | ||
5335 | { | ||
5336 | int start_index; | ||
5337 | int end_index; | ||
5338 | int frame_start_index; | ||
5339 | bool start_of_frame_found = false; | ||
5340 | bool end_of_frame_found = false; | ||
5341 | bool reprogram_dma = false; | ||
5342 | |||
5343 | DMABUFFERENTRY *buffer_list = info->rx_buffer_list; | ||
5344 | u32 phys_addr; | ||
5345 | |||
5346 | usc_DmaCmd( info, DmaCmd_PauseRxChannel ); | ||
5347 | usc_RCmd( info, RCmd_EnterHuntmode ); | ||
5348 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
5349 | |||
5350 | /* CurrentRxBuffer points to the 1st buffer of the next */ | ||
5351 | /* possibly available receive frame. */ | ||
5352 | |||
5353 | frame_start_index = start_index = end_index = info->current_rx_buffer; | ||
5354 | |||
5355 | /* Search for an unfinished string of buffers. This means */ | ||
5356 | /* that a receive frame started (at least one buffer with */ | ||
5357 | /* count set to zero) but there is no terminiting buffer */ | ||
5358 | /* (status set to non-zero). */ | ||
5359 | |||
5360 | while( !buffer_list[end_index].count ) | ||
5361 | { | ||
5362 | /* Count field has been reset to zero by 16C32. */ | ||
5363 | /* This buffer is currently in use. */ | ||
5364 | |||
5365 | if ( !start_of_frame_found ) | ||
5366 | { | ||
5367 | start_of_frame_found = true; | ||
5368 | frame_start_index = end_index; | ||
5369 | end_of_frame_found = false; | ||
5370 | } | ||
5371 | |||
5372 | if ( buffer_list[end_index].status ) | ||
5373 | { | ||
5374 | /* Status field has been set by 16C32. */ | ||
5375 | /* This is the last buffer of a received frame. */ | ||
5376 | |||
5377 | /* We want to leave the buffers for this frame intact. */ | ||
5378 | /* Move on to next possible frame. */ | ||
5379 | |||
5380 | start_of_frame_found = false; | ||
5381 | end_of_frame_found = true; | ||
5382 | } | ||
5383 | |||
5384 | /* advance to next buffer entry in linked list */ | ||
5385 | end_index++; | ||
5386 | if ( end_index == info->rx_buffer_count ) | ||
5387 | end_index = 0; | ||
5388 | |||
5389 | if ( start_index == end_index ) | ||
5390 | { | ||
5391 | /* The entire list has been searched with all Counts == 0 and */ | ||
5392 | /* all Status == 0. The receive buffers are */ | ||
5393 | /* completely screwed, reset all receive buffers! */ | ||
5394 | mgsl_reset_rx_dma_buffers( info ); | ||
5395 | frame_start_index = 0; | ||
5396 | start_of_frame_found = false; | ||
5397 | reprogram_dma = true; | ||
5398 | break; | ||
5399 | } | ||
5400 | } | ||
5401 | |||
5402 | if ( start_of_frame_found && !end_of_frame_found ) | ||
5403 | { | ||
5404 | /* There is an unfinished string of receive DMA buffers */ | ||
5405 | /* as a result of the receiver overrun. */ | ||
5406 | |||
5407 | /* Reset the buffers for the unfinished frame */ | ||
5408 | /* and reprogram the receive DMA controller to start */ | ||
5409 | /* at the 1st buffer of unfinished frame. */ | ||
5410 | |||
5411 | start_index = frame_start_index; | ||
5412 | |||
5413 | do | ||
5414 | { | ||
5415 | *((unsigned long *)&(info->rx_buffer_list[start_index++].count)) = DMABUFFERSIZE; | ||
5416 | |||
5417 | /* Adjust index for wrap around. */ | ||
5418 | if ( start_index == info->rx_buffer_count ) | ||
5419 | start_index = 0; | ||
5420 | |||
5421 | } while( start_index != end_index ); | ||
5422 | |||
5423 | reprogram_dma = true; | ||
5424 | } | ||
5425 | |||
5426 | if ( reprogram_dma ) | ||
5427 | { | ||
5428 | usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); | ||
5429 | usc_ClearIrqPendingBits(info, RECEIVE_DATA|RECEIVE_STATUS); | ||
5430 | usc_UnlatchRxstatusBits(info, RECEIVE_DATA|RECEIVE_STATUS); | ||
5431 | |||
5432 | usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); | ||
5433 | |||
5434 | /* This empties the receive FIFO and loads the RCC with RCLR */ | ||
5435 | usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); | ||
5436 | |||
5437 | /* program 16C32 with physical address of 1st DMA buffer entry */ | ||
5438 | phys_addr = info->rx_buffer_list[frame_start_index].phys_entry; | ||
5439 | usc_OutDmaReg( info, NRARL, (u16)phys_addr ); | ||
5440 | usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) ); | ||
5441 | |||
5442 | usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); | ||
5443 | usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS ); | ||
5444 | usc_EnableInterrupts( info, RECEIVE_STATUS ); | ||
5445 | |||
5446 | /* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */ | ||
5447 | /* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */ | ||
5448 | |||
5449 | usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 ); | ||
5450 | usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) ); | ||
5451 | usc_DmaCmd( info, DmaCmd_InitRxChannel ); | ||
5452 | if ( info->params.flags & HDLC_FLAG_AUTO_DCD ) | ||
5453 | usc_EnableReceiver(info,ENABLE_AUTO_DCD); | ||
5454 | else | ||
5455 | usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); | ||
5456 | } | ||
5457 | else | ||
5458 | { | ||
5459 | /* This empties the receive FIFO and loads the RCC with RCLR */ | ||
5460 | usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); | ||
5461 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
5462 | } | ||
5463 | |||
5464 | } /* end of usc_process_rxoverrun_sync() */ | ||
5465 | |||
5466 | /* usc_stop_receiver() | ||
5467 | * | ||
5468 | * Disable USC receiver | ||
5469 | * | ||
5470 | * Arguments: info pointer to device instance data | ||
5471 | * Return Value: None | ||
5472 | */ | ||
5473 | static void usc_stop_receiver( struct mgsl_struct *info ) | ||
5474 | { | ||
5475 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
5476 | printk("%s(%d):usc_stop_receiver(%s)\n", | ||
5477 | __FILE__,__LINE__, info->device_name ); | ||
5478 | |||
5479 | /* Disable receive DMA channel. */ | ||
5480 | /* This also disables receive DMA channel interrupts */ | ||
5481 | usc_DmaCmd( info, DmaCmd_ResetRxChannel ); | ||
5482 | |||
5483 | usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); | ||
5484 | usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS ); | ||
5485 | usc_DisableInterrupts( info, RECEIVE_DATA + RECEIVE_STATUS ); | ||
5486 | |||
5487 | usc_EnableReceiver(info,DISABLE_UNCONDITIONAL); | ||
5488 | |||
5489 | /* This empties the receive FIFO and loads the RCC with RCLR */ | ||
5490 | usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); | ||
5491 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
5492 | |||
5493 | info->rx_enabled = false; | ||
5494 | info->rx_overflow = false; | ||
5495 | info->rx_rcc_underrun = false; | ||
5496 | |||
5497 | } /* end of stop_receiver() */ | ||
5498 | |||
5499 | /* usc_start_receiver() | ||
5500 | * | ||
5501 | * Enable the USC receiver | ||
5502 | * | ||
5503 | * Arguments: info pointer to device instance data | ||
5504 | * Return Value: None | ||
5505 | */ | ||
5506 | static void usc_start_receiver( struct mgsl_struct *info ) | ||
5507 | { | ||
5508 | u32 phys_addr; | ||
5509 | |||
5510 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
5511 | printk("%s(%d):usc_start_receiver(%s)\n", | ||
5512 | __FILE__,__LINE__, info->device_name ); | ||
5513 | |||
5514 | mgsl_reset_rx_dma_buffers( info ); | ||
5515 | usc_stop_receiver( info ); | ||
5516 | |||
5517 | usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) ); | ||
5518 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
5519 | |||
5520 | if ( info->params.mode == MGSL_MODE_HDLC || | ||
5521 | info->params.mode == MGSL_MODE_RAW ) { | ||
5522 | /* DMA mode Transfers */ | ||
5523 | /* Program the DMA controller. */ | ||
5524 | /* Enable the DMA controller end of buffer interrupt. */ | ||
5525 | |||
5526 | /* program 16C32 with physical address of 1st DMA buffer entry */ | ||
5527 | phys_addr = info->rx_buffer_list[0].phys_entry; | ||
5528 | usc_OutDmaReg( info, NRARL, (u16)phys_addr ); | ||
5529 | usc_OutDmaReg( info, NRARU, (u16)(phys_addr >> 16) ); | ||
5530 | |||
5531 | usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); | ||
5532 | usc_ClearIrqPendingBits( info, RECEIVE_DATA + RECEIVE_STATUS ); | ||
5533 | usc_EnableInterrupts( info, RECEIVE_STATUS ); | ||
5534 | |||
5535 | /* 1. Arm End of Buffer (EOB) Receive DMA Interrupt (BIT2 of RDIAR) */ | ||
5536 | /* 2. Enable Receive DMA Interrupts (BIT1 of DICR) */ | ||
5537 | |||
5538 | usc_OutDmaReg( info, RDIAR, BIT3 + BIT2 ); | ||
5539 | usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT1) ); | ||
5540 | usc_DmaCmd( info, DmaCmd_InitRxChannel ); | ||
5541 | if ( info->params.flags & HDLC_FLAG_AUTO_DCD ) | ||
5542 | usc_EnableReceiver(info,ENABLE_AUTO_DCD); | ||
5543 | else | ||
5544 | usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); | ||
5545 | } else { | ||
5546 | usc_UnlatchRxstatusBits(info, RXSTATUS_ALL); | ||
5547 | usc_ClearIrqPendingBits(info, RECEIVE_DATA + RECEIVE_STATUS); | ||
5548 | usc_EnableInterrupts(info, RECEIVE_DATA); | ||
5549 | |||
5550 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
5551 | usc_RCmd( info, RCmd_EnterHuntmode ); | ||
5552 | |||
5553 | usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); | ||
5554 | } | ||
5555 | |||
5556 | usc_OutReg( info, CCSR, 0x1020 ); | ||
5557 | |||
5558 | info->rx_enabled = true; | ||
5559 | |||
5560 | } /* end of usc_start_receiver() */ | ||
5561 | |||
5562 | /* usc_start_transmitter() | ||
5563 | * | ||
5564 | * Enable the USC transmitter and send a transmit frame if | ||
5565 | * one is loaded in the DMA buffers. | ||
5566 | * | ||
5567 | * Arguments: info pointer to device instance data | ||
5568 | * Return Value: None | ||
5569 | */ | ||
5570 | static void usc_start_transmitter( struct mgsl_struct *info ) | ||
5571 | { | ||
5572 | u32 phys_addr; | ||
5573 | unsigned int FrameSize; | ||
5574 | |||
5575 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
5576 | printk("%s(%d):usc_start_transmitter(%s)\n", | ||
5577 | __FILE__,__LINE__, info->device_name ); | ||
5578 | |||
5579 | if ( info->xmit_cnt ) { | ||
5580 | |||
5581 | /* If auto RTS enabled and RTS is inactive, then assert */ | ||
5582 | /* RTS and set a flag indicating that the driver should */ | ||
5583 | /* negate RTS when the transmission completes. */ | ||
5584 | |||
5585 | info->drop_rts_on_tx_done = false; | ||
5586 | |||
5587 | if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { | ||
5588 | usc_get_serial_signals( info ); | ||
5589 | if ( !(info->serial_signals & SerialSignal_RTS) ) { | ||
5590 | info->serial_signals |= SerialSignal_RTS; | ||
5591 | usc_set_serial_signals( info ); | ||
5592 | info->drop_rts_on_tx_done = true; | ||
5593 | } | ||
5594 | } | ||
5595 | |||
5596 | |||
5597 | if ( info->params.mode == MGSL_MODE_ASYNC ) { | ||
5598 | if ( !info->tx_active ) { | ||
5599 | usc_UnlatchTxstatusBits(info, TXSTATUS_ALL); | ||
5600 | usc_ClearIrqPendingBits(info, TRANSMIT_STATUS + TRANSMIT_DATA); | ||
5601 | usc_EnableInterrupts(info, TRANSMIT_DATA); | ||
5602 | usc_load_txfifo(info); | ||
5603 | } | ||
5604 | } else { | ||
5605 | /* Disable transmit DMA controller while programming. */ | ||
5606 | usc_DmaCmd( info, DmaCmd_ResetTxChannel ); | ||
5607 | |||
5608 | /* Transmit DMA buffer is loaded, so program USC */ | ||
5609 | /* to send the frame contained in the buffers. */ | ||
5610 | |||
5611 | FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc; | ||
5612 | |||
5613 | /* if operating in Raw sync mode, reset the rcc component | ||
5614 | * of the tx dma buffer entry, otherwise, the serial controller | ||
5615 | * will send a closing sync char after this count. | ||
5616 | */ | ||
5617 | if ( info->params.mode == MGSL_MODE_RAW ) | ||
5618 | info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0; | ||
5619 | |||
5620 | /* Program the Transmit Character Length Register (TCLR) */ | ||
5621 | /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ | ||
5622 | usc_OutReg( info, TCLR, (u16)FrameSize ); | ||
5623 | |||
5624 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
5625 | |||
5626 | /* Program the address of the 1st DMA Buffer Entry in linked list */ | ||
5627 | phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry; | ||
5628 | usc_OutDmaReg( info, NTARL, (u16)phys_addr ); | ||
5629 | usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) ); | ||
5630 | |||
5631 | usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); | ||
5632 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); | ||
5633 | usc_EnableInterrupts( info, TRANSMIT_STATUS ); | ||
5634 | |||
5635 | if ( info->params.mode == MGSL_MODE_RAW && | ||
5636 | info->num_tx_dma_buffers > 1 ) { | ||
5637 | /* When running external sync mode, attempt to 'stream' transmit */ | ||
5638 | /* by filling tx dma buffers as they become available. To do this */ | ||
5639 | /* we need to enable Tx DMA EOB Status interrupts : */ | ||
5640 | /* */ | ||
5641 | /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */ | ||
5642 | /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */ | ||
5643 | |||
5644 | usc_OutDmaReg( info, TDIAR, BIT2|BIT3 ); | ||
5645 | usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) ); | ||
5646 | } | ||
5647 | |||
5648 | /* Initialize Transmit DMA Channel */ | ||
5649 | usc_DmaCmd( info, DmaCmd_InitTxChannel ); | ||
5650 | |||
5651 | usc_TCmd( info, TCmd_SendFrame ); | ||
5652 | |||
5653 | mod_timer(&info->tx_timer, jiffies + | ||
5654 | msecs_to_jiffies(5000)); | ||
5655 | } | ||
5656 | info->tx_active = true; | ||
5657 | } | ||
5658 | |||
5659 | if ( !info->tx_enabled ) { | ||
5660 | info->tx_enabled = true; | ||
5661 | if ( info->params.flags & HDLC_FLAG_AUTO_CTS ) | ||
5662 | usc_EnableTransmitter(info,ENABLE_AUTO_CTS); | ||
5663 | else | ||
5664 | usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); | ||
5665 | } | ||
5666 | |||
5667 | } /* end of usc_start_transmitter() */ | ||
5668 | |||
5669 | /* usc_stop_transmitter() | ||
5670 | * | ||
5671 | * Stops the transmitter and DMA | ||
5672 | * | ||
5673 | * Arguments: info pointer to device isntance data | ||
5674 | * Return Value: None | ||
5675 | */ | ||
5676 | static void usc_stop_transmitter( struct mgsl_struct *info ) | ||
5677 | { | ||
5678 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
5679 | printk("%s(%d):usc_stop_transmitter(%s)\n", | ||
5680 | __FILE__,__LINE__, info->device_name ); | ||
5681 | |||
5682 | del_timer(&info->tx_timer); | ||
5683 | |||
5684 | usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); | ||
5685 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA ); | ||
5686 | usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA ); | ||
5687 | |||
5688 | usc_EnableTransmitter(info,DISABLE_UNCONDITIONAL); | ||
5689 | usc_DmaCmd( info, DmaCmd_ResetTxChannel ); | ||
5690 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
5691 | |||
5692 | info->tx_enabled = false; | ||
5693 | info->tx_active = false; | ||
5694 | |||
5695 | } /* end of usc_stop_transmitter() */ | ||
5696 | |||
5697 | /* usc_load_txfifo() | ||
5698 | * | ||
5699 | * Fill the transmit FIFO until the FIFO is full or | ||
5700 | * there is no more data to load. | ||
5701 | * | ||
5702 | * Arguments: info pointer to device extension (instance data) | ||
5703 | * Return Value: None | ||
5704 | */ | ||
5705 | static void usc_load_txfifo( struct mgsl_struct *info ) | ||
5706 | { | ||
5707 | int Fifocount; | ||
5708 | u8 TwoBytes[2]; | ||
5709 | |||
5710 | if ( !info->xmit_cnt && !info->x_char ) | ||
5711 | return; | ||
5712 | |||
5713 | /* Select transmit FIFO status readback in TICR */ | ||
5714 | usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); | ||
5715 | |||
5716 | /* load the Transmit FIFO until FIFOs full or all data sent */ | ||
5717 | |||
5718 | while( (Fifocount = usc_InReg(info, TICR) >> 8) && info->xmit_cnt ) { | ||
5719 | /* there is more space in the transmit FIFO and */ | ||
5720 | /* there is more data in transmit buffer */ | ||
5721 | |||
5722 | if ( (info->xmit_cnt > 1) && (Fifocount > 1) && !info->x_char ) { | ||
5723 | /* write a 16-bit word from transmit buffer to 16C32 */ | ||
5724 | |||
5725 | TwoBytes[0] = info->xmit_buf[info->xmit_tail++]; | ||
5726 | info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); | ||
5727 | TwoBytes[1] = info->xmit_buf[info->xmit_tail++]; | ||
5728 | info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); | ||
5729 | |||
5730 | outw( *((u16 *)TwoBytes), info->io_base + DATAREG); | ||
5731 | |||
5732 | info->xmit_cnt -= 2; | ||
5733 | info->icount.tx += 2; | ||
5734 | } else { | ||
5735 | /* only 1 byte left to transmit or 1 FIFO slot left */ | ||
5736 | |||
5737 | outw( (inw( info->io_base + CCAR) & 0x0780) | (TDR+LSBONLY), | ||
5738 | info->io_base + CCAR ); | ||
5739 | |||
5740 | if (info->x_char) { | ||
5741 | /* transmit pending high priority char */ | ||
5742 | outw( info->x_char,info->io_base + CCAR ); | ||
5743 | info->x_char = 0; | ||
5744 | } else { | ||
5745 | outw( info->xmit_buf[info->xmit_tail++],info->io_base + CCAR ); | ||
5746 | info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); | ||
5747 | info->xmit_cnt--; | ||
5748 | } | ||
5749 | info->icount.tx++; | ||
5750 | } | ||
5751 | } | ||
5752 | |||
5753 | } /* end of usc_load_txfifo() */ | ||
5754 | |||
5755 | /* usc_reset() | ||
5756 | * | ||
5757 | * Reset the adapter to a known state and prepare it for further use. | ||
5758 | * | ||
5759 | * Arguments: info pointer to device instance data | ||
5760 | * Return Value: None | ||
5761 | */ | ||
5762 | static void usc_reset( struct mgsl_struct *info ) | ||
5763 | { | ||
5764 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) { | ||
5765 | int i; | ||
5766 | u32 readval; | ||
5767 | |||
5768 | /* Set BIT30 of Misc Control Register */ | ||
5769 | /* (Local Control Register 0x50) to force reset of USC. */ | ||
5770 | |||
5771 | volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); | ||
5772 | u32 *LCR0BRDR = (u32 *)(info->lcr_base + 0x28); | ||
5773 | |||
5774 | info->misc_ctrl_value |= BIT30; | ||
5775 | *MiscCtrl = info->misc_ctrl_value; | ||
5776 | |||
5777 | /* | ||
5778 | * Force at least 170ns delay before clearing | ||
5779 | * reset bit. Each read from LCR takes at least | ||
5780 | * 30ns so 10 times for 300ns to be safe. | ||
5781 | */ | ||
5782 | for(i=0;i<10;i++) | ||
5783 | readval = *MiscCtrl; | ||
5784 | |||
5785 | info->misc_ctrl_value &= ~BIT30; | ||
5786 | *MiscCtrl = info->misc_ctrl_value; | ||
5787 | |||
5788 | *LCR0BRDR = BUS_DESCRIPTOR( | ||
5789 | 1, // Write Strobe Hold (0-3) | ||
5790 | 2, // Write Strobe Delay (0-3) | ||
5791 | 2, // Read Strobe Delay (0-3) | ||
5792 | 0, // NWDD (Write data-data) (0-3) | ||
5793 | 4, // NWAD (Write Addr-data) (0-31) | ||
5794 | 0, // NXDA (Read/Write Data-Addr) (0-3) | ||
5795 | 0, // NRDD (Read Data-Data) (0-3) | ||
5796 | 5 // NRAD (Read Addr-Data) (0-31) | ||
5797 | ); | ||
5798 | } else { | ||
5799 | /* do HW reset */ | ||
5800 | outb( 0,info->io_base + 8 ); | ||
5801 | } | ||
5802 | |||
5803 | info->mbre_bit = 0; | ||
5804 | info->loopback_bits = 0; | ||
5805 | info->usc_idle_mode = 0; | ||
5806 | |||
5807 | /* | ||
5808 | * Program the Bus Configuration Register (BCR) | ||
5809 | * | ||
5810 | * <15> 0 Don't use separate address | ||
5811 | * <14..6> 0 reserved | ||
5812 | * <5..4> 00 IAckmode = Default, don't care | ||
5813 | * <3> 1 Bus Request Totem Pole output | ||
5814 | * <2> 1 Use 16 Bit data bus | ||
5815 | * <1> 0 IRQ Totem Pole output | ||
5816 | * <0> 0 Don't Shift Right Addr | ||
5817 | * | ||
5818 | * 0000 0000 0000 1100 = 0x000c | ||
5819 | * | ||
5820 | * By writing to io_base + SDPIN the Wait/Ack pin is | ||
5821 | * programmed to work as a Wait pin. | ||
5822 | */ | ||
5823 | |||
5824 | outw( 0x000c,info->io_base + SDPIN ); | ||
5825 | |||
5826 | |||
5827 | outw( 0,info->io_base ); | ||
5828 | outw( 0,info->io_base + CCAR ); | ||
5829 | |||
5830 | /* select little endian byte ordering */ | ||
5831 | usc_RTCmd( info, RTCmd_SelectLittleEndian ); | ||
5832 | |||
5833 | |||
5834 | /* Port Control Register (PCR) | ||
5835 | * | ||
5836 | * <15..14> 11 Port 7 is Output (~DMAEN, Bit 14 : 0 = Enabled) | ||
5837 | * <13..12> 11 Port 6 is Output (~INTEN, Bit 12 : 0 = Enabled) | ||
5838 | * <11..10> 00 Port 5 is Input (No Connect, Don't Care) | ||
5839 | * <9..8> 00 Port 4 is Input (No Connect, Don't Care) | ||
5840 | * <7..6> 11 Port 3 is Output (~RTS, Bit 6 : 0 = Enabled ) | ||
5841 | * <5..4> 11 Port 2 is Output (~DTR, Bit 4 : 0 = Enabled ) | ||
5842 | * <3..2> 01 Port 1 is Input (Dedicated RxC) | ||
5843 | * <1..0> 01 Port 0 is Input (Dedicated TxC) | ||
5844 | * | ||
5845 | * 1111 0000 1111 0101 = 0xf0f5 | ||
5846 | */ | ||
5847 | |||
5848 | usc_OutReg( info, PCR, 0xf0f5 ); | ||
5849 | |||
5850 | |||
5851 | /* | ||
5852 | * Input/Output Control Register | ||
5853 | * | ||
5854 | * <15..14> 00 CTS is active low input | ||
5855 | * <13..12> 00 DCD is active low input | ||
5856 | * <11..10> 00 TxREQ pin is input (DSR) | ||
5857 | * <9..8> 00 RxREQ pin is input (RI) | ||
5858 | * <7..6> 00 TxD is output (Transmit Data) | ||
5859 | * <5..3> 000 TxC Pin in Input (14.7456MHz Clock) | ||
5860 | * <2..0> 100 RxC is Output (drive with BRG0) | ||
5861 | * | ||
5862 | * 0000 0000 0000 0100 = 0x0004 | ||
5863 | */ | ||
5864 | |||
5865 | usc_OutReg( info, IOCR, 0x0004 ); | ||
5866 | |||
5867 | } /* end of usc_reset() */ | ||
5868 | |||
5869 | /* usc_set_async_mode() | ||
5870 | * | ||
5871 | * Program adapter for asynchronous communications. | ||
5872 | * | ||
5873 | * Arguments: info pointer to device instance data | ||
5874 | * Return Value: None | ||
5875 | */ | ||
5876 | static void usc_set_async_mode( struct mgsl_struct *info ) | ||
5877 | { | ||
5878 | u16 RegValue; | ||
5879 | |||
5880 | /* disable interrupts while programming USC */ | ||
5881 | usc_DisableMasterIrqBit( info ); | ||
5882 | |||
5883 | outw( 0, info->io_base ); /* clear Master Bus Enable (DCAR) */ | ||
5884 | usc_DmaCmd( info, DmaCmd_ResetAllChannels ); /* disable both DMA channels */ | ||
5885 | |||
5886 | usc_loopback_frame( info ); | ||
5887 | |||
5888 | /* Channel mode Register (CMR) | ||
5889 | * | ||
5890 | * <15..14> 00 Tx Sub modes, 00 = 1 Stop Bit | ||
5891 | * <13..12> 00 00 = 16X Clock | ||
5892 | * <11..8> 0000 Transmitter mode = Asynchronous | ||
5893 | * <7..6> 00 reserved? | ||
5894 | * <5..4> 00 Rx Sub modes, 00 = 16X Clock | ||
5895 | * <3..0> 0000 Receiver mode = Asynchronous | ||
5896 | * | ||
5897 | * 0000 0000 0000 0000 = 0x0 | ||
5898 | */ | ||
5899 | |||
5900 | RegValue = 0; | ||
5901 | if ( info->params.stop_bits != 1 ) | ||
5902 | RegValue |= BIT14; | ||
5903 | usc_OutReg( info, CMR, RegValue ); | ||
5904 | |||
5905 | |||
5906 | /* Receiver mode Register (RMR) | ||
5907 | * | ||
5908 | * <15..13> 000 encoding = None | ||
5909 | * <12..08> 00000 reserved (Sync Only) | ||
5910 | * <7..6> 00 Even parity | ||
5911 | * <5> 0 parity disabled | ||
5912 | * <4..2> 000 Receive Char Length = 8 bits | ||
5913 | * <1..0> 00 Disable Receiver | ||
5914 | * | ||
5915 | * 0000 0000 0000 0000 = 0x0 | ||
5916 | */ | ||
5917 | |||
5918 | RegValue = 0; | ||
5919 | |||
5920 | if ( info->params.data_bits != 8 ) | ||
5921 | RegValue |= BIT4+BIT3+BIT2; | ||
5922 | |||
5923 | if ( info->params.parity != ASYNC_PARITY_NONE ) { | ||
5924 | RegValue |= BIT5; | ||
5925 | if ( info->params.parity != ASYNC_PARITY_ODD ) | ||
5926 | RegValue |= BIT6; | ||
5927 | } | ||
5928 | |||
5929 | usc_OutReg( info, RMR, RegValue ); | ||
5930 | |||
5931 | |||
5932 | /* Set IRQ trigger level */ | ||
5933 | |||
5934 | usc_RCmd( info, RCmd_SelectRicrIntLevel ); | ||
5935 | |||
5936 | |||
5937 | /* Receive Interrupt Control Register (RICR) | ||
5938 | * | ||
5939 | * <15..8> ? RxFIFO IRQ Request Level | ||
5940 | * | ||
5941 | * Note: For async mode the receive FIFO level must be set | ||
5942 | * to 0 to avoid the situation where the FIFO contains fewer bytes | ||
5943 | * than the trigger level and no more data is expected. | ||
5944 | * | ||
5945 | * <7> 0 Exited Hunt IA (Interrupt Arm) | ||
5946 | * <6> 0 Idle Received IA | ||
5947 | * <5> 0 Break/Abort IA | ||
5948 | * <4> 0 Rx Bound IA | ||
5949 | * <3> 0 Queued status reflects oldest byte in FIFO | ||
5950 | * <2> 0 Abort/PE IA | ||
5951 | * <1> 0 Rx Overrun IA | ||
5952 | * <0> 0 Select TC0 value for readback | ||
5953 | * | ||
5954 | * 0000 0000 0100 0000 = 0x0000 + (FIFOLEVEL in MSB) | ||
5955 | */ | ||
5956 | |||
5957 | usc_OutReg( info, RICR, 0x0000 ); | ||
5958 | |||
5959 | usc_UnlatchRxstatusBits( info, RXSTATUS_ALL ); | ||
5960 | usc_ClearIrqPendingBits( info, RECEIVE_STATUS ); | ||
5961 | |||
5962 | |||
5963 | /* Transmit mode Register (TMR) | ||
5964 | * | ||
5965 | * <15..13> 000 encoding = None | ||
5966 | * <12..08> 00000 reserved (Sync Only) | ||
5967 | * <7..6> 00 Transmit parity Even | ||
5968 | * <5> 0 Transmit parity Disabled | ||
5969 | * <4..2> 000 Tx Char Length = 8 bits | ||
5970 | * <1..0> 00 Disable Transmitter | ||
5971 | * | ||
5972 | * 0000 0000 0000 0000 = 0x0 | ||
5973 | */ | ||
5974 | |||
5975 | RegValue = 0; | ||
5976 | |||
5977 | if ( info->params.data_bits != 8 ) | ||
5978 | RegValue |= BIT4+BIT3+BIT2; | ||
5979 | |||
5980 | if ( info->params.parity != ASYNC_PARITY_NONE ) { | ||
5981 | RegValue |= BIT5; | ||
5982 | if ( info->params.parity != ASYNC_PARITY_ODD ) | ||
5983 | RegValue |= BIT6; | ||
5984 | } | ||
5985 | |||
5986 | usc_OutReg( info, TMR, RegValue ); | ||
5987 | |||
5988 | usc_set_txidle( info ); | ||
5989 | |||
5990 | |||
5991 | /* Set IRQ trigger level */ | ||
5992 | |||
5993 | usc_TCmd( info, TCmd_SelectTicrIntLevel ); | ||
5994 | |||
5995 | |||
5996 | /* Transmit Interrupt Control Register (TICR) | ||
5997 | * | ||
5998 | * <15..8> ? Transmit FIFO IRQ Level | ||
5999 | * <7> 0 Present IA (Interrupt Arm) | ||
6000 | * <6> 1 Idle Sent IA | ||
6001 | * <5> 0 Abort Sent IA | ||
6002 | * <4> 0 EOF/EOM Sent IA | ||
6003 | * <3> 0 CRC Sent IA | ||
6004 | * <2> 0 1 = Wait for SW Trigger to Start Frame | ||
6005 | * <1> 0 Tx Underrun IA | ||
6006 | * <0> 0 TC0 constant on read back | ||
6007 | * | ||
6008 | * 0000 0000 0100 0000 = 0x0040 | ||
6009 | */ | ||
6010 | |||
6011 | usc_OutReg( info, TICR, 0x1f40 ); | ||
6012 | |||
6013 | usc_UnlatchTxstatusBits( info, TXSTATUS_ALL ); | ||
6014 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS ); | ||
6015 | |||
6016 | usc_enable_async_clock( info, info->params.data_rate ); | ||
6017 | |||
6018 | |||
6019 | /* Channel Control/status Register (CCSR) | ||
6020 | * | ||
6021 | * <15> X RCC FIFO Overflow status (RO) | ||
6022 | * <14> X RCC FIFO Not Empty status (RO) | ||
6023 | * <13> 0 1 = Clear RCC FIFO (WO) | ||
6024 | * <12> X DPLL in Sync status (RO) | ||
6025 | * <11> X DPLL 2 Missed Clocks status (RO) | ||
6026 | * <10> X DPLL 1 Missed Clock status (RO) | ||
6027 | * <9..8> 00 DPLL Resync on rising and falling edges (RW) | ||
6028 | * <7> X SDLC Loop On status (RO) | ||
6029 | * <6> X SDLC Loop Send status (RO) | ||
6030 | * <5> 1 Bypass counters for TxClk and RxClk (RW) | ||
6031 | * <4..2> 000 Last Char of SDLC frame has 8 bits (RW) | ||
6032 | * <1..0> 00 reserved | ||
6033 | * | ||
6034 | * 0000 0000 0010 0000 = 0x0020 | ||
6035 | */ | ||
6036 | |||
6037 | usc_OutReg( info, CCSR, 0x0020 ); | ||
6038 | |||
6039 | usc_DisableInterrupts( info, TRANSMIT_STATUS + TRANSMIT_DATA + | ||
6040 | RECEIVE_DATA + RECEIVE_STATUS ); | ||
6041 | |||
6042 | usc_ClearIrqPendingBits( info, TRANSMIT_STATUS + TRANSMIT_DATA + | ||
6043 | RECEIVE_DATA + RECEIVE_STATUS ); | ||
6044 | |||
6045 | usc_EnableMasterIrqBit( info ); | ||
6046 | |||
6047 | if (info->bus_type == MGSL_BUS_TYPE_ISA) { | ||
6048 | /* Enable INTEN (Port 6, Bit12) */ | ||
6049 | /* This connects the IRQ request signal to the ISA bus */ | ||
6050 | usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); | ||
6051 | } | ||
6052 | |||
6053 | if (info->params.loopback) { | ||
6054 | info->loopback_bits = 0x300; | ||
6055 | outw(0x0300, info->io_base + CCAR); | ||
6056 | } | ||
6057 | |||
6058 | } /* end of usc_set_async_mode() */ | ||
6059 | |||
6060 | /* usc_loopback_frame() | ||
6061 | * | ||
6062 | * Loop back a small (2 byte) dummy SDLC frame. | ||
6063 | * Interrupts and DMA are NOT used. The purpose of this is to | ||
6064 | * clear any 'stale' status info left over from running in async mode. | ||
6065 | * | ||
6066 | * The 16C32 shows the strange behaviour of marking the 1st | ||
6067 | * received SDLC frame with a CRC error even when there is no | ||
6068 | * CRC error. To get around this a small dummy from of 2 bytes | ||
6069 | * is looped back when switching from async to sync mode. | ||
6070 | * | ||
6071 | * Arguments: info pointer to device instance data | ||
6072 | * Return Value: None | ||
6073 | */ | ||
6074 | static void usc_loopback_frame( struct mgsl_struct *info ) | ||
6075 | { | ||
6076 | int i; | ||
6077 | unsigned long oldmode = info->params.mode; | ||
6078 | |||
6079 | info->params.mode = MGSL_MODE_HDLC; | ||
6080 | |||
6081 | usc_DisableMasterIrqBit( info ); | ||
6082 | |||
6083 | usc_set_sdlc_mode( info ); | ||
6084 | usc_enable_loopback( info, 1 ); | ||
6085 | |||
6086 | /* Write 16-bit Time Constant for BRG0 */ | ||
6087 | usc_OutReg( info, TC0R, 0 ); | ||
6088 | |||
6089 | /* Channel Control Register (CCR) | ||
6090 | * | ||
6091 | * <15..14> 00 Don't use 32-bit Tx Control Blocks (TCBs) | ||
6092 | * <13> 0 Trigger Tx on SW Command Disabled | ||
6093 | * <12> 0 Flag Preamble Disabled | ||
6094 | * <11..10> 00 Preamble Length = 8-Bits | ||
6095 | * <9..8> 01 Preamble Pattern = flags | ||
6096 | * <7..6> 10 Don't use 32-bit Rx status Blocks (RSBs) | ||
6097 | * <5> 0 Trigger Rx on SW Command Disabled | ||
6098 | * <4..0> 0 reserved | ||
6099 | * | ||
6100 | * 0000 0001 0000 0000 = 0x0100 | ||
6101 | */ | ||
6102 | |||
6103 | usc_OutReg( info, CCR, 0x0100 ); | ||
6104 | |||
6105 | /* SETUP RECEIVER */ | ||
6106 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
6107 | usc_EnableReceiver(info,ENABLE_UNCONDITIONAL); | ||
6108 | |||
6109 | /* SETUP TRANSMITTER */ | ||
6110 | /* Program the Transmit Character Length Register (TCLR) */ | ||
6111 | /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ | ||
6112 | usc_OutReg( info, TCLR, 2 ); | ||
6113 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
6114 | |||
6115 | /* unlatch Tx status bits, and start transmit channel. */ | ||
6116 | usc_UnlatchTxstatusBits(info,TXSTATUS_ALL); | ||
6117 | outw(0,info->io_base + DATAREG); | ||
6118 | |||
6119 | /* ENABLE TRANSMITTER */ | ||
6120 | usc_TCmd( info, TCmd_SendFrame ); | ||
6121 | usc_EnableTransmitter(info,ENABLE_UNCONDITIONAL); | ||
6122 | |||
6123 | /* WAIT FOR RECEIVE COMPLETE */ | ||
6124 | for (i=0 ; i<1000 ; i++) | ||
6125 | if (usc_InReg( info, RCSR ) & (BIT8 + BIT4 + BIT3 + BIT1)) | ||
6126 | break; | ||
6127 | |||
6128 | /* clear Internal Data loopback mode */ | ||
6129 | usc_enable_loopback(info, 0); | ||
6130 | |||
6131 | usc_EnableMasterIrqBit(info); | ||
6132 | |||
6133 | info->params.mode = oldmode; | ||
6134 | |||
6135 | } /* end of usc_loopback_frame() */ | ||
6136 | |||
6137 | /* usc_set_sync_mode() Programs the USC for SDLC communications. | ||
6138 | * | ||
6139 | * Arguments: info pointer to adapter info structure | ||
6140 | * Return Value: None | ||
6141 | */ | ||
6142 | static void usc_set_sync_mode( struct mgsl_struct *info ) | ||
6143 | { | ||
6144 | usc_loopback_frame( info ); | ||
6145 | usc_set_sdlc_mode( info ); | ||
6146 | |||
6147 | if (info->bus_type == MGSL_BUS_TYPE_ISA) { | ||
6148 | /* Enable INTEN (Port 6, Bit12) */ | ||
6149 | /* This connects the IRQ request signal to the ISA bus */ | ||
6150 | usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12)); | ||
6151 | } | ||
6152 | |||
6153 | usc_enable_aux_clock(info, info->params.clock_speed); | ||
6154 | |||
6155 | if (info->params.loopback) | ||
6156 | usc_enable_loopback(info,1); | ||
6157 | |||
6158 | } /* end of mgsl_set_sync_mode() */ | ||
6159 | |||
6160 | /* usc_set_txidle() Set the HDLC idle mode for the transmitter. | ||
6161 | * | ||
6162 | * Arguments: info pointer to device instance data | ||
6163 | * Return Value: None | ||
6164 | */ | ||
6165 | static void usc_set_txidle( struct mgsl_struct *info ) | ||
6166 | { | ||
6167 | u16 usc_idle_mode = IDLEMODE_FLAGS; | ||
6168 | |||
6169 | /* Map API idle mode to USC register bits */ | ||
6170 | |||
6171 | switch( info->idle_mode ){ | ||
6172 | case HDLC_TXIDLE_FLAGS: usc_idle_mode = IDLEMODE_FLAGS; break; | ||
6173 | case HDLC_TXIDLE_ALT_ZEROS_ONES: usc_idle_mode = IDLEMODE_ALT_ONE_ZERO; break; | ||
6174 | case HDLC_TXIDLE_ZEROS: usc_idle_mode = IDLEMODE_ZERO; break; | ||
6175 | case HDLC_TXIDLE_ONES: usc_idle_mode = IDLEMODE_ONE; break; | ||
6176 | case HDLC_TXIDLE_ALT_MARK_SPACE: usc_idle_mode = IDLEMODE_ALT_MARK_SPACE; break; | ||
6177 | case HDLC_TXIDLE_SPACE: usc_idle_mode = IDLEMODE_SPACE; break; | ||
6178 | case HDLC_TXIDLE_MARK: usc_idle_mode = IDLEMODE_MARK; break; | ||
6179 | } | ||
6180 | |||
6181 | info->usc_idle_mode = usc_idle_mode; | ||
6182 | //usc_OutReg(info, TCSR, usc_idle_mode); | ||
6183 | info->tcsr_value &= ~IDLEMODE_MASK; /* clear idle mode bits */ | ||
6184 | info->tcsr_value += usc_idle_mode; | ||
6185 | usc_OutReg(info, TCSR, info->tcsr_value); | ||
6186 | |||
6187 | /* | ||
6188 | * if SyncLink WAN adapter is running in external sync mode, the | ||
6189 | * transmitter has been set to Monosync in order to try to mimic | ||
6190 | * a true raw outbound bit stream. Monosync still sends an open/close | ||
6191 | * sync char at the start/end of a frame. Try to match those sync | ||
6192 | * patterns to the idle mode set here | ||
6193 | */ | ||
6194 | if ( info->params.mode == MGSL_MODE_RAW ) { | ||
6195 | unsigned char syncpat = 0; | ||
6196 | switch( info->idle_mode ) { | ||
6197 | case HDLC_TXIDLE_FLAGS: | ||
6198 | syncpat = 0x7e; | ||
6199 | break; | ||
6200 | case HDLC_TXIDLE_ALT_ZEROS_ONES: | ||
6201 | syncpat = 0x55; | ||
6202 | break; | ||
6203 | case HDLC_TXIDLE_ZEROS: | ||
6204 | case HDLC_TXIDLE_SPACE: | ||
6205 | syncpat = 0x00; | ||
6206 | break; | ||
6207 | case HDLC_TXIDLE_ONES: | ||
6208 | case HDLC_TXIDLE_MARK: | ||
6209 | syncpat = 0xff; | ||
6210 | break; | ||
6211 | case HDLC_TXIDLE_ALT_MARK_SPACE: | ||
6212 | syncpat = 0xaa; | ||
6213 | break; | ||
6214 | } | ||
6215 | |||
6216 | usc_SetTransmitSyncChars(info,syncpat,syncpat); | ||
6217 | } | ||
6218 | |||
6219 | } /* end of usc_set_txidle() */ | ||
6220 | |||
6221 | /* usc_get_serial_signals() | ||
6222 | * | ||
6223 | * Query the adapter for the state of the V24 status (input) signals. | ||
6224 | * | ||
6225 | * Arguments: info pointer to device instance data | ||
6226 | * Return Value: None | ||
6227 | */ | ||
6228 | static void usc_get_serial_signals( struct mgsl_struct *info ) | ||
6229 | { | ||
6230 | u16 status; | ||
6231 | |||
6232 | /* clear all serial signals except DTR and RTS */ | ||
6233 | info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; | ||
6234 | |||
6235 | /* Read the Misc Interrupt status Register (MISR) to get */ | ||
6236 | /* the V24 status signals. */ | ||
6237 | |||
6238 | status = usc_InReg( info, MISR ); | ||
6239 | |||
6240 | /* set serial signal bits to reflect MISR */ | ||
6241 | |||
6242 | if ( status & MISCSTATUS_CTS ) | ||
6243 | info->serial_signals |= SerialSignal_CTS; | ||
6244 | |||
6245 | if ( status & MISCSTATUS_DCD ) | ||
6246 | info->serial_signals |= SerialSignal_DCD; | ||
6247 | |||
6248 | if ( status & MISCSTATUS_RI ) | ||
6249 | info->serial_signals |= SerialSignal_RI; | ||
6250 | |||
6251 | if ( status & MISCSTATUS_DSR ) | ||
6252 | info->serial_signals |= SerialSignal_DSR; | ||
6253 | |||
6254 | } /* end of usc_get_serial_signals() */ | ||
6255 | |||
6256 | /* usc_set_serial_signals() | ||
6257 | * | ||
6258 | * Set the state of DTR and RTS based on contents of | ||
6259 | * serial_signals member of device extension. | ||
6260 | * | ||
6261 | * Arguments: info pointer to device instance data | ||
6262 | * Return Value: None | ||
6263 | */ | ||
6264 | static void usc_set_serial_signals( struct mgsl_struct *info ) | ||
6265 | { | ||
6266 | u16 Control; | ||
6267 | unsigned char V24Out = info->serial_signals; | ||
6268 | |||
6269 | /* get the current value of the Port Control Register (PCR) */ | ||
6270 | |||
6271 | Control = usc_InReg( info, PCR ); | ||
6272 | |||
6273 | if ( V24Out & SerialSignal_RTS ) | ||
6274 | Control &= ~(BIT6); | ||
6275 | else | ||
6276 | Control |= BIT6; | ||
6277 | |||
6278 | if ( V24Out & SerialSignal_DTR ) | ||
6279 | Control &= ~(BIT4); | ||
6280 | else | ||
6281 | Control |= BIT4; | ||
6282 | |||
6283 | usc_OutReg( info, PCR, Control ); | ||
6284 | |||
6285 | } /* end of usc_set_serial_signals() */ | ||
6286 | |||
6287 | /* usc_enable_async_clock() | ||
6288 | * | ||
6289 | * Enable the async clock at the specified frequency. | ||
6290 | * | ||
6291 | * Arguments: info pointer to device instance data | ||
6292 | * data_rate data rate of clock in bps | ||
6293 | * 0 disables the AUX clock. | ||
6294 | * Return Value: None | ||
6295 | */ | ||
6296 | static void usc_enable_async_clock( struct mgsl_struct *info, u32 data_rate ) | ||
6297 | { | ||
6298 | if ( data_rate ) { | ||
6299 | /* | ||
6300 | * Clock mode Control Register (CMCR) | ||
6301 | * | ||
6302 | * <15..14> 00 counter 1 Disabled | ||
6303 | * <13..12> 00 counter 0 Disabled | ||
6304 | * <11..10> 11 BRG1 Input is TxC Pin | ||
6305 | * <9..8> 11 BRG0 Input is TxC Pin | ||
6306 | * <7..6> 01 DPLL Input is BRG1 Output | ||
6307 | * <5..3> 100 TxCLK comes from BRG0 | ||
6308 | * <2..0> 100 RxCLK comes from BRG0 | ||
6309 | * | ||
6310 | * 0000 1111 0110 0100 = 0x0f64 | ||
6311 | */ | ||
6312 | |||
6313 | usc_OutReg( info, CMCR, 0x0f64 ); | ||
6314 | |||
6315 | |||
6316 | /* | ||
6317 | * Write 16-bit Time Constant for BRG0 | ||
6318 | * Time Constant = (ClkSpeed / data_rate) - 1 | ||
6319 | * ClkSpeed = 921600 (ISA), 691200 (PCI) | ||
6320 | */ | ||
6321 | |||
6322 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
6323 | usc_OutReg( info, TC0R, (u16)((691200/data_rate) - 1) ); | ||
6324 | else | ||
6325 | usc_OutReg( info, TC0R, (u16)((921600/data_rate) - 1) ); | ||
6326 | |||
6327 | |||
6328 | /* | ||
6329 | * Hardware Configuration Register (HCR) | ||
6330 | * Clear Bit 1, BRG0 mode = Continuous | ||
6331 | * Set Bit 0 to enable BRG0. | ||
6332 | */ | ||
6333 | |||
6334 | usc_OutReg( info, HCR, | ||
6335 | (u16)((usc_InReg( info, HCR ) & ~BIT1) | BIT0) ); | ||
6336 | |||
6337 | |||
6338 | /* Input/Output Control Reg, <2..0> = 100, Drive RxC pin with BRG0 */ | ||
6339 | |||
6340 | usc_OutReg( info, IOCR, | ||
6341 | (u16)((usc_InReg(info, IOCR) & 0xfff8) | 0x0004) ); | ||
6342 | } else { | ||
6343 | /* data rate == 0 so turn off BRG0 */ | ||
6344 | usc_OutReg( info, HCR, (u16)(usc_InReg( info, HCR ) & ~BIT0) ); | ||
6345 | } | ||
6346 | |||
6347 | } /* end of usc_enable_async_clock() */ | ||
6348 | |||
6349 | /* | ||
6350 | * Buffer Structures: | ||
6351 | * | ||
6352 | * Normal memory access uses virtual addresses that can make discontiguous | ||
6353 | * physical memory pages appear to be contiguous in the virtual address | ||
6354 | * space (the processors memory mapping handles the conversions). | ||
6355 | * | ||
6356 | * DMA transfers require physically contiguous memory. This is because | ||
6357 | * the DMA system controller and DMA bus masters deal with memory using | ||
6358 | * only physical addresses. | ||
6359 | * | ||
6360 | * This causes a problem under Windows NT when large DMA buffers are | ||
6361 | * needed. Fragmentation of the nonpaged pool prevents allocations of | ||
6362 | * physically contiguous buffers larger than the PAGE_SIZE. | ||
6363 | * | ||
6364 | * However the 16C32 supports Bus Master Scatter/Gather DMA which | ||
6365 | * allows DMA transfers to physically discontiguous buffers. Information | ||
6366 | * about each data transfer buffer is contained in a memory structure | ||
6367 | * called a 'buffer entry'. A list of buffer entries is maintained | ||
6368 | * to track and control the use of the data transfer buffers. | ||
6369 | * | ||
6370 | * To support this strategy we will allocate sufficient PAGE_SIZE | ||
6371 | * contiguous memory buffers to allow for the total required buffer | ||
6372 | * space. | ||
6373 | * | ||
6374 | * The 16C32 accesses the list of buffer entries using Bus Master | ||
6375 | * DMA. Control information is read from the buffer entries by the | ||
6376 | * 16C32 to control data transfers. status information is written to | ||
6377 | * the buffer entries by the 16C32 to indicate the status of completed | ||
6378 | * transfers. | ||
6379 | * | ||
6380 | * The CPU writes control information to the buffer entries to control | ||
6381 | * the 16C32 and reads status information from the buffer entries to | ||
6382 | * determine information about received and transmitted frames. | ||
6383 | * | ||
6384 | * Because the CPU and 16C32 (adapter) both need simultaneous access | ||
6385 | * to the buffer entries, the buffer entry memory is allocated with | ||
6386 | * HalAllocateCommonBuffer(). This restricts the size of the buffer | ||
6387 | * entry list to PAGE_SIZE. | ||
6388 | * | ||
6389 | * The actual data buffers on the other hand will only be accessed | ||
6390 | * by the CPU or the adapter but not by both simultaneously. This allows | ||
6391 | * Scatter/Gather packet based DMA procedures for using physically | ||
6392 | * discontiguous pages. | ||
6393 | */ | ||
6394 | |||
6395 | /* | ||
6396 | * mgsl_reset_tx_dma_buffers() | ||
6397 | * | ||
6398 | * Set the count for all transmit buffers to 0 to indicate the | ||
6399 | * buffer is available for use and set the current buffer to the | ||
6400 | * first buffer. This effectively makes all buffers free and | ||
6401 | * discards any data in buffers. | ||
6402 | * | ||
6403 | * Arguments: info pointer to device instance data | ||
6404 | * Return Value: None | ||
6405 | */ | ||
6406 | static void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info ) | ||
6407 | { | ||
6408 | unsigned int i; | ||
6409 | |||
6410 | for ( i = 0; i < info->tx_buffer_count; i++ ) { | ||
6411 | *((unsigned long *)&(info->tx_buffer_list[i].count)) = 0; | ||
6412 | } | ||
6413 | |||
6414 | info->current_tx_buffer = 0; | ||
6415 | info->start_tx_dma_buffer = 0; | ||
6416 | info->tx_dma_buffers_used = 0; | ||
6417 | |||
6418 | info->get_tx_holding_index = 0; | ||
6419 | info->put_tx_holding_index = 0; | ||
6420 | info->tx_holding_count = 0; | ||
6421 | |||
6422 | } /* end of mgsl_reset_tx_dma_buffers() */ | ||
6423 | |||
6424 | /* | ||
6425 | * num_free_tx_dma_buffers() | ||
6426 | * | ||
6427 | * returns the number of free tx dma buffers available | ||
6428 | * | ||
6429 | * Arguments: info pointer to device instance data | ||
6430 | * Return Value: number of free tx dma buffers | ||
6431 | */ | ||
6432 | static int num_free_tx_dma_buffers(struct mgsl_struct *info) | ||
6433 | { | ||
6434 | return info->tx_buffer_count - info->tx_dma_buffers_used; | ||
6435 | } | ||
6436 | |||
6437 | /* | ||
6438 | * mgsl_reset_rx_dma_buffers() | ||
6439 | * | ||
6440 | * Set the count for all receive buffers to DMABUFFERSIZE | ||
6441 | * and set the current buffer to the first buffer. This effectively | ||
6442 | * makes all buffers free and discards any data in buffers. | ||
6443 | * | ||
6444 | * Arguments: info pointer to device instance data | ||
6445 | * Return Value: None | ||
6446 | */ | ||
6447 | static void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info ) | ||
6448 | { | ||
6449 | unsigned int i; | ||
6450 | |||
6451 | for ( i = 0; i < info->rx_buffer_count; i++ ) { | ||
6452 | *((unsigned long *)&(info->rx_buffer_list[i].count)) = DMABUFFERSIZE; | ||
6453 | // info->rx_buffer_list[i].count = DMABUFFERSIZE; | ||
6454 | // info->rx_buffer_list[i].status = 0; | ||
6455 | } | ||
6456 | |||
6457 | info->current_rx_buffer = 0; | ||
6458 | |||
6459 | } /* end of mgsl_reset_rx_dma_buffers() */ | ||
6460 | |||
6461 | /* | ||
6462 | * mgsl_free_rx_frame_buffers() | ||
6463 | * | ||
6464 | * Free the receive buffers used by a received SDLC | ||
6465 | * frame such that the buffers can be reused. | ||
6466 | * | ||
6467 | * Arguments: | ||
6468 | * | ||
6469 | * info pointer to device instance data | ||
6470 | * StartIndex index of 1st receive buffer of frame | ||
6471 | * EndIndex index of last receive buffer of frame | ||
6472 | * | ||
6473 | * Return Value: None | ||
6474 | */ | ||
6475 | static void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex ) | ||
6476 | { | ||
6477 | bool Done = false; | ||
6478 | DMABUFFERENTRY *pBufEntry; | ||
6479 | unsigned int Index; | ||
6480 | |||
6481 | /* Starting with 1st buffer entry of the frame clear the status */ | ||
6482 | /* field and set the count field to DMA Buffer Size. */ | ||
6483 | |||
6484 | Index = StartIndex; | ||
6485 | |||
6486 | while( !Done ) { | ||
6487 | pBufEntry = &(info->rx_buffer_list[Index]); | ||
6488 | |||
6489 | if ( Index == EndIndex ) { | ||
6490 | /* This is the last buffer of the frame! */ | ||
6491 | Done = true; | ||
6492 | } | ||
6493 | |||
6494 | /* reset current buffer for reuse */ | ||
6495 | // pBufEntry->status = 0; | ||
6496 | // pBufEntry->count = DMABUFFERSIZE; | ||
6497 | *((unsigned long *)&(pBufEntry->count)) = DMABUFFERSIZE; | ||
6498 | |||
6499 | /* advance to next buffer entry in linked list */ | ||
6500 | Index++; | ||
6501 | if ( Index == info->rx_buffer_count ) | ||
6502 | Index = 0; | ||
6503 | } | ||
6504 | |||
6505 | /* set current buffer to next buffer after last buffer of frame */ | ||
6506 | info->current_rx_buffer = Index; | ||
6507 | |||
6508 | } /* end of free_rx_frame_buffers() */ | ||
6509 | |||
6510 | /* mgsl_get_rx_frame() | ||
6511 | * | ||
6512 | * This function attempts to return a received SDLC frame from the | ||
6513 | * receive DMA buffers. Only frames received without errors are returned. | ||
6514 | * | ||
6515 | * Arguments: info pointer to device extension | ||
6516 | * Return Value: true if frame returned, otherwise false | ||
6517 | */ | ||
6518 | static bool mgsl_get_rx_frame(struct mgsl_struct *info) | ||
6519 | { | ||
6520 | unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ | ||
6521 | unsigned short status; | ||
6522 | DMABUFFERENTRY *pBufEntry; | ||
6523 | unsigned int framesize = 0; | ||
6524 | bool ReturnCode = false; | ||
6525 | unsigned long flags; | ||
6526 | struct tty_struct *tty = info->port.tty; | ||
6527 | bool return_frame = false; | ||
6528 | |||
6529 | /* | ||
6530 | * current_rx_buffer points to the 1st buffer of the next available | ||
6531 | * receive frame. To find the last buffer of the frame look for | ||
6532 | * a non-zero status field in the buffer entries. (The status | ||
6533 | * field is set by the 16C32 after completing a receive frame. | ||
6534 | */ | ||
6535 | |||
6536 | StartIndex = EndIndex = info->current_rx_buffer; | ||
6537 | |||
6538 | while( !info->rx_buffer_list[EndIndex].status ) { | ||
6539 | /* | ||
6540 | * If the count field of the buffer entry is non-zero then | ||
6541 | * this buffer has not been used. (The 16C32 clears the count | ||
6542 | * field when it starts using the buffer.) If an unused buffer | ||
6543 | * is encountered then there are no frames available. | ||
6544 | */ | ||
6545 | |||
6546 | if ( info->rx_buffer_list[EndIndex].count ) | ||
6547 | goto Cleanup; | ||
6548 | |||
6549 | /* advance to next buffer entry in linked list */ | ||
6550 | EndIndex++; | ||
6551 | if ( EndIndex == info->rx_buffer_count ) | ||
6552 | EndIndex = 0; | ||
6553 | |||
6554 | /* if entire list searched then no frame available */ | ||
6555 | if ( EndIndex == StartIndex ) { | ||
6556 | /* If this occurs then something bad happened, | ||
6557 | * all buffers have been 'used' but none mark | ||
6558 | * the end of a frame. Reset buffers and receiver. | ||
6559 | */ | ||
6560 | |||
6561 | if ( info->rx_enabled ){ | ||
6562 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
6563 | usc_start_receiver(info); | ||
6564 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
6565 | } | ||
6566 | goto Cleanup; | ||
6567 | } | ||
6568 | } | ||
6569 | |||
6570 | |||
6571 | /* check status of receive frame */ | ||
6572 | |||
6573 | status = info->rx_buffer_list[EndIndex].status; | ||
6574 | |||
6575 | if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + | ||
6576 | RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { | ||
6577 | if ( status & RXSTATUS_SHORT_FRAME ) | ||
6578 | info->icount.rxshort++; | ||
6579 | else if ( status & RXSTATUS_ABORT ) | ||
6580 | info->icount.rxabort++; | ||
6581 | else if ( status & RXSTATUS_OVERRUN ) | ||
6582 | info->icount.rxover++; | ||
6583 | else { | ||
6584 | info->icount.rxcrc++; | ||
6585 | if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) | ||
6586 | return_frame = true; | ||
6587 | } | ||
6588 | framesize = 0; | ||
6589 | #if SYNCLINK_GENERIC_HDLC | ||
6590 | { | ||
6591 | info->netdev->stats.rx_errors++; | ||
6592 | info->netdev->stats.rx_frame_errors++; | ||
6593 | } | ||
6594 | #endif | ||
6595 | } else | ||
6596 | return_frame = true; | ||
6597 | |||
6598 | if ( return_frame ) { | ||
6599 | /* receive frame has no errors, get frame size. | ||
6600 | * The frame size is the starting value of the RCC (which was | ||
6601 | * set to 0xffff) minus the ending value of the RCC (decremented | ||
6602 | * once for each receive character) minus 2 for the 16-bit CRC. | ||
6603 | */ | ||
6604 | |||
6605 | framesize = RCLRVALUE - info->rx_buffer_list[EndIndex].rcc; | ||
6606 | |||
6607 | /* adjust frame size for CRC if any */ | ||
6608 | if ( info->params.crc_type == HDLC_CRC_16_CCITT ) | ||
6609 | framesize -= 2; | ||
6610 | else if ( info->params.crc_type == HDLC_CRC_32_CCITT ) | ||
6611 | framesize -= 4; | ||
6612 | } | ||
6613 | |||
6614 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
6615 | printk("%s(%d):mgsl_get_rx_frame(%s) status=%04X size=%d\n", | ||
6616 | __FILE__,__LINE__,info->device_name,status,framesize); | ||
6617 | |||
6618 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
6619 | mgsl_trace_block(info,info->rx_buffer_list[StartIndex].virt_addr, | ||
6620 | min_t(int, framesize, DMABUFFERSIZE),0); | ||
6621 | |||
6622 | if (framesize) { | ||
6623 | if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) && | ||
6624 | ((framesize+1) > info->max_frame_size) ) || | ||
6625 | (framesize > info->max_frame_size) ) | ||
6626 | info->icount.rxlong++; | ||
6627 | else { | ||
6628 | /* copy dma buffer(s) to contiguous intermediate buffer */ | ||
6629 | int copy_count = framesize; | ||
6630 | int index = StartIndex; | ||
6631 | unsigned char *ptmp = info->intermediate_rxbuffer; | ||
6632 | |||
6633 | if ( !(status & RXSTATUS_CRC_ERROR)) | ||
6634 | info->icount.rxok++; | ||
6635 | |||
6636 | while(copy_count) { | ||
6637 | int partial_count; | ||
6638 | if ( copy_count > DMABUFFERSIZE ) | ||
6639 | partial_count = DMABUFFERSIZE; | ||
6640 | else | ||
6641 | partial_count = copy_count; | ||
6642 | |||
6643 | pBufEntry = &(info->rx_buffer_list[index]); | ||
6644 | memcpy( ptmp, pBufEntry->virt_addr, partial_count ); | ||
6645 | ptmp += partial_count; | ||
6646 | copy_count -= partial_count; | ||
6647 | |||
6648 | if ( ++index == info->rx_buffer_count ) | ||
6649 | index = 0; | ||
6650 | } | ||
6651 | |||
6652 | if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) { | ||
6653 | ++framesize; | ||
6654 | *ptmp = (status & RXSTATUS_CRC_ERROR ? | ||
6655 | RX_CRC_ERROR : | ||
6656 | RX_OK); | ||
6657 | |||
6658 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
6659 | printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n", | ||
6660 | __FILE__,__LINE__,info->device_name, | ||
6661 | *ptmp); | ||
6662 | } | ||
6663 | |||
6664 | #if SYNCLINK_GENERIC_HDLC | ||
6665 | if (info->netcount) | ||
6666 | hdlcdev_rx(info,info->intermediate_rxbuffer,framesize); | ||
6667 | else | ||
6668 | #endif | ||
6669 | ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | ||
6670 | } | ||
6671 | } | ||
6672 | /* Free the buffers used by this frame. */ | ||
6673 | mgsl_free_rx_frame_buffers( info, StartIndex, EndIndex ); | ||
6674 | |||
6675 | ReturnCode = true; | ||
6676 | |||
6677 | Cleanup: | ||
6678 | |||
6679 | if ( info->rx_enabled && info->rx_overflow ) { | ||
6680 | /* The receiver needs to restarted because of | ||
6681 | * a receive overflow (buffer or FIFO). If the | ||
6682 | * receive buffers are now empty, then restart receiver. | ||
6683 | */ | ||
6684 | |||
6685 | if ( !info->rx_buffer_list[EndIndex].status && | ||
6686 | info->rx_buffer_list[EndIndex].count ) { | ||
6687 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
6688 | usc_start_receiver(info); | ||
6689 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
6690 | } | ||
6691 | } | ||
6692 | |||
6693 | return ReturnCode; | ||
6694 | |||
6695 | } /* end of mgsl_get_rx_frame() */ | ||
6696 | |||
6697 | /* mgsl_get_raw_rx_frame() | ||
6698 | * | ||
6699 | * This function attempts to return a received frame from the | ||
6700 | * receive DMA buffers when running in external loop mode. In this mode, | ||
6701 | * we will return at most one DMABUFFERSIZE frame to the application. | ||
6702 | * The USC receiver is triggering off of DCD going active to start a new | ||
6703 | * frame, and DCD going inactive to terminate the frame (similar to | ||
6704 | * processing a closing flag character). | ||
6705 | * | ||
6706 | * In this routine, we will return DMABUFFERSIZE "chunks" at a time. | ||
6707 | * If DCD goes inactive, the last Rx DMA Buffer will have a non-zero | ||
6708 | * status field and the RCC field will indicate the length of the | ||
6709 | * entire received frame. We take this RCC field and get the modulus | ||
6710 | * of RCC and DMABUFFERSIZE to determine if number of bytes in the | ||
6711 | * last Rx DMA buffer and return that last portion of the frame. | ||
6712 | * | ||
6713 | * Arguments: info pointer to device extension | ||
6714 | * Return Value: true if frame returned, otherwise false | ||
6715 | */ | ||
6716 | static bool mgsl_get_raw_rx_frame(struct mgsl_struct *info) | ||
6717 | { | ||
6718 | unsigned int CurrentIndex, NextIndex; | ||
6719 | unsigned short status; | ||
6720 | DMABUFFERENTRY *pBufEntry; | ||
6721 | unsigned int framesize = 0; | ||
6722 | bool ReturnCode = false; | ||
6723 | unsigned long flags; | ||
6724 | struct tty_struct *tty = info->port.tty; | ||
6725 | |||
6726 | /* | ||
6727 | * current_rx_buffer points to the 1st buffer of the next available | ||
6728 | * receive frame. The status field is set by the 16C32 after | ||
6729 | * completing a receive frame. If the status field of this buffer | ||
6730 | * is zero, either the USC is still filling this buffer or this | ||
6731 | * is one of a series of buffers making up a received frame. | ||
6732 | * | ||
6733 | * If the count field of this buffer is zero, the USC is either | ||
6734 | * using this buffer or has used this buffer. Look at the count | ||
6735 | * field of the next buffer. If that next buffer's count is | ||
6736 | * non-zero, the USC is still actively using the current buffer. | ||
6737 | * Otherwise, if the next buffer's count field is zero, the | ||
6738 | * current buffer is complete and the USC is using the next | ||
6739 | * buffer. | ||
6740 | */ | ||
6741 | CurrentIndex = NextIndex = info->current_rx_buffer; | ||
6742 | ++NextIndex; | ||
6743 | if ( NextIndex == info->rx_buffer_count ) | ||
6744 | NextIndex = 0; | ||
6745 | |||
6746 | if ( info->rx_buffer_list[CurrentIndex].status != 0 || | ||
6747 | (info->rx_buffer_list[CurrentIndex].count == 0 && | ||
6748 | info->rx_buffer_list[NextIndex].count == 0)) { | ||
6749 | /* | ||
6750 | * Either the status field of this dma buffer is non-zero | ||
6751 | * (indicating the last buffer of a receive frame) or the next | ||
6752 | * buffer is marked as in use -- implying this buffer is complete | ||
6753 | * and an intermediate buffer for this received frame. | ||
6754 | */ | ||
6755 | |||
6756 | status = info->rx_buffer_list[CurrentIndex].status; | ||
6757 | |||
6758 | if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN + | ||
6759 | RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) { | ||
6760 | if ( status & RXSTATUS_SHORT_FRAME ) | ||
6761 | info->icount.rxshort++; | ||
6762 | else if ( status & RXSTATUS_ABORT ) | ||
6763 | info->icount.rxabort++; | ||
6764 | else if ( status & RXSTATUS_OVERRUN ) | ||
6765 | info->icount.rxover++; | ||
6766 | else | ||
6767 | info->icount.rxcrc++; | ||
6768 | framesize = 0; | ||
6769 | } else { | ||
6770 | /* | ||
6771 | * A receive frame is available, get frame size and status. | ||
6772 | * | ||
6773 | * The frame size is the starting value of the RCC (which was | ||
6774 | * set to 0xffff) minus the ending value of the RCC (decremented | ||
6775 | * once for each receive character) minus 2 or 4 for the 16-bit | ||
6776 | * or 32-bit CRC. | ||
6777 | * | ||
6778 | * If the status field is zero, this is an intermediate buffer. | ||
6779 | * It's size is 4K. | ||
6780 | * | ||
6781 | * If the DMA Buffer Entry's Status field is non-zero, the | ||
6782 | * receive operation completed normally (ie: DCD dropped). The | ||
6783 | * RCC field is valid and holds the received frame size. | ||
6784 | * It is possible that the RCC field will be zero on a DMA buffer | ||
6785 | * entry with a non-zero status. This can occur if the total | ||
6786 | * frame size (number of bytes between the time DCD goes active | ||
6787 | * to the time DCD goes inactive) exceeds 65535 bytes. In this | ||
6788 | * case the 16C32 has underrun on the RCC count and appears to | ||
6789 | * stop updating this counter to let us know the actual received | ||
6790 | * frame size. If this happens (non-zero status and zero RCC), | ||
6791 | * simply return the entire RxDMA Buffer | ||
6792 | */ | ||
6793 | if ( status ) { | ||
6794 | /* | ||
6795 | * In the event that the final RxDMA Buffer is | ||
6796 | * terminated with a non-zero status and the RCC | ||
6797 | * field is zero, we interpret this as the RCC | ||
6798 | * having underflowed (received frame > 65535 bytes). | ||
6799 | * | ||
6800 | * Signal the event to the user by passing back | ||
6801 | * a status of RxStatus_CrcError returning the full | ||
6802 | * buffer and let the app figure out what data is | ||
6803 | * actually valid | ||
6804 | */ | ||
6805 | if ( info->rx_buffer_list[CurrentIndex].rcc ) | ||
6806 | framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc; | ||
6807 | else | ||
6808 | framesize = DMABUFFERSIZE; | ||
6809 | } | ||
6810 | else | ||
6811 | framesize = DMABUFFERSIZE; | ||
6812 | } | ||
6813 | |||
6814 | if ( framesize > DMABUFFERSIZE ) { | ||
6815 | /* | ||
6816 | * if running in raw sync mode, ISR handler for | ||
6817 | * End Of Buffer events terminates all buffers at 4K. | ||
6818 | * If this frame size is said to be >4K, get the | ||
6819 | * actual number of bytes of the frame in this buffer. | ||
6820 | */ | ||
6821 | framesize = framesize % DMABUFFERSIZE; | ||
6822 | } | ||
6823 | |||
6824 | |||
6825 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
6826 | printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n", | ||
6827 | __FILE__,__LINE__,info->device_name,status,framesize); | ||
6828 | |||
6829 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
6830 | mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr, | ||
6831 | min_t(int, framesize, DMABUFFERSIZE),0); | ||
6832 | |||
6833 | if (framesize) { | ||
6834 | /* copy dma buffer(s) to contiguous intermediate buffer */ | ||
6835 | /* NOTE: we never copy more than DMABUFFERSIZE bytes */ | ||
6836 | |||
6837 | pBufEntry = &(info->rx_buffer_list[CurrentIndex]); | ||
6838 | memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize); | ||
6839 | info->icount.rxok++; | ||
6840 | |||
6841 | ldisc_receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize); | ||
6842 | } | ||
6843 | |||
6844 | /* Free the buffers used by this frame. */ | ||
6845 | mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex ); | ||
6846 | |||
6847 | ReturnCode = true; | ||
6848 | } | ||
6849 | |||
6850 | |||
6851 | if ( info->rx_enabled && info->rx_overflow ) { | ||
6852 | /* The receiver needs to restarted because of | ||
6853 | * a receive overflow (buffer or FIFO). If the | ||
6854 | * receive buffers are now empty, then restart receiver. | ||
6855 | */ | ||
6856 | |||
6857 | if ( !info->rx_buffer_list[CurrentIndex].status && | ||
6858 | info->rx_buffer_list[CurrentIndex].count ) { | ||
6859 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
6860 | usc_start_receiver(info); | ||
6861 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
6862 | } | ||
6863 | } | ||
6864 | |||
6865 | return ReturnCode; | ||
6866 | |||
6867 | } /* end of mgsl_get_raw_rx_frame() */ | ||
6868 | |||
6869 | /* mgsl_load_tx_dma_buffer() | ||
6870 | * | ||
6871 | * Load the transmit DMA buffer with the specified data. | ||
6872 | * | ||
6873 | * Arguments: | ||
6874 | * | ||
6875 | * info pointer to device extension | ||
6876 | * Buffer pointer to buffer containing frame to load | ||
6877 | * BufferSize size in bytes of frame in Buffer | ||
6878 | * | ||
6879 | * Return Value: None | ||
6880 | */ | ||
6881 | static void mgsl_load_tx_dma_buffer(struct mgsl_struct *info, | ||
6882 | const char *Buffer, unsigned int BufferSize) | ||
6883 | { | ||
6884 | unsigned short Copycount; | ||
6885 | unsigned int i = 0; | ||
6886 | DMABUFFERENTRY *pBufEntry; | ||
6887 | |||
6888 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
6889 | mgsl_trace_block(info,Buffer, min_t(int, BufferSize, DMABUFFERSIZE), 1); | ||
6890 | |||
6891 | if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { | ||
6892 | /* set CMR:13 to start transmit when | ||
6893 | * next GoAhead (abort) is received | ||
6894 | */ | ||
6895 | info->cmr_value |= BIT13; | ||
6896 | } | ||
6897 | |||
6898 | /* begin loading the frame in the next available tx dma | ||
6899 | * buffer, remember it's starting location for setting | ||
6900 | * up tx dma operation | ||
6901 | */ | ||
6902 | i = info->current_tx_buffer; | ||
6903 | info->start_tx_dma_buffer = i; | ||
6904 | |||
6905 | /* Setup the status and RCC (Frame Size) fields of the 1st */ | ||
6906 | /* buffer entry in the transmit DMA buffer list. */ | ||
6907 | |||
6908 | info->tx_buffer_list[i].status = info->cmr_value & 0xf000; | ||
6909 | info->tx_buffer_list[i].rcc = BufferSize; | ||
6910 | info->tx_buffer_list[i].count = BufferSize; | ||
6911 | |||
6912 | /* Copy frame data from 1st source buffer to the DMA buffers. */ | ||
6913 | /* The frame data may span multiple DMA buffers. */ | ||
6914 | |||
6915 | while( BufferSize ){ | ||
6916 | /* Get a pointer to next DMA buffer entry. */ | ||
6917 | pBufEntry = &info->tx_buffer_list[i++]; | ||
6918 | |||
6919 | if ( i == info->tx_buffer_count ) | ||
6920 | i=0; | ||
6921 | |||
6922 | /* Calculate the number of bytes that can be copied from */ | ||
6923 | /* the source buffer to this DMA buffer. */ | ||
6924 | if ( BufferSize > DMABUFFERSIZE ) | ||
6925 | Copycount = DMABUFFERSIZE; | ||
6926 | else | ||
6927 | Copycount = BufferSize; | ||
6928 | |||
6929 | /* Actually copy data from source buffer to DMA buffer. */ | ||
6930 | /* Also set the data count for this individual DMA buffer. */ | ||
6931 | if ( info->bus_type == MGSL_BUS_TYPE_PCI ) | ||
6932 | mgsl_load_pci_memory(pBufEntry->virt_addr, Buffer,Copycount); | ||
6933 | else | ||
6934 | memcpy(pBufEntry->virt_addr, Buffer, Copycount); | ||
6935 | |||
6936 | pBufEntry->count = Copycount; | ||
6937 | |||
6938 | /* Advance source pointer and reduce remaining data count. */ | ||
6939 | Buffer += Copycount; | ||
6940 | BufferSize -= Copycount; | ||
6941 | |||
6942 | ++info->tx_dma_buffers_used; | ||
6943 | } | ||
6944 | |||
6945 | /* remember next available tx dma buffer */ | ||
6946 | info->current_tx_buffer = i; | ||
6947 | |||
6948 | } /* end of mgsl_load_tx_dma_buffer() */ | ||
6949 | |||
6950 | /* | ||
6951 | * mgsl_register_test() | ||
6952 | * | ||
6953 | * Performs a register test of the 16C32. | ||
6954 | * | ||
6955 | * Arguments: info pointer to device instance data | ||
6956 | * Return Value: true if test passed, otherwise false | ||
6957 | */ | ||
6958 | static bool mgsl_register_test( struct mgsl_struct *info ) | ||
6959 | { | ||
6960 | static unsigned short BitPatterns[] = | ||
6961 | { 0x0000, 0xffff, 0xaaaa, 0x5555, 0x1234, 0x6969, 0x9696, 0x0f0f }; | ||
6962 | static unsigned int Patterncount = ARRAY_SIZE(BitPatterns); | ||
6963 | unsigned int i; | ||
6964 | bool rc = true; | ||
6965 | unsigned long flags; | ||
6966 | |||
6967 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
6968 | usc_reset(info); | ||
6969 | |||
6970 | /* Verify the reset state of some registers. */ | ||
6971 | |||
6972 | if ( (usc_InReg( info, SICR ) != 0) || | ||
6973 | (usc_InReg( info, IVR ) != 0) || | ||
6974 | (usc_InDmaReg( info, DIVR ) != 0) ){ | ||
6975 | rc = false; | ||
6976 | } | ||
6977 | |||
6978 | if ( rc ){ | ||
6979 | /* Write bit patterns to various registers but do it out of */ | ||
6980 | /* sync, then read back and verify values. */ | ||
6981 | |||
6982 | for ( i = 0 ; i < Patterncount ; i++ ) { | ||
6983 | usc_OutReg( info, TC0R, BitPatterns[i] ); | ||
6984 | usc_OutReg( info, TC1R, BitPatterns[(i+1)%Patterncount] ); | ||
6985 | usc_OutReg( info, TCLR, BitPatterns[(i+2)%Patterncount] ); | ||
6986 | usc_OutReg( info, RCLR, BitPatterns[(i+3)%Patterncount] ); | ||
6987 | usc_OutReg( info, RSR, BitPatterns[(i+4)%Patterncount] ); | ||
6988 | usc_OutDmaReg( info, TBCR, BitPatterns[(i+5)%Patterncount] ); | ||
6989 | |||
6990 | if ( (usc_InReg( info, TC0R ) != BitPatterns[i]) || | ||
6991 | (usc_InReg( info, TC1R ) != BitPatterns[(i+1)%Patterncount]) || | ||
6992 | (usc_InReg( info, TCLR ) != BitPatterns[(i+2)%Patterncount]) || | ||
6993 | (usc_InReg( info, RCLR ) != BitPatterns[(i+3)%Patterncount]) || | ||
6994 | (usc_InReg( info, RSR ) != BitPatterns[(i+4)%Patterncount]) || | ||
6995 | (usc_InDmaReg( info, TBCR ) != BitPatterns[(i+5)%Patterncount]) ){ | ||
6996 | rc = false; | ||
6997 | break; | ||
6998 | } | ||
6999 | } | ||
7000 | } | ||
7001 | |||
7002 | usc_reset(info); | ||
7003 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7004 | |||
7005 | return rc; | ||
7006 | |||
7007 | } /* end of mgsl_register_test() */ | ||
7008 | |||
7009 | /* mgsl_irq_test() Perform interrupt test of the 16C32. | ||
7010 | * | ||
7011 | * Arguments: info pointer to device instance data | ||
7012 | * Return Value: true if test passed, otherwise false | ||
7013 | */ | ||
7014 | static bool mgsl_irq_test( struct mgsl_struct *info ) | ||
7015 | { | ||
7016 | unsigned long EndTime; | ||
7017 | unsigned long flags; | ||
7018 | |||
7019 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7020 | usc_reset(info); | ||
7021 | |||
7022 | /* | ||
7023 | * Setup 16C32 to interrupt on TxC pin (14MHz clock) transition. | ||
7024 | * The ISR sets irq_occurred to true. | ||
7025 | */ | ||
7026 | |||
7027 | info->irq_occurred = false; | ||
7028 | |||
7029 | /* Enable INTEN gate for ISA adapter (Port 6, Bit12) */ | ||
7030 | /* Enable INTEN (Port 6, Bit12) */ | ||
7031 | /* This connects the IRQ request signal to the ISA bus */ | ||
7032 | /* on the ISA adapter. This has no effect for the PCI adapter */ | ||
7033 | usc_OutReg( info, PCR, (unsigned short)((usc_InReg(info, PCR) | BIT13) & ~BIT12) ); | ||
7034 | |||
7035 | usc_EnableMasterIrqBit(info); | ||
7036 | usc_EnableInterrupts(info, IO_PIN); | ||
7037 | usc_ClearIrqPendingBits(info, IO_PIN); | ||
7038 | |||
7039 | usc_UnlatchIostatusBits(info, MISCSTATUS_TXC_LATCHED); | ||
7040 | usc_EnableStatusIrqs(info, SICR_TXC_ACTIVE + SICR_TXC_INACTIVE); | ||
7041 | |||
7042 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7043 | |||
7044 | EndTime=100; | ||
7045 | while( EndTime-- && !info->irq_occurred ) { | ||
7046 | msleep_interruptible(10); | ||
7047 | } | ||
7048 | |||
7049 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7050 | usc_reset(info); | ||
7051 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7052 | |||
7053 | return info->irq_occurred; | ||
7054 | |||
7055 | } /* end of mgsl_irq_test() */ | ||
7056 | |||
7057 | /* mgsl_dma_test() | ||
7058 | * | ||
7059 | * Perform a DMA test of the 16C32. A small frame is | ||
7060 | * transmitted via DMA from a transmit buffer to a receive buffer | ||
7061 | * using single buffer DMA mode. | ||
7062 | * | ||
7063 | * Arguments: info pointer to device instance data | ||
7064 | * Return Value: true if test passed, otherwise false | ||
7065 | */ | ||
7066 | static bool mgsl_dma_test( struct mgsl_struct *info ) | ||
7067 | { | ||
7068 | unsigned short FifoLevel; | ||
7069 | unsigned long phys_addr; | ||
7070 | unsigned int FrameSize; | ||
7071 | unsigned int i; | ||
7072 | char *TmpPtr; | ||
7073 | bool rc = true; | ||
7074 | unsigned short status=0; | ||
7075 | unsigned long EndTime; | ||
7076 | unsigned long flags; | ||
7077 | MGSL_PARAMS tmp_params; | ||
7078 | |||
7079 | /* save current port options */ | ||
7080 | memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS)); | ||
7081 | /* load default port options */ | ||
7082 | memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); | ||
7083 | |||
7084 | #define TESTFRAMESIZE 40 | ||
7085 | |||
7086 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7087 | |||
7088 | /* setup 16C32 for SDLC DMA transfer mode */ | ||
7089 | |||
7090 | usc_reset(info); | ||
7091 | usc_set_sdlc_mode(info); | ||
7092 | usc_enable_loopback(info,1); | ||
7093 | |||
7094 | /* Reprogram the RDMR so that the 16C32 does NOT clear the count | ||
7095 | * field of the buffer entry after fetching buffer address. This | ||
7096 | * way we can detect a DMA failure for a DMA read (which should be | ||
7097 | * non-destructive to system memory) before we try and write to | ||
7098 | * memory (where a failure could corrupt system memory). | ||
7099 | */ | ||
7100 | |||
7101 | /* Receive DMA mode Register (RDMR) | ||
7102 | * | ||
7103 | * <15..14> 11 DMA mode = Linked List Buffer mode | ||
7104 | * <13> 1 RSBinA/L = store Rx status Block in List entry | ||
7105 | * <12> 0 1 = Clear count of List Entry after fetching | ||
7106 | * <11..10> 00 Address mode = Increment | ||
7107 | * <9> 1 Terminate Buffer on RxBound | ||
7108 | * <8> 0 Bus Width = 16bits | ||
7109 | * <7..0> ? status Bits (write as 0s) | ||
7110 | * | ||
7111 | * 1110 0010 0000 0000 = 0xe200 | ||
7112 | */ | ||
7113 | |||
7114 | usc_OutDmaReg( info, RDMR, 0xe200 ); | ||
7115 | |||
7116 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7117 | |||
7118 | |||
7119 | /* SETUP TRANSMIT AND RECEIVE DMA BUFFERS */ | ||
7120 | |||
7121 | FrameSize = TESTFRAMESIZE; | ||
7122 | |||
7123 | /* setup 1st transmit buffer entry: */ | ||
7124 | /* with frame size and transmit control word */ | ||
7125 | |||
7126 | info->tx_buffer_list[0].count = FrameSize; | ||
7127 | info->tx_buffer_list[0].rcc = FrameSize; | ||
7128 | info->tx_buffer_list[0].status = 0x4000; | ||
7129 | |||
7130 | /* build a transmit frame in 1st transmit DMA buffer */ | ||
7131 | |||
7132 | TmpPtr = info->tx_buffer_list[0].virt_addr; | ||
7133 | for (i = 0; i < FrameSize; i++ ) | ||
7134 | *TmpPtr++ = i; | ||
7135 | |||
7136 | /* setup 1st receive buffer entry: */ | ||
7137 | /* clear status, set max receive buffer size */ | ||
7138 | |||
7139 | info->rx_buffer_list[0].status = 0; | ||
7140 | info->rx_buffer_list[0].count = FrameSize + 4; | ||
7141 | |||
7142 | /* zero out the 1st receive buffer */ | ||
7143 | |||
7144 | memset( info->rx_buffer_list[0].virt_addr, 0, FrameSize + 4 ); | ||
7145 | |||
7146 | /* Set count field of next buffer entries to prevent */ | ||
7147 | /* 16C32 from using buffers after the 1st one. */ | ||
7148 | |||
7149 | info->tx_buffer_list[1].count = 0; | ||
7150 | info->rx_buffer_list[1].count = 0; | ||
7151 | |||
7152 | |||
7153 | /***************************/ | ||
7154 | /* Program 16C32 receiver. */ | ||
7155 | /***************************/ | ||
7156 | |||
7157 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7158 | |||
7159 | /* setup DMA transfers */ | ||
7160 | usc_RTCmd( info, RTCmd_PurgeRxFifo ); | ||
7161 | |||
7162 | /* program 16C32 receiver with physical address of 1st DMA buffer entry */ | ||
7163 | phys_addr = info->rx_buffer_list[0].phys_entry; | ||
7164 | usc_OutDmaReg( info, NRARL, (unsigned short)phys_addr ); | ||
7165 | usc_OutDmaReg( info, NRARU, (unsigned short)(phys_addr >> 16) ); | ||
7166 | |||
7167 | /* Clear the Rx DMA status bits (read RDMR) and start channel */ | ||
7168 | usc_InDmaReg( info, RDMR ); | ||
7169 | usc_DmaCmd( info, DmaCmd_InitRxChannel ); | ||
7170 | |||
7171 | /* Enable Receiver (RMR <1..0> = 10) */ | ||
7172 | usc_OutReg( info, RMR, (unsigned short)((usc_InReg(info, RMR) & 0xfffc) | 0x0002) ); | ||
7173 | |||
7174 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7175 | |||
7176 | |||
7177 | /*************************************************************/ | ||
7178 | /* WAIT FOR RECEIVER TO DMA ALL PARAMETERS FROM BUFFER ENTRY */ | ||
7179 | /*************************************************************/ | ||
7180 | |||
7181 | /* Wait 100ms for interrupt. */ | ||
7182 | EndTime = jiffies + msecs_to_jiffies(100); | ||
7183 | |||
7184 | for(;;) { | ||
7185 | if (time_after(jiffies, EndTime)) { | ||
7186 | rc = false; | ||
7187 | break; | ||
7188 | } | ||
7189 | |||
7190 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7191 | status = usc_InDmaReg( info, RDMR ); | ||
7192 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7193 | |||
7194 | if ( !(status & BIT4) && (status & BIT5) ) { | ||
7195 | /* INITG (BIT 4) is inactive (no entry read in progress) AND */ | ||
7196 | /* BUSY (BIT 5) is active (channel still active). */ | ||
7197 | /* This means the buffer entry read has completed. */ | ||
7198 | break; | ||
7199 | } | ||
7200 | } | ||
7201 | |||
7202 | |||
7203 | /******************************/ | ||
7204 | /* Program 16C32 transmitter. */ | ||
7205 | /******************************/ | ||
7206 | |||
7207 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7208 | |||
7209 | /* Program the Transmit Character Length Register (TCLR) */ | ||
7210 | /* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */ | ||
7211 | |||
7212 | usc_OutReg( info, TCLR, (unsigned short)info->tx_buffer_list[0].count ); | ||
7213 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
7214 | |||
7215 | /* Program the address of the 1st DMA Buffer Entry in linked list */ | ||
7216 | |||
7217 | phys_addr = info->tx_buffer_list[0].phys_entry; | ||
7218 | usc_OutDmaReg( info, NTARL, (unsigned short)phys_addr ); | ||
7219 | usc_OutDmaReg( info, NTARU, (unsigned short)(phys_addr >> 16) ); | ||
7220 | |||
7221 | /* unlatch Tx status bits, and start transmit channel. */ | ||
7222 | |||
7223 | usc_OutReg( info, TCSR, (unsigned short)(( usc_InReg(info, TCSR) & 0x0f00) | 0xfa) ); | ||
7224 | usc_DmaCmd( info, DmaCmd_InitTxChannel ); | ||
7225 | |||
7226 | /* wait for DMA controller to fill transmit FIFO */ | ||
7227 | |||
7228 | usc_TCmd( info, TCmd_SelectTicrTxFifostatus ); | ||
7229 | |||
7230 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7231 | |||
7232 | |||
7233 | /**********************************/ | ||
7234 | /* WAIT FOR TRANSMIT FIFO TO FILL */ | ||
7235 | /**********************************/ | ||
7236 | |||
7237 | /* Wait 100ms */ | ||
7238 | EndTime = jiffies + msecs_to_jiffies(100); | ||
7239 | |||
7240 | for(;;) { | ||
7241 | if (time_after(jiffies, EndTime)) { | ||
7242 | rc = false; | ||
7243 | break; | ||
7244 | } | ||
7245 | |||
7246 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7247 | FifoLevel = usc_InReg(info, TICR) >> 8; | ||
7248 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7249 | |||
7250 | if ( FifoLevel < 16 ) | ||
7251 | break; | ||
7252 | else | ||
7253 | if ( FrameSize < 32 ) { | ||
7254 | /* This frame is smaller than the entire transmit FIFO */ | ||
7255 | /* so wait for the entire frame to be loaded. */ | ||
7256 | if ( FifoLevel <= (32 - FrameSize) ) | ||
7257 | break; | ||
7258 | } | ||
7259 | } | ||
7260 | |||
7261 | |||
7262 | if ( rc ) | ||
7263 | { | ||
7264 | /* Enable 16C32 transmitter. */ | ||
7265 | |||
7266 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7267 | |||
7268 | /* Transmit mode Register (TMR), <1..0> = 10, Enable Transmitter */ | ||
7269 | usc_TCmd( info, TCmd_SendFrame ); | ||
7270 | usc_OutReg( info, TMR, (unsigned short)((usc_InReg(info, TMR) & 0xfffc) | 0x0002) ); | ||
7271 | |||
7272 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7273 | |||
7274 | |||
7275 | /******************************/ | ||
7276 | /* WAIT FOR TRANSMIT COMPLETE */ | ||
7277 | /******************************/ | ||
7278 | |||
7279 | /* Wait 100ms */ | ||
7280 | EndTime = jiffies + msecs_to_jiffies(100); | ||
7281 | |||
7282 | /* While timer not expired wait for transmit complete */ | ||
7283 | |||
7284 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7285 | status = usc_InReg( info, TCSR ); | ||
7286 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7287 | |||
7288 | while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) { | ||
7289 | if (time_after(jiffies, EndTime)) { | ||
7290 | rc = false; | ||
7291 | break; | ||
7292 | } | ||
7293 | |||
7294 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7295 | status = usc_InReg( info, TCSR ); | ||
7296 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7297 | } | ||
7298 | } | ||
7299 | |||
7300 | |||
7301 | if ( rc ){ | ||
7302 | /* CHECK FOR TRANSMIT ERRORS */ | ||
7303 | if ( status & (BIT5 + BIT1) ) | ||
7304 | rc = false; | ||
7305 | } | ||
7306 | |||
7307 | if ( rc ) { | ||
7308 | /* WAIT FOR RECEIVE COMPLETE */ | ||
7309 | |||
7310 | /* Wait 100ms */ | ||
7311 | EndTime = jiffies + msecs_to_jiffies(100); | ||
7312 | |||
7313 | /* Wait for 16C32 to write receive status to buffer entry. */ | ||
7314 | status=info->rx_buffer_list[0].status; | ||
7315 | while ( status == 0 ) { | ||
7316 | if (time_after(jiffies, EndTime)) { | ||
7317 | rc = false; | ||
7318 | break; | ||
7319 | } | ||
7320 | status=info->rx_buffer_list[0].status; | ||
7321 | } | ||
7322 | } | ||
7323 | |||
7324 | |||
7325 | if ( rc ) { | ||
7326 | /* CHECK FOR RECEIVE ERRORS */ | ||
7327 | status = info->rx_buffer_list[0].status; | ||
7328 | |||
7329 | if ( status & (BIT8 + BIT3 + BIT1) ) { | ||
7330 | /* receive error has occurred */ | ||
7331 | rc = false; | ||
7332 | } else { | ||
7333 | if ( memcmp( info->tx_buffer_list[0].virt_addr , | ||
7334 | info->rx_buffer_list[0].virt_addr, FrameSize ) ){ | ||
7335 | rc = false; | ||
7336 | } | ||
7337 | } | ||
7338 | } | ||
7339 | |||
7340 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7341 | usc_reset( info ); | ||
7342 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7343 | |||
7344 | /* restore current port options */ | ||
7345 | memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); | ||
7346 | |||
7347 | return rc; | ||
7348 | |||
7349 | } /* end of mgsl_dma_test() */ | ||
7350 | |||
7351 | /* mgsl_adapter_test() | ||
7352 | * | ||
7353 | * Perform the register, IRQ, and DMA tests for the 16C32. | ||
7354 | * | ||
7355 | * Arguments: info pointer to device instance data | ||
7356 | * Return Value: 0 if success, otherwise -ENODEV | ||
7357 | */ | ||
7358 | static int mgsl_adapter_test( struct mgsl_struct *info ) | ||
7359 | { | ||
7360 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
7361 | printk( "%s(%d):Testing device %s\n", | ||
7362 | __FILE__,__LINE__,info->device_name ); | ||
7363 | |||
7364 | if ( !mgsl_register_test( info ) ) { | ||
7365 | info->init_error = DiagStatus_AddressFailure; | ||
7366 | printk( "%s(%d):Register test failure for device %s Addr=%04X\n", | ||
7367 | __FILE__,__LINE__,info->device_name, (unsigned short)(info->io_base) ); | ||
7368 | return -ENODEV; | ||
7369 | } | ||
7370 | |||
7371 | if ( !mgsl_irq_test( info ) ) { | ||
7372 | info->init_error = DiagStatus_IrqFailure; | ||
7373 | printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", | ||
7374 | __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); | ||
7375 | return -ENODEV; | ||
7376 | } | ||
7377 | |||
7378 | if ( !mgsl_dma_test( info ) ) { | ||
7379 | info->init_error = DiagStatus_DmaFailure; | ||
7380 | printk( "%s(%d):DMA test failure for device %s DMA=%d\n", | ||
7381 | __FILE__,__LINE__,info->device_name, (unsigned short)(info->dma_level) ); | ||
7382 | return -ENODEV; | ||
7383 | } | ||
7384 | |||
7385 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
7386 | printk( "%s(%d):device %s passed diagnostics\n", | ||
7387 | __FILE__,__LINE__,info->device_name ); | ||
7388 | |||
7389 | return 0; | ||
7390 | |||
7391 | } /* end of mgsl_adapter_test() */ | ||
7392 | |||
7393 | /* mgsl_memory_test() | ||
7394 | * | ||
7395 | * Test the shared memory on a PCI adapter. | ||
7396 | * | ||
7397 | * Arguments: info pointer to device instance data | ||
7398 | * Return Value: true if test passed, otherwise false | ||
7399 | */ | ||
7400 | static bool mgsl_memory_test( struct mgsl_struct *info ) | ||
7401 | { | ||
7402 | static unsigned long BitPatterns[] = | ||
7403 | { 0x0, 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; | ||
7404 | unsigned long Patterncount = ARRAY_SIZE(BitPatterns); | ||
7405 | unsigned long i; | ||
7406 | unsigned long TestLimit = SHARED_MEM_ADDRESS_SIZE/sizeof(unsigned long); | ||
7407 | unsigned long * TestAddr; | ||
7408 | |||
7409 | if ( info->bus_type != MGSL_BUS_TYPE_PCI ) | ||
7410 | return true; | ||
7411 | |||
7412 | TestAddr = (unsigned long *)info->memory_base; | ||
7413 | |||
7414 | /* Test data lines with test pattern at one location. */ | ||
7415 | |||
7416 | for ( i = 0 ; i < Patterncount ; i++ ) { | ||
7417 | *TestAddr = BitPatterns[i]; | ||
7418 | if ( *TestAddr != BitPatterns[i] ) | ||
7419 | return false; | ||
7420 | } | ||
7421 | |||
7422 | /* Test address lines with incrementing pattern over */ | ||
7423 | /* entire address range. */ | ||
7424 | |||
7425 | for ( i = 0 ; i < TestLimit ; i++ ) { | ||
7426 | *TestAddr = i * 4; | ||
7427 | TestAddr++; | ||
7428 | } | ||
7429 | |||
7430 | TestAddr = (unsigned long *)info->memory_base; | ||
7431 | |||
7432 | for ( i = 0 ; i < TestLimit ; i++ ) { | ||
7433 | if ( *TestAddr != i * 4 ) | ||
7434 | return false; | ||
7435 | TestAddr++; | ||
7436 | } | ||
7437 | |||
7438 | memset( info->memory_base, 0, SHARED_MEM_ADDRESS_SIZE ); | ||
7439 | |||
7440 | return true; | ||
7441 | |||
7442 | } /* End Of mgsl_memory_test() */ | ||
7443 | |||
7444 | |||
7445 | /* mgsl_load_pci_memory() | ||
7446 | * | ||
7447 | * Load a large block of data into the PCI shared memory. | ||
7448 | * Use this instead of memcpy() or memmove() to move data | ||
7449 | * into the PCI shared memory. | ||
7450 | * | ||
7451 | * Notes: | ||
7452 | * | ||
7453 | * This function prevents the PCI9050 interface chip from hogging | ||
7454 | * the adapter local bus, which can starve the 16C32 by preventing | ||
7455 | * 16C32 bus master cycles. | ||
7456 | * | ||
7457 | * The PCI9050 documentation says that the 9050 will always release | ||
7458 | * control of the local bus after completing the current read | ||
7459 | * or write operation. | ||
7460 | * | ||
7461 | * It appears that as long as the PCI9050 write FIFO is full, the | ||
7462 | * PCI9050 treats all of the writes as a single burst transaction | ||
7463 | * and will not release the bus. This causes DMA latency problems | ||
7464 | * at high speeds when copying large data blocks to the shared | ||
7465 | * memory. | ||
7466 | * | ||
7467 | * This function in effect, breaks the a large shared memory write | ||
7468 | * into multiple transations by interleaving a shared memory read | ||
7469 | * which will flush the write FIFO and 'complete' the write | ||
7470 | * transation. This allows any pending DMA request to gain control | ||
7471 | * of the local bus in a timely fasion. | ||
7472 | * | ||
7473 | * Arguments: | ||
7474 | * | ||
7475 | * TargetPtr pointer to target address in PCI shared memory | ||
7476 | * SourcePtr pointer to source buffer for data | ||
7477 | * count count in bytes of data to copy | ||
7478 | * | ||
7479 | * Return Value: None | ||
7480 | */ | ||
7481 | static void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, | ||
7482 | unsigned short count ) | ||
7483 | { | ||
7484 | /* 16 32-bit writes @ 60ns each = 960ns max latency on local bus */ | ||
7485 | #define PCI_LOAD_INTERVAL 64 | ||
7486 | |||
7487 | unsigned short Intervalcount = count / PCI_LOAD_INTERVAL; | ||
7488 | unsigned short Index; | ||
7489 | unsigned long Dummy; | ||
7490 | |||
7491 | for ( Index = 0 ; Index < Intervalcount ; Index++ ) | ||
7492 | { | ||
7493 | memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL); | ||
7494 | Dummy = *((volatile unsigned long *)TargetPtr); | ||
7495 | TargetPtr += PCI_LOAD_INTERVAL; | ||
7496 | SourcePtr += PCI_LOAD_INTERVAL; | ||
7497 | } | ||
7498 | |||
7499 | memcpy( TargetPtr, SourcePtr, count % PCI_LOAD_INTERVAL ); | ||
7500 | |||
7501 | } /* End Of mgsl_load_pci_memory() */ | ||
7502 | |||
7503 | static void mgsl_trace_block(struct mgsl_struct *info,const char* data, int count, int xmit) | ||
7504 | { | ||
7505 | int i; | ||
7506 | int linecount; | ||
7507 | if (xmit) | ||
7508 | printk("%s tx data:\n",info->device_name); | ||
7509 | else | ||
7510 | printk("%s rx data:\n",info->device_name); | ||
7511 | |||
7512 | while(count) { | ||
7513 | if (count > 16) | ||
7514 | linecount = 16; | ||
7515 | else | ||
7516 | linecount = count; | ||
7517 | |||
7518 | for(i=0;i<linecount;i++) | ||
7519 | printk("%02X ",(unsigned char)data[i]); | ||
7520 | for(;i<17;i++) | ||
7521 | printk(" "); | ||
7522 | for(i=0;i<linecount;i++) { | ||
7523 | if (data[i]>=040 && data[i]<=0176) | ||
7524 | printk("%c",data[i]); | ||
7525 | else | ||
7526 | printk("."); | ||
7527 | } | ||
7528 | printk("\n"); | ||
7529 | |||
7530 | data += linecount; | ||
7531 | count -= linecount; | ||
7532 | } | ||
7533 | } /* end of mgsl_trace_block() */ | ||
7534 | |||
7535 | /* mgsl_tx_timeout() | ||
7536 | * | ||
7537 | * called when HDLC frame times out | ||
7538 | * update stats and do tx completion processing | ||
7539 | * | ||
7540 | * Arguments: context pointer to device instance data | ||
7541 | * Return Value: None | ||
7542 | */ | ||
7543 | static void mgsl_tx_timeout(unsigned long context) | ||
7544 | { | ||
7545 | struct mgsl_struct *info = (struct mgsl_struct*)context; | ||
7546 | unsigned long flags; | ||
7547 | |||
7548 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
7549 | printk( "%s(%d):mgsl_tx_timeout(%s)\n", | ||
7550 | __FILE__,__LINE__,info->device_name); | ||
7551 | if(info->tx_active && | ||
7552 | (info->params.mode == MGSL_MODE_HDLC || | ||
7553 | info->params.mode == MGSL_MODE_RAW) ) { | ||
7554 | info->icount.txtimeout++; | ||
7555 | } | ||
7556 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7557 | info->tx_active = false; | ||
7558 | info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; | ||
7559 | |||
7560 | if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE ) | ||
7561 | usc_loopmode_cancel_transmit( info ); | ||
7562 | |||
7563 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7564 | |||
7565 | #if SYNCLINK_GENERIC_HDLC | ||
7566 | if (info->netcount) | ||
7567 | hdlcdev_tx_done(info); | ||
7568 | else | ||
7569 | #endif | ||
7570 | mgsl_bh_transmit(info); | ||
7571 | |||
7572 | } /* end of mgsl_tx_timeout() */ | ||
7573 | |||
7574 | /* signal that there are no more frames to send, so that | ||
7575 | * line is 'released' by echoing RxD to TxD when current | ||
7576 | * transmission is complete (or immediately if no tx in progress). | ||
7577 | */ | ||
7578 | static int mgsl_loopmode_send_done( struct mgsl_struct * info ) | ||
7579 | { | ||
7580 | unsigned long flags; | ||
7581 | |||
7582 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7583 | if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) { | ||
7584 | if (info->tx_active) | ||
7585 | info->loopmode_send_done_requested = true; | ||
7586 | else | ||
7587 | usc_loopmode_send_done(info); | ||
7588 | } | ||
7589 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7590 | |||
7591 | return 0; | ||
7592 | } | ||
7593 | |||
7594 | /* release the line by echoing RxD to TxD | ||
7595 | * upon completion of a transmit frame | ||
7596 | */ | ||
7597 | static void usc_loopmode_send_done( struct mgsl_struct * info ) | ||
7598 | { | ||
7599 | info->loopmode_send_done_requested = false; | ||
7600 | /* clear CMR:13 to 0 to start echoing RxData to TxData */ | ||
7601 | info->cmr_value &= ~BIT13; | ||
7602 | usc_OutReg(info, CMR, info->cmr_value); | ||
7603 | } | ||
7604 | |||
7605 | /* abort a transmit in progress while in HDLC LoopMode | ||
7606 | */ | ||
7607 | static void usc_loopmode_cancel_transmit( struct mgsl_struct * info ) | ||
7608 | { | ||
7609 | /* reset tx dma channel and purge TxFifo */ | ||
7610 | usc_RTCmd( info, RTCmd_PurgeTxFifo ); | ||
7611 | usc_DmaCmd( info, DmaCmd_ResetTxChannel ); | ||
7612 | usc_loopmode_send_done( info ); | ||
7613 | } | ||
7614 | |||
7615 | /* for HDLC/SDLC LoopMode, setting CMR:13 after the transmitter is enabled | ||
7616 | * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort) | ||
7617 | * we must clear CMR:13 to begin repeating TxData to RxData | ||
7618 | */ | ||
7619 | static void usc_loopmode_insert_request( struct mgsl_struct * info ) | ||
7620 | { | ||
7621 | info->loopmode_insert_requested = true; | ||
7622 | |||
7623 | /* enable RxAbort irq. On next RxAbort, clear CMR:13 to | ||
7624 | * begin repeating TxData on RxData (complete insertion) | ||
7625 | */ | ||
7626 | usc_OutReg( info, RICR, | ||
7627 | (usc_InReg( info, RICR ) | RXSTATUS_ABORT_RECEIVED ) ); | ||
7628 | |||
7629 | /* set CMR:13 to insert into loop on next GoAhead (RxAbort) */ | ||
7630 | info->cmr_value |= BIT13; | ||
7631 | usc_OutReg(info, CMR, info->cmr_value); | ||
7632 | } | ||
7633 | |||
7634 | /* return 1 if station is inserted into the loop, otherwise 0 | ||
7635 | */ | ||
7636 | static int usc_loopmode_active( struct mgsl_struct * info) | ||
7637 | { | ||
7638 | return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ; | ||
7639 | } | ||
7640 | |||
7641 | #if SYNCLINK_GENERIC_HDLC | ||
7642 | |||
7643 | /** | ||
7644 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | ||
7645 | * set encoding and frame check sequence (FCS) options | ||
7646 | * | ||
7647 | * dev pointer to network device structure | ||
7648 | * encoding serial encoding setting | ||
7649 | * parity FCS setting | ||
7650 | * | ||
7651 | * returns 0 if success, otherwise error code | ||
7652 | */ | ||
7653 | static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, | ||
7654 | unsigned short parity) | ||
7655 | { | ||
7656 | struct mgsl_struct *info = dev_to_port(dev); | ||
7657 | unsigned char new_encoding; | ||
7658 | unsigned short new_crctype; | ||
7659 | |||
7660 | /* return error if TTY interface open */ | ||
7661 | if (info->port.count) | ||
7662 | return -EBUSY; | ||
7663 | |||
7664 | switch (encoding) | ||
7665 | { | ||
7666 | case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; | ||
7667 | case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; | ||
7668 | case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; | ||
7669 | case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; | ||
7670 | case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; | ||
7671 | default: return -EINVAL; | ||
7672 | } | ||
7673 | |||
7674 | switch (parity) | ||
7675 | { | ||
7676 | case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; | ||
7677 | case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; | ||
7678 | case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; | ||
7679 | default: return -EINVAL; | ||
7680 | } | ||
7681 | |||
7682 | info->params.encoding = new_encoding; | ||
7683 | info->params.crc_type = new_crctype; | ||
7684 | |||
7685 | /* if network interface up, reprogram hardware */ | ||
7686 | if (info->netcount) | ||
7687 | mgsl_program_hw(info); | ||
7688 | |||
7689 | return 0; | ||
7690 | } | ||
7691 | |||
7692 | /** | ||
7693 | * called by generic HDLC layer to send frame | ||
7694 | * | ||
7695 | * skb socket buffer containing HDLC frame | ||
7696 | * dev pointer to network device structure | ||
7697 | */ | ||
7698 | static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, | ||
7699 | struct net_device *dev) | ||
7700 | { | ||
7701 | struct mgsl_struct *info = dev_to_port(dev); | ||
7702 | unsigned long flags; | ||
7703 | |||
7704 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7705 | printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); | ||
7706 | |||
7707 | /* stop sending until this frame completes */ | ||
7708 | netif_stop_queue(dev); | ||
7709 | |||
7710 | /* copy data to device buffers */ | ||
7711 | info->xmit_cnt = skb->len; | ||
7712 | mgsl_load_tx_dma_buffer(info, skb->data, skb->len); | ||
7713 | |||
7714 | /* update network statistics */ | ||
7715 | dev->stats.tx_packets++; | ||
7716 | dev->stats.tx_bytes += skb->len; | ||
7717 | |||
7718 | /* done with socket buffer, so free it */ | ||
7719 | dev_kfree_skb(skb); | ||
7720 | |||
7721 | /* save start time for transmit timeout detection */ | ||
7722 | dev->trans_start = jiffies; | ||
7723 | |||
7724 | /* start hardware transmitter if necessary */ | ||
7725 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7726 | if (!info->tx_active) | ||
7727 | usc_start_transmitter(info); | ||
7728 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7729 | |||
7730 | return NETDEV_TX_OK; | ||
7731 | } | ||
7732 | |||
7733 | /** | ||
7734 | * called by network layer when interface enabled | ||
7735 | * claim resources and initialize hardware | ||
7736 | * | ||
7737 | * dev pointer to network device structure | ||
7738 | * | ||
7739 | * returns 0 if success, otherwise error code | ||
7740 | */ | ||
7741 | static int hdlcdev_open(struct net_device *dev) | ||
7742 | { | ||
7743 | struct mgsl_struct *info = dev_to_port(dev); | ||
7744 | int rc; | ||
7745 | unsigned long flags; | ||
7746 | |||
7747 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7748 | printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); | ||
7749 | |||
7750 | /* generic HDLC layer open processing */ | ||
7751 | if ((rc = hdlc_open(dev))) | ||
7752 | return rc; | ||
7753 | |||
7754 | /* arbitrate between network and tty opens */ | ||
7755 | spin_lock_irqsave(&info->netlock, flags); | ||
7756 | if (info->port.count != 0 || info->netcount != 0) { | ||
7757 | printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); | ||
7758 | spin_unlock_irqrestore(&info->netlock, flags); | ||
7759 | return -EBUSY; | ||
7760 | } | ||
7761 | info->netcount=1; | ||
7762 | spin_unlock_irqrestore(&info->netlock, flags); | ||
7763 | |||
7764 | /* claim resources and init adapter */ | ||
7765 | if ((rc = startup(info)) != 0) { | ||
7766 | spin_lock_irqsave(&info->netlock, flags); | ||
7767 | info->netcount=0; | ||
7768 | spin_unlock_irqrestore(&info->netlock, flags); | ||
7769 | return rc; | ||
7770 | } | ||
7771 | |||
7772 | /* assert DTR and RTS, apply hardware settings */ | ||
7773 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
7774 | mgsl_program_hw(info); | ||
7775 | |||
7776 | /* enable network layer transmit */ | ||
7777 | dev->trans_start = jiffies; | ||
7778 | netif_start_queue(dev); | ||
7779 | |||
7780 | /* inform generic HDLC layer of current DCD status */ | ||
7781 | spin_lock_irqsave(&info->irq_spinlock, flags); | ||
7782 | usc_get_serial_signals(info); | ||
7783 | spin_unlock_irqrestore(&info->irq_spinlock, flags); | ||
7784 | if (info->serial_signals & SerialSignal_DCD) | ||
7785 | netif_carrier_on(dev); | ||
7786 | else | ||
7787 | netif_carrier_off(dev); | ||
7788 | return 0; | ||
7789 | } | ||
7790 | |||
7791 | /** | ||
7792 | * called by network layer when interface is disabled | ||
7793 | * shutdown hardware and release resources | ||
7794 | * | ||
7795 | * dev pointer to network device structure | ||
7796 | * | ||
7797 | * returns 0 if success, otherwise error code | ||
7798 | */ | ||
7799 | static int hdlcdev_close(struct net_device *dev) | ||
7800 | { | ||
7801 | struct mgsl_struct *info = dev_to_port(dev); | ||
7802 | unsigned long flags; | ||
7803 | |||
7804 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7805 | printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); | ||
7806 | |||
7807 | netif_stop_queue(dev); | ||
7808 | |||
7809 | /* shutdown adapter and release resources */ | ||
7810 | shutdown(info); | ||
7811 | |||
7812 | hdlc_close(dev); | ||
7813 | |||
7814 | spin_lock_irqsave(&info->netlock, flags); | ||
7815 | info->netcount=0; | ||
7816 | spin_unlock_irqrestore(&info->netlock, flags); | ||
7817 | |||
7818 | return 0; | ||
7819 | } | ||
7820 | |||
7821 | /** | ||
7822 | * called by network layer to process IOCTL call to network device | ||
7823 | * | ||
7824 | * dev pointer to network device structure | ||
7825 | * ifr pointer to network interface request structure | ||
7826 | * cmd IOCTL command code | ||
7827 | * | ||
7828 | * returns 0 if success, otherwise error code | ||
7829 | */ | ||
7830 | static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
7831 | { | ||
7832 | const size_t size = sizeof(sync_serial_settings); | ||
7833 | sync_serial_settings new_line; | ||
7834 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | ||
7835 | struct mgsl_struct *info = dev_to_port(dev); | ||
7836 | unsigned int flags; | ||
7837 | |||
7838 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7839 | printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); | ||
7840 | |||
7841 | /* return error if TTY interface open */ | ||
7842 | if (info->port.count) | ||
7843 | return -EBUSY; | ||
7844 | |||
7845 | if (cmd != SIOCWANDEV) | ||
7846 | return hdlc_ioctl(dev, ifr, cmd); | ||
7847 | |||
7848 | switch(ifr->ifr_settings.type) { | ||
7849 | case IF_GET_IFACE: /* return current sync_serial_settings */ | ||
7850 | |||
7851 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; | ||
7852 | if (ifr->ifr_settings.size < size) { | ||
7853 | ifr->ifr_settings.size = size; /* data size wanted */ | ||
7854 | return -ENOBUFS; | ||
7855 | } | ||
7856 | |||
7857 | flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
7858 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
7859 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
7860 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
7861 | |||
7862 | switch (flags){ | ||
7863 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; | ||
7864 | case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; | ||
7865 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; | ||
7866 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; | ||
7867 | default: new_line.clock_type = CLOCK_DEFAULT; | ||
7868 | } | ||
7869 | |||
7870 | new_line.clock_rate = info->params.clock_speed; | ||
7871 | new_line.loopback = info->params.loopback ? 1:0; | ||
7872 | |||
7873 | if (copy_to_user(line, &new_line, size)) | ||
7874 | return -EFAULT; | ||
7875 | return 0; | ||
7876 | |||
7877 | case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ | ||
7878 | |||
7879 | if(!capable(CAP_NET_ADMIN)) | ||
7880 | return -EPERM; | ||
7881 | if (copy_from_user(&new_line, line, size)) | ||
7882 | return -EFAULT; | ||
7883 | |||
7884 | switch (new_line.clock_type) | ||
7885 | { | ||
7886 | case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; | ||
7887 | case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; | ||
7888 | case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; | ||
7889 | case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; | ||
7890 | case CLOCK_DEFAULT: flags = info->params.flags & | ||
7891 | (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
7892 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
7893 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
7894 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; | ||
7895 | default: return -EINVAL; | ||
7896 | } | ||
7897 | |||
7898 | if (new_line.loopback != 0 && new_line.loopback != 1) | ||
7899 | return -EINVAL; | ||
7900 | |||
7901 | info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
7902 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
7903 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
7904 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
7905 | info->params.flags |= flags; | ||
7906 | |||
7907 | info->params.loopback = new_line.loopback; | ||
7908 | |||
7909 | if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) | ||
7910 | info->params.clock_speed = new_line.clock_rate; | ||
7911 | else | ||
7912 | info->params.clock_speed = 0; | ||
7913 | |||
7914 | /* if network interface up, reprogram hardware */ | ||
7915 | if (info->netcount) | ||
7916 | mgsl_program_hw(info); | ||
7917 | return 0; | ||
7918 | |||
7919 | default: | ||
7920 | return hdlc_ioctl(dev, ifr, cmd); | ||
7921 | } | ||
7922 | } | ||
7923 | |||
7924 | /** | ||
7925 | * called by network layer when transmit timeout is detected | ||
7926 | * | ||
7927 | * dev pointer to network device structure | ||
7928 | */ | ||
7929 | static void hdlcdev_tx_timeout(struct net_device *dev) | ||
7930 | { | ||
7931 | struct mgsl_struct *info = dev_to_port(dev); | ||
7932 | unsigned long flags; | ||
7933 | |||
7934 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7935 | printk("hdlcdev_tx_timeout(%s)\n",dev->name); | ||
7936 | |||
7937 | dev->stats.tx_errors++; | ||
7938 | dev->stats.tx_aborted_errors++; | ||
7939 | |||
7940 | spin_lock_irqsave(&info->irq_spinlock,flags); | ||
7941 | usc_stop_transmitter(info); | ||
7942 | spin_unlock_irqrestore(&info->irq_spinlock,flags); | ||
7943 | |||
7944 | netif_wake_queue(dev); | ||
7945 | } | ||
7946 | |||
7947 | /** | ||
7948 | * called by device driver when transmit completes | ||
7949 | * reenable network layer transmit if stopped | ||
7950 | * | ||
7951 | * info pointer to device instance information | ||
7952 | */ | ||
7953 | static void hdlcdev_tx_done(struct mgsl_struct *info) | ||
7954 | { | ||
7955 | if (netif_queue_stopped(info->netdev)) | ||
7956 | netif_wake_queue(info->netdev); | ||
7957 | } | ||
7958 | |||
7959 | /** | ||
7960 | * called by device driver when frame received | ||
7961 | * pass frame to network layer | ||
7962 | * | ||
7963 | * info pointer to device instance information | ||
7964 | * buf pointer to buffer contianing frame data | ||
7965 | * size count of data bytes in buf | ||
7966 | */ | ||
7967 | static void hdlcdev_rx(struct mgsl_struct *info, char *buf, int size) | ||
7968 | { | ||
7969 | struct sk_buff *skb = dev_alloc_skb(size); | ||
7970 | struct net_device *dev = info->netdev; | ||
7971 | |||
7972 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
7973 | printk("hdlcdev_rx(%s)\n", dev->name); | ||
7974 | |||
7975 | if (skb == NULL) { | ||
7976 | printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", | ||
7977 | dev->name); | ||
7978 | dev->stats.rx_dropped++; | ||
7979 | return; | ||
7980 | } | ||
7981 | |||
7982 | memcpy(skb_put(skb, size), buf, size); | ||
7983 | |||
7984 | skb->protocol = hdlc_type_trans(skb, dev); | ||
7985 | |||
7986 | dev->stats.rx_packets++; | ||
7987 | dev->stats.rx_bytes += size; | ||
7988 | |||
7989 | netif_rx(skb); | ||
7990 | } | ||
7991 | |||
7992 | static const struct net_device_ops hdlcdev_ops = { | ||
7993 | .ndo_open = hdlcdev_open, | ||
7994 | .ndo_stop = hdlcdev_close, | ||
7995 | .ndo_change_mtu = hdlc_change_mtu, | ||
7996 | .ndo_start_xmit = hdlc_start_xmit, | ||
7997 | .ndo_do_ioctl = hdlcdev_ioctl, | ||
7998 | .ndo_tx_timeout = hdlcdev_tx_timeout, | ||
7999 | }; | ||
8000 | |||
8001 | /** | ||
8002 | * called by device driver when adding device instance | ||
8003 | * do generic HDLC initialization | ||
8004 | * | ||
8005 | * info pointer to device instance information | ||
8006 | * | ||
8007 | * returns 0 if success, otherwise error code | ||
8008 | */ | ||
8009 | static int hdlcdev_init(struct mgsl_struct *info) | ||
8010 | { | ||
8011 | int rc; | ||
8012 | struct net_device *dev; | ||
8013 | hdlc_device *hdlc; | ||
8014 | |||
8015 | /* allocate and initialize network and HDLC layer objects */ | ||
8016 | |||
8017 | if (!(dev = alloc_hdlcdev(info))) { | ||
8018 | printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); | ||
8019 | return -ENOMEM; | ||
8020 | } | ||
8021 | |||
8022 | /* for network layer reporting purposes only */ | ||
8023 | dev->base_addr = info->io_base; | ||
8024 | dev->irq = info->irq_level; | ||
8025 | dev->dma = info->dma_level; | ||
8026 | |||
8027 | /* network layer callbacks and settings */ | ||
8028 | dev->netdev_ops = &hdlcdev_ops; | ||
8029 | dev->watchdog_timeo = 10 * HZ; | ||
8030 | dev->tx_queue_len = 50; | ||
8031 | |||
8032 | /* generic HDLC layer callbacks and settings */ | ||
8033 | hdlc = dev_to_hdlc(dev); | ||
8034 | hdlc->attach = hdlcdev_attach; | ||
8035 | hdlc->xmit = hdlcdev_xmit; | ||
8036 | |||
8037 | /* register objects with HDLC layer */ | ||
8038 | if ((rc = register_hdlc_device(dev))) { | ||
8039 | printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); | ||
8040 | free_netdev(dev); | ||
8041 | return rc; | ||
8042 | } | ||
8043 | |||
8044 | info->netdev = dev; | ||
8045 | return 0; | ||
8046 | } | ||
8047 | |||
8048 | /** | ||
8049 | * called by device driver when removing device instance | ||
8050 | * do generic HDLC cleanup | ||
8051 | * | ||
8052 | * info pointer to device instance information | ||
8053 | */ | ||
8054 | static void hdlcdev_exit(struct mgsl_struct *info) | ||
8055 | { | ||
8056 | unregister_hdlc_device(info->netdev); | ||
8057 | free_netdev(info->netdev); | ||
8058 | info->netdev = NULL; | ||
8059 | } | ||
8060 | |||
8061 | #endif /* CONFIG_HDLC */ | ||
8062 | |||
8063 | |||
8064 | static int __devinit synclink_init_one (struct pci_dev *dev, | ||
8065 | const struct pci_device_id *ent) | ||
8066 | { | ||
8067 | struct mgsl_struct *info; | ||
8068 | |||
8069 | if (pci_enable_device(dev)) { | ||
8070 | printk("error enabling pci device %p\n", dev); | ||
8071 | return -EIO; | ||
8072 | } | ||
8073 | |||
8074 | if (!(info = mgsl_allocate_device())) { | ||
8075 | printk("can't allocate device instance data.\n"); | ||
8076 | return -EIO; | ||
8077 | } | ||
8078 | |||
8079 | /* Copy user configuration info to device instance data */ | ||
8080 | |||
8081 | info->io_base = pci_resource_start(dev, 2); | ||
8082 | info->irq_level = dev->irq; | ||
8083 | info->phys_memory_base = pci_resource_start(dev, 3); | ||
8084 | |||
8085 | /* Because veremap only works on page boundaries we must map | ||
8086 | * a larger area than is actually implemented for the LCR | ||
8087 | * memory range. We map a full page starting at the page boundary. | ||
8088 | */ | ||
8089 | info->phys_lcr_base = pci_resource_start(dev, 0); | ||
8090 | info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); | ||
8091 | info->phys_lcr_base &= ~(PAGE_SIZE-1); | ||
8092 | |||
8093 | info->bus_type = MGSL_BUS_TYPE_PCI; | ||
8094 | info->io_addr_size = 8; | ||
8095 | info->irq_flags = IRQF_SHARED; | ||
8096 | |||
8097 | if (dev->device == 0x0210) { | ||
8098 | /* Version 1 PCI9030 based universal PCI adapter */ | ||
8099 | info->misc_ctrl_value = 0x007c4080; | ||
8100 | info->hw_version = 1; | ||
8101 | } else { | ||
8102 | /* Version 0 PCI9050 based 5V PCI adapter | ||
8103 | * A PCI9050 bug prevents reading LCR registers if | ||
8104 | * LCR base address bit 7 is set. Maintain shadow | ||
8105 | * value so we can write to LCR misc control reg. | ||
8106 | */ | ||
8107 | info->misc_ctrl_value = 0x087e4546; | ||
8108 | info->hw_version = 0; | ||
8109 | } | ||
8110 | |||
8111 | mgsl_add_device(info); | ||
8112 | |||
8113 | return 0; | ||
8114 | } | ||
8115 | |||
8116 | static void __devexit synclink_remove_one (struct pci_dev *dev) | ||
8117 | { | ||
8118 | } | ||
8119 | |||
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c new file mode 100644 index 000000000000..a35dd549a008 --- /dev/null +++ b/drivers/tty/synclink_gt.c | |||
@@ -0,0 +1,5161 @@ | |||
1 | /* | ||
2 | * Device driver for Microgate SyncLink GT serial adapters. | ||
3 | * | ||
4 | * written by Paul Fulghum for Microgate Corporation | ||
5 | * paulkf@microgate.com | ||
6 | * | ||
7 | * Microgate and SyncLink are trademarks of Microgate Corporation | ||
8 | * | ||
9 | * This code is released under the GNU General Public License (GPL) | ||
10 | * | ||
11 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
12 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
13 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
14 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
15 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
16 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
17 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
18 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
19 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
20 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
21 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * DEBUG OUTPUT DEFINITIONS | ||
26 | * | ||
27 | * uncomment lines below to enable specific types of debug output | ||
28 | * | ||
29 | * DBGINFO information - most verbose output | ||
30 | * DBGERR serious errors | ||
31 | * DBGBH bottom half service routine debugging | ||
32 | * DBGISR interrupt service routine debugging | ||
33 | * DBGDATA output receive and transmit data | ||
34 | * DBGTBUF output transmit DMA buffers and registers | ||
35 | * DBGRBUF output receive DMA buffers and registers | ||
36 | */ | ||
37 | |||
38 | #define DBGINFO(fmt) if (debug_level >= DEBUG_LEVEL_INFO) printk fmt | ||
39 | #define DBGERR(fmt) if (debug_level >= DEBUG_LEVEL_ERROR) printk fmt | ||
40 | #define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt | ||
41 | #define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt | ||
42 | #define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label)) | ||
43 | /*#define DBGTBUF(info) dump_tbufs(info)*/ | ||
44 | /*#define DBGRBUF(info) dump_rbufs(info)*/ | ||
45 | |||
46 | |||
47 | #include <linux/module.h> | ||
48 | #include <linux/errno.h> | ||
49 | #include <linux/signal.h> | ||
50 | #include <linux/sched.h> | ||
51 | #include <linux/timer.h> | ||
52 | #include <linux/interrupt.h> | ||
53 | #include <linux/pci.h> | ||
54 | #include <linux/tty.h> | ||
55 | #include <linux/tty_flip.h> | ||
56 | #include <linux/serial.h> | ||
57 | #include <linux/major.h> | ||
58 | #include <linux/string.h> | ||
59 | #include <linux/fcntl.h> | ||
60 | #include <linux/ptrace.h> | ||
61 | #include <linux/ioport.h> | ||
62 | #include <linux/mm.h> | ||
63 | #include <linux/seq_file.h> | ||
64 | #include <linux/slab.h> | ||
65 | #include <linux/netdevice.h> | ||
66 | #include <linux/vmalloc.h> | ||
67 | #include <linux/init.h> | ||
68 | #include <linux/delay.h> | ||
69 | #include <linux/ioctl.h> | ||
70 | #include <linux/termios.h> | ||
71 | #include <linux/bitops.h> | ||
72 | #include <linux/workqueue.h> | ||
73 | #include <linux/hdlc.h> | ||
74 | #include <linux/synclink.h> | ||
75 | |||
76 | #include <asm/system.h> | ||
77 | #include <asm/io.h> | ||
78 | #include <asm/irq.h> | ||
79 | #include <asm/dma.h> | ||
80 | #include <asm/types.h> | ||
81 | #include <asm/uaccess.h> | ||
82 | |||
83 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) | ||
84 | #define SYNCLINK_GENERIC_HDLC 1 | ||
85 | #else | ||
86 | #define SYNCLINK_GENERIC_HDLC 0 | ||
87 | #endif | ||
88 | |||
89 | /* | ||
90 | * module identification | ||
91 | */ | ||
92 | static char *driver_name = "SyncLink GT"; | ||
93 | static char *tty_driver_name = "synclink_gt"; | ||
94 | static char *tty_dev_prefix = "ttySLG"; | ||
95 | MODULE_LICENSE("GPL"); | ||
96 | #define MGSL_MAGIC 0x5401 | ||
97 | #define MAX_DEVICES 32 | ||
98 | |||
99 | static struct pci_device_id pci_table[] = { | ||
100 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, | ||
101 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, | ||
102 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, | ||
103 | {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, | ||
104 | {0,}, /* terminate list */ | ||
105 | }; | ||
106 | MODULE_DEVICE_TABLE(pci, pci_table); | ||
107 | |||
108 | static int init_one(struct pci_dev *dev,const struct pci_device_id *ent); | ||
109 | static void remove_one(struct pci_dev *dev); | ||
110 | static struct pci_driver pci_driver = { | ||
111 | .name = "synclink_gt", | ||
112 | .id_table = pci_table, | ||
113 | .probe = init_one, | ||
114 | .remove = __devexit_p(remove_one), | ||
115 | }; | ||
116 | |||
117 | static bool pci_registered; | ||
118 | |||
119 | /* | ||
120 | * module configuration and status | ||
121 | */ | ||
122 | static struct slgt_info *slgt_device_list; | ||
123 | static int slgt_device_count; | ||
124 | |||
125 | static int ttymajor; | ||
126 | static int debug_level; | ||
127 | static int maxframe[MAX_DEVICES]; | ||
128 | |||
129 | module_param(ttymajor, int, 0); | ||
130 | module_param(debug_level, int, 0); | ||
131 | module_param_array(maxframe, int, NULL, 0); | ||
132 | |||
133 | MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned"); | ||
134 | MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail"); | ||
135 | MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); | ||
136 | |||
137 | /* | ||
138 | * tty support and callbacks | ||
139 | */ | ||
140 | static struct tty_driver *serial_driver; | ||
141 | |||
142 | static int open(struct tty_struct *tty, struct file * filp); | ||
143 | static void close(struct tty_struct *tty, struct file * filp); | ||
144 | static void hangup(struct tty_struct *tty); | ||
145 | static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); | ||
146 | |||
147 | static int write(struct tty_struct *tty, const unsigned char *buf, int count); | ||
148 | static int put_char(struct tty_struct *tty, unsigned char ch); | ||
149 | static void send_xchar(struct tty_struct *tty, char ch); | ||
150 | static void wait_until_sent(struct tty_struct *tty, int timeout); | ||
151 | static int write_room(struct tty_struct *tty); | ||
152 | static void flush_chars(struct tty_struct *tty); | ||
153 | static void flush_buffer(struct tty_struct *tty); | ||
154 | static void tx_hold(struct tty_struct *tty); | ||
155 | static void tx_release(struct tty_struct *tty); | ||
156 | |||
157 | static int ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); | ||
158 | static int chars_in_buffer(struct tty_struct *tty); | ||
159 | static void throttle(struct tty_struct * tty); | ||
160 | static void unthrottle(struct tty_struct * tty); | ||
161 | static int set_break(struct tty_struct *tty, int break_state); | ||
162 | |||
163 | /* | ||
164 | * generic HDLC support and callbacks | ||
165 | */ | ||
166 | #if SYNCLINK_GENERIC_HDLC | ||
167 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | ||
168 | static void hdlcdev_tx_done(struct slgt_info *info); | ||
169 | static void hdlcdev_rx(struct slgt_info *info, char *buf, int size); | ||
170 | static int hdlcdev_init(struct slgt_info *info); | ||
171 | static void hdlcdev_exit(struct slgt_info *info); | ||
172 | #endif | ||
173 | |||
174 | |||
175 | /* | ||
176 | * device specific structures, macros and functions | ||
177 | */ | ||
178 | |||
179 | #define SLGT_MAX_PORTS 4 | ||
180 | #define SLGT_REG_SIZE 256 | ||
181 | |||
182 | /* | ||
183 | * conditional wait facility | ||
184 | */ | ||
185 | struct cond_wait { | ||
186 | struct cond_wait *next; | ||
187 | wait_queue_head_t q; | ||
188 | wait_queue_t wait; | ||
189 | unsigned int data; | ||
190 | }; | ||
191 | static void init_cond_wait(struct cond_wait *w, unsigned int data); | ||
192 | static void add_cond_wait(struct cond_wait **head, struct cond_wait *w); | ||
193 | static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w); | ||
194 | static void flush_cond_wait(struct cond_wait **head); | ||
195 | |||
196 | /* | ||
197 | * DMA buffer descriptor and access macros | ||
198 | */ | ||
199 | struct slgt_desc | ||
200 | { | ||
201 | __le16 count; | ||
202 | __le16 status; | ||
203 | __le32 pbuf; /* physical address of data buffer */ | ||
204 | __le32 next; /* physical address of next descriptor */ | ||
205 | |||
206 | /* driver book keeping */ | ||
207 | char *buf; /* virtual address of data buffer */ | ||
208 | unsigned int pdesc; /* physical address of this descriptor */ | ||
209 | dma_addr_t buf_dma_addr; | ||
210 | unsigned short buf_count; | ||
211 | }; | ||
212 | |||
213 | #define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) | ||
214 | #define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) | ||
215 | #define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) | ||
216 | #define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) | ||
217 | #define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b)) | ||
218 | #define desc_count(a) (le16_to_cpu((a).count)) | ||
219 | #define desc_status(a) (le16_to_cpu((a).status)) | ||
220 | #define desc_complete(a) (le16_to_cpu((a).status) & BIT15) | ||
221 | #define desc_eof(a) (le16_to_cpu((a).status) & BIT2) | ||
222 | #define desc_crc_error(a) (le16_to_cpu((a).status) & BIT1) | ||
223 | #define desc_abort(a) (le16_to_cpu((a).status) & BIT0) | ||
224 | #define desc_residue(a) ((le16_to_cpu((a).status) & 0x38) >> 3) | ||
225 | |||
226 | struct _input_signal_events { | ||
227 | int ri_up; | ||
228 | int ri_down; | ||
229 | int dsr_up; | ||
230 | int dsr_down; | ||
231 | int dcd_up; | ||
232 | int dcd_down; | ||
233 | int cts_up; | ||
234 | int cts_down; | ||
235 | }; | ||
236 | |||
237 | /* | ||
238 | * device instance data structure | ||
239 | */ | ||
240 | struct slgt_info { | ||
241 | void *if_ptr; /* General purpose pointer (used by SPPP) */ | ||
242 | struct tty_port port; | ||
243 | |||
244 | struct slgt_info *next_device; /* device list link */ | ||
245 | |||
246 | int magic; | ||
247 | |||
248 | char device_name[25]; | ||
249 | struct pci_dev *pdev; | ||
250 | |||
251 | int port_count; /* count of ports on adapter */ | ||
252 | int adapter_num; /* adapter instance number */ | ||
253 | int port_num; /* port instance number */ | ||
254 | |||
255 | /* array of pointers to port contexts on this adapter */ | ||
256 | struct slgt_info *port_array[SLGT_MAX_PORTS]; | ||
257 | |||
258 | int line; /* tty line instance number */ | ||
259 | |||
260 | struct mgsl_icount icount; | ||
261 | |||
262 | int timeout; | ||
263 | int x_char; /* xon/xoff character */ | ||
264 | unsigned int read_status_mask; | ||
265 | unsigned int ignore_status_mask; | ||
266 | |||
267 | wait_queue_head_t status_event_wait_q; | ||
268 | wait_queue_head_t event_wait_q; | ||
269 | struct timer_list tx_timer; | ||
270 | struct timer_list rx_timer; | ||
271 | |||
272 | unsigned int gpio_present; | ||
273 | struct cond_wait *gpio_wait_q; | ||
274 | |||
275 | spinlock_t lock; /* spinlock for synchronizing with ISR */ | ||
276 | |||
277 | struct work_struct task; | ||
278 | u32 pending_bh; | ||
279 | bool bh_requested; | ||
280 | bool bh_running; | ||
281 | |||
282 | int isr_overflow; | ||
283 | bool irq_requested; /* true if IRQ requested */ | ||
284 | bool irq_occurred; /* for diagnostics use */ | ||
285 | |||
286 | /* device configuration */ | ||
287 | |||
288 | unsigned int bus_type; | ||
289 | unsigned int irq_level; | ||
290 | unsigned long irq_flags; | ||
291 | |||
292 | unsigned char __iomem * reg_addr; /* memory mapped registers address */ | ||
293 | u32 phys_reg_addr; | ||
294 | bool reg_addr_requested; | ||
295 | |||
296 | MGSL_PARAMS params; /* communications parameters */ | ||
297 | u32 idle_mode; | ||
298 | u32 max_frame_size; /* as set by device config */ | ||
299 | |||
300 | unsigned int rbuf_fill_level; | ||
301 | unsigned int rx_pio; | ||
302 | unsigned int if_mode; | ||
303 | unsigned int base_clock; | ||
304 | unsigned int xsync; | ||
305 | unsigned int xctrl; | ||
306 | |||
307 | /* device status */ | ||
308 | |||
309 | bool rx_enabled; | ||
310 | bool rx_restart; | ||
311 | |||
312 | bool tx_enabled; | ||
313 | bool tx_active; | ||
314 | |||
315 | unsigned char signals; /* serial signal states */ | ||
316 | int init_error; /* initialization error */ | ||
317 | |||
318 | unsigned char *tx_buf; | ||
319 | int tx_count; | ||
320 | |||
321 | char flag_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
322 | char char_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
323 | bool drop_rts_on_tx_done; | ||
324 | struct _input_signal_events input_signal_events; | ||
325 | |||
326 | int dcd_chkcount; /* check counts to prevent */ | ||
327 | int cts_chkcount; /* too many IRQs if a signal */ | ||
328 | int dsr_chkcount; /* is floating */ | ||
329 | int ri_chkcount; | ||
330 | |||
331 | char *bufs; /* virtual address of DMA buffer lists */ | ||
332 | dma_addr_t bufs_dma_addr; /* physical address of buffer descriptors */ | ||
333 | |||
334 | unsigned int rbuf_count; | ||
335 | struct slgt_desc *rbufs; | ||
336 | unsigned int rbuf_current; | ||
337 | unsigned int rbuf_index; | ||
338 | unsigned int rbuf_fill_index; | ||
339 | unsigned short rbuf_fill_count; | ||
340 | |||
341 | unsigned int tbuf_count; | ||
342 | struct slgt_desc *tbufs; | ||
343 | unsigned int tbuf_current; | ||
344 | unsigned int tbuf_start; | ||
345 | |||
346 | unsigned char *tmp_rbuf; | ||
347 | unsigned int tmp_rbuf_count; | ||
348 | |||
349 | /* SPPP/Cisco HDLC device parts */ | ||
350 | |||
351 | int netcount; | ||
352 | spinlock_t netlock; | ||
353 | #if SYNCLINK_GENERIC_HDLC | ||
354 | struct net_device *netdev; | ||
355 | #endif | ||
356 | |||
357 | }; | ||
358 | |||
359 | static MGSL_PARAMS default_params = { | ||
360 | .mode = MGSL_MODE_HDLC, | ||
361 | .loopback = 0, | ||
362 | .flags = HDLC_FLAG_UNDERRUN_ABORT15, | ||
363 | .encoding = HDLC_ENCODING_NRZI_SPACE, | ||
364 | .clock_speed = 0, | ||
365 | .addr_filter = 0xff, | ||
366 | .crc_type = HDLC_CRC_16_CCITT, | ||
367 | .preamble_length = HDLC_PREAMBLE_LENGTH_8BITS, | ||
368 | .preamble = HDLC_PREAMBLE_PATTERN_NONE, | ||
369 | .data_rate = 9600, | ||
370 | .data_bits = 8, | ||
371 | .stop_bits = 1, | ||
372 | .parity = ASYNC_PARITY_NONE | ||
373 | }; | ||
374 | |||
375 | |||
376 | #define BH_RECEIVE 1 | ||
377 | #define BH_TRANSMIT 2 | ||
378 | #define BH_STATUS 4 | ||
379 | #define IO_PIN_SHUTDOWN_LIMIT 100 | ||
380 | |||
381 | #define DMABUFSIZE 256 | ||
382 | #define DESC_LIST_SIZE 4096 | ||
383 | |||
384 | #define MASK_PARITY BIT1 | ||
385 | #define MASK_FRAMING BIT0 | ||
386 | #define MASK_BREAK BIT14 | ||
387 | #define MASK_OVERRUN BIT4 | ||
388 | |||
389 | #define GSR 0x00 /* global status */ | ||
390 | #define JCR 0x04 /* JTAG control */ | ||
391 | #define IODR 0x08 /* GPIO direction */ | ||
392 | #define IOER 0x0c /* GPIO interrupt enable */ | ||
393 | #define IOVR 0x10 /* GPIO value */ | ||
394 | #define IOSR 0x14 /* GPIO interrupt status */ | ||
395 | #define TDR 0x80 /* tx data */ | ||
396 | #define RDR 0x80 /* rx data */ | ||
397 | #define TCR 0x82 /* tx control */ | ||
398 | #define TIR 0x84 /* tx idle */ | ||
399 | #define TPR 0x85 /* tx preamble */ | ||
400 | #define RCR 0x86 /* rx control */ | ||
401 | #define VCR 0x88 /* V.24 control */ | ||
402 | #define CCR 0x89 /* clock control */ | ||
403 | #define BDR 0x8a /* baud divisor */ | ||
404 | #define SCR 0x8c /* serial control */ | ||
405 | #define SSR 0x8e /* serial status */ | ||
406 | #define RDCSR 0x90 /* rx DMA control/status */ | ||
407 | #define TDCSR 0x94 /* tx DMA control/status */ | ||
408 | #define RDDAR 0x98 /* rx DMA descriptor address */ | ||
409 | #define TDDAR 0x9c /* tx DMA descriptor address */ | ||
410 | #define XSR 0x40 /* extended sync pattern */ | ||
411 | #define XCR 0x44 /* extended control */ | ||
412 | |||
413 | #define RXIDLE BIT14 | ||
414 | #define RXBREAK BIT14 | ||
415 | #define IRQ_TXDATA BIT13 | ||
416 | #define IRQ_TXIDLE BIT12 | ||
417 | #define IRQ_TXUNDER BIT11 /* HDLC */ | ||
418 | #define IRQ_RXDATA BIT10 | ||
419 | #define IRQ_RXIDLE BIT9 /* HDLC */ | ||
420 | #define IRQ_RXBREAK BIT9 /* async */ | ||
421 | #define IRQ_RXOVER BIT8 | ||
422 | #define IRQ_DSR BIT7 | ||
423 | #define IRQ_CTS BIT6 | ||
424 | #define IRQ_DCD BIT5 | ||
425 | #define IRQ_RI BIT4 | ||
426 | #define IRQ_ALL 0x3ff0 | ||
427 | #define IRQ_MASTER BIT0 | ||
428 | |||
429 | #define slgt_irq_on(info, mask) \ | ||
430 | wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) | (mask))) | ||
431 | #define slgt_irq_off(info, mask) \ | ||
432 | wr_reg16((info), SCR, (unsigned short)(rd_reg16((info), SCR) & ~(mask))) | ||
433 | |||
434 | static __u8 rd_reg8(struct slgt_info *info, unsigned int addr); | ||
435 | static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value); | ||
436 | static __u16 rd_reg16(struct slgt_info *info, unsigned int addr); | ||
437 | static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value); | ||
438 | static __u32 rd_reg32(struct slgt_info *info, unsigned int addr); | ||
439 | static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value); | ||
440 | |||
441 | static void msc_set_vcr(struct slgt_info *info); | ||
442 | |||
443 | static int startup(struct slgt_info *info); | ||
444 | static int block_til_ready(struct tty_struct *tty, struct file * filp,struct slgt_info *info); | ||
445 | static void shutdown(struct slgt_info *info); | ||
446 | static void program_hw(struct slgt_info *info); | ||
447 | static void change_params(struct slgt_info *info); | ||
448 | |||
449 | static int register_test(struct slgt_info *info); | ||
450 | static int irq_test(struct slgt_info *info); | ||
451 | static int loopback_test(struct slgt_info *info); | ||
452 | static int adapter_test(struct slgt_info *info); | ||
453 | |||
454 | static void reset_adapter(struct slgt_info *info); | ||
455 | static void reset_port(struct slgt_info *info); | ||
456 | static void async_mode(struct slgt_info *info); | ||
457 | static void sync_mode(struct slgt_info *info); | ||
458 | |||
459 | static void rx_stop(struct slgt_info *info); | ||
460 | static void rx_start(struct slgt_info *info); | ||
461 | static void reset_rbufs(struct slgt_info *info); | ||
462 | static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last); | ||
463 | static void rdma_reset(struct slgt_info *info); | ||
464 | static bool rx_get_frame(struct slgt_info *info); | ||
465 | static bool rx_get_buf(struct slgt_info *info); | ||
466 | |||
467 | static void tx_start(struct slgt_info *info); | ||
468 | static void tx_stop(struct slgt_info *info); | ||
469 | static void tx_set_idle(struct slgt_info *info); | ||
470 | static unsigned int free_tbuf_count(struct slgt_info *info); | ||
471 | static unsigned int tbuf_bytes(struct slgt_info *info); | ||
472 | static void reset_tbufs(struct slgt_info *info); | ||
473 | static void tdma_reset(struct slgt_info *info); | ||
474 | static bool tx_load(struct slgt_info *info, const char *buf, unsigned int count); | ||
475 | |||
476 | static void get_signals(struct slgt_info *info); | ||
477 | static void set_signals(struct slgt_info *info); | ||
478 | static void enable_loopback(struct slgt_info *info); | ||
479 | static void set_rate(struct slgt_info *info, u32 data_rate); | ||
480 | |||
481 | static int bh_action(struct slgt_info *info); | ||
482 | static void bh_handler(struct work_struct *work); | ||
483 | static void bh_transmit(struct slgt_info *info); | ||
484 | static void isr_serial(struct slgt_info *info); | ||
485 | static void isr_rdma(struct slgt_info *info); | ||
486 | static void isr_txeom(struct slgt_info *info, unsigned short status); | ||
487 | static void isr_tdma(struct slgt_info *info); | ||
488 | |||
489 | static int alloc_dma_bufs(struct slgt_info *info); | ||
490 | static void free_dma_bufs(struct slgt_info *info); | ||
491 | static int alloc_desc(struct slgt_info *info); | ||
492 | static void free_desc(struct slgt_info *info); | ||
493 | static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); | ||
494 | static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count); | ||
495 | |||
496 | static int alloc_tmp_rbuf(struct slgt_info *info); | ||
497 | static void free_tmp_rbuf(struct slgt_info *info); | ||
498 | |||
499 | static void tx_timeout(unsigned long context); | ||
500 | static void rx_timeout(unsigned long context); | ||
501 | |||
502 | /* | ||
503 | * ioctl handlers | ||
504 | */ | ||
505 | static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount); | ||
506 | static int get_params(struct slgt_info *info, MGSL_PARAMS __user *params); | ||
507 | static int set_params(struct slgt_info *info, MGSL_PARAMS __user *params); | ||
508 | static int get_txidle(struct slgt_info *info, int __user *idle_mode); | ||
509 | static int set_txidle(struct slgt_info *info, int idle_mode); | ||
510 | static int tx_enable(struct slgt_info *info, int enable); | ||
511 | static int tx_abort(struct slgt_info *info); | ||
512 | static int rx_enable(struct slgt_info *info, int enable); | ||
513 | static int modem_input_wait(struct slgt_info *info,int arg); | ||
514 | static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr); | ||
515 | static int tiocmget(struct tty_struct *tty); | ||
516 | static int tiocmset(struct tty_struct *tty, | ||
517 | unsigned int set, unsigned int clear); | ||
518 | static int set_break(struct tty_struct *tty, int break_state); | ||
519 | static int get_interface(struct slgt_info *info, int __user *if_mode); | ||
520 | static int set_interface(struct slgt_info *info, int if_mode); | ||
521 | static int set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
522 | static int get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
523 | static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio); | ||
524 | static int get_xsync(struct slgt_info *info, int __user *if_mode); | ||
525 | static int set_xsync(struct slgt_info *info, int if_mode); | ||
526 | static int get_xctrl(struct slgt_info *info, int __user *if_mode); | ||
527 | static int set_xctrl(struct slgt_info *info, int if_mode); | ||
528 | |||
529 | /* | ||
530 | * driver functions | ||
531 | */ | ||
532 | static void add_device(struct slgt_info *info); | ||
533 | static void device_init(int adapter_num, struct pci_dev *pdev); | ||
534 | static int claim_resources(struct slgt_info *info); | ||
535 | static void release_resources(struct slgt_info *info); | ||
536 | |||
537 | /* | ||
538 | * DEBUG OUTPUT CODE | ||
539 | */ | ||
540 | #ifndef DBGINFO | ||
541 | #define DBGINFO(fmt) | ||
542 | #endif | ||
543 | #ifndef DBGERR | ||
544 | #define DBGERR(fmt) | ||
545 | #endif | ||
546 | #ifndef DBGBH | ||
547 | #define DBGBH(fmt) | ||
548 | #endif | ||
549 | #ifndef DBGISR | ||
550 | #define DBGISR(fmt) | ||
551 | #endif | ||
552 | |||
553 | #ifdef DBGDATA | ||
554 | static void trace_block(struct slgt_info *info, const char *data, int count, const char *label) | ||
555 | { | ||
556 | int i; | ||
557 | int linecount; | ||
558 | printk("%s %s data:\n",info->device_name, label); | ||
559 | while(count) { | ||
560 | linecount = (count > 16) ? 16 : count; | ||
561 | for(i=0; i < linecount; i++) | ||
562 | printk("%02X ",(unsigned char)data[i]); | ||
563 | for(;i<17;i++) | ||
564 | printk(" "); | ||
565 | for(i=0;i<linecount;i++) { | ||
566 | if (data[i]>=040 && data[i]<=0176) | ||
567 | printk("%c",data[i]); | ||
568 | else | ||
569 | printk("."); | ||
570 | } | ||
571 | printk("\n"); | ||
572 | data += linecount; | ||
573 | count -= linecount; | ||
574 | } | ||
575 | } | ||
576 | #else | ||
577 | #define DBGDATA(info, buf, size, label) | ||
578 | #endif | ||
579 | |||
580 | #ifdef DBGTBUF | ||
581 | static void dump_tbufs(struct slgt_info *info) | ||
582 | { | ||
583 | int i; | ||
584 | printk("tbuf_current=%d\n", info->tbuf_current); | ||
585 | for (i=0 ; i < info->tbuf_count ; i++) { | ||
586 | printk("%d: count=%04X status=%04X\n", | ||
587 | i, le16_to_cpu(info->tbufs[i].count), le16_to_cpu(info->tbufs[i].status)); | ||
588 | } | ||
589 | } | ||
590 | #else | ||
591 | #define DBGTBUF(info) | ||
592 | #endif | ||
593 | |||
594 | #ifdef DBGRBUF | ||
595 | static void dump_rbufs(struct slgt_info *info) | ||
596 | { | ||
597 | int i; | ||
598 | printk("rbuf_current=%d\n", info->rbuf_current); | ||
599 | for (i=0 ; i < info->rbuf_count ; i++) { | ||
600 | printk("%d: count=%04X status=%04X\n", | ||
601 | i, le16_to_cpu(info->rbufs[i].count), le16_to_cpu(info->rbufs[i].status)); | ||
602 | } | ||
603 | } | ||
604 | #else | ||
605 | #define DBGRBUF(info) | ||
606 | #endif | ||
607 | |||
608 | static inline int sanity_check(struct slgt_info *info, char *devname, const char *name) | ||
609 | { | ||
610 | #ifdef SANITY_CHECK | ||
611 | if (!info) { | ||
612 | printk("null struct slgt_info for (%s) in %s\n", devname, name); | ||
613 | return 1; | ||
614 | } | ||
615 | if (info->magic != MGSL_MAGIC) { | ||
616 | printk("bad magic number struct slgt_info (%s) in %s\n", devname, name); | ||
617 | return 1; | ||
618 | } | ||
619 | #else | ||
620 | if (!info) | ||
621 | return 1; | ||
622 | #endif | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * line discipline callback wrappers | ||
628 | * | ||
629 | * The wrappers maintain line discipline references | ||
630 | * while calling into the line discipline. | ||
631 | * | ||
632 | * ldisc_receive_buf - pass receive data to line discipline | ||
633 | */ | ||
634 | static void ldisc_receive_buf(struct tty_struct *tty, | ||
635 | const __u8 *data, char *flags, int count) | ||
636 | { | ||
637 | struct tty_ldisc *ld; | ||
638 | if (!tty) | ||
639 | return; | ||
640 | ld = tty_ldisc_ref(tty); | ||
641 | if (ld) { | ||
642 | if (ld->ops->receive_buf) | ||
643 | ld->ops->receive_buf(tty, data, flags, count); | ||
644 | tty_ldisc_deref(ld); | ||
645 | } | ||
646 | } | ||
647 | |||
648 | /* tty callbacks */ | ||
649 | |||
650 | static int open(struct tty_struct *tty, struct file *filp) | ||
651 | { | ||
652 | struct slgt_info *info; | ||
653 | int retval, line; | ||
654 | unsigned long flags; | ||
655 | |||
656 | line = tty->index; | ||
657 | if ((line < 0) || (line >= slgt_device_count)) { | ||
658 | DBGERR(("%s: open with invalid line #%d.\n", driver_name, line)); | ||
659 | return -ENODEV; | ||
660 | } | ||
661 | |||
662 | info = slgt_device_list; | ||
663 | while(info && info->line != line) | ||
664 | info = info->next_device; | ||
665 | if (sanity_check(info, tty->name, "open")) | ||
666 | return -ENODEV; | ||
667 | if (info->init_error) { | ||
668 | DBGERR(("%s init error=%d\n", info->device_name, info->init_error)); | ||
669 | return -ENODEV; | ||
670 | } | ||
671 | |||
672 | tty->driver_data = info; | ||
673 | info->port.tty = tty; | ||
674 | |||
675 | DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); | ||
676 | |||
677 | /* If port is closing, signal caller to try again */ | ||
678 | if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ | ||
679 | if (info->port.flags & ASYNC_CLOSING) | ||
680 | interruptible_sleep_on(&info->port.close_wait); | ||
681 | retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? | ||
682 | -EAGAIN : -ERESTARTSYS); | ||
683 | goto cleanup; | ||
684 | } | ||
685 | |||
686 | mutex_lock(&info->port.mutex); | ||
687 | info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
688 | |||
689 | spin_lock_irqsave(&info->netlock, flags); | ||
690 | if (info->netcount) { | ||
691 | retval = -EBUSY; | ||
692 | spin_unlock_irqrestore(&info->netlock, flags); | ||
693 | mutex_unlock(&info->port.mutex); | ||
694 | goto cleanup; | ||
695 | } | ||
696 | info->port.count++; | ||
697 | spin_unlock_irqrestore(&info->netlock, flags); | ||
698 | |||
699 | if (info->port.count == 1) { | ||
700 | /* 1st open on this device, init hardware */ | ||
701 | retval = startup(info); | ||
702 | if (retval < 0) { | ||
703 | mutex_unlock(&info->port.mutex); | ||
704 | goto cleanup; | ||
705 | } | ||
706 | } | ||
707 | mutex_unlock(&info->port.mutex); | ||
708 | retval = block_til_ready(tty, filp, info); | ||
709 | if (retval) { | ||
710 | DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval)); | ||
711 | goto cleanup; | ||
712 | } | ||
713 | |||
714 | retval = 0; | ||
715 | |||
716 | cleanup: | ||
717 | if (retval) { | ||
718 | if (tty->count == 1) | ||
719 | info->port.tty = NULL; /* tty layer will release tty struct */ | ||
720 | if(info->port.count) | ||
721 | info->port.count--; | ||
722 | } | ||
723 | |||
724 | DBGINFO(("%s open rc=%d\n", info->device_name, retval)); | ||
725 | return retval; | ||
726 | } | ||
727 | |||
728 | static void close(struct tty_struct *tty, struct file *filp) | ||
729 | { | ||
730 | struct slgt_info *info = tty->driver_data; | ||
731 | |||
732 | if (sanity_check(info, tty->name, "close")) | ||
733 | return; | ||
734 | DBGINFO(("%s close entry, count=%d\n", info->device_name, info->port.count)); | ||
735 | |||
736 | if (tty_port_close_start(&info->port, tty, filp) == 0) | ||
737 | goto cleanup; | ||
738 | |||
739 | mutex_lock(&info->port.mutex); | ||
740 | if (info->port.flags & ASYNC_INITIALIZED) | ||
741 | wait_until_sent(tty, info->timeout); | ||
742 | flush_buffer(tty); | ||
743 | tty_ldisc_flush(tty); | ||
744 | |||
745 | shutdown(info); | ||
746 | mutex_unlock(&info->port.mutex); | ||
747 | |||
748 | tty_port_close_end(&info->port, tty); | ||
749 | info->port.tty = NULL; | ||
750 | cleanup: | ||
751 | DBGINFO(("%s close exit, count=%d\n", tty->driver->name, info->port.count)); | ||
752 | } | ||
753 | |||
754 | static void hangup(struct tty_struct *tty) | ||
755 | { | ||
756 | struct slgt_info *info = tty->driver_data; | ||
757 | unsigned long flags; | ||
758 | |||
759 | if (sanity_check(info, tty->name, "hangup")) | ||
760 | return; | ||
761 | DBGINFO(("%s hangup\n", info->device_name)); | ||
762 | |||
763 | flush_buffer(tty); | ||
764 | |||
765 | mutex_lock(&info->port.mutex); | ||
766 | shutdown(info); | ||
767 | |||
768 | spin_lock_irqsave(&info->port.lock, flags); | ||
769 | info->port.count = 0; | ||
770 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | ||
771 | info->port.tty = NULL; | ||
772 | spin_unlock_irqrestore(&info->port.lock, flags); | ||
773 | mutex_unlock(&info->port.mutex); | ||
774 | |||
775 | wake_up_interruptible(&info->port.open_wait); | ||
776 | } | ||
777 | |||
778 | static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
779 | { | ||
780 | struct slgt_info *info = tty->driver_data; | ||
781 | unsigned long flags; | ||
782 | |||
783 | DBGINFO(("%s set_termios\n", tty->driver->name)); | ||
784 | |||
785 | change_params(info); | ||
786 | |||
787 | /* Handle transition to B0 status */ | ||
788 | if (old_termios->c_cflag & CBAUD && | ||
789 | !(tty->termios->c_cflag & CBAUD)) { | ||
790 | info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
791 | spin_lock_irqsave(&info->lock,flags); | ||
792 | set_signals(info); | ||
793 | spin_unlock_irqrestore(&info->lock,flags); | ||
794 | } | ||
795 | |||
796 | /* Handle transition away from B0 status */ | ||
797 | if (!(old_termios->c_cflag & CBAUD) && | ||
798 | tty->termios->c_cflag & CBAUD) { | ||
799 | info->signals |= SerialSignal_DTR; | ||
800 | if (!(tty->termios->c_cflag & CRTSCTS) || | ||
801 | !test_bit(TTY_THROTTLED, &tty->flags)) { | ||
802 | info->signals |= SerialSignal_RTS; | ||
803 | } | ||
804 | spin_lock_irqsave(&info->lock,flags); | ||
805 | set_signals(info); | ||
806 | spin_unlock_irqrestore(&info->lock,flags); | ||
807 | } | ||
808 | |||
809 | /* Handle turning off CRTSCTS */ | ||
810 | if (old_termios->c_cflag & CRTSCTS && | ||
811 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
812 | tty->hw_stopped = 0; | ||
813 | tx_release(tty); | ||
814 | } | ||
815 | } | ||
816 | |||
817 | static void update_tx_timer(struct slgt_info *info) | ||
818 | { | ||
819 | /* | ||
820 | * use worst case speed of 1200bps to calculate transmit timeout | ||
821 | * based on data in buffers (tbuf_bytes) and FIFO (128 bytes) | ||
822 | */ | ||
823 | if (info->params.mode == MGSL_MODE_HDLC) { | ||
824 | int timeout = (tbuf_bytes(info) * 7) + 1000; | ||
825 | mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout)); | ||
826 | } | ||
827 | } | ||
828 | |||
829 | static int write(struct tty_struct *tty, | ||
830 | const unsigned char *buf, int count) | ||
831 | { | ||
832 | int ret = 0; | ||
833 | struct slgt_info *info = tty->driver_data; | ||
834 | unsigned long flags; | ||
835 | |||
836 | if (sanity_check(info, tty->name, "write")) | ||
837 | return -EIO; | ||
838 | |||
839 | DBGINFO(("%s write count=%d\n", info->device_name, count)); | ||
840 | |||
841 | if (!info->tx_buf || (count > info->max_frame_size)) | ||
842 | return -EIO; | ||
843 | |||
844 | if (!count || tty->stopped || tty->hw_stopped) | ||
845 | return 0; | ||
846 | |||
847 | spin_lock_irqsave(&info->lock, flags); | ||
848 | |||
849 | if (info->tx_count) { | ||
850 | /* send accumulated data from send_char() */ | ||
851 | if (!tx_load(info, info->tx_buf, info->tx_count)) | ||
852 | goto cleanup; | ||
853 | info->tx_count = 0; | ||
854 | } | ||
855 | |||
856 | if (tx_load(info, buf, count)) | ||
857 | ret = count; | ||
858 | |||
859 | cleanup: | ||
860 | spin_unlock_irqrestore(&info->lock, flags); | ||
861 | DBGINFO(("%s write rc=%d\n", info->device_name, ret)); | ||
862 | return ret; | ||
863 | } | ||
864 | |||
865 | static int put_char(struct tty_struct *tty, unsigned char ch) | ||
866 | { | ||
867 | struct slgt_info *info = tty->driver_data; | ||
868 | unsigned long flags; | ||
869 | int ret = 0; | ||
870 | |||
871 | if (sanity_check(info, tty->name, "put_char")) | ||
872 | return 0; | ||
873 | DBGINFO(("%s put_char(%d)\n", info->device_name, ch)); | ||
874 | if (!info->tx_buf) | ||
875 | return 0; | ||
876 | spin_lock_irqsave(&info->lock,flags); | ||
877 | if (info->tx_count < info->max_frame_size) { | ||
878 | info->tx_buf[info->tx_count++] = ch; | ||
879 | ret = 1; | ||
880 | } | ||
881 | spin_unlock_irqrestore(&info->lock,flags); | ||
882 | return ret; | ||
883 | } | ||
884 | |||
885 | static void send_xchar(struct tty_struct *tty, char ch) | ||
886 | { | ||
887 | struct slgt_info *info = tty->driver_data; | ||
888 | unsigned long flags; | ||
889 | |||
890 | if (sanity_check(info, tty->name, "send_xchar")) | ||
891 | return; | ||
892 | DBGINFO(("%s send_xchar(%d)\n", info->device_name, ch)); | ||
893 | info->x_char = ch; | ||
894 | if (ch) { | ||
895 | spin_lock_irqsave(&info->lock,flags); | ||
896 | if (!info->tx_enabled) | ||
897 | tx_start(info); | ||
898 | spin_unlock_irqrestore(&info->lock,flags); | ||
899 | } | ||
900 | } | ||
901 | |||
902 | static void wait_until_sent(struct tty_struct *tty, int timeout) | ||
903 | { | ||
904 | struct slgt_info *info = tty->driver_data; | ||
905 | unsigned long orig_jiffies, char_time; | ||
906 | |||
907 | if (!info ) | ||
908 | return; | ||
909 | if (sanity_check(info, tty->name, "wait_until_sent")) | ||
910 | return; | ||
911 | DBGINFO(("%s wait_until_sent entry\n", info->device_name)); | ||
912 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
913 | goto exit; | ||
914 | |||
915 | orig_jiffies = jiffies; | ||
916 | |||
917 | /* Set check interval to 1/5 of estimated time to | ||
918 | * send a character, and make it at least 1. The check | ||
919 | * interval should also be less than the timeout. | ||
920 | * Note: use tight timings here to satisfy the NIST-PCTS. | ||
921 | */ | ||
922 | |||
923 | if (info->params.data_rate) { | ||
924 | char_time = info->timeout/(32 * 5); | ||
925 | if (!char_time) | ||
926 | char_time++; | ||
927 | } else | ||
928 | char_time = 1; | ||
929 | |||
930 | if (timeout) | ||
931 | char_time = min_t(unsigned long, char_time, timeout); | ||
932 | |||
933 | while (info->tx_active) { | ||
934 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
935 | if (signal_pending(current)) | ||
936 | break; | ||
937 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
938 | break; | ||
939 | } | ||
940 | exit: | ||
941 | DBGINFO(("%s wait_until_sent exit\n", info->device_name)); | ||
942 | } | ||
943 | |||
944 | static int write_room(struct tty_struct *tty) | ||
945 | { | ||
946 | struct slgt_info *info = tty->driver_data; | ||
947 | int ret; | ||
948 | |||
949 | if (sanity_check(info, tty->name, "write_room")) | ||
950 | return 0; | ||
951 | ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; | ||
952 | DBGINFO(("%s write_room=%d\n", info->device_name, ret)); | ||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void flush_chars(struct tty_struct *tty) | ||
957 | { | ||
958 | struct slgt_info *info = tty->driver_data; | ||
959 | unsigned long flags; | ||
960 | |||
961 | if (sanity_check(info, tty->name, "flush_chars")) | ||
962 | return; | ||
963 | DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); | ||
964 | |||
965 | if (info->tx_count <= 0 || tty->stopped || | ||
966 | tty->hw_stopped || !info->tx_buf) | ||
967 | return; | ||
968 | |||
969 | DBGINFO(("%s flush_chars start transmit\n", info->device_name)); | ||
970 | |||
971 | spin_lock_irqsave(&info->lock,flags); | ||
972 | if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count)) | ||
973 | info->tx_count = 0; | ||
974 | spin_unlock_irqrestore(&info->lock,flags); | ||
975 | } | ||
976 | |||
977 | static void flush_buffer(struct tty_struct *tty) | ||
978 | { | ||
979 | struct slgt_info *info = tty->driver_data; | ||
980 | unsigned long flags; | ||
981 | |||
982 | if (sanity_check(info, tty->name, "flush_buffer")) | ||
983 | return; | ||
984 | DBGINFO(("%s flush_buffer\n", info->device_name)); | ||
985 | |||
986 | spin_lock_irqsave(&info->lock, flags); | ||
987 | info->tx_count = 0; | ||
988 | spin_unlock_irqrestore(&info->lock, flags); | ||
989 | |||
990 | tty_wakeup(tty); | ||
991 | } | ||
992 | |||
993 | /* | ||
994 | * throttle (stop) transmitter | ||
995 | */ | ||
996 | static void tx_hold(struct tty_struct *tty) | ||
997 | { | ||
998 | struct slgt_info *info = tty->driver_data; | ||
999 | unsigned long flags; | ||
1000 | |||
1001 | if (sanity_check(info, tty->name, "tx_hold")) | ||
1002 | return; | ||
1003 | DBGINFO(("%s tx_hold\n", info->device_name)); | ||
1004 | spin_lock_irqsave(&info->lock,flags); | ||
1005 | if (info->tx_enabled && info->params.mode == MGSL_MODE_ASYNC) | ||
1006 | tx_stop(info); | ||
1007 | spin_unlock_irqrestore(&info->lock,flags); | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * release (start) transmitter | ||
1012 | */ | ||
1013 | static void tx_release(struct tty_struct *tty) | ||
1014 | { | ||
1015 | struct slgt_info *info = tty->driver_data; | ||
1016 | unsigned long flags; | ||
1017 | |||
1018 | if (sanity_check(info, tty->name, "tx_release")) | ||
1019 | return; | ||
1020 | DBGINFO(("%s tx_release\n", info->device_name)); | ||
1021 | spin_lock_irqsave(&info->lock, flags); | ||
1022 | if (info->tx_count && tx_load(info, info->tx_buf, info->tx_count)) | ||
1023 | info->tx_count = 0; | ||
1024 | spin_unlock_irqrestore(&info->lock, flags); | ||
1025 | } | ||
1026 | |||
1027 | /* | ||
1028 | * Service an IOCTL request | ||
1029 | * | ||
1030 | * Arguments | ||
1031 | * | ||
1032 | * tty pointer to tty instance data | ||
1033 | * cmd IOCTL command code | ||
1034 | * arg command argument/context | ||
1035 | * | ||
1036 | * Return 0 if success, otherwise error code | ||
1037 | */ | ||
1038 | static int ioctl(struct tty_struct *tty, | ||
1039 | unsigned int cmd, unsigned long arg) | ||
1040 | { | ||
1041 | struct slgt_info *info = tty->driver_data; | ||
1042 | void __user *argp = (void __user *)arg; | ||
1043 | int ret; | ||
1044 | |||
1045 | if (sanity_check(info, tty->name, "ioctl")) | ||
1046 | return -ENODEV; | ||
1047 | DBGINFO(("%s ioctl() cmd=%08X\n", info->device_name, cmd)); | ||
1048 | |||
1049 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||
1050 | (cmd != TIOCMIWAIT)) { | ||
1051 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1052 | return -EIO; | ||
1053 | } | ||
1054 | |||
1055 | switch (cmd) { | ||
1056 | case MGSL_IOCWAITEVENT: | ||
1057 | return wait_mgsl_event(info, argp); | ||
1058 | case TIOCMIWAIT: | ||
1059 | return modem_input_wait(info,(int)arg); | ||
1060 | case MGSL_IOCSGPIO: | ||
1061 | return set_gpio(info, argp); | ||
1062 | case MGSL_IOCGGPIO: | ||
1063 | return get_gpio(info, argp); | ||
1064 | case MGSL_IOCWAITGPIO: | ||
1065 | return wait_gpio(info, argp); | ||
1066 | case MGSL_IOCGXSYNC: | ||
1067 | return get_xsync(info, argp); | ||
1068 | case MGSL_IOCSXSYNC: | ||
1069 | return set_xsync(info, (int)arg); | ||
1070 | case MGSL_IOCGXCTRL: | ||
1071 | return get_xctrl(info, argp); | ||
1072 | case MGSL_IOCSXCTRL: | ||
1073 | return set_xctrl(info, (int)arg); | ||
1074 | } | ||
1075 | mutex_lock(&info->port.mutex); | ||
1076 | switch (cmd) { | ||
1077 | case MGSL_IOCGPARAMS: | ||
1078 | ret = get_params(info, argp); | ||
1079 | break; | ||
1080 | case MGSL_IOCSPARAMS: | ||
1081 | ret = set_params(info, argp); | ||
1082 | break; | ||
1083 | case MGSL_IOCGTXIDLE: | ||
1084 | ret = get_txidle(info, argp); | ||
1085 | break; | ||
1086 | case MGSL_IOCSTXIDLE: | ||
1087 | ret = set_txidle(info, (int)arg); | ||
1088 | break; | ||
1089 | case MGSL_IOCTXENABLE: | ||
1090 | ret = tx_enable(info, (int)arg); | ||
1091 | break; | ||
1092 | case MGSL_IOCRXENABLE: | ||
1093 | ret = rx_enable(info, (int)arg); | ||
1094 | break; | ||
1095 | case MGSL_IOCTXABORT: | ||
1096 | ret = tx_abort(info); | ||
1097 | break; | ||
1098 | case MGSL_IOCGSTATS: | ||
1099 | ret = get_stats(info, argp); | ||
1100 | break; | ||
1101 | case MGSL_IOCGIF: | ||
1102 | ret = get_interface(info, argp); | ||
1103 | break; | ||
1104 | case MGSL_IOCSIF: | ||
1105 | ret = set_interface(info,(int)arg); | ||
1106 | break; | ||
1107 | default: | ||
1108 | ret = -ENOIOCTLCMD; | ||
1109 | } | ||
1110 | mutex_unlock(&info->port.mutex); | ||
1111 | return ret; | ||
1112 | } | ||
1113 | |||
1114 | static int get_icount(struct tty_struct *tty, | ||
1115 | struct serial_icounter_struct *icount) | ||
1116 | |||
1117 | { | ||
1118 | struct slgt_info *info = tty->driver_data; | ||
1119 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1120 | unsigned long flags; | ||
1121 | |||
1122 | spin_lock_irqsave(&info->lock,flags); | ||
1123 | cnow = info->icount; | ||
1124 | spin_unlock_irqrestore(&info->lock,flags); | ||
1125 | |||
1126 | icount->cts = cnow.cts; | ||
1127 | icount->dsr = cnow.dsr; | ||
1128 | icount->rng = cnow.rng; | ||
1129 | icount->dcd = cnow.dcd; | ||
1130 | icount->rx = cnow.rx; | ||
1131 | icount->tx = cnow.tx; | ||
1132 | icount->frame = cnow.frame; | ||
1133 | icount->overrun = cnow.overrun; | ||
1134 | icount->parity = cnow.parity; | ||
1135 | icount->brk = cnow.brk; | ||
1136 | icount->buf_overrun = cnow.buf_overrun; | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | /* | ||
1142 | * support for 32 bit ioctl calls on 64 bit systems | ||
1143 | */ | ||
1144 | #ifdef CONFIG_COMPAT | ||
1145 | static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params) | ||
1146 | { | ||
1147 | struct MGSL_PARAMS32 tmp_params; | ||
1148 | |||
1149 | DBGINFO(("%s get_params32\n", info->device_name)); | ||
1150 | memset(&tmp_params, 0, sizeof(tmp_params)); | ||
1151 | tmp_params.mode = (compat_ulong_t)info->params.mode; | ||
1152 | tmp_params.loopback = info->params.loopback; | ||
1153 | tmp_params.flags = info->params.flags; | ||
1154 | tmp_params.encoding = info->params.encoding; | ||
1155 | tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed; | ||
1156 | tmp_params.addr_filter = info->params.addr_filter; | ||
1157 | tmp_params.crc_type = info->params.crc_type; | ||
1158 | tmp_params.preamble_length = info->params.preamble_length; | ||
1159 | tmp_params.preamble = info->params.preamble; | ||
1160 | tmp_params.data_rate = (compat_ulong_t)info->params.data_rate; | ||
1161 | tmp_params.data_bits = info->params.data_bits; | ||
1162 | tmp_params.stop_bits = info->params.stop_bits; | ||
1163 | tmp_params.parity = info->params.parity; | ||
1164 | if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32))) | ||
1165 | return -EFAULT; | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params) | ||
1170 | { | ||
1171 | struct MGSL_PARAMS32 tmp_params; | ||
1172 | |||
1173 | DBGINFO(("%s set_params32\n", info->device_name)); | ||
1174 | if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32))) | ||
1175 | return -EFAULT; | ||
1176 | |||
1177 | spin_lock(&info->lock); | ||
1178 | if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) { | ||
1179 | info->base_clock = tmp_params.clock_speed; | ||
1180 | } else { | ||
1181 | info->params.mode = tmp_params.mode; | ||
1182 | info->params.loopback = tmp_params.loopback; | ||
1183 | info->params.flags = tmp_params.flags; | ||
1184 | info->params.encoding = tmp_params.encoding; | ||
1185 | info->params.clock_speed = tmp_params.clock_speed; | ||
1186 | info->params.addr_filter = tmp_params.addr_filter; | ||
1187 | info->params.crc_type = tmp_params.crc_type; | ||
1188 | info->params.preamble_length = tmp_params.preamble_length; | ||
1189 | info->params.preamble = tmp_params.preamble; | ||
1190 | info->params.data_rate = tmp_params.data_rate; | ||
1191 | info->params.data_bits = tmp_params.data_bits; | ||
1192 | info->params.stop_bits = tmp_params.stop_bits; | ||
1193 | info->params.parity = tmp_params.parity; | ||
1194 | } | ||
1195 | spin_unlock(&info->lock); | ||
1196 | |||
1197 | program_hw(info); | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static long slgt_compat_ioctl(struct tty_struct *tty, | ||
1203 | unsigned int cmd, unsigned long arg) | ||
1204 | { | ||
1205 | struct slgt_info *info = tty->driver_data; | ||
1206 | int rc = -ENOIOCTLCMD; | ||
1207 | |||
1208 | if (sanity_check(info, tty->name, "compat_ioctl")) | ||
1209 | return -ENODEV; | ||
1210 | DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); | ||
1211 | |||
1212 | switch (cmd) { | ||
1213 | |||
1214 | case MGSL_IOCSPARAMS32: | ||
1215 | rc = set_params32(info, compat_ptr(arg)); | ||
1216 | break; | ||
1217 | |||
1218 | case MGSL_IOCGPARAMS32: | ||
1219 | rc = get_params32(info, compat_ptr(arg)); | ||
1220 | break; | ||
1221 | |||
1222 | case MGSL_IOCGPARAMS: | ||
1223 | case MGSL_IOCSPARAMS: | ||
1224 | case MGSL_IOCGTXIDLE: | ||
1225 | case MGSL_IOCGSTATS: | ||
1226 | case MGSL_IOCWAITEVENT: | ||
1227 | case MGSL_IOCGIF: | ||
1228 | case MGSL_IOCSGPIO: | ||
1229 | case MGSL_IOCGGPIO: | ||
1230 | case MGSL_IOCWAITGPIO: | ||
1231 | case MGSL_IOCGXSYNC: | ||
1232 | case MGSL_IOCGXCTRL: | ||
1233 | case MGSL_IOCSTXIDLE: | ||
1234 | case MGSL_IOCTXENABLE: | ||
1235 | case MGSL_IOCRXENABLE: | ||
1236 | case MGSL_IOCTXABORT: | ||
1237 | case TIOCMIWAIT: | ||
1238 | case MGSL_IOCSIF: | ||
1239 | case MGSL_IOCSXSYNC: | ||
1240 | case MGSL_IOCSXCTRL: | ||
1241 | rc = ioctl(tty, cmd, arg); | ||
1242 | break; | ||
1243 | } | ||
1244 | |||
1245 | DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); | ||
1246 | return rc; | ||
1247 | } | ||
1248 | #else | ||
1249 | #define slgt_compat_ioctl NULL | ||
1250 | #endif /* ifdef CONFIG_COMPAT */ | ||
1251 | |||
1252 | /* | ||
1253 | * proc fs support | ||
1254 | */ | ||
1255 | static inline void line_info(struct seq_file *m, struct slgt_info *info) | ||
1256 | { | ||
1257 | char stat_buf[30]; | ||
1258 | unsigned long flags; | ||
1259 | |||
1260 | seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", | ||
1261 | info->device_name, info->phys_reg_addr, | ||
1262 | info->irq_level, info->max_frame_size); | ||
1263 | |||
1264 | /* output current serial signal states */ | ||
1265 | spin_lock_irqsave(&info->lock,flags); | ||
1266 | get_signals(info); | ||
1267 | spin_unlock_irqrestore(&info->lock,flags); | ||
1268 | |||
1269 | stat_buf[0] = 0; | ||
1270 | stat_buf[1] = 0; | ||
1271 | if (info->signals & SerialSignal_RTS) | ||
1272 | strcat(stat_buf, "|RTS"); | ||
1273 | if (info->signals & SerialSignal_CTS) | ||
1274 | strcat(stat_buf, "|CTS"); | ||
1275 | if (info->signals & SerialSignal_DTR) | ||
1276 | strcat(stat_buf, "|DTR"); | ||
1277 | if (info->signals & SerialSignal_DSR) | ||
1278 | strcat(stat_buf, "|DSR"); | ||
1279 | if (info->signals & SerialSignal_DCD) | ||
1280 | strcat(stat_buf, "|CD"); | ||
1281 | if (info->signals & SerialSignal_RI) | ||
1282 | strcat(stat_buf, "|RI"); | ||
1283 | |||
1284 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
1285 | seq_printf(m, "\tHDLC txok:%d rxok:%d", | ||
1286 | info->icount.txok, info->icount.rxok); | ||
1287 | if (info->icount.txunder) | ||
1288 | seq_printf(m, " txunder:%d", info->icount.txunder); | ||
1289 | if (info->icount.txabort) | ||
1290 | seq_printf(m, " txabort:%d", info->icount.txabort); | ||
1291 | if (info->icount.rxshort) | ||
1292 | seq_printf(m, " rxshort:%d", info->icount.rxshort); | ||
1293 | if (info->icount.rxlong) | ||
1294 | seq_printf(m, " rxlong:%d", info->icount.rxlong); | ||
1295 | if (info->icount.rxover) | ||
1296 | seq_printf(m, " rxover:%d", info->icount.rxover); | ||
1297 | if (info->icount.rxcrc) | ||
1298 | seq_printf(m, " rxcrc:%d", info->icount.rxcrc); | ||
1299 | } else { | ||
1300 | seq_printf(m, "\tASYNC tx:%d rx:%d", | ||
1301 | info->icount.tx, info->icount.rx); | ||
1302 | if (info->icount.frame) | ||
1303 | seq_printf(m, " fe:%d", info->icount.frame); | ||
1304 | if (info->icount.parity) | ||
1305 | seq_printf(m, " pe:%d", info->icount.parity); | ||
1306 | if (info->icount.brk) | ||
1307 | seq_printf(m, " brk:%d", info->icount.brk); | ||
1308 | if (info->icount.overrun) | ||
1309 | seq_printf(m, " oe:%d", info->icount.overrun); | ||
1310 | } | ||
1311 | |||
1312 | /* Append serial signal status to end */ | ||
1313 | seq_printf(m, " %s\n", stat_buf+1); | ||
1314 | |||
1315 | seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", | ||
1316 | info->tx_active,info->bh_requested,info->bh_running, | ||
1317 | info->pending_bh); | ||
1318 | } | ||
1319 | |||
1320 | /* Called to print information about devices | ||
1321 | */ | ||
1322 | static int synclink_gt_proc_show(struct seq_file *m, void *v) | ||
1323 | { | ||
1324 | struct slgt_info *info; | ||
1325 | |||
1326 | seq_puts(m, "synclink_gt driver\n"); | ||
1327 | |||
1328 | info = slgt_device_list; | ||
1329 | while( info ) { | ||
1330 | line_info(m, info); | ||
1331 | info = info->next_device; | ||
1332 | } | ||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | static int synclink_gt_proc_open(struct inode *inode, struct file *file) | ||
1337 | { | ||
1338 | return single_open(file, synclink_gt_proc_show, NULL); | ||
1339 | } | ||
1340 | |||
1341 | static const struct file_operations synclink_gt_proc_fops = { | ||
1342 | .owner = THIS_MODULE, | ||
1343 | .open = synclink_gt_proc_open, | ||
1344 | .read = seq_read, | ||
1345 | .llseek = seq_lseek, | ||
1346 | .release = single_release, | ||
1347 | }; | ||
1348 | |||
1349 | /* | ||
1350 | * return count of bytes in transmit buffer | ||
1351 | */ | ||
1352 | static int chars_in_buffer(struct tty_struct *tty) | ||
1353 | { | ||
1354 | struct slgt_info *info = tty->driver_data; | ||
1355 | int count; | ||
1356 | if (sanity_check(info, tty->name, "chars_in_buffer")) | ||
1357 | return 0; | ||
1358 | count = tbuf_bytes(info); | ||
1359 | DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count)); | ||
1360 | return count; | ||
1361 | } | ||
1362 | |||
1363 | /* | ||
1364 | * signal remote device to throttle send data (our receive data) | ||
1365 | */ | ||
1366 | static void throttle(struct tty_struct * tty) | ||
1367 | { | ||
1368 | struct slgt_info *info = tty->driver_data; | ||
1369 | unsigned long flags; | ||
1370 | |||
1371 | if (sanity_check(info, tty->name, "throttle")) | ||
1372 | return; | ||
1373 | DBGINFO(("%s throttle\n", info->device_name)); | ||
1374 | if (I_IXOFF(tty)) | ||
1375 | send_xchar(tty, STOP_CHAR(tty)); | ||
1376 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1377 | spin_lock_irqsave(&info->lock,flags); | ||
1378 | info->signals &= ~SerialSignal_RTS; | ||
1379 | set_signals(info); | ||
1380 | spin_unlock_irqrestore(&info->lock,flags); | ||
1381 | } | ||
1382 | } | ||
1383 | |||
1384 | /* | ||
1385 | * signal remote device to stop throttling send data (our receive data) | ||
1386 | */ | ||
1387 | static void unthrottle(struct tty_struct * tty) | ||
1388 | { | ||
1389 | struct slgt_info *info = tty->driver_data; | ||
1390 | unsigned long flags; | ||
1391 | |||
1392 | if (sanity_check(info, tty->name, "unthrottle")) | ||
1393 | return; | ||
1394 | DBGINFO(("%s unthrottle\n", info->device_name)); | ||
1395 | if (I_IXOFF(tty)) { | ||
1396 | if (info->x_char) | ||
1397 | info->x_char = 0; | ||
1398 | else | ||
1399 | send_xchar(tty, START_CHAR(tty)); | ||
1400 | } | ||
1401 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1402 | spin_lock_irqsave(&info->lock,flags); | ||
1403 | info->signals |= SerialSignal_RTS; | ||
1404 | set_signals(info); | ||
1405 | spin_unlock_irqrestore(&info->lock,flags); | ||
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | /* | ||
1410 | * set or clear transmit break condition | ||
1411 | * break_state -1=set break condition, 0=clear | ||
1412 | */ | ||
1413 | static int set_break(struct tty_struct *tty, int break_state) | ||
1414 | { | ||
1415 | struct slgt_info *info = tty->driver_data; | ||
1416 | unsigned short value; | ||
1417 | unsigned long flags; | ||
1418 | |||
1419 | if (sanity_check(info, tty->name, "set_break")) | ||
1420 | return -EINVAL; | ||
1421 | DBGINFO(("%s set_break(%d)\n", info->device_name, break_state)); | ||
1422 | |||
1423 | spin_lock_irqsave(&info->lock,flags); | ||
1424 | value = rd_reg16(info, TCR); | ||
1425 | if (break_state == -1) | ||
1426 | value |= BIT6; | ||
1427 | else | ||
1428 | value &= ~BIT6; | ||
1429 | wr_reg16(info, TCR, value); | ||
1430 | spin_unlock_irqrestore(&info->lock,flags); | ||
1431 | return 0; | ||
1432 | } | ||
1433 | |||
1434 | #if SYNCLINK_GENERIC_HDLC | ||
1435 | |||
1436 | /** | ||
1437 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | ||
1438 | * set encoding and frame check sequence (FCS) options | ||
1439 | * | ||
1440 | * dev pointer to network device structure | ||
1441 | * encoding serial encoding setting | ||
1442 | * parity FCS setting | ||
1443 | * | ||
1444 | * returns 0 if success, otherwise error code | ||
1445 | */ | ||
1446 | static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, | ||
1447 | unsigned short parity) | ||
1448 | { | ||
1449 | struct slgt_info *info = dev_to_port(dev); | ||
1450 | unsigned char new_encoding; | ||
1451 | unsigned short new_crctype; | ||
1452 | |||
1453 | /* return error if TTY interface open */ | ||
1454 | if (info->port.count) | ||
1455 | return -EBUSY; | ||
1456 | |||
1457 | DBGINFO(("%s hdlcdev_attach\n", info->device_name)); | ||
1458 | |||
1459 | switch (encoding) | ||
1460 | { | ||
1461 | case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; | ||
1462 | case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; | ||
1463 | case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; | ||
1464 | case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; | ||
1465 | case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; | ||
1466 | default: return -EINVAL; | ||
1467 | } | ||
1468 | |||
1469 | switch (parity) | ||
1470 | { | ||
1471 | case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; | ||
1472 | case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; | ||
1473 | case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; | ||
1474 | default: return -EINVAL; | ||
1475 | } | ||
1476 | |||
1477 | info->params.encoding = new_encoding; | ||
1478 | info->params.crc_type = new_crctype; | ||
1479 | |||
1480 | /* if network interface up, reprogram hardware */ | ||
1481 | if (info->netcount) | ||
1482 | program_hw(info); | ||
1483 | |||
1484 | return 0; | ||
1485 | } | ||
1486 | |||
1487 | /** | ||
1488 | * called by generic HDLC layer to send frame | ||
1489 | * | ||
1490 | * skb socket buffer containing HDLC frame | ||
1491 | * dev pointer to network device structure | ||
1492 | */ | ||
1493 | static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, | ||
1494 | struct net_device *dev) | ||
1495 | { | ||
1496 | struct slgt_info *info = dev_to_port(dev); | ||
1497 | unsigned long flags; | ||
1498 | |||
1499 | DBGINFO(("%s hdlc_xmit\n", dev->name)); | ||
1500 | |||
1501 | if (!skb->len) | ||
1502 | return NETDEV_TX_OK; | ||
1503 | |||
1504 | /* stop sending until this frame completes */ | ||
1505 | netif_stop_queue(dev); | ||
1506 | |||
1507 | /* update network statistics */ | ||
1508 | dev->stats.tx_packets++; | ||
1509 | dev->stats.tx_bytes += skb->len; | ||
1510 | |||
1511 | /* save start time for transmit timeout detection */ | ||
1512 | dev->trans_start = jiffies; | ||
1513 | |||
1514 | spin_lock_irqsave(&info->lock, flags); | ||
1515 | tx_load(info, skb->data, skb->len); | ||
1516 | spin_unlock_irqrestore(&info->lock, flags); | ||
1517 | |||
1518 | /* done with socket buffer, so free it */ | ||
1519 | dev_kfree_skb(skb); | ||
1520 | |||
1521 | return NETDEV_TX_OK; | ||
1522 | } | ||
1523 | |||
1524 | /** | ||
1525 | * called by network layer when interface enabled | ||
1526 | * claim resources and initialize hardware | ||
1527 | * | ||
1528 | * dev pointer to network device structure | ||
1529 | * | ||
1530 | * returns 0 if success, otherwise error code | ||
1531 | */ | ||
1532 | static int hdlcdev_open(struct net_device *dev) | ||
1533 | { | ||
1534 | struct slgt_info *info = dev_to_port(dev); | ||
1535 | int rc; | ||
1536 | unsigned long flags; | ||
1537 | |||
1538 | if (!try_module_get(THIS_MODULE)) | ||
1539 | return -EBUSY; | ||
1540 | |||
1541 | DBGINFO(("%s hdlcdev_open\n", dev->name)); | ||
1542 | |||
1543 | /* generic HDLC layer open processing */ | ||
1544 | if ((rc = hdlc_open(dev))) | ||
1545 | return rc; | ||
1546 | |||
1547 | /* arbitrate between network and tty opens */ | ||
1548 | spin_lock_irqsave(&info->netlock, flags); | ||
1549 | if (info->port.count != 0 || info->netcount != 0) { | ||
1550 | DBGINFO(("%s hdlc_open busy\n", dev->name)); | ||
1551 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1552 | return -EBUSY; | ||
1553 | } | ||
1554 | info->netcount=1; | ||
1555 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1556 | |||
1557 | /* claim resources and init adapter */ | ||
1558 | if ((rc = startup(info)) != 0) { | ||
1559 | spin_lock_irqsave(&info->netlock, flags); | ||
1560 | info->netcount=0; | ||
1561 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1562 | return rc; | ||
1563 | } | ||
1564 | |||
1565 | /* assert DTR and RTS, apply hardware settings */ | ||
1566 | info->signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
1567 | program_hw(info); | ||
1568 | |||
1569 | /* enable network layer transmit */ | ||
1570 | dev->trans_start = jiffies; | ||
1571 | netif_start_queue(dev); | ||
1572 | |||
1573 | /* inform generic HDLC layer of current DCD status */ | ||
1574 | spin_lock_irqsave(&info->lock, flags); | ||
1575 | get_signals(info); | ||
1576 | spin_unlock_irqrestore(&info->lock, flags); | ||
1577 | if (info->signals & SerialSignal_DCD) | ||
1578 | netif_carrier_on(dev); | ||
1579 | else | ||
1580 | netif_carrier_off(dev); | ||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | /** | ||
1585 | * called by network layer when interface is disabled | ||
1586 | * shutdown hardware and release resources | ||
1587 | * | ||
1588 | * dev pointer to network device structure | ||
1589 | * | ||
1590 | * returns 0 if success, otherwise error code | ||
1591 | */ | ||
1592 | static int hdlcdev_close(struct net_device *dev) | ||
1593 | { | ||
1594 | struct slgt_info *info = dev_to_port(dev); | ||
1595 | unsigned long flags; | ||
1596 | |||
1597 | DBGINFO(("%s hdlcdev_close\n", dev->name)); | ||
1598 | |||
1599 | netif_stop_queue(dev); | ||
1600 | |||
1601 | /* shutdown adapter and release resources */ | ||
1602 | shutdown(info); | ||
1603 | |||
1604 | hdlc_close(dev); | ||
1605 | |||
1606 | spin_lock_irqsave(&info->netlock, flags); | ||
1607 | info->netcount=0; | ||
1608 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1609 | |||
1610 | module_put(THIS_MODULE); | ||
1611 | return 0; | ||
1612 | } | ||
1613 | |||
1614 | /** | ||
1615 | * called by network layer to process IOCTL call to network device | ||
1616 | * | ||
1617 | * dev pointer to network device structure | ||
1618 | * ifr pointer to network interface request structure | ||
1619 | * cmd IOCTL command code | ||
1620 | * | ||
1621 | * returns 0 if success, otherwise error code | ||
1622 | */ | ||
1623 | static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1624 | { | ||
1625 | const size_t size = sizeof(sync_serial_settings); | ||
1626 | sync_serial_settings new_line; | ||
1627 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | ||
1628 | struct slgt_info *info = dev_to_port(dev); | ||
1629 | unsigned int flags; | ||
1630 | |||
1631 | DBGINFO(("%s hdlcdev_ioctl\n", dev->name)); | ||
1632 | |||
1633 | /* return error if TTY interface open */ | ||
1634 | if (info->port.count) | ||
1635 | return -EBUSY; | ||
1636 | |||
1637 | if (cmd != SIOCWANDEV) | ||
1638 | return hdlc_ioctl(dev, ifr, cmd); | ||
1639 | |||
1640 | memset(&new_line, 0, sizeof(new_line)); | ||
1641 | |||
1642 | switch(ifr->ifr_settings.type) { | ||
1643 | case IF_GET_IFACE: /* return current sync_serial_settings */ | ||
1644 | |||
1645 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; | ||
1646 | if (ifr->ifr_settings.size < size) { | ||
1647 | ifr->ifr_settings.size = size; /* data size wanted */ | ||
1648 | return -ENOBUFS; | ||
1649 | } | ||
1650 | |||
1651 | flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1652 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1653 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1654 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
1655 | |||
1656 | switch (flags){ | ||
1657 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; | ||
1658 | case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; | ||
1659 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; | ||
1660 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; | ||
1661 | default: new_line.clock_type = CLOCK_DEFAULT; | ||
1662 | } | ||
1663 | |||
1664 | new_line.clock_rate = info->params.clock_speed; | ||
1665 | new_line.loopback = info->params.loopback ? 1:0; | ||
1666 | |||
1667 | if (copy_to_user(line, &new_line, size)) | ||
1668 | return -EFAULT; | ||
1669 | return 0; | ||
1670 | |||
1671 | case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ | ||
1672 | |||
1673 | if(!capable(CAP_NET_ADMIN)) | ||
1674 | return -EPERM; | ||
1675 | if (copy_from_user(&new_line, line, size)) | ||
1676 | return -EFAULT; | ||
1677 | |||
1678 | switch (new_line.clock_type) | ||
1679 | { | ||
1680 | case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; | ||
1681 | case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; | ||
1682 | case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; | ||
1683 | case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; | ||
1684 | case CLOCK_DEFAULT: flags = info->params.flags & | ||
1685 | (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1686 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1687 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1688 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; | ||
1689 | default: return -EINVAL; | ||
1690 | } | ||
1691 | |||
1692 | if (new_line.loopback != 0 && new_line.loopback != 1) | ||
1693 | return -EINVAL; | ||
1694 | |||
1695 | info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1696 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1697 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1698 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
1699 | info->params.flags |= flags; | ||
1700 | |||
1701 | info->params.loopback = new_line.loopback; | ||
1702 | |||
1703 | if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) | ||
1704 | info->params.clock_speed = new_line.clock_rate; | ||
1705 | else | ||
1706 | info->params.clock_speed = 0; | ||
1707 | |||
1708 | /* if network interface up, reprogram hardware */ | ||
1709 | if (info->netcount) | ||
1710 | program_hw(info); | ||
1711 | return 0; | ||
1712 | |||
1713 | default: | ||
1714 | return hdlc_ioctl(dev, ifr, cmd); | ||
1715 | } | ||
1716 | } | ||
1717 | |||
1718 | /** | ||
1719 | * called by network layer when transmit timeout is detected | ||
1720 | * | ||
1721 | * dev pointer to network device structure | ||
1722 | */ | ||
1723 | static void hdlcdev_tx_timeout(struct net_device *dev) | ||
1724 | { | ||
1725 | struct slgt_info *info = dev_to_port(dev); | ||
1726 | unsigned long flags; | ||
1727 | |||
1728 | DBGINFO(("%s hdlcdev_tx_timeout\n", dev->name)); | ||
1729 | |||
1730 | dev->stats.tx_errors++; | ||
1731 | dev->stats.tx_aborted_errors++; | ||
1732 | |||
1733 | spin_lock_irqsave(&info->lock,flags); | ||
1734 | tx_stop(info); | ||
1735 | spin_unlock_irqrestore(&info->lock,flags); | ||
1736 | |||
1737 | netif_wake_queue(dev); | ||
1738 | } | ||
1739 | |||
1740 | /** | ||
1741 | * called by device driver when transmit completes | ||
1742 | * reenable network layer transmit if stopped | ||
1743 | * | ||
1744 | * info pointer to device instance information | ||
1745 | */ | ||
1746 | static void hdlcdev_tx_done(struct slgt_info *info) | ||
1747 | { | ||
1748 | if (netif_queue_stopped(info->netdev)) | ||
1749 | netif_wake_queue(info->netdev); | ||
1750 | } | ||
1751 | |||
1752 | /** | ||
1753 | * called by device driver when frame received | ||
1754 | * pass frame to network layer | ||
1755 | * | ||
1756 | * info pointer to device instance information | ||
1757 | * buf pointer to buffer contianing frame data | ||
1758 | * size count of data bytes in buf | ||
1759 | */ | ||
1760 | static void hdlcdev_rx(struct slgt_info *info, char *buf, int size) | ||
1761 | { | ||
1762 | struct sk_buff *skb = dev_alloc_skb(size); | ||
1763 | struct net_device *dev = info->netdev; | ||
1764 | |||
1765 | DBGINFO(("%s hdlcdev_rx\n", dev->name)); | ||
1766 | |||
1767 | if (skb == NULL) { | ||
1768 | DBGERR(("%s: can't alloc skb, drop packet\n", dev->name)); | ||
1769 | dev->stats.rx_dropped++; | ||
1770 | return; | ||
1771 | } | ||
1772 | |||
1773 | memcpy(skb_put(skb, size), buf, size); | ||
1774 | |||
1775 | skb->protocol = hdlc_type_trans(skb, dev); | ||
1776 | |||
1777 | dev->stats.rx_packets++; | ||
1778 | dev->stats.rx_bytes += size; | ||
1779 | |||
1780 | netif_rx(skb); | ||
1781 | } | ||
1782 | |||
1783 | static const struct net_device_ops hdlcdev_ops = { | ||
1784 | .ndo_open = hdlcdev_open, | ||
1785 | .ndo_stop = hdlcdev_close, | ||
1786 | .ndo_change_mtu = hdlc_change_mtu, | ||
1787 | .ndo_start_xmit = hdlc_start_xmit, | ||
1788 | .ndo_do_ioctl = hdlcdev_ioctl, | ||
1789 | .ndo_tx_timeout = hdlcdev_tx_timeout, | ||
1790 | }; | ||
1791 | |||
1792 | /** | ||
1793 | * called by device driver when adding device instance | ||
1794 | * do generic HDLC initialization | ||
1795 | * | ||
1796 | * info pointer to device instance information | ||
1797 | * | ||
1798 | * returns 0 if success, otherwise error code | ||
1799 | */ | ||
1800 | static int hdlcdev_init(struct slgt_info *info) | ||
1801 | { | ||
1802 | int rc; | ||
1803 | struct net_device *dev; | ||
1804 | hdlc_device *hdlc; | ||
1805 | |||
1806 | /* allocate and initialize network and HDLC layer objects */ | ||
1807 | |||
1808 | if (!(dev = alloc_hdlcdev(info))) { | ||
1809 | printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); | ||
1810 | return -ENOMEM; | ||
1811 | } | ||
1812 | |||
1813 | /* for network layer reporting purposes only */ | ||
1814 | dev->mem_start = info->phys_reg_addr; | ||
1815 | dev->mem_end = info->phys_reg_addr + SLGT_REG_SIZE - 1; | ||
1816 | dev->irq = info->irq_level; | ||
1817 | |||
1818 | /* network layer callbacks and settings */ | ||
1819 | dev->netdev_ops = &hdlcdev_ops; | ||
1820 | dev->watchdog_timeo = 10 * HZ; | ||
1821 | dev->tx_queue_len = 50; | ||
1822 | |||
1823 | /* generic HDLC layer callbacks and settings */ | ||
1824 | hdlc = dev_to_hdlc(dev); | ||
1825 | hdlc->attach = hdlcdev_attach; | ||
1826 | hdlc->xmit = hdlcdev_xmit; | ||
1827 | |||
1828 | /* register objects with HDLC layer */ | ||
1829 | if ((rc = register_hdlc_device(dev))) { | ||
1830 | printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); | ||
1831 | free_netdev(dev); | ||
1832 | return rc; | ||
1833 | } | ||
1834 | |||
1835 | info->netdev = dev; | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | /** | ||
1840 | * called by device driver when removing device instance | ||
1841 | * do generic HDLC cleanup | ||
1842 | * | ||
1843 | * info pointer to device instance information | ||
1844 | */ | ||
1845 | static void hdlcdev_exit(struct slgt_info *info) | ||
1846 | { | ||
1847 | unregister_hdlc_device(info->netdev); | ||
1848 | free_netdev(info->netdev); | ||
1849 | info->netdev = NULL; | ||
1850 | } | ||
1851 | |||
1852 | #endif /* ifdef CONFIG_HDLC */ | ||
1853 | |||
1854 | /* | ||
1855 | * get async data from rx DMA buffers | ||
1856 | */ | ||
1857 | static void rx_async(struct slgt_info *info) | ||
1858 | { | ||
1859 | struct tty_struct *tty = info->port.tty; | ||
1860 | struct mgsl_icount *icount = &info->icount; | ||
1861 | unsigned int start, end; | ||
1862 | unsigned char *p; | ||
1863 | unsigned char status; | ||
1864 | struct slgt_desc *bufs = info->rbufs; | ||
1865 | int i, count; | ||
1866 | int chars = 0; | ||
1867 | int stat; | ||
1868 | unsigned char ch; | ||
1869 | |||
1870 | start = end = info->rbuf_current; | ||
1871 | |||
1872 | while(desc_complete(bufs[end])) { | ||
1873 | count = desc_count(bufs[end]) - info->rbuf_index; | ||
1874 | p = bufs[end].buf + info->rbuf_index; | ||
1875 | |||
1876 | DBGISR(("%s rx_async count=%d\n", info->device_name, count)); | ||
1877 | DBGDATA(info, p, count, "rx"); | ||
1878 | |||
1879 | for(i=0 ; i < count; i+=2, p+=2) { | ||
1880 | ch = *p; | ||
1881 | icount->rx++; | ||
1882 | |||
1883 | stat = 0; | ||
1884 | |||
1885 | if ((status = *(p+1) & (BIT1 + BIT0))) { | ||
1886 | if (status & BIT1) | ||
1887 | icount->parity++; | ||
1888 | else if (status & BIT0) | ||
1889 | icount->frame++; | ||
1890 | /* discard char if tty control flags say so */ | ||
1891 | if (status & info->ignore_status_mask) | ||
1892 | continue; | ||
1893 | if (status & BIT1) | ||
1894 | stat = TTY_PARITY; | ||
1895 | else if (status & BIT0) | ||
1896 | stat = TTY_FRAME; | ||
1897 | } | ||
1898 | if (tty) { | ||
1899 | tty_insert_flip_char(tty, ch, stat); | ||
1900 | chars++; | ||
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | if (i < count) { | ||
1905 | /* receive buffer not completed */ | ||
1906 | info->rbuf_index += i; | ||
1907 | mod_timer(&info->rx_timer, jiffies + 1); | ||
1908 | break; | ||
1909 | } | ||
1910 | |||
1911 | info->rbuf_index = 0; | ||
1912 | free_rbufs(info, end, end); | ||
1913 | |||
1914 | if (++end == info->rbuf_count) | ||
1915 | end = 0; | ||
1916 | |||
1917 | /* if entire list searched then no frame available */ | ||
1918 | if (end == start) | ||
1919 | break; | ||
1920 | } | ||
1921 | |||
1922 | if (tty && chars) | ||
1923 | tty_flip_buffer_push(tty); | ||
1924 | } | ||
1925 | |||
1926 | /* | ||
1927 | * return next bottom half action to perform | ||
1928 | */ | ||
1929 | static int bh_action(struct slgt_info *info) | ||
1930 | { | ||
1931 | unsigned long flags; | ||
1932 | int rc; | ||
1933 | |||
1934 | spin_lock_irqsave(&info->lock,flags); | ||
1935 | |||
1936 | if (info->pending_bh & BH_RECEIVE) { | ||
1937 | info->pending_bh &= ~BH_RECEIVE; | ||
1938 | rc = BH_RECEIVE; | ||
1939 | } else if (info->pending_bh & BH_TRANSMIT) { | ||
1940 | info->pending_bh &= ~BH_TRANSMIT; | ||
1941 | rc = BH_TRANSMIT; | ||
1942 | } else if (info->pending_bh & BH_STATUS) { | ||
1943 | info->pending_bh &= ~BH_STATUS; | ||
1944 | rc = BH_STATUS; | ||
1945 | } else { | ||
1946 | /* Mark BH routine as complete */ | ||
1947 | info->bh_running = false; | ||
1948 | info->bh_requested = false; | ||
1949 | rc = 0; | ||
1950 | } | ||
1951 | |||
1952 | spin_unlock_irqrestore(&info->lock,flags); | ||
1953 | |||
1954 | return rc; | ||
1955 | } | ||
1956 | |||
1957 | /* | ||
1958 | * perform bottom half processing | ||
1959 | */ | ||
1960 | static void bh_handler(struct work_struct *work) | ||
1961 | { | ||
1962 | struct slgt_info *info = container_of(work, struct slgt_info, task); | ||
1963 | int action; | ||
1964 | |||
1965 | if (!info) | ||
1966 | return; | ||
1967 | info->bh_running = true; | ||
1968 | |||
1969 | while((action = bh_action(info))) { | ||
1970 | switch (action) { | ||
1971 | case BH_RECEIVE: | ||
1972 | DBGBH(("%s bh receive\n", info->device_name)); | ||
1973 | switch(info->params.mode) { | ||
1974 | case MGSL_MODE_ASYNC: | ||
1975 | rx_async(info); | ||
1976 | break; | ||
1977 | case MGSL_MODE_HDLC: | ||
1978 | while(rx_get_frame(info)); | ||
1979 | break; | ||
1980 | case MGSL_MODE_RAW: | ||
1981 | case MGSL_MODE_MONOSYNC: | ||
1982 | case MGSL_MODE_BISYNC: | ||
1983 | case MGSL_MODE_XSYNC: | ||
1984 | while(rx_get_buf(info)); | ||
1985 | break; | ||
1986 | } | ||
1987 | /* restart receiver if rx DMA buffers exhausted */ | ||
1988 | if (info->rx_restart) | ||
1989 | rx_start(info); | ||
1990 | break; | ||
1991 | case BH_TRANSMIT: | ||
1992 | bh_transmit(info); | ||
1993 | break; | ||
1994 | case BH_STATUS: | ||
1995 | DBGBH(("%s bh status\n", info->device_name)); | ||
1996 | info->ri_chkcount = 0; | ||
1997 | info->dsr_chkcount = 0; | ||
1998 | info->dcd_chkcount = 0; | ||
1999 | info->cts_chkcount = 0; | ||
2000 | break; | ||
2001 | default: | ||
2002 | DBGBH(("%s unknown action\n", info->device_name)); | ||
2003 | break; | ||
2004 | } | ||
2005 | } | ||
2006 | DBGBH(("%s bh_handler exit\n", info->device_name)); | ||
2007 | } | ||
2008 | |||
2009 | static void bh_transmit(struct slgt_info *info) | ||
2010 | { | ||
2011 | struct tty_struct *tty = info->port.tty; | ||
2012 | |||
2013 | DBGBH(("%s bh_transmit\n", info->device_name)); | ||
2014 | if (tty) | ||
2015 | tty_wakeup(tty); | ||
2016 | } | ||
2017 | |||
2018 | static void dsr_change(struct slgt_info *info, unsigned short status) | ||
2019 | { | ||
2020 | if (status & BIT3) { | ||
2021 | info->signals |= SerialSignal_DSR; | ||
2022 | info->input_signal_events.dsr_up++; | ||
2023 | } else { | ||
2024 | info->signals &= ~SerialSignal_DSR; | ||
2025 | info->input_signal_events.dsr_down++; | ||
2026 | } | ||
2027 | DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); | ||
2028 | if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { | ||
2029 | slgt_irq_off(info, IRQ_DSR); | ||
2030 | return; | ||
2031 | } | ||
2032 | info->icount.dsr++; | ||
2033 | wake_up_interruptible(&info->status_event_wait_q); | ||
2034 | wake_up_interruptible(&info->event_wait_q); | ||
2035 | info->pending_bh |= BH_STATUS; | ||
2036 | } | ||
2037 | |||
2038 | static void cts_change(struct slgt_info *info, unsigned short status) | ||
2039 | { | ||
2040 | if (status & BIT2) { | ||
2041 | info->signals |= SerialSignal_CTS; | ||
2042 | info->input_signal_events.cts_up++; | ||
2043 | } else { | ||
2044 | info->signals &= ~SerialSignal_CTS; | ||
2045 | info->input_signal_events.cts_down++; | ||
2046 | } | ||
2047 | DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); | ||
2048 | if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { | ||
2049 | slgt_irq_off(info, IRQ_CTS); | ||
2050 | return; | ||
2051 | } | ||
2052 | info->icount.cts++; | ||
2053 | wake_up_interruptible(&info->status_event_wait_q); | ||
2054 | wake_up_interruptible(&info->event_wait_q); | ||
2055 | info->pending_bh |= BH_STATUS; | ||
2056 | |||
2057 | if (info->port.flags & ASYNC_CTS_FLOW) { | ||
2058 | if (info->port.tty) { | ||
2059 | if (info->port.tty->hw_stopped) { | ||
2060 | if (info->signals & SerialSignal_CTS) { | ||
2061 | info->port.tty->hw_stopped = 0; | ||
2062 | info->pending_bh |= BH_TRANSMIT; | ||
2063 | return; | ||
2064 | } | ||
2065 | } else { | ||
2066 | if (!(info->signals & SerialSignal_CTS)) | ||
2067 | info->port.tty->hw_stopped = 1; | ||
2068 | } | ||
2069 | } | ||
2070 | } | ||
2071 | } | ||
2072 | |||
2073 | static void dcd_change(struct slgt_info *info, unsigned short status) | ||
2074 | { | ||
2075 | if (status & BIT1) { | ||
2076 | info->signals |= SerialSignal_DCD; | ||
2077 | info->input_signal_events.dcd_up++; | ||
2078 | } else { | ||
2079 | info->signals &= ~SerialSignal_DCD; | ||
2080 | info->input_signal_events.dcd_down++; | ||
2081 | } | ||
2082 | DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); | ||
2083 | if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { | ||
2084 | slgt_irq_off(info, IRQ_DCD); | ||
2085 | return; | ||
2086 | } | ||
2087 | info->icount.dcd++; | ||
2088 | #if SYNCLINK_GENERIC_HDLC | ||
2089 | if (info->netcount) { | ||
2090 | if (info->signals & SerialSignal_DCD) | ||
2091 | netif_carrier_on(info->netdev); | ||
2092 | else | ||
2093 | netif_carrier_off(info->netdev); | ||
2094 | } | ||
2095 | #endif | ||
2096 | wake_up_interruptible(&info->status_event_wait_q); | ||
2097 | wake_up_interruptible(&info->event_wait_q); | ||
2098 | info->pending_bh |= BH_STATUS; | ||
2099 | |||
2100 | if (info->port.flags & ASYNC_CHECK_CD) { | ||
2101 | if (info->signals & SerialSignal_DCD) | ||
2102 | wake_up_interruptible(&info->port.open_wait); | ||
2103 | else { | ||
2104 | if (info->port.tty) | ||
2105 | tty_hangup(info->port.tty); | ||
2106 | } | ||
2107 | } | ||
2108 | } | ||
2109 | |||
2110 | static void ri_change(struct slgt_info *info, unsigned short status) | ||
2111 | { | ||
2112 | if (status & BIT0) { | ||
2113 | info->signals |= SerialSignal_RI; | ||
2114 | info->input_signal_events.ri_up++; | ||
2115 | } else { | ||
2116 | info->signals &= ~SerialSignal_RI; | ||
2117 | info->input_signal_events.ri_down++; | ||
2118 | } | ||
2119 | DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); | ||
2120 | if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { | ||
2121 | slgt_irq_off(info, IRQ_RI); | ||
2122 | return; | ||
2123 | } | ||
2124 | info->icount.rng++; | ||
2125 | wake_up_interruptible(&info->status_event_wait_q); | ||
2126 | wake_up_interruptible(&info->event_wait_q); | ||
2127 | info->pending_bh |= BH_STATUS; | ||
2128 | } | ||
2129 | |||
2130 | static void isr_rxdata(struct slgt_info *info) | ||
2131 | { | ||
2132 | unsigned int count = info->rbuf_fill_count; | ||
2133 | unsigned int i = info->rbuf_fill_index; | ||
2134 | unsigned short reg; | ||
2135 | |||
2136 | while (rd_reg16(info, SSR) & IRQ_RXDATA) { | ||
2137 | reg = rd_reg16(info, RDR); | ||
2138 | DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg)); | ||
2139 | if (desc_complete(info->rbufs[i])) { | ||
2140 | /* all buffers full */ | ||
2141 | rx_stop(info); | ||
2142 | info->rx_restart = 1; | ||
2143 | continue; | ||
2144 | } | ||
2145 | info->rbufs[i].buf[count++] = (unsigned char)reg; | ||
2146 | /* async mode saves status byte to buffer for each data byte */ | ||
2147 | if (info->params.mode == MGSL_MODE_ASYNC) | ||
2148 | info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8); | ||
2149 | if (count == info->rbuf_fill_level || (reg & BIT10)) { | ||
2150 | /* buffer full or end of frame */ | ||
2151 | set_desc_count(info->rbufs[i], count); | ||
2152 | set_desc_status(info->rbufs[i], BIT15 | (reg >> 8)); | ||
2153 | info->rbuf_fill_count = count = 0; | ||
2154 | if (++i == info->rbuf_count) | ||
2155 | i = 0; | ||
2156 | info->pending_bh |= BH_RECEIVE; | ||
2157 | } | ||
2158 | } | ||
2159 | |||
2160 | info->rbuf_fill_index = i; | ||
2161 | info->rbuf_fill_count = count; | ||
2162 | } | ||
2163 | |||
2164 | static void isr_serial(struct slgt_info *info) | ||
2165 | { | ||
2166 | unsigned short status = rd_reg16(info, SSR); | ||
2167 | |||
2168 | DBGISR(("%s isr_serial status=%04X\n", info->device_name, status)); | ||
2169 | |||
2170 | wr_reg16(info, SSR, status); /* clear pending */ | ||
2171 | |||
2172 | info->irq_occurred = true; | ||
2173 | |||
2174 | if (info->params.mode == MGSL_MODE_ASYNC) { | ||
2175 | if (status & IRQ_TXIDLE) { | ||
2176 | if (info->tx_active) | ||
2177 | isr_txeom(info, status); | ||
2178 | } | ||
2179 | if (info->rx_pio && (status & IRQ_RXDATA)) | ||
2180 | isr_rxdata(info); | ||
2181 | if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { | ||
2182 | info->icount.brk++; | ||
2183 | /* process break detection if tty control allows */ | ||
2184 | if (info->port.tty) { | ||
2185 | if (!(status & info->ignore_status_mask)) { | ||
2186 | if (info->read_status_mask & MASK_BREAK) { | ||
2187 | tty_insert_flip_char(info->port.tty, 0, TTY_BREAK); | ||
2188 | if (info->port.flags & ASYNC_SAK) | ||
2189 | do_SAK(info->port.tty); | ||
2190 | } | ||
2191 | } | ||
2192 | } | ||
2193 | } | ||
2194 | } else { | ||
2195 | if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) | ||
2196 | isr_txeom(info, status); | ||
2197 | if (info->rx_pio && (status & IRQ_RXDATA)) | ||
2198 | isr_rxdata(info); | ||
2199 | if (status & IRQ_RXIDLE) { | ||
2200 | if (status & RXIDLE) | ||
2201 | info->icount.rxidle++; | ||
2202 | else | ||
2203 | info->icount.exithunt++; | ||
2204 | wake_up_interruptible(&info->event_wait_q); | ||
2205 | } | ||
2206 | |||
2207 | if (status & IRQ_RXOVER) | ||
2208 | rx_start(info); | ||
2209 | } | ||
2210 | |||
2211 | if (status & IRQ_DSR) | ||
2212 | dsr_change(info, status); | ||
2213 | if (status & IRQ_CTS) | ||
2214 | cts_change(info, status); | ||
2215 | if (status & IRQ_DCD) | ||
2216 | dcd_change(info, status); | ||
2217 | if (status & IRQ_RI) | ||
2218 | ri_change(info, status); | ||
2219 | } | ||
2220 | |||
2221 | static void isr_rdma(struct slgt_info *info) | ||
2222 | { | ||
2223 | unsigned int status = rd_reg32(info, RDCSR); | ||
2224 | |||
2225 | DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status)); | ||
2226 | |||
2227 | /* RDCSR (rx DMA control/status) | ||
2228 | * | ||
2229 | * 31..07 reserved | ||
2230 | * 06 save status byte to DMA buffer | ||
2231 | * 05 error | ||
2232 | * 04 eol (end of list) | ||
2233 | * 03 eob (end of buffer) | ||
2234 | * 02 IRQ enable | ||
2235 | * 01 reset | ||
2236 | * 00 enable | ||
2237 | */ | ||
2238 | wr_reg32(info, RDCSR, status); /* clear pending */ | ||
2239 | |||
2240 | if (status & (BIT5 + BIT4)) { | ||
2241 | DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name)); | ||
2242 | info->rx_restart = true; | ||
2243 | } | ||
2244 | info->pending_bh |= BH_RECEIVE; | ||
2245 | } | ||
2246 | |||
2247 | static void isr_tdma(struct slgt_info *info) | ||
2248 | { | ||
2249 | unsigned int status = rd_reg32(info, TDCSR); | ||
2250 | |||
2251 | DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status)); | ||
2252 | |||
2253 | /* TDCSR (tx DMA control/status) | ||
2254 | * | ||
2255 | * 31..06 reserved | ||
2256 | * 05 error | ||
2257 | * 04 eol (end of list) | ||
2258 | * 03 eob (end of buffer) | ||
2259 | * 02 IRQ enable | ||
2260 | * 01 reset | ||
2261 | * 00 enable | ||
2262 | */ | ||
2263 | wr_reg32(info, TDCSR, status); /* clear pending */ | ||
2264 | |||
2265 | if (status & (BIT5 + BIT4 + BIT3)) { | ||
2266 | // another transmit buffer has completed | ||
2267 | // run bottom half to get more send data from user | ||
2268 | info->pending_bh |= BH_TRANSMIT; | ||
2269 | } | ||
2270 | } | ||
2271 | |||
2272 | /* | ||
2273 | * return true if there are unsent tx DMA buffers, otherwise false | ||
2274 | * | ||
2275 | * if there are unsent buffers then info->tbuf_start | ||
2276 | * is set to index of first unsent buffer | ||
2277 | */ | ||
2278 | static bool unsent_tbufs(struct slgt_info *info) | ||
2279 | { | ||
2280 | unsigned int i = info->tbuf_current; | ||
2281 | bool rc = false; | ||
2282 | |||
2283 | /* | ||
2284 | * search backwards from last loaded buffer (precedes tbuf_current) | ||
2285 | * for first unsent buffer (desc_count > 0) | ||
2286 | */ | ||
2287 | |||
2288 | do { | ||
2289 | if (i) | ||
2290 | i--; | ||
2291 | else | ||
2292 | i = info->tbuf_count - 1; | ||
2293 | if (!desc_count(info->tbufs[i])) | ||
2294 | break; | ||
2295 | info->tbuf_start = i; | ||
2296 | rc = true; | ||
2297 | } while (i != info->tbuf_current); | ||
2298 | |||
2299 | return rc; | ||
2300 | } | ||
2301 | |||
2302 | static void isr_txeom(struct slgt_info *info, unsigned short status) | ||
2303 | { | ||
2304 | DBGISR(("%s txeom status=%04x\n", info->device_name, status)); | ||
2305 | |||
2306 | slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); | ||
2307 | tdma_reset(info); | ||
2308 | if (status & IRQ_TXUNDER) { | ||
2309 | unsigned short val = rd_reg16(info, TCR); | ||
2310 | wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ | ||
2311 | wr_reg16(info, TCR, val); /* clear reset bit */ | ||
2312 | } | ||
2313 | |||
2314 | if (info->tx_active) { | ||
2315 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
2316 | if (status & IRQ_TXUNDER) | ||
2317 | info->icount.txunder++; | ||
2318 | else if (status & IRQ_TXIDLE) | ||
2319 | info->icount.txok++; | ||
2320 | } | ||
2321 | |||
2322 | if (unsent_tbufs(info)) { | ||
2323 | tx_start(info); | ||
2324 | update_tx_timer(info); | ||
2325 | return; | ||
2326 | } | ||
2327 | info->tx_active = false; | ||
2328 | |||
2329 | del_timer(&info->tx_timer); | ||
2330 | |||
2331 | if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) { | ||
2332 | info->signals &= ~SerialSignal_RTS; | ||
2333 | info->drop_rts_on_tx_done = false; | ||
2334 | set_signals(info); | ||
2335 | } | ||
2336 | |||
2337 | #if SYNCLINK_GENERIC_HDLC | ||
2338 | if (info->netcount) | ||
2339 | hdlcdev_tx_done(info); | ||
2340 | else | ||
2341 | #endif | ||
2342 | { | ||
2343 | if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { | ||
2344 | tx_stop(info); | ||
2345 | return; | ||
2346 | } | ||
2347 | info->pending_bh |= BH_TRANSMIT; | ||
2348 | } | ||
2349 | } | ||
2350 | } | ||
2351 | |||
2352 | static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state) | ||
2353 | { | ||
2354 | struct cond_wait *w, *prev; | ||
2355 | |||
2356 | /* wake processes waiting for specific transitions */ | ||
2357 | for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) { | ||
2358 | if (w->data & changed) { | ||
2359 | w->data = state; | ||
2360 | wake_up_interruptible(&w->q); | ||
2361 | if (prev != NULL) | ||
2362 | prev->next = w->next; | ||
2363 | else | ||
2364 | info->gpio_wait_q = w->next; | ||
2365 | } else | ||
2366 | prev = w; | ||
2367 | } | ||
2368 | } | ||
2369 | |||
2370 | /* interrupt service routine | ||
2371 | * | ||
2372 | * irq interrupt number | ||
2373 | * dev_id device ID supplied during interrupt registration | ||
2374 | */ | ||
2375 | static irqreturn_t slgt_interrupt(int dummy, void *dev_id) | ||
2376 | { | ||
2377 | struct slgt_info *info = dev_id; | ||
2378 | unsigned int gsr; | ||
2379 | unsigned int i; | ||
2380 | |||
2381 | DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level)); | ||
2382 | |||
2383 | while((gsr = rd_reg32(info, GSR) & 0xffffff00)) { | ||
2384 | DBGISR(("%s gsr=%08x\n", info->device_name, gsr)); | ||
2385 | info->irq_occurred = true; | ||
2386 | for(i=0; i < info->port_count ; i++) { | ||
2387 | if (info->port_array[i] == NULL) | ||
2388 | continue; | ||
2389 | spin_lock(&info->port_array[i]->lock); | ||
2390 | if (gsr & (BIT8 << i)) | ||
2391 | isr_serial(info->port_array[i]); | ||
2392 | if (gsr & (BIT16 << (i*2))) | ||
2393 | isr_rdma(info->port_array[i]); | ||
2394 | if (gsr & (BIT17 << (i*2))) | ||
2395 | isr_tdma(info->port_array[i]); | ||
2396 | spin_unlock(&info->port_array[i]->lock); | ||
2397 | } | ||
2398 | } | ||
2399 | |||
2400 | if (info->gpio_present) { | ||
2401 | unsigned int state; | ||
2402 | unsigned int changed; | ||
2403 | spin_lock(&info->lock); | ||
2404 | while ((changed = rd_reg32(info, IOSR)) != 0) { | ||
2405 | DBGISR(("%s iosr=%08x\n", info->device_name, changed)); | ||
2406 | /* read latched state of GPIO signals */ | ||
2407 | state = rd_reg32(info, IOVR); | ||
2408 | /* clear pending GPIO interrupt bits */ | ||
2409 | wr_reg32(info, IOSR, changed); | ||
2410 | for (i=0 ; i < info->port_count ; i++) { | ||
2411 | if (info->port_array[i] != NULL) | ||
2412 | isr_gpio(info->port_array[i], changed, state); | ||
2413 | } | ||
2414 | } | ||
2415 | spin_unlock(&info->lock); | ||
2416 | } | ||
2417 | |||
2418 | for(i=0; i < info->port_count ; i++) { | ||
2419 | struct slgt_info *port = info->port_array[i]; | ||
2420 | if (port == NULL) | ||
2421 | continue; | ||
2422 | spin_lock(&port->lock); | ||
2423 | if ((port->port.count || port->netcount) && | ||
2424 | port->pending_bh && !port->bh_running && | ||
2425 | !port->bh_requested) { | ||
2426 | DBGISR(("%s bh queued\n", port->device_name)); | ||
2427 | schedule_work(&port->task); | ||
2428 | port->bh_requested = true; | ||
2429 | } | ||
2430 | spin_unlock(&port->lock); | ||
2431 | } | ||
2432 | |||
2433 | DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level)); | ||
2434 | return IRQ_HANDLED; | ||
2435 | } | ||
2436 | |||
2437 | static int startup(struct slgt_info *info) | ||
2438 | { | ||
2439 | DBGINFO(("%s startup\n", info->device_name)); | ||
2440 | |||
2441 | if (info->port.flags & ASYNC_INITIALIZED) | ||
2442 | return 0; | ||
2443 | |||
2444 | if (!info->tx_buf) { | ||
2445 | info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); | ||
2446 | if (!info->tx_buf) { | ||
2447 | DBGERR(("%s can't allocate tx buffer\n", info->device_name)); | ||
2448 | return -ENOMEM; | ||
2449 | } | ||
2450 | } | ||
2451 | |||
2452 | info->pending_bh = 0; | ||
2453 | |||
2454 | memset(&info->icount, 0, sizeof(info->icount)); | ||
2455 | |||
2456 | /* program hardware for current parameters */ | ||
2457 | change_params(info); | ||
2458 | |||
2459 | if (info->port.tty) | ||
2460 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2461 | |||
2462 | info->port.flags |= ASYNC_INITIALIZED; | ||
2463 | |||
2464 | return 0; | ||
2465 | } | ||
2466 | |||
2467 | /* | ||
2468 | * called by close() and hangup() to shutdown hardware | ||
2469 | */ | ||
2470 | static void shutdown(struct slgt_info *info) | ||
2471 | { | ||
2472 | unsigned long flags; | ||
2473 | |||
2474 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
2475 | return; | ||
2476 | |||
2477 | DBGINFO(("%s shutdown\n", info->device_name)); | ||
2478 | |||
2479 | /* clear status wait queue because status changes */ | ||
2480 | /* can't happen after shutting down the hardware */ | ||
2481 | wake_up_interruptible(&info->status_event_wait_q); | ||
2482 | wake_up_interruptible(&info->event_wait_q); | ||
2483 | |||
2484 | del_timer_sync(&info->tx_timer); | ||
2485 | del_timer_sync(&info->rx_timer); | ||
2486 | |||
2487 | kfree(info->tx_buf); | ||
2488 | info->tx_buf = NULL; | ||
2489 | |||
2490 | spin_lock_irqsave(&info->lock,flags); | ||
2491 | |||
2492 | tx_stop(info); | ||
2493 | rx_stop(info); | ||
2494 | |||
2495 | slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); | ||
2496 | |||
2497 | if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { | ||
2498 | info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | ||
2499 | set_signals(info); | ||
2500 | } | ||
2501 | |||
2502 | flush_cond_wait(&info->gpio_wait_q); | ||
2503 | |||
2504 | spin_unlock_irqrestore(&info->lock,flags); | ||
2505 | |||
2506 | if (info->port.tty) | ||
2507 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2508 | |||
2509 | info->port.flags &= ~ASYNC_INITIALIZED; | ||
2510 | } | ||
2511 | |||
2512 | static void program_hw(struct slgt_info *info) | ||
2513 | { | ||
2514 | unsigned long flags; | ||
2515 | |||
2516 | spin_lock_irqsave(&info->lock,flags); | ||
2517 | |||
2518 | rx_stop(info); | ||
2519 | tx_stop(info); | ||
2520 | |||
2521 | if (info->params.mode != MGSL_MODE_ASYNC || | ||
2522 | info->netcount) | ||
2523 | sync_mode(info); | ||
2524 | else | ||
2525 | async_mode(info); | ||
2526 | |||
2527 | set_signals(info); | ||
2528 | |||
2529 | info->dcd_chkcount = 0; | ||
2530 | info->cts_chkcount = 0; | ||
2531 | info->ri_chkcount = 0; | ||
2532 | info->dsr_chkcount = 0; | ||
2533 | |||
2534 | slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR | IRQ_RI); | ||
2535 | get_signals(info); | ||
2536 | |||
2537 | if (info->netcount || | ||
2538 | (info->port.tty && info->port.tty->termios->c_cflag & CREAD)) | ||
2539 | rx_start(info); | ||
2540 | |||
2541 | spin_unlock_irqrestore(&info->lock,flags); | ||
2542 | } | ||
2543 | |||
2544 | /* | ||
2545 | * reconfigure adapter based on new parameters | ||
2546 | */ | ||
2547 | static void change_params(struct slgt_info *info) | ||
2548 | { | ||
2549 | unsigned cflag; | ||
2550 | int bits_per_char; | ||
2551 | |||
2552 | if (!info->port.tty || !info->port.tty->termios) | ||
2553 | return; | ||
2554 | DBGINFO(("%s change_params\n", info->device_name)); | ||
2555 | |||
2556 | cflag = info->port.tty->termios->c_cflag; | ||
2557 | |||
2558 | /* if B0 rate (hangup) specified then negate DTR and RTS */ | ||
2559 | /* otherwise assert DTR and RTS */ | ||
2560 | if (cflag & CBAUD) | ||
2561 | info->signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
2562 | else | ||
2563 | info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
2564 | |||
2565 | /* byte size and parity */ | ||
2566 | |||
2567 | switch (cflag & CSIZE) { | ||
2568 | case CS5: info->params.data_bits = 5; break; | ||
2569 | case CS6: info->params.data_bits = 6; break; | ||
2570 | case CS7: info->params.data_bits = 7; break; | ||
2571 | case CS8: info->params.data_bits = 8; break; | ||
2572 | default: info->params.data_bits = 7; break; | ||
2573 | } | ||
2574 | |||
2575 | info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1; | ||
2576 | |||
2577 | if (cflag & PARENB) | ||
2578 | info->params.parity = (cflag & PARODD) ? ASYNC_PARITY_ODD : ASYNC_PARITY_EVEN; | ||
2579 | else | ||
2580 | info->params.parity = ASYNC_PARITY_NONE; | ||
2581 | |||
2582 | /* calculate number of jiffies to transmit a full | ||
2583 | * FIFO (32 bytes) at specified data rate | ||
2584 | */ | ||
2585 | bits_per_char = info->params.data_bits + | ||
2586 | info->params.stop_bits + 1; | ||
2587 | |||
2588 | info->params.data_rate = tty_get_baud_rate(info->port.tty); | ||
2589 | |||
2590 | if (info->params.data_rate) { | ||
2591 | info->timeout = (32*HZ*bits_per_char) / | ||
2592 | info->params.data_rate; | ||
2593 | } | ||
2594 | info->timeout += HZ/50; /* Add .02 seconds of slop */ | ||
2595 | |||
2596 | if (cflag & CRTSCTS) | ||
2597 | info->port.flags |= ASYNC_CTS_FLOW; | ||
2598 | else | ||
2599 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
2600 | |||
2601 | if (cflag & CLOCAL) | ||
2602 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
2603 | else | ||
2604 | info->port.flags |= ASYNC_CHECK_CD; | ||
2605 | |||
2606 | /* process tty input control flags */ | ||
2607 | |||
2608 | info->read_status_mask = IRQ_RXOVER; | ||
2609 | if (I_INPCK(info->port.tty)) | ||
2610 | info->read_status_mask |= MASK_PARITY | MASK_FRAMING; | ||
2611 | if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) | ||
2612 | info->read_status_mask |= MASK_BREAK; | ||
2613 | if (I_IGNPAR(info->port.tty)) | ||
2614 | info->ignore_status_mask |= MASK_PARITY | MASK_FRAMING; | ||
2615 | if (I_IGNBRK(info->port.tty)) { | ||
2616 | info->ignore_status_mask |= MASK_BREAK; | ||
2617 | /* If ignoring parity and break indicators, ignore | ||
2618 | * overruns too. (For real raw support). | ||
2619 | */ | ||
2620 | if (I_IGNPAR(info->port.tty)) | ||
2621 | info->ignore_status_mask |= MASK_OVERRUN; | ||
2622 | } | ||
2623 | |||
2624 | program_hw(info); | ||
2625 | } | ||
2626 | |||
2627 | static int get_stats(struct slgt_info *info, struct mgsl_icount __user *user_icount) | ||
2628 | { | ||
2629 | DBGINFO(("%s get_stats\n", info->device_name)); | ||
2630 | if (!user_icount) { | ||
2631 | memset(&info->icount, 0, sizeof(info->icount)); | ||
2632 | } else { | ||
2633 | if (copy_to_user(user_icount, &info->icount, sizeof(struct mgsl_icount))) | ||
2634 | return -EFAULT; | ||
2635 | } | ||
2636 | return 0; | ||
2637 | } | ||
2638 | |||
2639 | static int get_params(struct slgt_info *info, MGSL_PARAMS __user *user_params) | ||
2640 | { | ||
2641 | DBGINFO(("%s get_params\n", info->device_name)); | ||
2642 | if (copy_to_user(user_params, &info->params, sizeof(MGSL_PARAMS))) | ||
2643 | return -EFAULT; | ||
2644 | return 0; | ||
2645 | } | ||
2646 | |||
2647 | static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params) | ||
2648 | { | ||
2649 | unsigned long flags; | ||
2650 | MGSL_PARAMS tmp_params; | ||
2651 | |||
2652 | DBGINFO(("%s set_params\n", info->device_name)); | ||
2653 | if (copy_from_user(&tmp_params, new_params, sizeof(MGSL_PARAMS))) | ||
2654 | return -EFAULT; | ||
2655 | |||
2656 | spin_lock_irqsave(&info->lock, flags); | ||
2657 | if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) | ||
2658 | info->base_clock = tmp_params.clock_speed; | ||
2659 | else | ||
2660 | memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); | ||
2661 | spin_unlock_irqrestore(&info->lock, flags); | ||
2662 | |||
2663 | program_hw(info); | ||
2664 | |||
2665 | return 0; | ||
2666 | } | ||
2667 | |||
2668 | static int get_txidle(struct slgt_info *info, int __user *idle_mode) | ||
2669 | { | ||
2670 | DBGINFO(("%s get_txidle=%d\n", info->device_name, info->idle_mode)); | ||
2671 | if (put_user(info->idle_mode, idle_mode)) | ||
2672 | return -EFAULT; | ||
2673 | return 0; | ||
2674 | } | ||
2675 | |||
2676 | static int set_txidle(struct slgt_info *info, int idle_mode) | ||
2677 | { | ||
2678 | unsigned long flags; | ||
2679 | DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode)); | ||
2680 | spin_lock_irqsave(&info->lock,flags); | ||
2681 | info->idle_mode = idle_mode; | ||
2682 | if (info->params.mode != MGSL_MODE_ASYNC) | ||
2683 | tx_set_idle(info); | ||
2684 | spin_unlock_irqrestore(&info->lock,flags); | ||
2685 | return 0; | ||
2686 | } | ||
2687 | |||
2688 | static int tx_enable(struct slgt_info *info, int enable) | ||
2689 | { | ||
2690 | unsigned long flags; | ||
2691 | DBGINFO(("%s tx_enable(%d)\n", info->device_name, enable)); | ||
2692 | spin_lock_irqsave(&info->lock,flags); | ||
2693 | if (enable) { | ||
2694 | if (!info->tx_enabled) | ||
2695 | tx_start(info); | ||
2696 | } else { | ||
2697 | if (info->tx_enabled) | ||
2698 | tx_stop(info); | ||
2699 | } | ||
2700 | spin_unlock_irqrestore(&info->lock,flags); | ||
2701 | return 0; | ||
2702 | } | ||
2703 | |||
2704 | /* | ||
2705 | * abort transmit HDLC frame | ||
2706 | */ | ||
2707 | static int tx_abort(struct slgt_info *info) | ||
2708 | { | ||
2709 | unsigned long flags; | ||
2710 | DBGINFO(("%s tx_abort\n", info->device_name)); | ||
2711 | spin_lock_irqsave(&info->lock,flags); | ||
2712 | tdma_reset(info); | ||
2713 | spin_unlock_irqrestore(&info->lock,flags); | ||
2714 | return 0; | ||
2715 | } | ||
2716 | |||
2717 | static int rx_enable(struct slgt_info *info, int enable) | ||
2718 | { | ||
2719 | unsigned long flags; | ||
2720 | unsigned int rbuf_fill_level; | ||
2721 | DBGINFO(("%s rx_enable(%08x)\n", info->device_name, enable)); | ||
2722 | spin_lock_irqsave(&info->lock,flags); | ||
2723 | /* | ||
2724 | * enable[31..16] = receive DMA buffer fill level | ||
2725 | * 0 = noop (leave fill level unchanged) | ||
2726 | * fill level must be multiple of 4 and <= buffer size | ||
2727 | */ | ||
2728 | rbuf_fill_level = ((unsigned int)enable) >> 16; | ||
2729 | if (rbuf_fill_level) { | ||
2730 | if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) { | ||
2731 | spin_unlock_irqrestore(&info->lock, flags); | ||
2732 | return -EINVAL; | ||
2733 | } | ||
2734 | info->rbuf_fill_level = rbuf_fill_level; | ||
2735 | if (rbuf_fill_level < 128) | ||
2736 | info->rx_pio = 1; /* PIO mode */ | ||
2737 | else | ||
2738 | info->rx_pio = 0; /* DMA mode */ | ||
2739 | rx_stop(info); /* restart receiver to use new fill level */ | ||
2740 | } | ||
2741 | |||
2742 | /* | ||
2743 | * enable[1..0] = receiver enable command | ||
2744 | * 0 = disable | ||
2745 | * 1 = enable | ||
2746 | * 2 = enable or force hunt mode if already enabled | ||
2747 | */ | ||
2748 | enable &= 3; | ||
2749 | if (enable) { | ||
2750 | if (!info->rx_enabled) | ||
2751 | rx_start(info); | ||
2752 | else if (enable == 2) { | ||
2753 | /* force hunt mode (write 1 to RCR[3]) */ | ||
2754 | wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3); | ||
2755 | } | ||
2756 | } else { | ||
2757 | if (info->rx_enabled) | ||
2758 | rx_stop(info); | ||
2759 | } | ||
2760 | spin_unlock_irqrestore(&info->lock,flags); | ||
2761 | return 0; | ||
2762 | } | ||
2763 | |||
2764 | /* | ||
2765 | * wait for specified event to occur | ||
2766 | */ | ||
2767 | static int wait_mgsl_event(struct slgt_info *info, int __user *mask_ptr) | ||
2768 | { | ||
2769 | unsigned long flags; | ||
2770 | int s; | ||
2771 | int rc=0; | ||
2772 | struct mgsl_icount cprev, cnow; | ||
2773 | int events; | ||
2774 | int mask; | ||
2775 | struct _input_signal_events oldsigs, newsigs; | ||
2776 | DECLARE_WAITQUEUE(wait, current); | ||
2777 | |||
2778 | if (get_user(mask, mask_ptr)) | ||
2779 | return -EFAULT; | ||
2780 | |||
2781 | DBGINFO(("%s wait_mgsl_event(%d)\n", info->device_name, mask)); | ||
2782 | |||
2783 | spin_lock_irqsave(&info->lock,flags); | ||
2784 | |||
2785 | /* return immediately if state matches requested events */ | ||
2786 | get_signals(info); | ||
2787 | s = info->signals; | ||
2788 | |||
2789 | events = mask & | ||
2790 | ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + | ||
2791 | ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + | ||
2792 | ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + | ||
2793 | ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); | ||
2794 | if (events) { | ||
2795 | spin_unlock_irqrestore(&info->lock,flags); | ||
2796 | goto exit; | ||
2797 | } | ||
2798 | |||
2799 | /* save current irq counts */ | ||
2800 | cprev = info->icount; | ||
2801 | oldsigs = info->input_signal_events; | ||
2802 | |||
2803 | /* enable hunt and idle irqs if needed */ | ||
2804 | if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { | ||
2805 | unsigned short val = rd_reg16(info, SCR); | ||
2806 | if (!(val & IRQ_RXIDLE)) | ||
2807 | wr_reg16(info, SCR, (unsigned short)(val | IRQ_RXIDLE)); | ||
2808 | } | ||
2809 | |||
2810 | set_current_state(TASK_INTERRUPTIBLE); | ||
2811 | add_wait_queue(&info->event_wait_q, &wait); | ||
2812 | |||
2813 | spin_unlock_irqrestore(&info->lock,flags); | ||
2814 | |||
2815 | for(;;) { | ||
2816 | schedule(); | ||
2817 | if (signal_pending(current)) { | ||
2818 | rc = -ERESTARTSYS; | ||
2819 | break; | ||
2820 | } | ||
2821 | |||
2822 | /* get current irq counts */ | ||
2823 | spin_lock_irqsave(&info->lock,flags); | ||
2824 | cnow = info->icount; | ||
2825 | newsigs = info->input_signal_events; | ||
2826 | set_current_state(TASK_INTERRUPTIBLE); | ||
2827 | spin_unlock_irqrestore(&info->lock,flags); | ||
2828 | |||
2829 | /* if no change, wait aborted for some reason */ | ||
2830 | if (newsigs.dsr_up == oldsigs.dsr_up && | ||
2831 | newsigs.dsr_down == oldsigs.dsr_down && | ||
2832 | newsigs.dcd_up == oldsigs.dcd_up && | ||
2833 | newsigs.dcd_down == oldsigs.dcd_down && | ||
2834 | newsigs.cts_up == oldsigs.cts_up && | ||
2835 | newsigs.cts_down == oldsigs.cts_down && | ||
2836 | newsigs.ri_up == oldsigs.ri_up && | ||
2837 | newsigs.ri_down == oldsigs.ri_down && | ||
2838 | cnow.exithunt == cprev.exithunt && | ||
2839 | cnow.rxidle == cprev.rxidle) { | ||
2840 | rc = -EIO; | ||
2841 | break; | ||
2842 | } | ||
2843 | |||
2844 | events = mask & | ||
2845 | ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + | ||
2846 | (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + | ||
2847 | (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + | ||
2848 | (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + | ||
2849 | (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + | ||
2850 | (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + | ||
2851 | (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + | ||
2852 | (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + | ||
2853 | (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + | ||
2854 | (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); | ||
2855 | if (events) | ||
2856 | break; | ||
2857 | |||
2858 | cprev = cnow; | ||
2859 | oldsigs = newsigs; | ||
2860 | } | ||
2861 | |||
2862 | remove_wait_queue(&info->event_wait_q, &wait); | ||
2863 | set_current_state(TASK_RUNNING); | ||
2864 | |||
2865 | |||
2866 | if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { | ||
2867 | spin_lock_irqsave(&info->lock,flags); | ||
2868 | if (!waitqueue_active(&info->event_wait_q)) { | ||
2869 | /* disable enable exit hunt mode/idle rcvd IRQs */ | ||
2870 | wr_reg16(info, SCR, | ||
2871 | (unsigned short)(rd_reg16(info, SCR) & ~IRQ_RXIDLE)); | ||
2872 | } | ||
2873 | spin_unlock_irqrestore(&info->lock,flags); | ||
2874 | } | ||
2875 | exit: | ||
2876 | if (rc == 0) | ||
2877 | rc = put_user(events, mask_ptr); | ||
2878 | return rc; | ||
2879 | } | ||
2880 | |||
2881 | static int get_interface(struct slgt_info *info, int __user *if_mode) | ||
2882 | { | ||
2883 | DBGINFO(("%s get_interface=%x\n", info->device_name, info->if_mode)); | ||
2884 | if (put_user(info->if_mode, if_mode)) | ||
2885 | return -EFAULT; | ||
2886 | return 0; | ||
2887 | } | ||
2888 | |||
2889 | static int set_interface(struct slgt_info *info, int if_mode) | ||
2890 | { | ||
2891 | unsigned long flags; | ||
2892 | unsigned short val; | ||
2893 | |||
2894 | DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode)); | ||
2895 | spin_lock_irqsave(&info->lock,flags); | ||
2896 | info->if_mode = if_mode; | ||
2897 | |||
2898 | msc_set_vcr(info); | ||
2899 | |||
2900 | /* TCR (tx control) 07 1=RTS driver control */ | ||
2901 | val = rd_reg16(info, TCR); | ||
2902 | if (info->if_mode & MGSL_INTERFACE_RTS_EN) | ||
2903 | val |= BIT7; | ||
2904 | else | ||
2905 | val &= ~BIT7; | ||
2906 | wr_reg16(info, TCR, val); | ||
2907 | |||
2908 | spin_unlock_irqrestore(&info->lock,flags); | ||
2909 | return 0; | ||
2910 | } | ||
2911 | |||
2912 | static int get_xsync(struct slgt_info *info, int __user *xsync) | ||
2913 | { | ||
2914 | DBGINFO(("%s get_xsync=%x\n", info->device_name, info->xsync)); | ||
2915 | if (put_user(info->xsync, xsync)) | ||
2916 | return -EFAULT; | ||
2917 | return 0; | ||
2918 | } | ||
2919 | |||
2920 | /* | ||
2921 | * set extended sync pattern (1 to 4 bytes) for extended sync mode | ||
2922 | * | ||
2923 | * sync pattern is contained in least significant bytes of value | ||
2924 | * most significant byte of sync pattern is oldest (1st sent/detected) | ||
2925 | */ | ||
2926 | static int set_xsync(struct slgt_info *info, int xsync) | ||
2927 | { | ||
2928 | unsigned long flags; | ||
2929 | |||
2930 | DBGINFO(("%s set_xsync=%x)\n", info->device_name, xsync)); | ||
2931 | spin_lock_irqsave(&info->lock, flags); | ||
2932 | info->xsync = xsync; | ||
2933 | wr_reg32(info, XSR, xsync); | ||
2934 | spin_unlock_irqrestore(&info->lock, flags); | ||
2935 | return 0; | ||
2936 | } | ||
2937 | |||
2938 | static int get_xctrl(struct slgt_info *info, int __user *xctrl) | ||
2939 | { | ||
2940 | DBGINFO(("%s get_xctrl=%x\n", info->device_name, info->xctrl)); | ||
2941 | if (put_user(info->xctrl, xctrl)) | ||
2942 | return -EFAULT; | ||
2943 | return 0; | ||
2944 | } | ||
2945 | |||
2946 | /* | ||
2947 | * set extended control options | ||
2948 | * | ||
2949 | * xctrl[31:19] reserved, must be zero | ||
2950 | * xctrl[18:17] extended sync pattern length in bytes | ||
2951 | * 00 = 1 byte in xsr[7:0] | ||
2952 | * 01 = 2 bytes in xsr[15:0] | ||
2953 | * 10 = 3 bytes in xsr[23:0] | ||
2954 | * 11 = 4 bytes in xsr[31:0] | ||
2955 | * xctrl[16] 1 = enable terminal count, 0=disabled | ||
2956 | * xctrl[15:0] receive terminal count for fixed length packets | ||
2957 | * value is count minus one (0 = 1 byte packet) | ||
2958 | * when terminal count is reached, receiver | ||
2959 | * automatically returns to hunt mode and receive | ||
2960 | * FIFO contents are flushed to DMA buffers with | ||
2961 | * end of frame (EOF) status | ||
2962 | */ | ||
2963 | static int set_xctrl(struct slgt_info *info, int xctrl) | ||
2964 | { | ||
2965 | unsigned long flags; | ||
2966 | |||
2967 | DBGINFO(("%s set_xctrl=%x)\n", info->device_name, xctrl)); | ||
2968 | spin_lock_irqsave(&info->lock, flags); | ||
2969 | info->xctrl = xctrl; | ||
2970 | wr_reg32(info, XCR, xctrl); | ||
2971 | spin_unlock_irqrestore(&info->lock, flags); | ||
2972 | return 0; | ||
2973 | } | ||
2974 | |||
2975 | /* | ||
2976 | * set general purpose IO pin state and direction | ||
2977 | * | ||
2978 | * user_gpio fields: | ||
2979 | * state each bit indicates a pin state | ||
2980 | * smask set bit indicates pin state to set | ||
2981 | * dir each bit indicates a pin direction (0=input, 1=output) | ||
2982 | * dmask set bit indicates pin direction to set | ||
2983 | */ | ||
2984 | static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
2985 | { | ||
2986 | unsigned long flags; | ||
2987 | struct gpio_desc gpio; | ||
2988 | __u32 data; | ||
2989 | |||
2990 | if (!info->gpio_present) | ||
2991 | return -EINVAL; | ||
2992 | if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) | ||
2993 | return -EFAULT; | ||
2994 | DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n", | ||
2995 | info->device_name, gpio.state, gpio.smask, | ||
2996 | gpio.dir, gpio.dmask)); | ||
2997 | |||
2998 | spin_lock_irqsave(&info->port_array[0]->lock, flags); | ||
2999 | if (gpio.dmask) { | ||
3000 | data = rd_reg32(info, IODR); | ||
3001 | data |= gpio.dmask & gpio.dir; | ||
3002 | data &= ~(gpio.dmask & ~gpio.dir); | ||
3003 | wr_reg32(info, IODR, data); | ||
3004 | } | ||
3005 | if (gpio.smask) { | ||
3006 | data = rd_reg32(info, IOVR); | ||
3007 | data |= gpio.smask & gpio.state; | ||
3008 | data &= ~(gpio.smask & ~gpio.state); | ||
3009 | wr_reg32(info, IOVR, data); | ||
3010 | } | ||
3011 | spin_unlock_irqrestore(&info->port_array[0]->lock, flags); | ||
3012 | |||
3013 | return 0; | ||
3014 | } | ||
3015 | |||
3016 | /* | ||
3017 | * get general purpose IO pin state and direction | ||
3018 | */ | ||
3019 | static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
3020 | { | ||
3021 | struct gpio_desc gpio; | ||
3022 | if (!info->gpio_present) | ||
3023 | return -EINVAL; | ||
3024 | gpio.state = rd_reg32(info, IOVR); | ||
3025 | gpio.smask = 0xffffffff; | ||
3026 | gpio.dir = rd_reg32(info, IODR); | ||
3027 | gpio.dmask = 0xffffffff; | ||
3028 | if (copy_to_user(user_gpio, &gpio, sizeof(gpio))) | ||
3029 | return -EFAULT; | ||
3030 | DBGINFO(("%s get_gpio state=%08x dir=%08x\n", | ||
3031 | info->device_name, gpio.state, gpio.dir)); | ||
3032 | return 0; | ||
3033 | } | ||
3034 | |||
3035 | /* | ||
3036 | * conditional wait facility | ||
3037 | */ | ||
3038 | static void init_cond_wait(struct cond_wait *w, unsigned int data) | ||
3039 | { | ||
3040 | init_waitqueue_head(&w->q); | ||
3041 | init_waitqueue_entry(&w->wait, current); | ||
3042 | w->data = data; | ||
3043 | } | ||
3044 | |||
3045 | static void add_cond_wait(struct cond_wait **head, struct cond_wait *w) | ||
3046 | { | ||
3047 | set_current_state(TASK_INTERRUPTIBLE); | ||
3048 | add_wait_queue(&w->q, &w->wait); | ||
3049 | w->next = *head; | ||
3050 | *head = w; | ||
3051 | } | ||
3052 | |||
3053 | static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw) | ||
3054 | { | ||
3055 | struct cond_wait *w, *prev; | ||
3056 | remove_wait_queue(&cw->q, &cw->wait); | ||
3057 | set_current_state(TASK_RUNNING); | ||
3058 | for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) { | ||
3059 | if (w == cw) { | ||
3060 | if (prev != NULL) | ||
3061 | prev->next = w->next; | ||
3062 | else | ||
3063 | *head = w->next; | ||
3064 | break; | ||
3065 | } | ||
3066 | } | ||
3067 | } | ||
3068 | |||
3069 | static void flush_cond_wait(struct cond_wait **head) | ||
3070 | { | ||
3071 | while (*head != NULL) { | ||
3072 | wake_up_interruptible(&(*head)->q); | ||
3073 | *head = (*head)->next; | ||
3074 | } | ||
3075 | } | ||
3076 | |||
3077 | /* | ||
3078 | * wait for general purpose I/O pin(s) to enter specified state | ||
3079 | * | ||
3080 | * user_gpio fields: | ||
3081 | * state - bit indicates target pin state | ||
3082 | * smask - set bit indicates watched pin | ||
3083 | * | ||
3084 | * The wait ends when at least one watched pin enters the specified | ||
3085 | * state. When 0 (no error) is returned, user_gpio->state is set to the | ||
3086 | * state of all GPIO pins when the wait ends. | ||
3087 | * | ||
3088 | * Note: Each pin may be a dedicated input, dedicated output, or | ||
3089 | * configurable input/output. The number and configuration of pins | ||
3090 | * varies with the specific adapter model. Only input pins (dedicated | ||
3091 | * or configured) can be monitored with this function. | ||
3092 | */ | ||
3093 | static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio) | ||
3094 | { | ||
3095 | unsigned long flags; | ||
3096 | int rc = 0; | ||
3097 | struct gpio_desc gpio; | ||
3098 | struct cond_wait wait; | ||
3099 | u32 state; | ||
3100 | |||
3101 | if (!info->gpio_present) | ||
3102 | return -EINVAL; | ||
3103 | if (copy_from_user(&gpio, user_gpio, sizeof(gpio))) | ||
3104 | return -EFAULT; | ||
3105 | DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n", | ||
3106 | info->device_name, gpio.state, gpio.smask)); | ||
3107 | /* ignore output pins identified by set IODR bit */ | ||
3108 | if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0) | ||
3109 | return -EINVAL; | ||
3110 | init_cond_wait(&wait, gpio.smask); | ||
3111 | |||
3112 | spin_lock_irqsave(&info->port_array[0]->lock, flags); | ||
3113 | /* enable interrupts for watched pins */ | ||
3114 | wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask); | ||
3115 | /* get current pin states */ | ||
3116 | state = rd_reg32(info, IOVR); | ||
3117 | |||
3118 | if (gpio.smask & ~(state ^ gpio.state)) { | ||
3119 | /* already in target state */ | ||
3120 | gpio.state = state; | ||
3121 | } else { | ||
3122 | /* wait for target state */ | ||
3123 | add_cond_wait(&info->gpio_wait_q, &wait); | ||
3124 | spin_unlock_irqrestore(&info->port_array[0]->lock, flags); | ||
3125 | schedule(); | ||
3126 | if (signal_pending(current)) | ||
3127 | rc = -ERESTARTSYS; | ||
3128 | else | ||
3129 | gpio.state = wait.data; | ||
3130 | spin_lock_irqsave(&info->port_array[0]->lock, flags); | ||
3131 | remove_cond_wait(&info->gpio_wait_q, &wait); | ||
3132 | } | ||
3133 | |||
3134 | /* disable all GPIO interrupts if no waiting processes */ | ||
3135 | if (info->gpio_wait_q == NULL) | ||
3136 | wr_reg32(info, IOER, 0); | ||
3137 | spin_unlock_irqrestore(&info->port_array[0]->lock, flags); | ||
3138 | |||
3139 | if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio))) | ||
3140 | rc = -EFAULT; | ||
3141 | return rc; | ||
3142 | } | ||
3143 | |||
3144 | static int modem_input_wait(struct slgt_info *info,int arg) | ||
3145 | { | ||
3146 | unsigned long flags; | ||
3147 | int rc; | ||
3148 | struct mgsl_icount cprev, cnow; | ||
3149 | DECLARE_WAITQUEUE(wait, current); | ||
3150 | |||
3151 | /* save current irq counts */ | ||
3152 | spin_lock_irqsave(&info->lock,flags); | ||
3153 | cprev = info->icount; | ||
3154 | add_wait_queue(&info->status_event_wait_q, &wait); | ||
3155 | set_current_state(TASK_INTERRUPTIBLE); | ||
3156 | spin_unlock_irqrestore(&info->lock,flags); | ||
3157 | |||
3158 | for(;;) { | ||
3159 | schedule(); | ||
3160 | if (signal_pending(current)) { | ||
3161 | rc = -ERESTARTSYS; | ||
3162 | break; | ||
3163 | } | ||
3164 | |||
3165 | /* get new irq counts */ | ||
3166 | spin_lock_irqsave(&info->lock,flags); | ||
3167 | cnow = info->icount; | ||
3168 | set_current_state(TASK_INTERRUPTIBLE); | ||
3169 | spin_unlock_irqrestore(&info->lock,flags); | ||
3170 | |||
3171 | /* if no change, wait aborted for some reason */ | ||
3172 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
3173 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { | ||
3174 | rc = -EIO; | ||
3175 | break; | ||
3176 | } | ||
3177 | |||
3178 | /* check for change in caller specified modem input */ | ||
3179 | if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || | ||
3180 | (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || | ||
3181 | (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || | ||
3182 | (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { | ||
3183 | rc = 0; | ||
3184 | break; | ||
3185 | } | ||
3186 | |||
3187 | cprev = cnow; | ||
3188 | } | ||
3189 | remove_wait_queue(&info->status_event_wait_q, &wait); | ||
3190 | set_current_state(TASK_RUNNING); | ||
3191 | return rc; | ||
3192 | } | ||
3193 | |||
3194 | /* | ||
3195 | * return state of serial control and status signals | ||
3196 | */ | ||
3197 | static int tiocmget(struct tty_struct *tty) | ||
3198 | { | ||
3199 | struct slgt_info *info = tty->driver_data; | ||
3200 | unsigned int result; | ||
3201 | unsigned long flags; | ||
3202 | |||
3203 | spin_lock_irqsave(&info->lock,flags); | ||
3204 | get_signals(info); | ||
3205 | spin_unlock_irqrestore(&info->lock,flags); | ||
3206 | |||
3207 | result = ((info->signals & SerialSignal_RTS) ? TIOCM_RTS:0) + | ||
3208 | ((info->signals & SerialSignal_DTR) ? TIOCM_DTR:0) + | ||
3209 | ((info->signals & SerialSignal_DCD) ? TIOCM_CAR:0) + | ||
3210 | ((info->signals & SerialSignal_RI) ? TIOCM_RNG:0) + | ||
3211 | ((info->signals & SerialSignal_DSR) ? TIOCM_DSR:0) + | ||
3212 | ((info->signals & SerialSignal_CTS) ? TIOCM_CTS:0); | ||
3213 | |||
3214 | DBGINFO(("%s tiocmget value=%08X\n", info->device_name, result)); | ||
3215 | return result; | ||
3216 | } | ||
3217 | |||
3218 | /* | ||
3219 | * set modem control signals (DTR/RTS) | ||
3220 | * | ||
3221 | * cmd signal command: TIOCMBIS = set bit TIOCMBIC = clear bit | ||
3222 | * TIOCMSET = set/clear signal values | ||
3223 | * value bit mask for command | ||
3224 | */ | ||
3225 | static int tiocmset(struct tty_struct *tty, | ||
3226 | unsigned int set, unsigned int clear) | ||
3227 | { | ||
3228 | struct slgt_info *info = tty->driver_data; | ||
3229 | unsigned long flags; | ||
3230 | |||
3231 | DBGINFO(("%s tiocmset(%x,%x)\n", info->device_name, set, clear)); | ||
3232 | |||
3233 | if (set & TIOCM_RTS) | ||
3234 | info->signals |= SerialSignal_RTS; | ||
3235 | if (set & TIOCM_DTR) | ||
3236 | info->signals |= SerialSignal_DTR; | ||
3237 | if (clear & TIOCM_RTS) | ||
3238 | info->signals &= ~SerialSignal_RTS; | ||
3239 | if (clear & TIOCM_DTR) | ||
3240 | info->signals &= ~SerialSignal_DTR; | ||
3241 | |||
3242 | spin_lock_irqsave(&info->lock,flags); | ||
3243 | set_signals(info); | ||
3244 | spin_unlock_irqrestore(&info->lock,flags); | ||
3245 | return 0; | ||
3246 | } | ||
3247 | |||
3248 | static int carrier_raised(struct tty_port *port) | ||
3249 | { | ||
3250 | unsigned long flags; | ||
3251 | struct slgt_info *info = container_of(port, struct slgt_info, port); | ||
3252 | |||
3253 | spin_lock_irqsave(&info->lock,flags); | ||
3254 | get_signals(info); | ||
3255 | spin_unlock_irqrestore(&info->lock,flags); | ||
3256 | return (info->signals & SerialSignal_DCD) ? 1 : 0; | ||
3257 | } | ||
3258 | |||
3259 | static void dtr_rts(struct tty_port *port, int on) | ||
3260 | { | ||
3261 | unsigned long flags; | ||
3262 | struct slgt_info *info = container_of(port, struct slgt_info, port); | ||
3263 | |||
3264 | spin_lock_irqsave(&info->lock,flags); | ||
3265 | if (on) | ||
3266 | info->signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
3267 | else | ||
3268 | info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
3269 | set_signals(info); | ||
3270 | spin_unlock_irqrestore(&info->lock,flags); | ||
3271 | } | ||
3272 | |||
3273 | |||
3274 | /* | ||
3275 | * block current process until the device is ready to open | ||
3276 | */ | ||
3277 | static int block_til_ready(struct tty_struct *tty, struct file *filp, | ||
3278 | struct slgt_info *info) | ||
3279 | { | ||
3280 | DECLARE_WAITQUEUE(wait, current); | ||
3281 | int retval; | ||
3282 | bool do_clocal = false; | ||
3283 | bool extra_count = false; | ||
3284 | unsigned long flags; | ||
3285 | int cd; | ||
3286 | struct tty_port *port = &info->port; | ||
3287 | |||
3288 | DBGINFO(("%s block_til_ready\n", tty->driver->name)); | ||
3289 | |||
3290 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ | ||
3291 | /* nonblock mode is set or port is not enabled */ | ||
3292 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3293 | return 0; | ||
3294 | } | ||
3295 | |||
3296 | if (tty->termios->c_cflag & CLOCAL) | ||
3297 | do_clocal = true; | ||
3298 | |||
3299 | /* Wait for carrier detect and the line to become | ||
3300 | * free (i.e., not in use by the callout). While we are in | ||
3301 | * this loop, port->count is dropped by one, so that | ||
3302 | * close() knows when to free things. We restore it upon | ||
3303 | * exit, either normal or abnormal. | ||
3304 | */ | ||
3305 | |||
3306 | retval = 0; | ||
3307 | add_wait_queue(&port->open_wait, &wait); | ||
3308 | |||
3309 | spin_lock_irqsave(&info->lock, flags); | ||
3310 | if (!tty_hung_up_p(filp)) { | ||
3311 | extra_count = true; | ||
3312 | port->count--; | ||
3313 | } | ||
3314 | spin_unlock_irqrestore(&info->lock, flags); | ||
3315 | port->blocked_open++; | ||
3316 | |||
3317 | while (1) { | ||
3318 | if ((tty->termios->c_cflag & CBAUD)) | ||
3319 | tty_port_raise_dtr_rts(port); | ||
3320 | |||
3321 | set_current_state(TASK_INTERRUPTIBLE); | ||
3322 | |||
3323 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ | ||
3324 | retval = (port->flags & ASYNC_HUP_NOTIFY) ? | ||
3325 | -EAGAIN : -ERESTARTSYS; | ||
3326 | break; | ||
3327 | } | ||
3328 | |||
3329 | cd = tty_port_carrier_raised(port); | ||
3330 | |||
3331 | if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd )) | ||
3332 | break; | ||
3333 | |||
3334 | if (signal_pending(current)) { | ||
3335 | retval = -ERESTARTSYS; | ||
3336 | break; | ||
3337 | } | ||
3338 | |||
3339 | DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); | ||
3340 | tty_unlock(); | ||
3341 | schedule(); | ||
3342 | tty_lock(); | ||
3343 | } | ||
3344 | |||
3345 | set_current_state(TASK_RUNNING); | ||
3346 | remove_wait_queue(&port->open_wait, &wait); | ||
3347 | |||
3348 | if (extra_count) | ||
3349 | port->count++; | ||
3350 | port->blocked_open--; | ||
3351 | |||
3352 | if (!retval) | ||
3353 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3354 | |||
3355 | DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval)); | ||
3356 | return retval; | ||
3357 | } | ||
3358 | |||
3359 | static int alloc_tmp_rbuf(struct slgt_info *info) | ||
3360 | { | ||
3361 | info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL); | ||
3362 | if (info->tmp_rbuf == NULL) | ||
3363 | return -ENOMEM; | ||
3364 | return 0; | ||
3365 | } | ||
3366 | |||
3367 | static void free_tmp_rbuf(struct slgt_info *info) | ||
3368 | { | ||
3369 | kfree(info->tmp_rbuf); | ||
3370 | info->tmp_rbuf = NULL; | ||
3371 | } | ||
3372 | |||
3373 | /* | ||
3374 | * allocate DMA descriptor lists. | ||
3375 | */ | ||
3376 | static int alloc_desc(struct slgt_info *info) | ||
3377 | { | ||
3378 | unsigned int i; | ||
3379 | unsigned int pbufs; | ||
3380 | |||
3381 | /* allocate memory to hold descriptor lists */ | ||
3382 | info->bufs = pci_alloc_consistent(info->pdev, DESC_LIST_SIZE, &info->bufs_dma_addr); | ||
3383 | if (info->bufs == NULL) | ||
3384 | return -ENOMEM; | ||
3385 | |||
3386 | memset(info->bufs, 0, DESC_LIST_SIZE); | ||
3387 | |||
3388 | info->rbufs = (struct slgt_desc*)info->bufs; | ||
3389 | info->tbufs = ((struct slgt_desc*)info->bufs) + info->rbuf_count; | ||
3390 | |||
3391 | pbufs = (unsigned int)info->bufs_dma_addr; | ||
3392 | |||
3393 | /* | ||
3394 | * Build circular lists of descriptors | ||
3395 | */ | ||
3396 | |||
3397 | for (i=0; i < info->rbuf_count; i++) { | ||
3398 | /* physical address of this descriptor */ | ||
3399 | info->rbufs[i].pdesc = pbufs + (i * sizeof(struct slgt_desc)); | ||
3400 | |||
3401 | /* physical address of next descriptor */ | ||
3402 | if (i == info->rbuf_count - 1) | ||
3403 | info->rbufs[i].next = cpu_to_le32(pbufs); | ||
3404 | else | ||
3405 | info->rbufs[i].next = cpu_to_le32(pbufs + ((i+1) * sizeof(struct slgt_desc))); | ||
3406 | set_desc_count(info->rbufs[i], DMABUFSIZE); | ||
3407 | } | ||
3408 | |||
3409 | for (i=0; i < info->tbuf_count; i++) { | ||
3410 | /* physical address of this descriptor */ | ||
3411 | info->tbufs[i].pdesc = pbufs + ((info->rbuf_count + i) * sizeof(struct slgt_desc)); | ||
3412 | |||
3413 | /* physical address of next descriptor */ | ||
3414 | if (i == info->tbuf_count - 1) | ||
3415 | info->tbufs[i].next = cpu_to_le32(pbufs + info->rbuf_count * sizeof(struct slgt_desc)); | ||
3416 | else | ||
3417 | info->tbufs[i].next = cpu_to_le32(pbufs + ((info->rbuf_count + i + 1) * sizeof(struct slgt_desc))); | ||
3418 | } | ||
3419 | |||
3420 | return 0; | ||
3421 | } | ||
3422 | |||
3423 | static void free_desc(struct slgt_info *info) | ||
3424 | { | ||
3425 | if (info->bufs != NULL) { | ||
3426 | pci_free_consistent(info->pdev, DESC_LIST_SIZE, info->bufs, info->bufs_dma_addr); | ||
3427 | info->bufs = NULL; | ||
3428 | info->rbufs = NULL; | ||
3429 | info->tbufs = NULL; | ||
3430 | } | ||
3431 | } | ||
3432 | |||
3433 | static int alloc_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) | ||
3434 | { | ||
3435 | int i; | ||
3436 | for (i=0; i < count; i++) { | ||
3437 | if ((bufs[i].buf = pci_alloc_consistent(info->pdev, DMABUFSIZE, &bufs[i].buf_dma_addr)) == NULL) | ||
3438 | return -ENOMEM; | ||
3439 | bufs[i].pbuf = cpu_to_le32((unsigned int)bufs[i].buf_dma_addr); | ||
3440 | } | ||
3441 | return 0; | ||
3442 | } | ||
3443 | |||
3444 | static void free_bufs(struct slgt_info *info, struct slgt_desc *bufs, int count) | ||
3445 | { | ||
3446 | int i; | ||
3447 | for (i=0; i < count; i++) { | ||
3448 | if (bufs[i].buf == NULL) | ||
3449 | continue; | ||
3450 | pci_free_consistent(info->pdev, DMABUFSIZE, bufs[i].buf, bufs[i].buf_dma_addr); | ||
3451 | bufs[i].buf = NULL; | ||
3452 | } | ||
3453 | } | ||
3454 | |||
3455 | static int alloc_dma_bufs(struct slgt_info *info) | ||
3456 | { | ||
3457 | info->rbuf_count = 32; | ||
3458 | info->tbuf_count = 32; | ||
3459 | |||
3460 | if (alloc_desc(info) < 0 || | ||
3461 | alloc_bufs(info, info->rbufs, info->rbuf_count) < 0 || | ||
3462 | alloc_bufs(info, info->tbufs, info->tbuf_count) < 0 || | ||
3463 | alloc_tmp_rbuf(info) < 0) { | ||
3464 | DBGERR(("%s DMA buffer alloc fail\n", info->device_name)); | ||
3465 | return -ENOMEM; | ||
3466 | } | ||
3467 | reset_rbufs(info); | ||
3468 | return 0; | ||
3469 | } | ||
3470 | |||
3471 | static void free_dma_bufs(struct slgt_info *info) | ||
3472 | { | ||
3473 | if (info->bufs) { | ||
3474 | free_bufs(info, info->rbufs, info->rbuf_count); | ||
3475 | free_bufs(info, info->tbufs, info->tbuf_count); | ||
3476 | free_desc(info); | ||
3477 | } | ||
3478 | free_tmp_rbuf(info); | ||
3479 | } | ||
3480 | |||
3481 | static int claim_resources(struct slgt_info *info) | ||
3482 | { | ||
3483 | if (request_mem_region(info->phys_reg_addr, SLGT_REG_SIZE, "synclink_gt") == NULL) { | ||
3484 | DBGERR(("%s reg addr conflict, addr=%08X\n", | ||
3485 | info->device_name, info->phys_reg_addr)); | ||
3486 | info->init_error = DiagStatus_AddressConflict; | ||
3487 | goto errout; | ||
3488 | } | ||
3489 | else | ||
3490 | info->reg_addr_requested = true; | ||
3491 | |||
3492 | info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE); | ||
3493 | if (!info->reg_addr) { | ||
3494 | DBGERR(("%s cant map device registers, addr=%08X\n", | ||
3495 | info->device_name, info->phys_reg_addr)); | ||
3496 | info->init_error = DiagStatus_CantAssignPciResources; | ||
3497 | goto errout; | ||
3498 | } | ||
3499 | return 0; | ||
3500 | |||
3501 | errout: | ||
3502 | release_resources(info); | ||
3503 | return -ENODEV; | ||
3504 | } | ||
3505 | |||
3506 | static void release_resources(struct slgt_info *info) | ||
3507 | { | ||
3508 | if (info->irq_requested) { | ||
3509 | free_irq(info->irq_level, info); | ||
3510 | info->irq_requested = false; | ||
3511 | } | ||
3512 | |||
3513 | if (info->reg_addr_requested) { | ||
3514 | release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE); | ||
3515 | info->reg_addr_requested = false; | ||
3516 | } | ||
3517 | |||
3518 | if (info->reg_addr) { | ||
3519 | iounmap(info->reg_addr); | ||
3520 | info->reg_addr = NULL; | ||
3521 | } | ||
3522 | } | ||
3523 | |||
3524 | /* Add the specified device instance data structure to the | ||
3525 | * global linked list of devices and increment the device count. | ||
3526 | */ | ||
3527 | static void add_device(struct slgt_info *info) | ||
3528 | { | ||
3529 | char *devstr; | ||
3530 | |||
3531 | info->next_device = NULL; | ||
3532 | info->line = slgt_device_count; | ||
3533 | sprintf(info->device_name, "%s%d", tty_dev_prefix, info->line); | ||
3534 | |||
3535 | if (info->line < MAX_DEVICES) { | ||
3536 | if (maxframe[info->line]) | ||
3537 | info->max_frame_size = maxframe[info->line]; | ||
3538 | } | ||
3539 | |||
3540 | slgt_device_count++; | ||
3541 | |||
3542 | if (!slgt_device_list) | ||
3543 | slgt_device_list = info; | ||
3544 | else { | ||
3545 | struct slgt_info *current_dev = slgt_device_list; | ||
3546 | while(current_dev->next_device) | ||
3547 | current_dev = current_dev->next_device; | ||
3548 | current_dev->next_device = info; | ||
3549 | } | ||
3550 | |||
3551 | if (info->max_frame_size < 4096) | ||
3552 | info->max_frame_size = 4096; | ||
3553 | else if (info->max_frame_size > 65535) | ||
3554 | info->max_frame_size = 65535; | ||
3555 | |||
3556 | switch(info->pdev->device) { | ||
3557 | case SYNCLINK_GT_DEVICE_ID: | ||
3558 | devstr = "GT"; | ||
3559 | break; | ||
3560 | case SYNCLINK_GT2_DEVICE_ID: | ||
3561 | devstr = "GT2"; | ||
3562 | break; | ||
3563 | case SYNCLINK_GT4_DEVICE_ID: | ||
3564 | devstr = "GT4"; | ||
3565 | break; | ||
3566 | case SYNCLINK_AC_DEVICE_ID: | ||
3567 | devstr = "AC"; | ||
3568 | info->params.mode = MGSL_MODE_ASYNC; | ||
3569 | break; | ||
3570 | default: | ||
3571 | devstr = "(unknown model)"; | ||
3572 | } | ||
3573 | printk("SyncLink %s %s IO=%08x IRQ=%d MaxFrameSize=%u\n", | ||
3574 | devstr, info->device_name, info->phys_reg_addr, | ||
3575 | info->irq_level, info->max_frame_size); | ||
3576 | |||
3577 | #if SYNCLINK_GENERIC_HDLC | ||
3578 | hdlcdev_init(info); | ||
3579 | #endif | ||
3580 | } | ||
3581 | |||
3582 | static const struct tty_port_operations slgt_port_ops = { | ||
3583 | .carrier_raised = carrier_raised, | ||
3584 | .dtr_rts = dtr_rts, | ||
3585 | }; | ||
3586 | |||
3587 | /* | ||
3588 | * allocate device instance structure, return NULL on failure | ||
3589 | */ | ||
3590 | static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) | ||
3591 | { | ||
3592 | struct slgt_info *info; | ||
3593 | |||
3594 | info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL); | ||
3595 | |||
3596 | if (!info) { | ||
3597 | DBGERR(("%s device alloc failed adapter=%d port=%d\n", | ||
3598 | driver_name, adapter_num, port_num)); | ||
3599 | } else { | ||
3600 | tty_port_init(&info->port); | ||
3601 | info->port.ops = &slgt_port_ops; | ||
3602 | info->magic = MGSL_MAGIC; | ||
3603 | INIT_WORK(&info->task, bh_handler); | ||
3604 | info->max_frame_size = 4096; | ||
3605 | info->base_clock = 14745600; | ||
3606 | info->rbuf_fill_level = DMABUFSIZE; | ||
3607 | info->port.close_delay = 5*HZ/10; | ||
3608 | info->port.closing_wait = 30*HZ; | ||
3609 | init_waitqueue_head(&info->status_event_wait_q); | ||
3610 | init_waitqueue_head(&info->event_wait_q); | ||
3611 | spin_lock_init(&info->netlock); | ||
3612 | memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); | ||
3613 | info->idle_mode = HDLC_TXIDLE_FLAGS; | ||
3614 | info->adapter_num = adapter_num; | ||
3615 | info->port_num = port_num; | ||
3616 | |||
3617 | setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); | ||
3618 | setup_timer(&info->rx_timer, rx_timeout, (unsigned long)info); | ||
3619 | |||
3620 | /* Copy configuration info to device instance data */ | ||
3621 | info->pdev = pdev; | ||
3622 | info->irq_level = pdev->irq; | ||
3623 | info->phys_reg_addr = pci_resource_start(pdev,0); | ||
3624 | |||
3625 | info->bus_type = MGSL_BUS_TYPE_PCI; | ||
3626 | info->irq_flags = IRQF_SHARED; | ||
3627 | |||
3628 | info->init_error = -1; /* assume error, set to 0 on successful init */ | ||
3629 | } | ||
3630 | |||
3631 | return info; | ||
3632 | } | ||
3633 | |||
3634 | static void device_init(int adapter_num, struct pci_dev *pdev) | ||
3635 | { | ||
3636 | struct slgt_info *port_array[SLGT_MAX_PORTS]; | ||
3637 | int i; | ||
3638 | int port_count = 1; | ||
3639 | |||
3640 | if (pdev->device == SYNCLINK_GT2_DEVICE_ID) | ||
3641 | port_count = 2; | ||
3642 | else if (pdev->device == SYNCLINK_GT4_DEVICE_ID) | ||
3643 | port_count = 4; | ||
3644 | |||
3645 | /* allocate device instances for all ports */ | ||
3646 | for (i=0; i < port_count; ++i) { | ||
3647 | port_array[i] = alloc_dev(adapter_num, i, pdev); | ||
3648 | if (port_array[i] == NULL) { | ||
3649 | for (--i; i >= 0; --i) | ||
3650 | kfree(port_array[i]); | ||
3651 | return; | ||
3652 | } | ||
3653 | } | ||
3654 | |||
3655 | /* give copy of port_array to all ports and add to device list */ | ||
3656 | for (i=0; i < port_count; ++i) { | ||
3657 | memcpy(port_array[i]->port_array, port_array, sizeof(port_array)); | ||
3658 | add_device(port_array[i]); | ||
3659 | port_array[i]->port_count = port_count; | ||
3660 | spin_lock_init(&port_array[i]->lock); | ||
3661 | } | ||
3662 | |||
3663 | /* Allocate and claim adapter resources */ | ||
3664 | if (!claim_resources(port_array[0])) { | ||
3665 | |||
3666 | alloc_dma_bufs(port_array[0]); | ||
3667 | |||
3668 | /* copy resource information from first port to others */ | ||
3669 | for (i = 1; i < port_count; ++i) { | ||
3670 | port_array[i]->irq_level = port_array[0]->irq_level; | ||
3671 | port_array[i]->reg_addr = port_array[0]->reg_addr; | ||
3672 | alloc_dma_bufs(port_array[i]); | ||
3673 | } | ||
3674 | |||
3675 | if (request_irq(port_array[0]->irq_level, | ||
3676 | slgt_interrupt, | ||
3677 | port_array[0]->irq_flags, | ||
3678 | port_array[0]->device_name, | ||
3679 | port_array[0]) < 0) { | ||
3680 | DBGERR(("%s request_irq failed IRQ=%d\n", | ||
3681 | port_array[0]->device_name, | ||
3682 | port_array[0]->irq_level)); | ||
3683 | } else { | ||
3684 | port_array[0]->irq_requested = true; | ||
3685 | adapter_test(port_array[0]); | ||
3686 | for (i=1 ; i < port_count ; i++) { | ||
3687 | port_array[i]->init_error = port_array[0]->init_error; | ||
3688 | port_array[i]->gpio_present = port_array[0]->gpio_present; | ||
3689 | } | ||
3690 | } | ||
3691 | } | ||
3692 | |||
3693 | for (i=0; i < port_count; ++i) | ||
3694 | tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev)); | ||
3695 | } | ||
3696 | |||
3697 | static int __devinit init_one(struct pci_dev *dev, | ||
3698 | const struct pci_device_id *ent) | ||
3699 | { | ||
3700 | if (pci_enable_device(dev)) { | ||
3701 | printk("error enabling pci device %p\n", dev); | ||
3702 | return -EIO; | ||
3703 | } | ||
3704 | pci_set_master(dev); | ||
3705 | device_init(slgt_device_count, dev); | ||
3706 | return 0; | ||
3707 | } | ||
3708 | |||
3709 | static void __devexit remove_one(struct pci_dev *dev) | ||
3710 | { | ||
3711 | } | ||
3712 | |||
3713 | static const struct tty_operations ops = { | ||
3714 | .open = open, | ||
3715 | .close = close, | ||
3716 | .write = write, | ||
3717 | .put_char = put_char, | ||
3718 | .flush_chars = flush_chars, | ||
3719 | .write_room = write_room, | ||
3720 | .chars_in_buffer = chars_in_buffer, | ||
3721 | .flush_buffer = flush_buffer, | ||
3722 | .ioctl = ioctl, | ||
3723 | .compat_ioctl = slgt_compat_ioctl, | ||
3724 | .throttle = throttle, | ||
3725 | .unthrottle = unthrottle, | ||
3726 | .send_xchar = send_xchar, | ||
3727 | .break_ctl = set_break, | ||
3728 | .wait_until_sent = wait_until_sent, | ||
3729 | .set_termios = set_termios, | ||
3730 | .stop = tx_hold, | ||
3731 | .start = tx_release, | ||
3732 | .hangup = hangup, | ||
3733 | .tiocmget = tiocmget, | ||
3734 | .tiocmset = tiocmset, | ||
3735 | .get_icount = get_icount, | ||
3736 | .proc_fops = &synclink_gt_proc_fops, | ||
3737 | }; | ||
3738 | |||
3739 | static void slgt_cleanup(void) | ||
3740 | { | ||
3741 | int rc; | ||
3742 | struct slgt_info *info; | ||
3743 | struct slgt_info *tmp; | ||
3744 | |||
3745 | printk(KERN_INFO "unload %s\n", driver_name); | ||
3746 | |||
3747 | if (serial_driver) { | ||
3748 | for (info=slgt_device_list ; info != NULL ; info=info->next_device) | ||
3749 | tty_unregister_device(serial_driver, info->line); | ||
3750 | if ((rc = tty_unregister_driver(serial_driver))) | ||
3751 | DBGERR(("tty_unregister_driver error=%d\n", rc)); | ||
3752 | put_tty_driver(serial_driver); | ||
3753 | } | ||
3754 | |||
3755 | /* reset devices */ | ||
3756 | info = slgt_device_list; | ||
3757 | while(info) { | ||
3758 | reset_port(info); | ||
3759 | info = info->next_device; | ||
3760 | } | ||
3761 | |||
3762 | /* release devices */ | ||
3763 | info = slgt_device_list; | ||
3764 | while(info) { | ||
3765 | #if SYNCLINK_GENERIC_HDLC | ||
3766 | hdlcdev_exit(info); | ||
3767 | #endif | ||
3768 | free_dma_bufs(info); | ||
3769 | free_tmp_rbuf(info); | ||
3770 | if (info->port_num == 0) | ||
3771 | release_resources(info); | ||
3772 | tmp = info; | ||
3773 | info = info->next_device; | ||
3774 | kfree(tmp); | ||
3775 | } | ||
3776 | |||
3777 | if (pci_registered) | ||
3778 | pci_unregister_driver(&pci_driver); | ||
3779 | } | ||
3780 | |||
3781 | /* | ||
3782 | * Driver initialization entry point. | ||
3783 | */ | ||
3784 | static int __init slgt_init(void) | ||
3785 | { | ||
3786 | int rc; | ||
3787 | |||
3788 | printk(KERN_INFO "%s\n", driver_name); | ||
3789 | |||
3790 | serial_driver = alloc_tty_driver(MAX_DEVICES); | ||
3791 | if (!serial_driver) { | ||
3792 | printk("%s can't allocate tty driver\n", driver_name); | ||
3793 | return -ENOMEM; | ||
3794 | } | ||
3795 | |||
3796 | /* Initialize the tty_driver structure */ | ||
3797 | |||
3798 | serial_driver->owner = THIS_MODULE; | ||
3799 | serial_driver->driver_name = tty_driver_name; | ||
3800 | serial_driver->name = tty_dev_prefix; | ||
3801 | serial_driver->major = ttymajor; | ||
3802 | serial_driver->minor_start = 64; | ||
3803 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
3804 | serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
3805 | serial_driver->init_termios = tty_std_termios; | ||
3806 | serial_driver->init_termios.c_cflag = | ||
3807 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
3808 | serial_driver->init_termios.c_ispeed = 9600; | ||
3809 | serial_driver->init_termios.c_ospeed = 9600; | ||
3810 | serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; | ||
3811 | tty_set_operations(serial_driver, &ops); | ||
3812 | if ((rc = tty_register_driver(serial_driver)) < 0) { | ||
3813 | DBGERR(("%s can't register serial driver\n", driver_name)); | ||
3814 | put_tty_driver(serial_driver); | ||
3815 | serial_driver = NULL; | ||
3816 | goto error; | ||
3817 | } | ||
3818 | |||
3819 | printk(KERN_INFO "%s, tty major#%d\n", | ||
3820 | driver_name, serial_driver->major); | ||
3821 | |||
3822 | slgt_device_count = 0; | ||
3823 | if ((rc = pci_register_driver(&pci_driver)) < 0) { | ||
3824 | printk("%s pci_register_driver error=%d\n", driver_name, rc); | ||
3825 | goto error; | ||
3826 | } | ||
3827 | pci_registered = true; | ||
3828 | |||
3829 | if (!slgt_device_list) | ||
3830 | printk("%s no devices found\n",driver_name); | ||
3831 | |||
3832 | return 0; | ||
3833 | |||
3834 | error: | ||
3835 | slgt_cleanup(); | ||
3836 | return rc; | ||
3837 | } | ||
3838 | |||
3839 | static void __exit slgt_exit(void) | ||
3840 | { | ||
3841 | slgt_cleanup(); | ||
3842 | } | ||
3843 | |||
3844 | module_init(slgt_init); | ||
3845 | module_exit(slgt_exit); | ||
3846 | |||
3847 | /* | ||
3848 | * register access routines | ||
3849 | */ | ||
3850 | |||
3851 | #define CALC_REGADDR() \ | ||
3852 | unsigned long reg_addr = ((unsigned long)info->reg_addr) + addr; \ | ||
3853 | if (addr >= 0x80) \ | ||
3854 | reg_addr += (info->port_num) * 32; \ | ||
3855 | else if (addr >= 0x40) \ | ||
3856 | reg_addr += (info->port_num) * 16; | ||
3857 | |||
3858 | static __u8 rd_reg8(struct slgt_info *info, unsigned int addr) | ||
3859 | { | ||
3860 | CALC_REGADDR(); | ||
3861 | return readb((void __iomem *)reg_addr); | ||
3862 | } | ||
3863 | |||
3864 | static void wr_reg8(struct slgt_info *info, unsigned int addr, __u8 value) | ||
3865 | { | ||
3866 | CALC_REGADDR(); | ||
3867 | writeb(value, (void __iomem *)reg_addr); | ||
3868 | } | ||
3869 | |||
3870 | static __u16 rd_reg16(struct slgt_info *info, unsigned int addr) | ||
3871 | { | ||
3872 | CALC_REGADDR(); | ||
3873 | return readw((void __iomem *)reg_addr); | ||
3874 | } | ||
3875 | |||
3876 | static void wr_reg16(struct slgt_info *info, unsigned int addr, __u16 value) | ||
3877 | { | ||
3878 | CALC_REGADDR(); | ||
3879 | writew(value, (void __iomem *)reg_addr); | ||
3880 | } | ||
3881 | |||
3882 | static __u32 rd_reg32(struct slgt_info *info, unsigned int addr) | ||
3883 | { | ||
3884 | CALC_REGADDR(); | ||
3885 | return readl((void __iomem *)reg_addr); | ||
3886 | } | ||
3887 | |||
3888 | static void wr_reg32(struct slgt_info *info, unsigned int addr, __u32 value) | ||
3889 | { | ||
3890 | CALC_REGADDR(); | ||
3891 | writel(value, (void __iomem *)reg_addr); | ||
3892 | } | ||
3893 | |||
3894 | static void rdma_reset(struct slgt_info *info) | ||
3895 | { | ||
3896 | unsigned int i; | ||
3897 | |||
3898 | /* set reset bit */ | ||
3899 | wr_reg32(info, RDCSR, BIT1); | ||
3900 | |||
3901 | /* wait for enable bit cleared */ | ||
3902 | for(i=0 ; i < 1000 ; i++) | ||
3903 | if (!(rd_reg32(info, RDCSR) & BIT0)) | ||
3904 | break; | ||
3905 | } | ||
3906 | |||
3907 | static void tdma_reset(struct slgt_info *info) | ||
3908 | { | ||
3909 | unsigned int i; | ||
3910 | |||
3911 | /* set reset bit */ | ||
3912 | wr_reg32(info, TDCSR, BIT1); | ||
3913 | |||
3914 | /* wait for enable bit cleared */ | ||
3915 | for(i=0 ; i < 1000 ; i++) | ||
3916 | if (!(rd_reg32(info, TDCSR) & BIT0)) | ||
3917 | break; | ||
3918 | } | ||
3919 | |||
3920 | /* | ||
3921 | * enable internal loopback | ||
3922 | * TxCLK and RxCLK are generated from BRG | ||
3923 | * and TxD is looped back to RxD internally. | ||
3924 | */ | ||
3925 | static void enable_loopback(struct slgt_info *info) | ||
3926 | { | ||
3927 | /* SCR (serial control) BIT2=looopback enable */ | ||
3928 | wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT2)); | ||
3929 | |||
3930 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
3931 | /* CCR (clock control) | ||
3932 | * 07..05 tx clock source (010 = BRG) | ||
3933 | * 04..02 rx clock source (010 = BRG) | ||
3934 | * 01 auxclk enable (0 = disable) | ||
3935 | * 00 BRG enable (1 = enable) | ||
3936 | * | ||
3937 | * 0100 1001 | ||
3938 | */ | ||
3939 | wr_reg8(info, CCR, 0x49); | ||
3940 | |||
3941 | /* set speed if available, otherwise use default */ | ||
3942 | if (info->params.clock_speed) | ||
3943 | set_rate(info, info->params.clock_speed); | ||
3944 | else | ||
3945 | set_rate(info, 3686400); | ||
3946 | } | ||
3947 | } | ||
3948 | |||
3949 | /* | ||
3950 | * set baud rate generator to specified rate | ||
3951 | */ | ||
3952 | static void set_rate(struct slgt_info *info, u32 rate) | ||
3953 | { | ||
3954 | unsigned int div; | ||
3955 | unsigned int osc = info->base_clock; | ||
3956 | |||
3957 | /* div = osc/rate - 1 | ||
3958 | * | ||
3959 | * Round div up if osc/rate is not integer to | ||
3960 | * force to next slowest rate. | ||
3961 | */ | ||
3962 | |||
3963 | if (rate) { | ||
3964 | div = osc/rate; | ||
3965 | if (!(osc % rate) && div) | ||
3966 | div--; | ||
3967 | wr_reg16(info, BDR, (unsigned short)div); | ||
3968 | } | ||
3969 | } | ||
3970 | |||
3971 | static void rx_stop(struct slgt_info *info) | ||
3972 | { | ||
3973 | unsigned short val; | ||
3974 | |||
3975 | /* disable and reset receiver */ | ||
3976 | val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ | ||
3977 | wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ | ||
3978 | wr_reg16(info, RCR, val); /* clear reset bit */ | ||
3979 | |||
3980 | slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA + IRQ_RXIDLE); | ||
3981 | |||
3982 | /* clear pending rx interrupts */ | ||
3983 | wr_reg16(info, SSR, IRQ_RXIDLE + IRQ_RXOVER); | ||
3984 | |||
3985 | rdma_reset(info); | ||
3986 | |||
3987 | info->rx_enabled = false; | ||
3988 | info->rx_restart = false; | ||
3989 | } | ||
3990 | |||
3991 | static void rx_start(struct slgt_info *info) | ||
3992 | { | ||
3993 | unsigned short val; | ||
3994 | |||
3995 | slgt_irq_off(info, IRQ_RXOVER + IRQ_RXDATA); | ||
3996 | |||
3997 | /* clear pending rx overrun IRQ */ | ||
3998 | wr_reg16(info, SSR, IRQ_RXOVER); | ||
3999 | |||
4000 | /* reset and disable receiver */ | ||
4001 | val = rd_reg16(info, RCR) & ~BIT1; /* clear enable bit */ | ||
4002 | wr_reg16(info, RCR, (unsigned short)(val | BIT2)); /* set reset bit */ | ||
4003 | wr_reg16(info, RCR, val); /* clear reset bit */ | ||
4004 | |||
4005 | rdma_reset(info); | ||
4006 | reset_rbufs(info); | ||
4007 | |||
4008 | if (info->rx_pio) { | ||
4009 | /* rx request when rx FIFO not empty */ | ||
4010 | wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14)); | ||
4011 | slgt_irq_on(info, IRQ_RXDATA); | ||
4012 | if (info->params.mode == MGSL_MODE_ASYNC) { | ||
4013 | /* enable saving of rx status */ | ||
4014 | wr_reg32(info, RDCSR, BIT6); | ||
4015 | } | ||
4016 | } else { | ||
4017 | /* rx request when rx FIFO half full */ | ||
4018 | wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14)); | ||
4019 | /* set 1st descriptor address */ | ||
4020 | wr_reg32(info, RDDAR, info->rbufs[0].pdesc); | ||
4021 | |||
4022 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
4023 | /* enable rx DMA and DMA interrupt */ | ||
4024 | wr_reg32(info, RDCSR, (BIT2 + BIT0)); | ||
4025 | } else { | ||
4026 | /* enable saving of rx status, rx DMA and DMA interrupt */ | ||
4027 | wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); | ||
4028 | } | ||
4029 | } | ||
4030 | |||
4031 | slgt_irq_on(info, IRQ_RXOVER); | ||
4032 | |||
4033 | /* enable receiver */ | ||
4034 | wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1)); | ||
4035 | |||
4036 | info->rx_restart = false; | ||
4037 | info->rx_enabled = true; | ||
4038 | } | ||
4039 | |||
4040 | static void tx_start(struct slgt_info *info) | ||
4041 | { | ||
4042 | if (!info->tx_enabled) { | ||
4043 | wr_reg16(info, TCR, | ||
4044 | (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2)); | ||
4045 | info->tx_enabled = true; | ||
4046 | } | ||
4047 | |||
4048 | if (desc_count(info->tbufs[info->tbuf_start])) { | ||
4049 | info->drop_rts_on_tx_done = false; | ||
4050 | |||
4051 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
4052 | if (info->params.flags & HDLC_FLAG_AUTO_RTS) { | ||
4053 | get_signals(info); | ||
4054 | if (!(info->signals & SerialSignal_RTS)) { | ||
4055 | info->signals |= SerialSignal_RTS; | ||
4056 | set_signals(info); | ||
4057 | info->drop_rts_on_tx_done = true; | ||
4058 | } | ||
4059 | } | ||
4060 | |||
4061 | slgt_irq_off(info, IRQ_TXDATA); | ||
4062 | slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE); | ||
4063 | /* clear tx idle and underrun status bits */ | ||
4064 | wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); | ||
4065 | } else { | ||
4066 | slgt_irq_off(info, IRQ_TXDATA); | ||
4067 | slgt_irq_on(info, IRQ_TXIDLE); | ||
4068 | /* clear tx idle status bit */ | ||
4069 | wr_reg16(info, SSR, IRQ_TXIDLE); | ||
4070 | } | ||
4071 | /* set 1st descriptor address and start DMA */ | ||
4072 | wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc); | ||
4073 | wr_reg32(info, TDCSR, BIT2 + BIT0); | ||
4074 | info->tx_active = true; | ||
4075 | } | ||
4076 | } | ||
4077 | |||
4078 | static void tx_stop(struct slgt_info *info) | ||
4079 | { | ||
4080 | unsigned short val; | ||
4081 | |||
4082 | del_timer(&info->tx_timer); | ||
4083 | |||
4084 | tdma_reset(info); | ||
4085 | |||
4086 | /* reset and disable transmitter */ | ||
4087 | val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */ | ||
4088 | wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */ | ||
4089 | |||
4090 | slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER); | ||
4091 | |||
4092 | /* clear tx idle and underrun status bit */ | ||
4093 | wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER)); | ||
4094 | |||
4095 | reset_tbufs(info); | ||
4096 | |||
4097 | info->tx_enabled = false; | ||
4098 | info->tx_active = false; | ||
4099 | } | ||
4100 | |||
4101 | static void reset_port(struct slgt_info *info) | ||
4102 | { | ||
4103 | if (!info->reg_addr) | ||
4104 | return; | ||
4105 | |||
4106 | tx_stop(info); | ||
4107 | rx_stop(info); | ||
4108 | |||
4109 | info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | ||
4110 | set_signals(info); | ||
4111 | |||
4112 | slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); | ||
4113 | } | ||
4114 | |||
4115 | static void reset_adapter(struct slgt_info *info) | ||
4116 | { | ||
4117 | int i; | ||
4118 | for (i=0; i < info->port_count; ++i) { | ||
4119 | if (info->port_array[i]) | ||
4120 | reset_port(info->port_array[i]); | ||
4121 | } | ||
4122 | } | ||
4123 | |||
4124 | static void async_mode(struct slgt_info *info) | ||
4125 | { | ||
4126 | unsigned short val; | ||
4127 | |||
4128 | slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); | ||
4129 | tx_stop(info); | ||
4130 | rx_stop(info); | ||
4131 | |||
4132 | /* TCR (tx control) | ||
4133 | * | ||
4134 | * 15..13 mode, 010=async | ||
4135 | * 12..10 encoding, 000=NRZ | ||
4136 | * 09 parity enable | ||
4137 | * 08 1=odd parity, 0=even parity | ||
4138 | * 07 1=RTS driver control | ||
4139 | * 06 1=break enable | ||
4140 | * 05..04 character length | ||
4141 | * 00=5 bits | ||
4142 | * 01=6 bits | ||
4143 | * 10=7 bits | ||
4144 | * 11=8 bits | ||
4145 | * 03 0=1 stop bit, 1=2 stop bits | ||
4146 | * 02 reset | ||
4147 | * 01 enable | ||
4148 | * 00 auto-CTS enable | ||
4149 | */ | ||
4150 | val = 0x4000; | ||
4151 | |||
4152 | if (info->if_mode & MGSL_INTERFACE_RTS_EN) | ||
4153 | val |= BIT7; | ||
4154 | |||
4155 | if (info->params.parity != ASYNC_PARITY_NONE) { | ||
4156 | val |= BIT9; | ||
4157 | if (info->params.parity == ASYNC_PARITY_ODD) | ||
4158 | val |= BIT8; | ||
4159 | } | ||
4160 | |||
4161 | switch (info->params.data_bits) | ||
4162 | { | ||
4163 | case 6: val |= BIT4; break; | ||
4164 | case 7: val |= BIT5; break; | ||
4165 | case 8: val |= BIT5 + BIT4; break; | ||
4166 | } | ||
4167 | |||
4168 | if (info->params.stop_bits != 1) | ||
4169 | val |= BIT3; | ||
4170 | |||
4171 | if (info->params.flags & HDLC_FLAG_AUTO_CTS) | ||
4172 | val |= BIT0; | ||
4173 | |||
4174 | wr_reg16(info, TCR, val); | ||
4175 | |||
4176 | /* RCR (rx control) | ||
4177 | * | ||
4178 | * 15..13 mode, 010=async | ||
4179 | * 12..10 encoding, 000=NRZ | ||
4180 | * 09 parity enable | ||
4181 | * 08 1=odd parity, 0=even parity | ||
4182 | * 07..06 reserved, must be 0 | ||
4183 | * 05..04 character length | ||
4184 | * 00=5 bits | ||
4185 | * 01=6 bits | ||
4186 | * 10=7 bits | ||
4187 | * 11=8 bits | ||
4188 | * 03 reserved, must be zero | ||
4189 | * 02 reset | ||
4190 | * 01 enable | ||
4191 | * 00 auto-DCD enable | ||
4192 | */ | ||
4193 | val = 0x4000; | ||
4194 | |||
4195 | if (info->params.parity != ASYNC_PARITY_NONE) { | ||
4196 | val |= BIT9; | ||
4197 | if (info->params.parity == ASYNC_PARITY_ODD) | ||
4198 | val |= BIT8; | ||
4199 | } | ||
4200 | |||
4201 | switch (info->params.data_bits) | ||
4202 | { | ||
4203 | case 6: val |= BIT4; break; | ||
4204 | case 7: val |= BIT5; break; | ||
4205 | case 8: val |= BIT5 + BIT4; break; | ||
4206 | } | ||
4207 | |||
4208 | if (info->params.flags & HDLC_FLAG_AUTO_DCD) | ||
4209 | val |= BIT0; | ||
4210 | |||
4211 | wr_reg16(info, RCR, val); | ||
4212 | |||
4213 | /* CCR (clock control) | ||
4214 | * | ||
4215 | * 07..05 011 = tx clock source is BRG/16 | ||
4216 | * 04..02 010 = rx clock source is BRG | ||
4217 | * 01 0 = auxclk disabled | ||
4218 | * 00 1 = BRG enabled | ||
4219 | * | ||
4220 | * 0110 1001 | ||
4221 | */ | ||
4222 | wr_reg8(info, CCR, 0x69); | ||
4223 | |||
4224 | msc_set_vcr(info); | ||
4225 | |||
4226 | /* SCR (serial control) | ||
4227 | * | ||
4228 | * 15 1=tx req on FIFO half empty | ||
4229 | * 14 1=rx req on FIFO half full | ||
4230 | * 13 tx data IRQ enable | ||
4231 | * 12 tx idle IRQ enable | ||
4232 | * 11 rx break on IRQ enable | ||
4233 | * 10 rx data IRQ enable | ||
4234 | * 09 rx break off IRQ enable | ||
4235 | * 08 overrun IRQ enable | ||
4236 | * 07 DSR IRQ enable | ||
4237 | * 06 CTS IRQ enable | ||
4238 | * 05 DCD IRQ enable | ||
4239 | * 04 RI IRQ enable | ||
4240 | * 03 0=16x sampling, 1=8x sampling | ||
4241 | * 02 1=txd->rxd internal loopback enable | ||
4242 | * 01 reserved, must be zero | ||
4243 | * 00 1=master IRQ enable | ||
4244 | */ | ||
4245 | val = BIT15 + BIT14 + BIT0; | ||
4246 | /* JCR[8] : 1 = x8 async mode feature available */ | ||
4247 | if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate && | ||
4248 | ((info->base_clock < (info->params.data_rate * 16)) || | ||
4249 | (info->base_clock % (info->params.data_rate * 16)))) { | ||
4250 | /* use 8x sampling */ | ||
4251 | val |= BIT3; | ||
4252 | set_rate(info, info->params.data_rate * 8); | ||
4253 | } else { | ||
4254 | /* use 16x sampling */ | ||
4255 | set_rate(info, info->params.data_rate * 16); | ||
4256 | } | ||
4257 | wr_reg16(info, SCR, val); | ||
4258 | |||
4259 | slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER); | ||
4260 | |||
4261 | if (info->params.loopback) | ||
4262 | enable_loopback(info); | ||
4263 | } | ||
4264 | |||
4265 | static void sync_mode(struct slgt_info *info) | ||
4266 | { | ||
4267 | unsigned short val; | ||
4268 | |||
4269 | slgt_irq_off(info, IRQ_ALL | IRQ_MASTER); | ||
4270 | tx_stop(info); | ||
4271 | rx_stop(info); | ||
4272 | |||
4273 | /* TCR (tx control) | ||
4274 | * | ||
4275 | * 15..13 mode | ||
4276 | * 000=HDLC/SDLC | ||
4277 | * 001=raw bit synchronous | ||
4278 | * 010=asynchronous/isochronous | ||
4279 | * 011=monosync byte synchronous | ||
4280 | * 100=bisync byte synchronous | ||
4281 | * 101=xsync byte synchronous | ||
4282 | * 12..10 encoding | ||
4283 | * 09 CRC enable | ||
4284 | * 08 CRC32 | ||
4285 | * 07 1=RTS driver control | ||
4286 | * 06 preamble enable | ||
4287 | * 05..04 preamble length | ||
4288 | * 03 share open/close flag | ||
4289 | * 02 reset | ||
4290 | * 01 enable | ||
4291 | * 00 auto-CTS enable | ||
4292 | */ | ||
4293 | val = BIT2; | ||
4294 | |||
4295 | switch(info->params.mode) { | ||
4296 | case MGSL_MODE_XSYNC: | ||
4297 | val |= BIT15 + BIT13; | ||
4298 | break; | ||
4299 | case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; | ||
4300 | case MGSL_MODE_BISYNC: val |= BIT15; break; | ||
4301 | case MGSL_MODE_RAW: val |= BIT13; break; | ||
4302 | } | ||
4303 | if (info->if_mode & MGSL_INTERFACE_RTS_EN) | ||
4304 | val |= BIT7; | ||
4305 | |||
4306 | switch(info->params.encoding) | ||
4307 | { | ||
4308 | case HDLC_ENCODING_NRZB: val |= BIT10; break; | ||
4309 | case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; | ||
4310 | case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; | ||
4311 | case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; | ||
4312 | case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; | ||
4313 | case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; | ||
4314 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; | ||
4315 | } | ||
4316 | |||
4317 | switch (info->params.crc_type & HDLC_CRC_MASK) | ||
4318 | { | ||
4319 | case HDLC_CRC_16_CCITT: val |= BIT9; break; | ||
4320 | case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; | ||
4321 | } | ||
4322 | |||
4323 | if (info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE) | ||
4324 | val |= BIT6; | ||
4325 | |||
4326 | switch (info->params.preamble_length) | ||
4327 | { | ||
4328 | case HDLC_PREAMBLE_LENGTH_16BITS: val |= BIT5; break; | ||
4329 | case HDLC_PREAMBLE_LENGTH_32BITS: val |= BIT4; break; | ||
4330 | case HDLC_PREAMBLE_LENGTH_64BITS: val |= BIT5 + BIT4; break; | ||
4331 | } | ||
4332 | |||
4333 | if (info->params.flags & HDLC_FLAG_AUTO_CTS) | ||
4334 | val |= BIT0; | ||
4335 | |||
4336 | wr_reg16(info, TCR, val); | ||
4337 | |||
4338 | /* TPR (transmit preamble) */ | ||
4339 | |||
4340 | switch (info->params.preamble) | ||
4341 | { | ||
4342 | case HDLC_PREAMBLE_PATTERN_FLAGS: val = 0x7e; break; | ||
4343 | case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break; | ||
4344 | case HDLC_PREAMBLE_PATTERN_ZEROS: val = 0x00; break; | ||
4345 | case HDLC_PREAMBLE_PATTERN_10: val = 0x55; break; | ||
4346 | case HDLC_PREAMBLE_PATTERN_01: val = 0xaa; break; | ||
4347 | default: val = 0x7e; break; | ||
4348 | } | ||
4349 | wr_reg8(info, TPR, (unsigned char)val); | ||
4350 | |||
4351 | /* RCR (rx control) | ||
4352 | * | ||
4353 | * 15..13 mode | ||
4354 | * 000=HDLC/SDLC | ||
4355 | * 001=raw bit synchronous | ||
4356 | * 010=asynchronous/isochronous | ||
4357 | * 011=monosync byte synchronous | ||
4358 | * 100=bisync byte synchronous | ||
4359 | * 101=xsync byte synchronous | ||
4360 | * 12..10 encoding | ||
4361 | * 09 CRC enable | ||
4362 | * 08 CRC32 | ||
4363 | * 07..03 reserved, must be 0 | ||
4364 | * 02 reset | ||
4365 | * 01 enable | ||
4366 | * 00 auto-DCD enable | ||
4367 | */ | ||
4368 | val = 0; | ||
4369 | |||
4370 | switch(info->params.mode) { | ||
4371 | case MGSL_MODE_XSYNC: | ||
4372 | val |= BIT15 + BIT13; | ||
4373 | break; | ||
4374 | case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break; | ||
4375 | case MGSL_MODE_BISYNC: val |= BIT15; break; | ||
4376 | case MGSL_MODE_RAW: val |= BIT13; break; | ||
4377 | } | ||
4378 | |||
4379 | switch(info->params.encoding) | ||
4380 | { | ||
4381 | case HDLC_ENCODING_NRZB: val |= BIT10; break; | ||
4382 | case HDLC_ENCODING_NRZI_MARK: val |= BIT11; break; | ||
4383 | case HDLC_ENCODING_NRZI: val |= BIT11 + BIT10; break; | ||
4384 | case HDLC_ENCODING_BIPHASE_MARK: val |= BIT12; break; | ||
4385 | case HDLC_ENCODING_BIPHASE_SPACE: val |= BIT12 + BIT10; break; | ||
4386 | case HDLC_ENCODING_BIPHASE_LEVEL: val |= BIT12 + BIT11; break; | ||
4387 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break; | ||
4388 | } | ||
4389 | |||
4390 | switch (info->params.crc_type & HDLC_CRC_MASK) | ||
4391 | { | ||
4392 | case HDLC_CRC_16_CCITT: val |= BIT9; break; | ||
4393 | case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break; | ||
4394 | } | ||
4395 | |||
4396 | if (info->params.flags & HDLC_FLAG_AUTO_DCD) | ||
4397 | val |= BIT0; | ||
4398 | |||
4399 | wr_reg16(info, RCR, val); | ||
4400 | |||
4401 | /* CCR (clock control) | ||
4402 | * | ||
4403 | * 07..05 tx clock source | ||
4404 | * 04..02 rx clock source | ||
4405 | * 01 auxclk enable | ||
4406 | * 00 BRG enable | ||
4407 | */ | ||
4408 | val = 0; | ||
4409 | |||
4410 | if (info->params.flags & HDLC_FLAG_TXC_BRG) | ||
4411 | { | ||
4412 | // when RxC source is DPLL, BRG generates 16X DPLL | ||
4413 | // reference clock, so take TxC from BRG/16 to get | ||
4414 | // transmit clock at actual data rate | ||
4415 | if (info->params.flags & HDLC_FLAG_RXC_DPLL) | ||
4416 | val |= BIT6 + BIT5; /* 011, txclk = BRG/16 */ | ||
4417 | else | ||
4418 | val |= BIT6; /* 010, txclk = BRG */ | ||
4419 | } | ||
4420 | else if (info->params.flags & HDLC_FLAG_TXC_DPLL) | ||
4421 | val |= BIT7; /* 100, txclk = DPLL Input */ | ||
4422 | else if (info->params.flags & HDLC_FLAG_TXC_RXCPIN) | ||
4423 | val |= BIT5; /* 001, txclk = RXC Input */ | ||
4424 | |||
4425 | if (info->params.flags & HDLC_FLAG_RXC_BRG) | ||
4426 | val |= BIT3; /* 010, rxclk = BRG */ | ||
4427 | else if (info->params.flags & HDLC_FLAG_RXC_DPLL) | ||
4428 | val |= BIT4; /* 100, rxclk = DPLL */ | ||
4429 | else if (info->params.flags & HDLC_FLAG_RXC_TXCPIN) | ||
4430 | val |= BIT2; /* 001, rxclk = TXC Input */ | ||
4431 | |||
4432 | if (info->params.clock_speed) | ||
4433 | val |= BIT1 + BIT0; | ||
4434 | |||
4435 | wr_reg8(info, CCR, (unsigned char)val); | ||
4436 | |||
4437 | if (info->params.flags & (HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL)) | ||
4438 | { | ||
4439 | // program DPLL mode | ||
4440 | switch(info->params.encoding) | ||
4441 | { | ||
4442 | case HDLC_ENCODING_BIPHASE_MARK: | ||
4443 | case HDLC_ENCODING_BIPHASE_SPACE: | ||
4444 | val = BIT7; break; | ||
4445 | case HDLC_ENCODING_BIPHASE_LEVEL: | ||
4446 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: | ||
4447 | val = BIT7 + BIT6; break; | ||
4448 | default: val = BIT6; // NRZ encodings | ||
4449 | } | ||
4450 | wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | val)); | ||
4451 | |||
4452 | // DPLL requires a 16X reference clock from BRG | ||
4453 | set_rate(info, info->params.clock_speed * 16); | ||
4454 | } | ||
4455 | else | ||
4456 | set_rate(info, info->params.clock_speed); | ||
4457 | |||
4458 | tx_set_idle(info); | ||
4459 | |||
4460 | msc_set_vcr(info); | ||
4461 | |||
4462 | /* SCR (serial control) | ||
4463 | * | ||
4464 | * 15 1=tx req on FIFO half empty | ||
4465 | * 14 1=rx req on FIFO half full | ||
4466 | * 13 tx data IRQ enable | ||
4467 | * 12 tx idle IRQ enable | ||
4468 | * 11 underrun IRQ enable | ||
4469 | * 10 rx data IRQ enable | ||
4470 | * 09 rx idle IRQ enable | ||
4471 | * 08 overrun IRQ enable | ||
4472 | * 07 DSR IRQ enable | ||
4473 | * 06 CTS IRQ enable | ||
4474 | * 05 DCD IRQ enable | ||
4475 | * 04 RI IRQ enable | ||
4476 | * 03 reserved, must be zero | ||
4477 | * 02 1=txd->rxd internal loopback enable | ||
4478 | * 01 reserved, must be zero | ||
4479 | * 00 1=master IRQ enable | ||
4480 | */ | ||
4481 | wr_reg16(info, SCR, BIT15 + BIT14 + BIT0); | ||
4482 | |||
4483 | if (info->params.loopback) | ||
4484 | enable_loopback(info); | ||
4485 | } | ||
4486 | |||
4487 | /* | ||
4488 | * set transmit idle mode | ||
4489 | */ | ||
4490 | static void tx_set_idle(struct slgt_info *info) | ||
4491 | { | ||
4492 | unsigned char val; | ||
4493 | unsigned short tcr; | ||
4494 | |||
4495 | /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits | ||
4496 | * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits | ||
4497 | */ | ||
4498 | tcr = rd_reg16(info, TCR); | ||
4499 | if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) { | ||
4500 | /* disable preamble, set idle size to 16 bits */ | ||
4501 | tcr = (tcr & ~(BIT6 + BIT5)) | BIT4; | ||
4502 | /* MSB of 16 bit idle specified in tx preamble register (TPR) */ | ||
4503 | wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff)); | ||
4504 | } else if (!(tcr & BIT6)) { | ||
4505 | /* preamble is disabled, set idle size to 8 bits */ | ||
4506 | tcr &= ~(BIT5 + BIT4); | ||
4507 | } | ||
4508 | wr_reg16(info, TCR, tcr); | ||
4509 | |||
4510 | if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) { | ||
4511 | /* LSB of custom tx idle specified in tx idle register */ | ||
4512 | val = (unsigned char)(info->idle_mode & 0xff); | ||
4513 | } else { | ||
4514 | /* standard 8 bit idle patterns */ | ||
4515 | switch(info->idle_mode) | ||
4516 | { | ||
4517 | case HDLC_TXIDLE_FLAGS: val = 0x7e; break; | ||
4518 | case HDLC_TXIDLE_ALT_ZEROS_ONES: | ||
4519 | case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break; | ||
4520 | case HDLC_TXIDLE_ZEROS: | ||
4521 | case HDLC_TXIDLE_SPACE: val = 0x00; break; | ||
4522 | default: val = 0xff; | ||
4523 | } | ||
4524 | } | ||
4525 | |||
4526 | wr_reg8(info, TIR, val); | ||
4527 | } | ||
4528 | |||
4529 | /* | ||
4530 | * get state of V24 status (input) signals | ||
4531 | */ | ||
4532 | static void get_signals(struct slgt_info *info) | ||
4533 | { | ||
4534 | unsigned short status = rd_reg16(info, SSR); | ||
4535 | |||
4536 | /* clear all serial signals except DTR and RTS */ | ||
4537 | info->signals &= SerialSignal_DTR + SerialSignal_RTS; | ||
4538 | |||
4539 | if (status & BIT3) | ||
4540 | info->signals |= SerialSignal_DSR; | ||
4541 | if (status & BIT2) | ||
4542 | info->signals |= SerialSignal_CTS; | ||
4543 | if (status & BIT1) | ||
4544 | info->signals |= SerialSignal_DCD; | ||
4545 | if (status & BIT0) | ||
4546 | info->signals |= SerialSignal_RI; | ||
4547 | } | ||
4548 | |||
4549 | /* | ||
4550 | * set V.24 Control Register based on current configuration | ||
4551 | */ | ||
4552 | static void msc_set_vcr(struct slgt_info *info) | ||
4553 | { | ||
4554 | unsigned char val = 0; | ||
4555 | |||
4556 | /* VCR (V.24 control) | ||
4557 | * | ||
4558 | * 07..04 serial IF select | ||
4559 | * 03 DTR | ||
4560 | * 02 RTS | ||
4561 | * 01 LL | ||
4562 | * 00 RL | ||
4563 | */ | ||
4564 | |||
4565 | switch(info->if_mode & MGSL_INTERFACE_MASK) | ||
4566 | { | ||
4567 | case MGSL_INTERFACE_RS232: | ||
4568 | val |= BIT5; /* 0010 */ | ||
4569 | break; | ||
4570 | case MGSL_INTERFACE_V35: | ||
4571 | val |= BIT7 + BIT6 + BIT5; /* 1110 */ | ||
4572 | break; | ||
4573 | case MGSL_INTERFACE_RS422: | ||
4574 | val |= BIT6; /* 0100 */ | ||
4575 | break; | ||
4576 | } | ||
4577 | |||
4578 | if (info->if_mode & MGSL_INTERFACE_MSB_FIRST) | ||
4579 | val |= BIT4; | ||
4580 | if (info->signals & SerialSignal_DTR) | ||
4581 | val |= BIT3; | ||
4582 | if (info->signals & SerialSignal_RTS) | ||
4583 | val |= BIT2; | ||
4584 | if (info->if_mode & MGSL_INTERFACE_LL) | ||
4585 | val |= BIT1; | ||
4586 | if (info->if_mode & MGSL_INTERFACE_RL) | ||
4587 | val |= BIT0; | ||
4588 | wr_reg8(info, VCR, val); | ||
4589 | } | ||
4590 | |||
4591 | /* | ||
4592 | * set state of V24 control (output) signals | ||
4593 | */ | ||
4594 | static void set_signals(struct slgt_info *info) | ||
4595 | { | ||
4596 | unsigned char val = rd_reg8(info, VCR); | ||
4597 | if (info->signals & SerialSignal_DTR) | ||
4598 | val |= BIT3; | ||
4599 | else | ||
4600 | val &= ~BIT3; | ||
4601 | if (info->signals & SerialSignal_RTS) | ||
4602 | val |= BIT2; | ||
4603 | else | ||
4604 | val &= ~BIT2; | ||
4605 | wr_reg8(info, VCR, val); | ||
4606 | } | ||
4607 | |||
4608 | /* | ||
4609 | * free range of receive DMA buffers (i to last) | ||
4610 | */ | ||
4611 | static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last) | ||
4612 | { | ||
4613 | int done = 0; | ||
4614 | |||
4615 | while(!done) { | ||
4616 | /* reset current buffer for reuse */ | ||
4617 | info->rbufs[i].status = 0; | ||
4618 | set_desc_count(info->rbufs[i], info->rbuf_fill_level); | ||
4619 | if (i == last) | ||
4620 | done = 1; | ||
4621 | if (++i == info->rbuf_count) | ||
4622 | i = 0; | ||
4623 | } | ||
4624 | info->rbuf_current = i; | ||
4625 | } | ||
4626 | |||
4627 | /* | ||
4628 | * mark all receive DMA buffers as free | ||
4629 | */ | ||
4630 | static void reset_rbufs(struct slgt_info *info) | ||
4631 | { | ||
4632 | free_rbufs(info, 0, info->rbuf_count - 1); | ||
4633 | info->rbuf_fill_index = 0; | ||
4634 | info->rbuf_fill_count = 0; | ||
4635 | } | ||
4636 | |||
4637 | /* | ||
4638 | * pass receive HDLC frame to upper layer | ||
4639 | * | ||
4640 | * return true if frame available, otherwise false | ||
4641 | */ | ||
4642 | static bool rx_get_frame(struct slgt_info *info) | ||
4643 | { | ||
4644 | unsigned int start, end; | ||
4645 | unsigned short status; | ||
4646 | unsigned int framesize = 0; | ||
4647 | unsigned long flags; | ||
4648 | struct tty_struct *tty = info->port.tty; | ||
4649 | unsigned char addr_field = 0xff; | ||
4650 | unsigned int crc_size = 0; | ||
4651 | |||
4652 | switch (info->params.crc_type & HDLC_CRC_MASK) { | ||
4653 | case HDLC_CRC_16_CCITT: crc_size = 2; break; | ||
4654 | case HDLC_CRC_32_CCITT: crc_size = 4; break; | ||
4655 | } | ||
4656 | |||
4657 | check_again: | ||
4658 | |||
4659 | framesize = 0; | ||
4660 | addr_field = 0xff; | ||
4661 | start = end = info->rbuf_current; | ||
4662 | |||
4663 | for (;;) { | ||
4664 | if (!desc_complete(info->rbufs[end])) | ||
4665 | goto cleanup; | ||
4666 | |||
4667 | if (framesize == 0 && info->params.addr_filter != 0xff) | ||
4668 | addr_field = info->rbufs[end].buf[0]; | ||
4669 | |||
4670 | framesize += desc_count(info->rbufs[end]); | ||
4671 | |||
4672 | if (desc_eof(info->rbufs[end])) | ||
4673 | break; | ||
4674 | |||
4675 | if (++end == info->rbuf_count) | ||
4676 | end = 0; | ||
4677 | |||
4678 | if (end == info->rbuf_current) { | ||
4679 | if (info->rx_enabled){ | ||
4680 | spin_lock_irqsave(&info->lock,flags); | ||
4681 | rx_start(info); | ||
4682 | spin_unlock_irqrestore(&info->lock,flags); | ||
4683 | } | ||
4684 | goto cleanup; | ||
4685 | } | ||
4686 | } | ||
4687 | |||
4688 | /* status | ||
4689 | * | ||
4690 | * 15 buffer complete | ||
4691 | * 14..06 reserved | ||
4692 | * 05..04 residue | ||
4693 | * 02 eof (end of frame) | ||
4694 | * 01 CRC error | ||
4695 | * 00 abort | ||
4696 | */ | ||
4697 | status = desc_status(info->rbufs[end]); | ||
4698 | |||
4699 | /* ignore CRC bit if not using CRC (bit is undefined) */ | ||
4700 | if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE) | ||
4701 | status &= ~BIT1; | ||
4702 | |||
4703 | if (framesize == 0 || | ||
4704 | (addr_field != 0xff && addr_field != info->params.addr_filter)) { | ||
4705 | free_rbufs(info, start, end); | ||
4706 | goto check_again; | ||
4707 | } | ||
4708 | |||
4709 | if (framesize < (2 + crc_size) || status & BIT0) { | ||
4710 | info->icount.rxshort++; | ||
4711 | framesize = 0; | ||
4712 | } else if (status & BIT1) { | ||
4713 | info->icount.rxcrc++; | ||
4714 | if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) | ||
4715 | framesize = 0; | ||
4716 | } | ||
4717 | |||
4718 | #if SYNCLINK_GENERIC_HDLC | ||
4719 | if (framesize == 0) { | ||
4720 | info->netdev->stats.rx_errors++; | ||
4721 | info->netdev->stats.rx_frame_errors++; | ||
4722 | } | ||
4723 | #endif | ||
4724 | |||
4725 | DBGBH(("%s rx frame status=%04X size=%d\n", | ||
4726 | info->device_name, status, framesize)); | ||
4727 | DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx"); | ||
4728 | |||
4729 | if (framesize) { | ||
4730 | if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) { | ||
4731 | framesize -= crc_size; | ||
4732 | crc_size = 0; | ||
4733 | } | ||
4734 | |||
4735 | if (framesize > info->max_frame_size + crc_size) | ||
4736 | info->icount.rxlong++; | ||
4737 | else { | ||
4738 | /* copy dma buffer(s) to contiguous temp buffer */ | ||
4739 | int copy_count = framesize; | ||
4740 | int i = start; | ||
4741 | unsigned char *p = info->tmp_rbuf; | ||
4742 | info->tmp_rbuf_count = framesize; | ||
4743 | |||
4744 | info->icount.rxok++; | ||
4745 | |||
4746 | while(copy_count) { | ||
4747 | int partial_count = min_t(int, copy_count, info->rbuf_fill_level); | ||
4748 | memcpy(p, info->rbufs[i].buf, partial_count); | ||
4749 | p += partial_count; | ||
4750 | copy_count -= partial_count; | ||
4751 | if (++i == info->rbuf_count) | ||
4752 | i = 0; | ||
4753 | } | ||
4754 | |||
4755 | if (info->params.crc_type & HDLC_CRC_RETURN_EX) { | ||
4756 | *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK; | ||
4757 | framesize++; | ||
4758 | } | ||
4759 | |||
4760 | #if SYNCLINK_GENERIC_HDLC | ||
4761 | if (info->netcount) | ||
4762 | hdlcdev_rx(info,info->tmp_rbuf, framesize); | ||
4763 | else | ||
4764 | #endif | ||
4765 | ldisc_receive_buf(tty, info->tmp_rbuf, info->flag_buf, framesize); | ||
4766 | } | ||
4767 | } | ||
4768 | free_rbufs(info, start, end); | ||
4769 | return true; | ||
4770 | |||
4771 | cleanup: | ||
4772 | return false; | ||
4773 | } | ||
4774 | |||
4775 | /* | ||
4776 | * pass receive buffer (RAW synchronous mode) to tty layer | ||
4777 | * return true if buffer available, otherwise false | ||
4778 | */ | ||
4779 | static bool rx_get_buf(struct slgt_info *info) | ||
4780 | { | ||
4781 | unsigned int i = info->rbuf_current; | ||
4782 | unsigned int count; | ||
4783 | |||
4784 | if (!desc_complete(info->rbufs[i])) | ||
4785 | return false; | ||
4786 | count = desc_count(info->rbufs[i]); | ||
4787 | switch(info->params.mode) { | ||
4788 | case MGSL_MODE_MONOSYNC: | ||
4789 | case MGSL_MODE_BISYNC: | ||
4790 | case MGSL_MODE_XSYNC: | ||
4791 | /* ignore residue in byte synchronous modes */ | ||
4792 | if (desc_residue(info->rbufs[i])) | ||
4793 | count--; | ||
4794 | break; | ||
4795 | } | ||
4796 | DBGDATA(info, info->rbufs[i].buf, count, "rx"); | ||
4797 | DBGINFO(("rx_get_buf size=%d\n", count)); | ||
4798 | if (count) | ||
4799 | ldisc_receive_buf(info->port.tty, info->rbufs[i].buf, | ||
4800 | info->flag_buf, count); | ||
4801 | free_rbufs(info, i, i); | ||
4802 | return true; | ||
4803 | } | ||
4804 | |||
4805 | static void reset_tbufs(struct slgt_info *info) | ||
4806 | { | ||
4807 | unsigned int i; | ||
4808 | info->tbuf_current = 0; | ||
4809 | for (i=0 ; i < info->tbuf_count ; i++) { | ||
4810 | info->tbufs[i].status = 0; | ||
4811 | info->tbufs[i].count = 0; | ||
4812 | } | ||
4813 | } | ||
4814 | |||
4815 | /* | ||
4816 | * return number of free transmit DMA buffers | ||
4817 | */ | ||
4818 | static unsigned int free_tbuf_count(struct slgt_info *info) | ||
4819 | { | ||
4820 | unsigned int count = 0; | ||
4821 | unsigned int i = info->tbuf_current; | ||
4822 | |||
4823 | do | ||
4824 | { | ||
4825 | if (desc_count(info->tbufs[i])) | ||
4826 | break; /* buffer in use */ | ||
4827 | ++count; | ||
4828 | if (++i == info->tbuf_count) | ||
4829 | i=0; | ||
4830 | } while (i != info->tbuf_current); | ||
4831 | |||
4832 | /* if tx DMA active, last zero count buffer is in use */ | ||
4833 | if (count && (rd_reg32(info, TDCSR) & BIT0)) | ||
4834 | --count; | ||
4835 | |||
4836 | return count; | ||
4837 | } | ||
4838 | |||
4839 | /* | ||
4840 | * return number of bytes in unsent transmit DMA buffers | ||
4841 | * and the serial controller tx FIFO | ||
4842 | */ | ||
4843 | static unsigned int tbuf_bytes(struct slgt_info *info) | ||
4844 | { | ||
4845 | unsigned int total_count = 0; | ||
4846 | unsigned int i = info->tbuf_current; | ||
4847 | unsigned int reg_value; | ||
4848 | unsigned int count; | ||
4849 | unsigned int active_buf_count = 0; | ||
4850 | |||
4851 | /* | ||
4852 | * Add descriptor counts for all tx DMA buffers. | ||
4853 | * If count is zero (cleared by DMA controller after read), | ||
4854 | * the buffer is complete or is actively being read from. | ||
4855 | * | ||
4856 | * Record buf_count of last buffer with zero count starting | ||
4857 | * from current ring position. buf_count is mirror | ||
4858 | * copy of count and is not cleared by serial controller. | ||
4859 | * If DMA controller is active, that buffer is actively | ||
4860 | * being read so add to total. | ||
4861 | */ | ||
4862 | do { | ||
4863 | count = desc_count(info->tbufs[i]); | ||
4864 | if (count) | ||
4865 | total_count += count; | ||
4866 | else if (!total_count) | ||
4867 | active_buf_count = info->tbufs[i].buf_count; | ||
4868 | if (++i == info->tbuf_count) | ||
4869 | i = 0; | ||
4870 | } while (i != info->tbuf_current); | ||
4871 | |||
4872 | /* read tx DMA status register */ | ||
4873 | reg_value = rd_reg32(info, TDCSR); | ||
4874 | |||
4875 | /* if tx DMA active, last zero count buffer is in use */ | ||
4876 | if (reg_value & BIT0) | ||
4877 | total_count += active_buf_count; | ||
4878 | |||
4879 | /* add tx FIFO count = reg_value[15..8] */ | ||
4880 | total_count += (reg_value >> 8) & 0xff; | ||
4881 | |||
4882 | /* if transmitter active add one byte for shift register */ | ||
4883 | if (info->tx_active) | ||
4884 | total_count++; | ||
4885 | |||
4886 | return total_count; | ||
4887 | } | ||
4888 | |||
4889 | /* | ||
4890 | * load data into transmit DMA buffer ring and start transmitter if needed | ||
4891 | * return true if data accepted, otherwise false (buffers full) | ||
4892 | */ | ||
4893 | static bool tx_load(struct slgt_info *info, const char *buf, unsigned int size) | ||
4894 | { | ||
4895 | unsigned short count; | ||
4896 | unsigned int i; | ||
4897 | struct slgt_desc *d; | ||
4898 | |||
4899 | /* check required buffer space */ | ||
4900 | if (DIV_ROUND_UP(size, DMABUFSIZE) > free_tbuf_count(info)) | ||
4901 | return false; | ||
4902 | |||
4903 | DBGDATA(info, buf, size, "tx"); | ||
4904 | |||
4905 | /* | ||
4906 | * copy data to one or more DMA buffers in circular ring | ||
4907 | * tbuf_start = first buffer for this data | ||
4908 | * tbuf_current = next free buffer | ||
4909 | * | ||
4910 | * Copy all data before making data visible to DMA controller by | ||
4911 | * setting descriptor count of the first buffer. | ||
4912 | * This prevents an active DMA controller from reading the first DMA | ||
4913 | * buffers of a frame and stopping before the final buffers are filled. | ||
4914 | */ | ||
4915 | |||
4916 | info->tbuf_start = i = info->tbuf_current; | ||
4917 | |||
4918 | while (size) { | ||
4919 | d = &info->tbufs[i]; | ||
4920 | |||
4921 | count = (unsigned short)((size > DMABUFSIZE) ? DMABUFSIZE : size); | ||
4922 | memcpy(d->buf, buf, count); | ||
4923 | |||
4924 | size -= count; | ||
4925 | buf += count; | ||
4926 | |||
4927 | /* | ||
4928 | * set EOF bit for last buffer of HDLC frame or | ||
4929 | * for every buffer in raw mode | ||
4930 | */ | ||
4931 | if ((!size && info->params.mode == MGSL_MODE_HDLC) || | ||
4932 | info->params.mode == MGSL_MODE_RAW) | ||
4933 | set_desc_eof(*d, 1); | ||
4934 | else | ||
4935 | set_desc_eof(*d, 0); | ||
4936 | |||
4937 | /* set descriptor count for all but first buffer */ | ||
4938 | if (i != info->tbuf_start) | ||
4939 | set_desc_count(*d, count); | ||
4940 | d->buf_count = count; | ||
4941 | |||
4942 | if (++i == info->tbuf_count) | ||
4943 | i = 0; | ||
4944 | } | ||
4945 | |||
4946 | info->tbuf_current = i; | ||
4947 | |||
4948 | /* set first buffer count to make new data visible to DMA controller */ | ||
4949 | d = &info->tbufs[info->tbuf_start]; | ||
4950 | set_desc_count(*d, d->buf_count); | ||
4951 | |||
4952 | /* start transmitter if needed and update transmit timeout */ | ||
4953 | if (!info->tx_active) | ||
4954 | tx_start(info); | ||
4955 | update_tx_timer(info); | ||
4956 | |||
4957 | return true; | ||
4958 | } | ||
4959 | |||
4960 | static int register_test(struct slgt_info *info) | ||
4961 | { | ||
4962 | static unsigned short patterns[] = | ||
4963 | {0x0000, 0xffff, 0xaaaa, 0x5555, 0x6969, 0x9696}; | ||
4964 | static unsigned int count = ARRAY_SIZE(patterns); | ||
4965 | unsigned int i; | ||
4966 | int rc = 0; | ||
4967 | |||
4968 | for (i=0 ; i < count ; i++) { | ||
4969 | wr_reg16(info, TIR, patterns[i]); | ||
4970 | wr_reg16(info, BDR, patterns[(i+1)%count]); | ||
4971 | if ((rd_reg16(info, TIR) != patterns[i]) || | ||
4972 | (rd_reg16(info, BDR) != patterns[(i+1)%count])) { | ||
4973 | rc = -ENODEV; | ||
4974 | break; | ||
4975 | } | ||
4976 | } | ||
4977 | info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0; | ||
4978 | info->init_error = rc ? 0 : DiagStatus_AddressFailure; | ||
4979 | return rc; | ||
4980 | } | ||
4981 | |||
4982 | static int irq_test(struct slgt_info *info) | ||
4983 | { | ||
4984 | unsigned long timeout; | ||
4985 | unsigned long flags; | ||
4986 | struct tty_struct *oldtty = info->port.tty; | ||
4987 | u32 speed = info->params.data_rate; | ||
4988 | |||
4989 | info->params.data_rate = 921600; | ||
4990 | info->port.tty = NULL; | ||
4991 | |||
4992 | spin_lock_irqsave(&info->lock, flags); | ||
4993 | async_mode(info); | ||
4994 | slgt_irq_on(info, IRQ_TXIDLE); | ||
4995 | |||
4996 | /* enable transmitter */ | ||
4997 | wr_reg16(info, TCR, | ||
4998 | (unsigned short)(rd_reg16(info, TCR) | BIT1)); | ||
4999 | |||
5000 | /* write one byte and wait for tx idle */ | ||
5001 | wr_reg16(info, TDR, 0); | ||
5002 | |||
5003 | /* assume failure */ | ||
5004 | info->init_error = DiagStatus_IrqFailure; | ||
5005 | info->irq_occurred = false; | ||
5006 | |||
5007 | spin_unlock_irqrestore(&info->lock, flags); | ||
5008 | |||
5009 | timeout=100; | ||
5010 | while(timeout-- && !info->irq_occurred) | ||
5011 | msleep_interruptible(10); | ||
5012 | |||
5013 | spin_lock_irqsave(&info->lock,flags); | ||
5014 | reset_port(info); | ||
5015 | spin_unlock_irqrestore(&info->lock,flags); | ||
5016 | |||
5017 | info->params.data_rate = speed; | ||
5018 | info->port.tty = oldtty; | ||
5019 | |||
5020 | info->init_error = info->irq_occurred ? 0 : DiagStatus_IrqFailure; | ||
5021 | return info->irq_occurred ? 0 : -ENODEV; | ||
5022 | } | ||
5023 | |||
5024 | static int loopback_test_rx(struct slgt_info *info) | ||
5025 | { | ||
5026 | unsigned char *src, *dest; | ||
5027 | int count; | ||
5028 | |||
5029 | if (desc_complete(info->rbufs[0])) { | ||
5030 | count = desc_count(info->rbufs[0]); | ||
5031 | src = info->rbufs[0].buf; | ||
5032 | dest = info->tmp_rbuf; | ||
5033 | |||
5034 | for( ; count ; count-=2, src+=2) { | ||
5035 | /* src=data byte (src+1)=status byte */ | ||
5036 | if (!(*(src+1) & (BIT9 + BIT8))) { | ||
5037 | *dest = *src; | ||
5038 | dest++; | ||
5039 | info->tmp_rbuf_count++; | ||
5040 | } | ||
5041 | } | ||
5042 | DBGDATA(info, info->tmp_rbuf, info->tmp_rbuf_count, "rx"); | ||
5043 | return 1; | ||
5044 | } | ||
5045 | return 0; | ||
5046 | } | ||
5047 | |||
5048 | static int loopback_test(struct slgt_info *info) | ||
5049 | { | ||
5050 | #define TESTFRAMESIZE 20 | ||
5051 | |||
5052 | unsigned long timeout; | ||
5053 | u16 count = TESTFRAMESIZE; | ||
5054 | unsigned char buf[TESTFRAMESIZE]; | ||
5055 | int rc = -ENODEV; | ||
5056 | unsigned long flags; | ||
5057 | |||
5058 | struct tty_struct *oldtty = info->port.tty; | ||
5059 | MGSL_PARAMS params; | ||
5060 | |||
5061 | memcpy(¶ms, &info->params, sizeof(params)); | ||
5062 | |||
5063 | info->params.mode = MGSL_MODE_ASYNC; | ||
5064 | info->params.data_rate = 921600; | ||
5065 | info->params.loopback = 1; | ||
5066 | info->port.tty = NULL; | ||
5067 | |||
5068 | /* build and send transmit frame */ | ||
5069 | for (count = 0; count < TESTFRAMESIZE; ++count) | ||
5070 | buf[count] = (unsigned char)count; | ||
5071 | |||
5072 | info->tmp_rbuf_count = 0; | ||
5073 | memset(info->tmp_rbuf, 0, TESTFRAMESIZE); | ||
5074 | |||
5075 | /* program hardware for HDLC and enabled receiver */ | ||
5076 | spin_lock_irqsave(&info->lock,flags); | ||
5077 | async_mode(info); | ||
5078 | rx_start(info); | ||
5079 | tx_load(info, buf, count); | ||
5080 | spin_unlock_irqrestore(&info->lock, flags); | ||
5081 | |||
5082 | /* wait for receive complete */ | ||
5083 | for (timeout = 100; timeout; --timeout) { | ||
5084 | msleep_interruptible(10); | ||
5085 | if (loopback_test_rx(info)) { | ||
5086 | rc = 0; | ||
5087 | break; | ||
5088 | } | ||
5089 | } | ||
5090 | |||
5091 | /* verify received frame length and contents */ | ||
5092 | if (!rc && (info->tmp_rbuf_count != count || | ||
5093 | memcmp(buf, info->tmp_rbuf, count))) { | ||
5094 | rc = -ENODEV; | ||
5095 | } | ||
5096 | |||
5097 | spin_lock_irqsave(&info->lock,flags); | ||
5098 | reset_adapter(info); | ||
5099 | spin_unlock_irqrestore(&info->lock,flags); | ||
5100 | |||
5101 | memcpy(&info->params, ¶ms, sizeof(info->params)); | ||
5102 | info->port.tty = oldtty; | ||
5103 | |||
5104 | info->init_error = rc ? DiagStatus_DmaFailure : 0; | ||
5105 | return rc; | ||
5106 | } | ||
5107 | |||
5108 | static int adapter_test(struct slgt_info *info) | ||
5109 | { | ||
5110 | DBGINFO(("testing %s\n", info->device_name)); | ||
5111 | if (register_test(info) < 0) { | ||
5112 | printk("register test failure %s addr=%08X\n", | ||
5113 | info->device_name, info->phys_reg_addr); | ||
5114 | } else if (irq_test(info) < 0) { | ||
5115 | printk("IRQ test failure %s IRQ=%d\n", | ||
5116 | info->device_name, info->irq_level); | ||
5117 | } else if (loopback_test(info) < 0) { | ||
5118 | printk("loopback test failure %s\n", info->device_name); | ||
5119 | } | ||
5120 | return info->init_error; | ||
5121 | } | ||
5122 | |||
5123 | /* | ||
5124 | * transmit timeout handler | ||
5125 | */ | ||
5126 | static void tx_timeout(unsigned long context) | ||
5127 | { | ||
5128 | struct slgt_info *info = (struct slgt_info*)context; | ||
5129 | unsigned long flags; | ||
5130 | |||
5131 | DBGINFO(("%s tx_timeout\n", info->device_name)); | ||
5132 | if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { | ||
5133 | info->icount.txtimeout++; | ||
5134 | } | ||
5135 | spin_lock_irqsave(&info->lock,flags); | ||
5136 | tx_stop(info); | ||
5137 | spin_unlock_irqrestore(&info->lock,flags); | ||
5138 | |||
5139 | #if SYNCLINK_GENERIC_HDLC | ||
5140 | if (info->netcount) | ||
5141 | hdlcdev_tx_done(info); | ||
5142 | else | ||
5143 | #endif | ||
5144 | bh_transmit(info); | ||
5145 | } | ||
5146 | |||
5147 | /* | ||
5148 | * receive buffer polling timer | ||
5149 | */ | ||
5150 | static void rx_timeout(unsigned long context) | ||
5151 | { | ||
5152 | struct slgt_info *info = (struct slgt_info*)context; | ||
5153 | unsigned long flags; | ||
5154 | |||
5155 | DBGINFO(("%s rx_timeout\n", info->device_name)); | ||
5156 | spin_lock_irqsave(&info->lock, flags); | ||
5157 | info->pending_bh |= BH_RECEIVE; | ||
5158 | spin_unlock_irqrestore(&info->lock, flags); | ||
5159 | bh_handler(&info->task); | ||
5160 | } | ||
5161 | |||
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c new file mode 100644 index 000000000000..327343694473 --- /dev/null +++ b/drivers/tty/synclinkmp.c | |||
@@ -0,0 +1,5600 @@ | |||
1 | /* | ||
2 | * $Id: synclinkmp.c,v 4.38 2005/07/15 13:29:44 paulkf Exp $ | ||
3 | * | ||
4 | * Device driver for Microgate SyncLink Multiport | ||
5 | * high speed multiprotocol serial adapter. | ||
6 | * | ||
7 | * written by Paul Fulghum for Microgate Corporation | ||
8 | * paulkf@microgate.com | ||
9 | * | ||
10 | * Microgate and SyncLink are trademarks of Microgate Corporation | ||
11 | * | ||
12 | * Derived from serial.c written by Theodore Ts'o and Linus Torvalds | ||
13 | * This code is released under the GNU General Public License (GPL) | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
18 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | ||
19 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
23 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
25 | * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | #define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) | ||
29 | #if defined(__i386__) | ||
30 | # define BREAKPOINT() asm(" int $3"); | ||
31 | #else | ||
32 | # define BREAKPOINT() { } | ||
33 | #endif | ||
34 | |||
35 | #define MAX_DEVICES 12 | ||
36 | |||
37 | #include <linux/module.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/signal.h> | ||
40 | #include <linux/sched.h> | ||
41 | #include <linux/timer.h> | ||
42 | #include <linux/interrupt.h> | ||
43 | #include <linux/pci.h> | ||
44 | #include <linux/tty.h> | ||
45 | #include <linux/tty_flip.h> | ||
46 | #include <linux/serial.h> | ||
47 | #include <linux/major.h> | ||
48 | #include <linux/string.h> | ||
49 | #include <linux/fcntl.h> | ||
50 | #include <linux/ptrace.h> | ||
51 | #include <linux/ioport.h> | ||
52 | #include <linux/mm.h> | ||
53 | #include <linux/seq_file.h> | ||
54 | #include <linux/slab.h> | ||
55 | #include <linux/netdevice.h> | ||
56 | #include <linux/vmalloc.h> | ||
57 | #include <linux/init.h> | ||
58 | #include <linux/delay.h> | ||
59 | #include <linux/ioctl.h> | ||
60 | |||
61 | #include <asm/system.h> | ||
62 | #include <asm/io.h> | ||
63 | #include <asm/irq.h> | ||
64 | #include <asm/dma.h> | ||
65 | #include <linux/bitops.h> | ||
66 | #include <asm/types.h> | ||
67 | #include <linux/termios.h> | ||
68 | #include <linux/workqueue.h> | ||
69 | #include <linux/hdlc.h> | ||
70 | #include <linux/synclink.h> | ||
71 | |||
72 | #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) | ||
73 | #define SYNCLINK_GENERIC_HDLC 1 | ||
74 | #else | ||
75 | #define SYNCLINK_GENERIC_HDLC 0 | ||
76 | #endif | ||
77 | |||
78 | #define GET_USER(error,value,addr) error = get_user(value,addr) | ||
79 | #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 | ||
80 | #define PUT_USER(error,value,addr) error = put_user(value,addr) | ||
81 | #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 | ||
82 | |||
83 | #include <asm/uaccess.h> | ||
84 | |||
85 | static MGSL_PARAMS default_params = { | ||
86 | MGSL_MODE_HDLC, /* unsigned long mode */ | ||
87 | 0, /* unsigned char loopback; */ | ||
88 | HDLC_FLAG_UNDERRUN_ABORT15, /* unsigned short flags; */ | ||
89 | HDLC_ENCODING_NRZI_SPACE, /* unsigned char encoding; */ | ||
90 | 0, /* unsigned long clock_speed; */ | ||
91 | 0xff, /* unsigned char addr_filter; */ | ||
92 | HDLC_CRC_16_CCITT, /* unsigned short crc_type; */ | ||
93 | HDLC_PREAMBLE_LENGTH_8BITS, /* unsigned char preamble_length; */ | ||
94 | HDLC_PREAMBLE_PATTERN_NONE, /* unsigned char preamble; */ | ||
95 | 9600, /* unsigned long data_rate; */ | ||
96 | 8, /* unsigned char data_bits; */ | ||
97 | 1, /* unsigned char stop_bits; */ | ||
98 | ASYNC_PARITY_NONE /* unsigned char parity; */ | ||
99 | }; | ||
100 | |||
101 | /* size in bytes of DMA data buffers */ | ||
102 | #define SCABUFSIZE 1024 | ||
103 | #define SCA_MEM_SIZE 0x40000 | ||
104 | #define SCA_BASE_SIZE 512 | ||
105 | #define SCA_REG_SIZE 16 | ||
106 | #define SCA_MAX_PORTS 4 | ||
107 | #define SCAMAXDESC 128 | ||
108 | |||
109 | #define BUFFERLISTSIZE 4096 | ||
110 | |||
111 | /* SCA-I style DMA buffer descriptor */ | ||
112 | typedef struct _SCADESC | ||
113 | { | ||
114 | u16 next; /* lower l6 bits of next descriptor addr */ | ||
115 | u16 buf_ptr; /* lower 16 bits of buffer addr */ | ||
116 | u8 buf_base; /* upper 8 bits of buffer addr */ | ||
117 | u8 pad1; | ||
118 | u16 length; /* length of buffer */ | ||
119 | u8 status; /* status of buffer */ | ||
120 | u8 pad2; | ||
121 | } SCADESC, *PSCADESC; | ||
122 | |||
123 | typedef struct _SCADESC_EX | ||
124 | { | ||
125 | /* device driver bookkeeping section */ | ||
126 | char *virt_addr; /* virtual address of data buffer */ | ||
127 | u16 phys_entry; /* lower 16-bits of physical address of this descriptor */ | ||
128 | } SCADESC_EX, *PSCADESC_EX; | ||
129 | |||
130 | /* The queue of BH actions to be performed */ | ||
131 | |||
132 | #define BH_RECEIVE 1 | ||
133 | #define BH_TRANSMIT 2 | ||
134 | #define BH_STATUS 4 | ||
135 | |||
136 | #define IO_PIN_SHUTDOWN_LIMIT 100 | ||
137 | |||
138 | struct _input_signal_events { | ||
139 | int ri_up; | ||
140 | int ri_down; | ||
141 | int dsr_up; | ||
142 | int dsr_down; | ||
143 | int dcd_up; | ||
144 | int dcd_down; | ||
145 | int cts_up; | ||
146 | int cts_down; | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * Device instance data structure | ||
151 | */ | ||
152 | typedef struct _synclinkmp_info { | ||
153 | void *if_ptr; /* General purpose pointer (used by SPPP) */ | ||
154 | int magic; | ||
155 | struct tty_port port; | ||
156 | int line; | ||
157 | unsigned short close_delay; | ||
158 | unsigned short closing_wait; /* time to wait before closing */ | ||
159 | |||
160 | struct mgsl_icount icount; | ||
161 | |||
162 | int timeout; | ||
163 | int x_char; /* xon/xoff character */ | ||
164 | u16 read_status_mask1; /* break detection (SR1 indications) */ | ||
165 | u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ | ||
166 | unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ | ||
167 | unsigned char ignore_status_mask2; /* parity/framing/overun (SR2 indications) */ | ||
168 | unsigned char *tx_buf; | ||
169 | int tx_put; | ||
170 | int tx_get; | ||
171 | int tx_count; | ||
172 | |||
173 | wait_queue_head_t status_event_wait_q; | ||
174 | wait_queue_head_t event_wait_q; | ||
175 | struct timer_list tx_timer; /* HDLC transmit timeout timer */ | ||
176 | struct _synclinkmp_info *next_device; /* device list link */ | ||
177 | struct timer_list status_timer; /* input signal status check timer */ | ||
178 | |||
179 | spinlock_t lock; /* spinlock for synchronizing with ISR */ | ||
180 | struct work_struct task; /* task structure for scheduling bh */ | ||
181 | |||
182 | u32 max_frame_size; /* as set by device config */ | ||
183 | |||
184 | u32 pending_bh; | ||
185 | |||
186 | bool bh_running; /* Protection from multiple */ | ||
187 | int isr_overflow; | ||
188 | bool bh_requested; | ||
189 | |||
190 | int dcd_chkcount; /* check counts to prevent */ | ||
191 | int cts_chkcount; /* too many IRQs if a signal */ | ||
192 | int dsr_chkcount; /* is floating */ | ||
193 | int ri_chkcount; | ||
194 | |||
195 | char *buffer_list; /* virtual address of Rx & Tx buffer lists */ | ||
196 | unsigned long buffer_list_phys; | ||
197 | |||
198 | unsigned int rx_buf_count; /* count of total allocated Rx buffers */ | ||
199 | SCADESC *rx_buf_list; /* list of receive buffer entries */ | ||
200 | SCADESC_EX rx_buf_list_ex[SCAMAXDESC]; /* list of receive buffer entries */ | ||
201 | unsigned int current_rx_buf; | ||
202 | |||
203 | unsigned int tx_buf_count; /* count of total allocated Tx buffers */ | ||
204 | SCADESC *tx_buf_list; /* list of transmit buffer entries */ | ||
205 | SCADESC_EX tx_buf_list_ex[SCAMAXDESC]; /* list of transmit buffer entries */ | ||
206 | unsigned int last_tx_buf; | ||
207 | |||
208 | unsigned char *tmp_rx_buf; | ||
209 | unsigned int tmp_rx_buf_count; | ||
210 | |||
211 | bool rx_enabled; | ||
212 | bool rx_overflow; | ||
213 | |||
214 | bool tx_enabled; | ||
215 | bool tx_active; | ||
216 | u32 idle_mode; | ||
217 | |||
218 | unsigned char ie0_value; | ||
219 | unsigned char ie1_value; | ||
220 | unsigned char ie2_value; | ||
221 | unsigned char ctrlreg_value; | ||
222 | unsigned char old_signals; | ||
223 | |||
224 | char device_name[25]; /* device instance name */ | ||
225 | |||
226 | int port_count; | ||
227 | int adapter_num; | ||
228 | int port_num; | ||
229 | |||
230 | struct _synclinkmp_info *port_array[SCA_MAX_PORTS]; | ||
231 | |||
232 | unsigned int bus_type; /* expansion bus type (ISA,EISA,PCI) */ | ||
233 | |||
234 | unsigned int irq_level; /* interrupt level */ | ||
235 | unsigned long irq_flags; | ||
236 | bool irq_requested; /* true if IRQ requested */ | ||
237 | |||
238 | MGSL_PARAMS params; /* communications parameters */ | ||
239 | |||
240 | unsigned char serial_signals; /* current serial signal states */ | ||
241 | |||
242 | bool irq_occurred; /* for diagnostics use */ | ||
243 | unsigned int init_error; /* Initialization startup error */ | ||
244 | |||
245 | u32 last_mem_alloc; | ||
246 | unsigned char* memory_base; /* shared memory address (PCI only) */ | ||
247 | u32 phys_memory_base; | ||
248 | int shared_mem_requested; | ||
249 | |||
250 | unsigned char* sca_base; /* HD64570 SCA Memory address */ | ||
251 | u32 phys_sca_base; | ||
252 | u32 sca_offset; | ||
253 | bool sca_base_requested; | ||
254 | |||
255 | unsigned char* lcr_base; /* local config registers (PCI only) */ | ||
256 | u32 phys_lcr_base; | ||
257 | u32 lcr_offset; | ||
258 | int lcr_mem_requested; | ||
259 | |||
260 | unsigned char* statctrl_base; /* status/control register memory */ | ||
261 | u32 phys_statctrl_base; | ||
262 | u32 statctrl_offset; | ||
263 | bool sca_statctrl_requested; | ||
264 | |||
265 | u32 misc_ctrl_value; | ||
266 | char flag_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
267 | char char_buf[MAX_ASYNC_BUFFER_SIZE]; | ||
268 | bool drop_rts_on_tx_done; | ||
269 | |||
270 | struct _input_signal_events input_signal_events; | ||
271 | |||
272 | /* SPPP/Cisco HDLC device parts */ | ||
273 | int netcount; | ||
274 | spinlock_t netlock; | ||
275 | |||
276 | #if SYNCLINK_GENERIC_HDLC | ||
277 | struct net_device *netdev; | ||
278 | #endif | ||
279 | |||
280 | } SLMP_INFO; | ||
281 | |||
282 | #define MGSL_MAGIC 0x5401 | ||
283 | |||
284 | /* | ||
285 | * define serial signal status change macros | ||
286 | */ | ||
287 | #define MISCSTATUS_DCD_LATCHED (SerialSignal_DCD<<8) /* indicates change in DCD */ | ||
288 | #define MISCSTATUS_RI_LATCHED (SerialSignal_RI<<8) /* indicates change in RI */ | ||
289 | #define MISCSTATUS_CTS_LATCHED (SerialSignal_CTS<<8) /* indicates change in CTS */ | ||
290 | #define MISCSTATUS_DSR_LATCHED (SerialSignal_DSR<<8) /* change in DSR */ | ||
291 | |||
292 | /* Common Register macros */ | ||
293 | #define LPR 0x00 | ||
294 | #define PABR0 0x02 | ||
295 | #define PABR1 0x03 | ||
296 | #define WCRL 0x04 | ||
297 | #define WCRM 0x05 | ||
298 | #define WCRH 0x06 | ||
299 | #define DPCR 0x08 | ||
300 | #define DMER 0x09 | ||
301 | #define ISR0 0x10 | ||
302 | #define ISR1 0x11 | ||
303 | #define ISR2 0x12 | ||
304 | #define IER0 0x14 | ||
305 | #define IER1 0x15 | ||
306 | #define IER2 0x16 | ||
307 | #define ITCR 0x18 | ||
308 | #define INTVR 0x1a | ||
309 | #define IMVR 0x1c | ||
310 | |||
311 | /* MSCI Register macros */ | ||
312 | #define TRB 0x20 | ||
313 | #define TRBL 0x20 | ||
314 | #define TRBH 0x21 | ||
315 | #define SR0 0x22 | ||
316 | #define SR1 0x23 | ||
317 | #define SR2 0x24 | ||
318 | #define SR3 0x25 | ||
319 | #define FST 0x26 | ||
320 | #define IE0 0x28 | ||
321 | #define IE1 0x29 | ||
322 | #define IE2 0x2a | ||
323 | #define FIE 0x2b | ||
324 | #define CMD 0x2c | ||
325 | #define MD0 0x2e | ||
326 | #define MD1 0x2f | ||
327 | #define MD2 0x30 | ||
328 | #define CTL 0x31 | ||
329 | #define SA0 0x32 | ||
330 | #define SA1 0x33 | ||
331 | #define IDL 0x34 | ||
332 | #define TMC 0x35 | ||
333 | #define RXS 0x36 | ||
334 | #define TXS 0x37 | ||
335 | #define TRC0 0x38 | ||
336 | #define TRC1 0x39 | ||
337 | #define RRC 0x3a | ||
338 | #define CST0 0x3c | ||
339 | #define CST1 0x3d | ||
340 | |||
341 | /* Timer Register Macros */ | ||
342 | #define TCNT 0x60 | ||
343 | #define TCNTL 0x60 | ||
344 | #define TCNTH 0x61 | ||
345 | #define TCONR 0x62 | ||
346 | #define TCONRL 0x62 | ||
347 | #define TCONRH 0x63 | ||
348 | #define TMCS 0x64 | ||
349 | #define TEPR 0x65 | ||
350 | |||
351 | /* DMA Controller Register macros */ | ||
352 | #define DARL 0x80 | ||
353 | #define DARH 0x81 | ||
354 | #define DARB 0x82 | ||
355 | #define BAR 0x80 | ||
356 | #define BARL 0x80 | ||
357 | #define BARH 0x81 | ||
358 | #define BARB 0x82 | ||
359 | #define SAR 0x84 | ||
360 | #define SARL 0x84 | ||
361 | #define SARH 0x85 | ||
362 | #define SARB 0x86 | ||
363 | #define CPB 0x86 | ||
364 | #define CDA 0x88 | ||
365 | #define CDAL 0x88 | ||
366 | #define CDAH 0x89 | ||
367 | #define EDA 0x8a | ||
368 | #define EDAL 0x8a | ||
369 | #define EDAH 0x8b | ||
370 | #define BFL 0x8c | ||
371 | #define BFLL 0x8c | ||
372 | #define BFLH 0x8d | ||
373 | #define BCR 0x8e | ||
374 | #define BCRL 0x8e | ||
375 | #define BCRH 0x8f | ||
376 | #define DSR 0x90 | ||
377 | #define DMR 0x91 | ||
378 | #define FCT 0x93 | ||
379 | #define DIR 0x94 | ||
380 | #define DCMD 0x95 | ||
381 | |||
382 | /* combine with timer or DMA register address */ | ||
383 | #define TIMER0 0x00 | ||
384 | #define TIMER1 0x08 | ||
385 | #define TIMER2 0x10 | ||
386 | #define TIMER3 0x18 | ||
387 | #define RXDMA 0x00 | ||
388 | #define TXDMA 0x20 | ||
389 | |||
390 | /* SCA Command Codes */ | ||
391 | #define NOOP 0x00 | ||
392 | #define TXRESET 0x01 | ||
393 | #define TXENABLE 0x02 | ||
394 | #define TXDISABLE 0x03 | ||
395 | #define TXCRCINIT 0x04 | ||
396 | #define TXCRCEXCL 0x05 | ||
397 | #define TXEOM 0x06 | ||
398 | #define TXABORT 0x07 | ||
399 | #define MPON 0x08 | ||
400 | #define TXBUFCLR 0x09 | ||
401 | #define RXRESET 0x11 | ||
402 | #define RXENABLE 0x12 | ||
403 | #define RXDISABLE 0x13 | ||
404 | #define RXCRCINIT 0x14 | ||
405 | #define RXREJECT 0x15 | ||
406 | #define SEARCHMP 0x16 | ||
407 | #define RXCRCEXCL 0x17 | ||
408 | #define RXCRCCALC 0x18 | ||
409 | #define CHRESET 0x21 | ||
410 | #define HUNT 0x31 | ||
411 | |||
412 | /* DMA command codes */ | ||
413 | #define SWABORT 0x01 | ||
414 | #define FEICLEAR 0x02 | ||
415 | |||
416 | /* IE0 */ | ||
417 | #define TXINTE BIT7 | ||
418 | #define RXINTE BIT6 | ||
419 | #define TXRDYE BIT1 | ||
420 | #define RXRDYE BIT0 | ||
421 | |||
422 | /* IE1 & SR1 */ | ||
423 | #define UDRN BIT7 | ||
424 | #define IDLE BIT6 | ||
425 | #define SYNCD BIT4 | ||
426 | #define FLGD BIT4 | ||
427 | #define CCTS BIT3 | ||
428 | #define CDCD BIT2 | ||
429 | #define BRKD BIT1 | ||
430 | #define ABTD BIT1 | ||
431 | #define GAPD BIT1 | ||
432 | #define BRKE BIT0 | ||
433 | #define IDLD BIT0 | ||
434 | |||
435 | /* IE2 & SR2 */ | ||
436 | #define EOM BIT7 | ||
437 | #define PMP BIT6 | ||
438 | #define SHRT BIT6 | ||
439 | #define PE BIT5 | ||
440 | #define ABT BIT5 | ||
441 | #define FRME BIT4 | ||
442 | #define RBIT BIT4 | ||
443 | #define OVRN BIT3 | ||
444 | #define CRCE BIT2 | ||
445 | |||
446 | |||
447 | /* | ||
448 | * Global linked list of SyncLink devices | ||
449 | */ | ||
450 | static SLMP_INFO *synclinkmp_device_list = NULL; | ||
451 | static int synclinkmp_adapter_count = -1; | ||
452 | static int synclinkmp_device_count = 0; | ||
453 | |||
454 | /* | ||
455 | * Set this param to non-zero to load eax with the | ||
456 | * .text section address and breakpoint on module load. | ||
457 | * This is useful for use with gdb and add-symbol-file command. | ||
458 | */ | ||
459 | static int break_on_load = 0; | ||
460 | |||
461 | /* | ||
462 | * Driver major number, defaults to zero to get auto | ||
463 | * assigned major number. May be forced as module parameter. | ||
464 | */ | ||
465 | static int ttymajor = 0; | ||
466 | |||
467 | /* | ||
468 | * Array of user specified options for ISA adapters. | ||
469 | */ | ||
470 | static int debug_level = 0; | ||
471 | static int maxframe[MAX_DEVICES] = {0,}; | ||
472 | |||
473 | module_param(break_on_load, bool, 0); | ||
474 | module_param(ttymajor, int, 0); | ||
475 | module_param(debug_level, int, 0); | ||
476 | module_param_array(maxframe, int, NULL, 0); | ||
477 | |||
478 | static char *driver_name = "SyncLink MultiPort driver"; | ||
479 | static char *driver_version = "$Revision: 4.38 $"; | ||
480 | |||
481 | static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); | ||
482 | static void synclinkmp_remove_one(struct pci_dev *dev); | ||
483 | |||
484 | static struct pci_device_id synclinkmp_pci_tbl[] = { | ||
485 | { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, | ||
486 | { 0, }, /* terminate list */ | ||
487 | }; | ||
488 | MODULE_DEVICE_TABLE(pci, synclinkmp_pci_tbl); | ||
489 | |||
490 | MODULE_LICENSE("GPL"); | ||
491 | |||
492 | static struct pci_driver synclinkmp_pci_driver = { | ||
493 | .name = "synclinkmp", | ||
494 | .id_table = synclinkmp_pci_tbl, | ||
495 | .probe = synclinkmp_init_one, | ||
496 | .remove = __devexit_p(synclinkmp_remove_one), | ||
497 | }; | ||
498 | |||
499 | |||
500 | static struct tty_driver *serial_driver; | ||
501 | |||
502 | /* number of characters left in xmit buffer before we ask for more */ | ||
503 | #define WAKEUP_CHARS 256 | ||
504 | |||
505 | |||
506 | /* tty callbacks */ | ||
507 | |||
508 | static int open(struct tty_struct *tty, struct file * filp); | ||
509 | static void close(struct tty_struct *tty, struct file * filp); | ||
510 | static void hangup(struct tty_struct *tty); | ||
511 | static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); | ||
512 | |||
513 | static int write(struct tty_struct *tty, const unsigned char *buf, int count); | ||
514 | static int put_char(struct tty_struct *tty, unsigned char ch); | ||
515 | static void send_xchar(struct tty_struct *tty, char ch); | ||
516 | static void wait_until_sent(struct tty_struct *tty, int timeout); | ||
517 | static int write_room(struct tty_struct *tty); | ||
518 | static void flush_chars(struct tty_struct *tty); | ||
519 | static void flush_buffer(struct tty_struct *tty); | ||
520 | static void tx_hold(struct tty_struct *tty); | ||
521 | static void tx_release(struct tty_struct *tty); | ||
522 | |||
523 | static int ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); | ||
524 | static int chars_in_buffer(struct tty_struct *tty); | ||
525 | static void throttle(struct tty_struct * tty); | ||
526 | static void unthrottle(struct tty_struct * tty); | ||
527 | static int set_break(struct tty_struct *tty, int break_state); | ||
528 | |||
529 | #if SYNCLINK_GENERIC_HDLC | ||
530 | #define dev_to_port(D) (dev_to_hdlc(D)->priv) | ||
531 | static void hdlcdev_tx_done(SLMP_INFO *info); | ||
532 | static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size); | ||
533 | static int hdlcdev_init(SLMP_INFO *info); | ||
534 | static void hdlcdev_exit(SLMP_INFO *info); | ||
535 | #endif | ||
536 | |||
537 | /* ioctl handlers */ | ||
538 | |||
539 | static int get_stats(SLMP_INFO *info, struct mgsl_icount __user *user_icount); | ||
540 | static int get_params(SLMP_INFO *info, MGSL_PARAMS __user *params); | ||
541 | static int set_params(SLMP_INFO *info, MGSL_PARAMS __user *params); | ||
542 | static int get_txidle(SLMP_INFO *info, int __user *idle_mode); | ||
543 | static int set_txidle(SLMP_INFO *info, int idle_mode); | ||
544 | static int tx_enable(SLMP_INFO *info, int enable); | ||
545 | static int tx_abort(SLMP_INFO *info); | ||
546 | static int rx_enable(SLMP_INFO *info, int enable); | ||
547 | static int modem_input_wait(SLMP_INFO *info,int arg); | ||
548 | static int wait_mgsl_event(SLMP_INFO *info, int __user *mask_ptr); | ||
549 | static int tiocmget(struct tty_struct *tty); | ||
550 | static int tiocmset(struct tty_struct *tty, | ||
551 | unsigned int set, unsigned int clear); | ||
552 | static int set_break(struct tty_struct *tty, int break_state); | ||
553 | |||
554 | static void add_device(SLMP_INFO *info); | ||
555 | static void device_init(int adapter_num, struct pci_dev *pdev); | ||
556 | static int claim_resources(SLMP_INFO *info); | ||
557 | static void release_resources(SLMP_INFO *info); | ||
558 | |||
559 | static int startup(SLMP_INFO *info); | ||
560 | static int block_til_ready(struct tty_struct *tty, struct file * filp,SLMP_INFO *info); | ||
561 | static int carrier_raised(struct tty_port *port); | ||
562 | static void shutdown(SLMP_INFO *info); | ||
563 | static void program_hw(SLMP_INFO *info); | ||
564 | static void change_params(SLMP_INFO *info); | ||
565 | |||
566 | static bool init_adapter(SLMP_INFO *info); | ||
567 | static bool register_test(SLMP_INFO *info); | ||
568 | static bool irq_test(SLMP_INFO *info); | ||
569 | static bool loopback_test(SLMP_INFO *info); | ||
570 | static int adapter_test(SLMP_INFO *info); | ||
571 | static bool memory_test(SLMP_INFO *info); | ||
572 | |||
573 | static void reset_adapter(SLMP_INFO *info); | ||
574 | static void reset_port(SLMP_INFO *info); | ||
575 | static void async_mode(SLMP_INFO *info); | ||
576 | static void hdlc_mode(SLMP_INFO *info); | ||
577 | |||
578 | static void rx_stop(SLMP_INFO *info); | ||
579 | static void rx_start(SLMP_INFO *info); | ||
580 | static void rx_reset_buffers(SLMP_INFO *info); | ||
581 | static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last); | ||
582 | static bool rx_get_frame(SLMP_INFO *info); | ||
583 | |||
584 | static void tx_start(SLMP_INFO *info); | ||
585 | static void tx_stop(SLMP_INFO *info); | ||
586 | static void tx_load_fifo(SLMP_INFO *info); | ||
587 | static void tx_set_idle(SLMP_INFO *info); | ||
588 | static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count); | ||
589 | |||
590 | static void get_signals(SLMP_INFO *info); | ||
591 | static void set_signals(SLMP_INFO *info); | ||
592 | static void enable_loopback(SLMP_INFO *info, int enable); | ||
593 | static void set_rate(SLMP_INFO *info, u32 data_rate); | ||
594 | |||
595 | static int bh_action(SLMP_INFO *info); | ||
596 | static void bh_handler(struct work_struct *work); | ||
597 | static void bh_receive(SLMP_INFO *info); | ||
598 | static void bh_transmit(SLMP_INFO *info); | ||
599 | static void bh_status(SLMP_INFO *info); | ||
600 | static void isr_timer(SLMP_INFO *info); | ||
601 | static void isr_rxint(SLMP_INFO *info); | ||
602 | static void isr_rxrdy(SLMP_INFO *info); | ||
603 | static void isr_txint(SLMP_INFO *info); | ||
604 | static void isr_txrdy(SLMP_INFO *info); | ||
605 | static void isr_rxdmaok(SLMP_INFO *info); | ||
606 | static void isr_rxdmaerror(SLMP_INFO *info); | ||
607 | static void isr_txdmaok(SLMP_INFO *info); | ||
608 | static void isr_txdmaerror(SLMP_INFO *info); | ||
609 | static void isr_io_pin(SLMP_INFO *info, u16 status); | ||
610 | |||
611 | static int alloc_dma_bufs(SLMP_INFO *info); | ||
612 | static void free_dma_bufs(SLMP_INFO *info); | ||
613 | static int alloc_buf_list(SLMP_INFO *info); | ||
614 | static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *list, SCADESC_EX *list_ex,int count); | ||
615 | static int alloc_tmp_rx_buf(SLMP_INFO *info); | ||
616 | static void free_tmp_rx_buf(SLMP_INFO *info); | ||
617 | |||
618 | static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count); | ||
619 | static void trace_block(SLMP_INFO *info, const char* data, int count, int xmit); | ||
620 | static void tx_timeout(unsigned long context); | ||
621 | static void status_timeout(unsigned long context); | ||
622 | |||
623 | static unsigned char read_reg(SLMP_INFO *info, unsigned char addr); | ||
624 | static void write_reg(SLMP_INFO *info, unsigned char addr, unsigned char val); | ||
625 | static u16 read_reg16(SLMP_INFO *info, unsigned char addr); | ||
626 | static void write_reg16(SLMP_INFO *info, unsigned char addr, u16 val); | ||
627 | static unsigned char read_status_reg(SLMP_INFO * info); | ||
628 | static void write_control_reg(SLMP_INFO * info); | ||
629 | |||
630 | |||
631 | static unsigned char rx_active_fifo_level = 16; // rx request FIFO activation level in bytes | ||
632 | static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation level in bytes | ||
633 | static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes | ||
634 | |||
635 | static u32 misc_ctrl_value = 0x007e4040; | ||
636 | static u32 lcr1_brdr_value = 0x00800028; | ||
637 | |||
638 | static u32 read_ahead_count = 8; | ||
639 | |||
640 | /* DPCR, DMA Priority Control | ||
641 | * | ||
642 | * 07..05 Not used, must be 0 | ||
643 | * 04 BRC, bus release condition: 0=all transfers complete | ||
644 | * 1=release after 1 xfer on all channels | ||
645 | * 03 CCC, channel change condition: 0=every cycle | ||
646 | * 1=after each channel completes all xfers | ||
647 | * 02..00 PR<2..0>, priority 100=round robin | ||
648 | * | ||
649 | * 00000100 = 0x00 | ||
650 | */ | ||
651 | static unsigned char dma_priority = 0x04; | ||
652 | |||
653 | // Number of bytes that can be written to shared RAM | ||
654 | // in a single write operation | ||
655 | static u32 sca_pci_load_interval = 64; | ||
656 | |||
657 | /* | ||
658 | * 1st function defined in .text section. Calling this function in | ||
659 | * init_module() followed by a breakpoint allows a remote debugger | ||
660 | * (gdb) to get the .text address for the add-symbol-file command. | ||
661 | * This allows remote debugging of dynamically loadable modules. | ||
662 | */ | ||
663 | static void* synclinkmp_get_text_ptr(void); | ||
664 | static void* synclinkmp_get_text_ptr(void) {return synclinkmp_get_text_ptr;} | ||
665 | |||
666 | static inline int sanity_check(SLMP_INFO *info, | ||
667 | char *name, const char *routine) | ||
668 | { | ||
669 | #ifdef SANITY_CHECK | ||
670 | static const char *badmagic = | ||
671 | "Warning: bad magic number for synclinkmp_struct (%s) in %s\n"; | ||
672 | static const char *badinfo = | ||
673 | "Warning: null synclinkmp_struct for (%s) in %s\n"; | ||
674 | |||
675 | if (!info) { | ||
676 | printk(badinfo, name, routine); | ||
677 | return 1; | ||
678 | } | ||
679 | if (info->magic != MGSL_MAGIC) { | ||
680 | printk(badmagic, name, routine); | ||
681 | return 1; | ||
682 | } | ||
683 | #else | ||
684 | if (!info) | ||
685 | return 1; | ||
686 | #endif | ||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | /** | ||
691 | * line discipline callback wrappers | ||
692 | * | ||
693 | * The wrappers maintain line discipline references | ||
694 | * while calling into the line discipline. | ||
695 | * | ||
696 | * ldisc_receive_buf - pass receive data to line discipline | ||
697 | */ | ||
698 | |||
699 | static void ldisc_receive_buf(struct tty_struct *tty, | ||
700 | const __u8 *data, char *flags, int count) | ||
701 | { | ||
702 | struct tty_ldisc *ld; | ||
703 | if (!tty) | ||
704 | return; | ||
705 | ld = tty_ldisc_ref(tty); | ||
706 | if (ld) { | ||
707 | if (ld->ops->receive_buf) | ||
708 | ld->ops->receive_buf(tty, data, flags, count); | ||
709 | tty_ldisc_deref(ld); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | /* tty callbacks */ | ||
714 | |||
715 | /* Called when a port is opened. Init and enable port. | ||
716 | */ | ||
717 | static int open(struct tty_struct *tty, struct file *filp) | ||
718 | { | ||
719 | SLMP_INFO *info; | ||
720 | int retval, line; | ||
721 | unsigned long flags; | ||
722 | |||
723 | line = tty->index; | ||
724 | if ((line < 0) || (line >= synclinkmp_device_count)) { | ||
725 | printk("%s(%d): open with invalid line #%d.\n", | ||
726 | __FILE__,__LINE__,line); | ||
727 | return -ENODEV; | ||
728 | } | ||
729 | |||
730 | info = synclinkmp_device_list; | ||
731 | while(info && info->line != line) | ||
732 | info = info->next_device; | ||
733 | if (sanity_check(info, tty->name, "open")) | ||
734 | return -ENODEV; | ||
735 | if ( info->init_error ) { | ||
736 | printk("%s(%d):%s device is not allocated, init error=%d\n", | ||
737 | __FILE__,__LINE__,info->device_name,info->init_error); | ||
738 | return -ENODEV; | ||
739 | } | ||
740 | |||
741 | tty->driver_data = info; | ||
742 | info->port.tty = tty; | ||
743 | |||
744 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
745 | printk("%s(%d):%s open(), old ref count = %d\n", | ||
746 | __FILE__,__LINE__,tty->driver->name, info->port.count); | ||
747 | |||
748 | /* If port is closing, signal caller to try again */ | ||
749 | if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){ | ||
750 | if (info->port.flags & ASYNC_CLOSING) | ||
751 | interruptible_sleep_on(&info->port.close_wait); | ||
752 | retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? | ||
753 | -EAGAIN : -ERESTARTSYS); | ||
754 | goto cleanup; | ||
755 | } | ||
756 | |||
757 | info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; | ||
758 | |||
759 | spin_lock_irqsave(&info->netlock, flags); | ||
760 | if (info->netcount) { | ||
761 | retval = -EBUSY; | ||
762 | spin_unlock_irqrestore(&info->netlock, flags); | ||
763 | goto cleanup; | ||
764 | } | ||
765 | info->port.count++; | ||
766 | spin_unlock_irqrestore(&info->netlock, flags); | ||
767 | |||
768 | if (info->port.count == 1) { | ||
769 | /* 1st open on this device, init hardware */ | ||
770 | retval = startup(info); | ||
771 | if (retval < 0) | ||
772 | goto cleanup; | ||
773 | } | ||
774 | |||
775 | retval = block_til_ready(tty, filp, info); | ||
776 | if (retval) { | ||
777 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
778 | printk("%s(%d):%s block_til_ready() returned %d\n", | ||
779 | __FILE__,__LINE__, info->device_name, retval); | ||
780 | goto cleanup; | ||
781 | } | ||
782 | |||
783 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
784 | printk("%s(%d):%s open() success\n", | ||
785 | __FILE__,__LINE__, info->device_name); | ||
786 | retval = 0; | ||
787 | |||
788 | cleanup: | ||
789 | if (retval) { | ||
790 | if (tty->count == 1) | ||
791 | info->port.tty = NULL; /* tty layer will release tty struct */ | ||
792 | if(info->port.count) | ||
793 | info->port.count--; | ||
794 | } | ||
795 | |||
796 | return retval; | ||
797 | } | ||
798 | |||
799 | /* Called when port is closed. Wait for remaining data to be | ||
800 | * sent. Disable port and free resources. | ||
801 | */ | ||
802 | static void close(struct tty_struct *tty, struct file *filp) | ||
803 | { | ||
804 | SLMP_INFO * info = tty->driver_data; | ||
805 | |||
806 | if (sanity_check(info, tty->name, "close")) | ||
807 | return; | ||
808 | |||
809 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
810 | printk("%s(%d):%s close() entry, count=%d\n", | ||
811 | __FILE__,__LINE__, info->device_name, info->port.count); | ||
812 | |||
813 | if (tty_port_close_start(&info->port, tty, filp) == 0) | ||
814 | goto cleanup; | ||
815 | |||
816 | mutex_lock(&info->port.mutex); | ||
817 | if (info->port.flags & ASYNC_INITIALIZED) | ||
818 | wait_until_sent(tty, info->timeout); | ||
819 | |||
820 | flush_buffer(tty); | ||
821 | tty_ldisc_flush(tty); | ||
822 | shutdown(info); | ||
823 | mutex_unlock(&info->port.mutex); | ||
824 | |||
825 | tty_port_close_end(&info->port, tty); | ||
826 | info->port.tty = NULL; | ||
827 | cleanup: | ||
828 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
829 | printk("%s(%d):%s close() exit, count=%d\n", __FILE__,__LINE__, | ||
830 | tty->driver->name, info->port.count); | ||
831 | } | ||
832 | |||
833 | /* Called by tty_hangup() when a hangup is signaled. | ||
834 | * This is the same as closing all open descriptors for the port. | ||
835 | */ | ||
836 | static void hangup(struct tty_struct *tty) | ||
837 | { | ||
838 | SLMP_INFO *info = tty->driver_data; | ||
839 | unsigned long flags; | ||
840 | |||
841 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
842 | printk("%s(%d):%s hangup()\n", | ||
843 | __FILE__,__LINE__, info->device_name ); | ||
844 | |||
845 | if (sanity_check(info, tty->name, "hangup")) | ||
846 | return; | ||
847 | |||
848 | mutex_lock(&info->port.mutex); | ||
849 | flush_buffer(tty); | ||
850 | shutdown(info); | ||
851 | |||
852 | spin_lock_irqsave(&info->port.lock, flags); | ||
853 | info->port.count = 0; | ||
854 | info->port.flags &= ~ASYNC_NORMAL_ACTIVE; | ||
855 | info->port.tty = NULL; | ||
856 | spin_unlock_irqrestore(&info->port.lock, flags); | ||
857 | mutex_unlock(&info->port.mutex); | ||
858 | |||
859 | wake_up_interruptible(&info->port.open_wait); | ||
860 | } | ||
861 | |||
862 | /* Set new termios settings | ||
863 | */ | ||
864 | static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) | ||
865 | { | ||
866 | SLMP_INFO *info = tty->driver_data; | ||
867 | unsigned long flags; | ||
868 | |||
869 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
870 | printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, | ||
871 | tty->driver->name ); | ||
872 | |||
873 | change_params(info); | ||
874 | |||
875 | /* Handle transition to B0 status */ | ||
876 | if (old_termios->c_cflag & CBAUD && | ||
877 | !(tty->termios->c_cflag & CBAUD)) { | ||
878 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
879 | spin_lock_irqsave(&info->lock,flags); | ||
880 | set_signals(info); | ||
881 | spin_unlock_irqrestore(&info->lock,flags); | ||
882 | } | ||
883 | |||
884 | /* Handle transition away from B0 status */ | ||
885 | if (!(old_termios->c_cflag & CBAUD) && | ||
886 | tty->termios->c_cflag & CBAUD) { | ||
887 | info->serial_signals |= SerialSignal_DTR; | ||
888 | if (!(tty->termios->c_cflag & CRTSCTS) || | ||
889 | !test_bit(TTY_THROTTLED, &tty->flags)) { | ||
890 | info->serial_signals |= SerialSignal_RTS; | ||
891 | } | ||
892 | spin_lock_irqsave(&info->lock,flags); | ||
893 | set_signals(info); | ||
894 | spin_unlock_irqrestore(&info->lock,flags); | ||
895 | } | ||
896 | |||
897 | /* Handle turning off CRTSCTS */ | ||
898 | if (old_termios->c_cflag & CRTSCTS && | ||
899 | !(tty->termios->c_cflag & CRTSCTS)) { | ||
900 | tty->hw_stopped = 0; | ||
901 | tx_release(tty); | ||
902 | } | ||
903 | } | ||
904 | |||
905 | /* Send a block of data | ||
906 | * | ||
907 | * Arguments: | ||
908 | * | ||
909 | * tty pointer to tty information structure | ||
910 | * buf pointer to buffer containing send data | ||
911 | * count size of send data in bytes | ||
912 | * | ||
913 | * Return Value: number of characters written | ||
914 | */ | ||
915 | static int write(struct tty_struct *tty, | ||
916 | const unsigned char *buf, int count) | ||
917 | { | ||
918 | int c, ret = 0; | ||
919 | SLMP_INFO *info = tty->driver_data; | ||
920 | unsigned long flags; | ||
921 | |||
922 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
923 | printk("%s(%d):%s write() count=%d\n", | ||
924 | __FILE__,__LINE__,info->device_name,count); | ||
925 | |||
926 | if (sanity_check(info, tty->name, "write")) | ||
927 | goto cleanup; | ||
928 | |||
929 | if (!info->tx_buf) | ||
930 | goto cleanup; | ||
931 | |||
932 | if (info->params.mode == MGSL_MODE_HDLC) { | ||
933 | if (count > info->max_frame_size) { | ||
934 | ret = -EIO; | ||
935 | goto cleanup; | ||
936 | } | ||
937 | if (info->tx_active) | ||
938 | goto cleanup; | ||
939 | if (info->tx_count) { | ||
940 | /* send accumulated data from send_char() calls */ | ||
941 | /* as frame and wait before accepting more data. */ | ||
942 | tx_load_dma_buffer(info, info->tx_buf, info->tx_count); | ||
943 | goto start; | ||
944 | } | ||
945 | ret = info->tx_count = count; | ||
946 | tx_load_dma_buffer(info, buf, count); | ||
947 | goto start; | ||
948 | } | ||
949 | |||
950 | for (;;) { | ||
951 | c = min_t(int, count, | ||
952 | min(info->max_frame_size - info->tx_count - 1, | ||
953 | info->max_frame_size - info->tx_put)); | ||
954 | if (c <= 0) | ||
955 | break; | ||
956 | |||
957 | memcpy(info->tx_buf + info->tx_put, buf, c); | ||
958 | |||
959 | spin_lock_irqsave(&info->lock,flags); | ||
960 | info->tx_put += c; | ||
961 | if (info->tx_put >= info->max_frame_size) | ||
962 | info->tx_put -= info->max_frame_size; | ||
963 | info->tx_count += c; | ||
964 | spin_unlock_irqrestore(&info->lock,flags); | ||
965 | |||
966 | buf += c; | ||
967 | count -= c; | ||
968 | ret += c; | ||
969 | } | ||
970 | |||
971 | if (info->params.mode == MGSL_MODE_HDLC) { | ||
972 | if (count) { | ||
973 | ret = info->tx_count = 0; | ||
974 | goto cleanup; | ||
975 | } | ||
976 | tx_load_dma_buffer(info, info->tx_buf, info->tx_count); | ||
977 | } | ||
978 | start: | ||
979 | if (info->tx_count && !tty->stopped && !tty->hw_stopped) { | ||
980 | spin_lock_irqsave(&info->lock,flags); | ||
981 | if (!info->tx_active) | ||
982 | tx_start(info); | ||
983 | spin_unlock_irqrestore(&info->lock,flags); | ||
984 | } | ||
985 | |||
986 | cleanup: | ||
987 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
988 | printk( "%s(%d):%s write() returning=%d\n", | ||
989 | __FILE__,__LINE__,info->device_name,ret); | ||
990 | return ret; | ||
991 | } | ||
992 | |||
993 | /* Add a character to the transmit buffer. | ||
994 | */ | ||
995 | static int put_char(struct tty_struct *tty, unsigned char ch) | ||
996 | { | ||
997 | SLMP_INFO *info = tty->driver_data; | ||
998 | unsigned long flags; | ||
999 | int ret = 0; | ||
1000 | |||
1001 | if ( debug_level >= DEBUG_LEVEL_INFO ) { | ||
1002 | printk( "%s(%d):%s put_char(%d)\n", | ||
1003 | __FILE__,__LINE__,info->device_name,ch); | ||
1004 | } | ||
1005 | |||
1006 | if (sanity_check(info, tty->name, "put_char")) | ||
1007 | return 0; | ||
1008 | |||
1009 | if (!info->tx_buf) | ||
1010 | return 0; | ||
1011 | |||
1012 | spin_lock_irqsave(&info->lock,flags); | ||
1013 | |||
1014 | if ( (info->params.mode != MGSL_MODE_HDLC) || | ||
1015 | !info->tx_active ) { | ||
1016 | |||
1017 | if (info->tx_count < info->max_frame_size - 1) { | ||
1018 | info->tx_buf[info->tx_put++] = ch; | ||
1019 | if (info->tx_put >= info->max_frame_size) | ||
1020 | info->tx_put -= info->max_frame_size; | ||
1021 | info->tx_count++; | ||
1022 | ret = 1; | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | spin_unlock_irqrestore(&info->lock,flags); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | /* Send a high-priority XON/XOFF character | ||
1031 | */ | ||
1032 | static void send_xchar(struct tty_struct *tty, char ch) | ||
1033 | { | ||
1034 | SLMP_INFO *info = tty->driver_data; | ||
1035 | unsigned long flags; | ||
1036 | |||
1037 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1038 | printk("%s(%d):%s send_xchar(%d)\n", | ||
1039 | __FILE__,__LINE__, info->device_name, ch ); | ||
1040 | |||
1041 | if (sanity_check(info, tty->name, "send_xchar")) | ||
1042 | return; | ||
1043 | |||
1044 | info->x_char = ch; | ||
1045 | if (ch) { | ||
1046 | /* Make sure transmit interrupts are on */ | ||
1047 | spin_lock_irqsave(&info->lock,flags); | ||
1048 | if (!info->tx_enabled) | ||
1049 | tx_start(info); | ||
1050 | spin_unlock_irqrestore(&info->lock,flags); | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | /* Wait until the transmitter is empty. | ||
1055 | */ | ||
1056 | static void wait_until_sent(struct tty_struct *tty, int timeout) | ||
1057 | { | ||
1058 | SLMP_INFO * info = tty->driver_data; | ||
1059 | unsigned long orig_jiffies, char_time; | ||
1060 | |||
1061 | if (!info ) | ||
1062 | return; | ||
1063 | |||
1064 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1065 | printk("%s(%d):%s wait_until_sent() entry\n", | ||
1066 | __FILE__,__LINE__, info->device_name ); | ||
1067 | |||
1068 | if (sanity_check(info, tty->name, "wait_until_sent")) | ||
1069 | return; | ||
1070 | |||
1071 | if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags)) | ||
1072 | goto exit; | ||
1073 | |||
1074 | orig_jiffies = jiffies; | ||
1075 | |||
1076 | /* Set check interval to 1/5 of estimated time to | ||
1077 | * send a character, and make it at least 1. The check | ||
1078 | * interval should also be less than the timeout. | ||
1079 | * Note: use tight timings here to satisfy the NIST-PCTS. | ||
1080 | */ | ||
1081 | |||
1082 | if ( info->params.data_rate ) { | ||
1083 | char_time = info->timeout/(32 * 5); | ||
1084 | if (!char_time) | ||
1085 | char_time++; | ||
1086 | } else | ||
1087 | char_time = 1; | ||
1088 | |||
1089 | if (timeout) | ||
1090 | char_time = min_t(unsigned long, char_time, timeout); | ||
1091 | |||
1092 | if ( info->params.mode == MGSL_MODE_HDLC ) { | ||
1093 | while (info->tx_active) { | ||
1094 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
1095 | if (signal_pending(current)) | ||
1096 | break; | ||
1097 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
1098 | break; | ||
1099 | } | ||
1100 | } else { | ||
1101 | /* | ||
1102 | * TODO: determine if there is something similar to USC16C32 | ||
1103 | * TXSTATUS_ALL_SENT status | ||
1104 | */ | ||
1105 | while ( info->tx_active && info->tx_enabled) { | ||
1106 | msleep_interruptible(jiffies_to_msecs(char_time)); | ||
1107 | if (signal_pending(current)) | ||
1108 | break; | ||
1109 | if (timeout && time_after(jiffies, orig_jiffies + timeout)) | ||
1110 | break; | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | exit: | ||
1115 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1116 | printk("%s(%d):%s wait_until_sent() exit\n", | ||
1117 | __FILE__,__LINE__, info->device_name ); | ||
1118 | } | ||
1119 | |||
1120 | /* Return the count of free bytes in transmit buffer | ||
1121 | */ | ||
1122 | static int write_room(struct tty_struct *tty) | ||
1123 | { | ||
1124 | SLMP_INFO *info = tty->driver_data; | ||
1125 | int ret; | ||
1126 | |||
1127 | if (sanity_check(info, tty->name, "write_room")) | ||
1128 | return 0; | ||
1129 | |||
1130 | if (info->params.mode == MGSL_MODE_HDLC) { | ||
1131 | ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; | ||
1132 | } else { | ||
1133 | ret = info->max_frame_size - info->tx_count - 1; | ||
1134 | if (ret < 0) | ||
1135 | ret = 0; | ||
1136 | } | ||
1137 | |||
1138 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1139 | printk("%s(%d):%s write_room()=%d\n", | ||
1140 | __FILE__, __LINE__, info->device_name, ret); | ||
1141 | |||
1142 | return ret; | ||
1143 | } | ||
1144 | |||
1145 | /* enable transmitter and send remaining buffered characters | ||
1146 | */ | ||
1147 | static void flush_chars(struct tty_struct *tty) | ||
1148 | { | ||
1149 | SLMP_INFO *info = tty->driver_data; | ||
1150 | unsigned long flags; | ||
1151 | |||
1152 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1153 | printk( "%s(%d):%s flush_chars() entry tx_count=%d\n", | ||
1154 | __FILE__,__LINE__,info->device_name,info->tx_count); | ||
1155 | |||
1156 | if (sanity_check(info, tty->name, "flush_chars")) | ||
1157 | return; | ||
1158 | |||
1159 | if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || | ||
1160 | !info->tx_buf) | ||
1161 | return; | ||
1162 | |||
1163 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1164 | printk( "%s(%d):%s flush_chars() entry, starting transmitter\n", | ||
1165 | __FILE__,__LINE__,info->device_name ); | ||
1166 | |||
1167 | spin_lock_irqsave(&info->lock,flags); | ||
1168 | |||
1169 | if (!info->tx_active) { | ||
1170 | if ( (info->params.mode == MGSL_MODE_HDLC) && | ||
1171 | info->tx_count ) { | ||
1172 | /* operating in synchronous (frame oriented) mode */ | ||
1173 | /* copy data from circular tx_buf to */ | ||
1174 | /* transmit DMA buffer. */ | ||
1175 | tx_load_dma_buffer(info, | ||
1176 | info->tx_buf,info->tx_count); | ||
1177 | } | ||
1178 | tx_start(info); | ||
1179 | } | ||
1180 | |||
1181 | spin_unlock_irqrestore(&info->lock,flags); | ||
1182 | } | ||
1183 | |||
1184 | /* Discard all data in the send buffer | ||
1185 | */ | ||
1186 | static void flush_buffer(struct tty_struct *tty) | ||
1187 | { | ||
1188 | SLMP_INFO *info = tty->driver_data; | ||
1189 | unsigned long flags; | ||
1190 | |||
1191 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1192 | printk("%s(%d):%s flush_buffer() entry\n", | ||
1193 | __FILE__,__LINE__, info->device_name ); | ||
1194 | |||
1195 | if (sanity_check(info, tty->name, "flush_buffer")) | ||
1196 | return; | ||
1197 | |||
1198 | spin_lock_irqsave(&info->lock,flags); | ||
1199 | info->tx_count = info->tx_put = info->tx_get = 0; | ||
1200 | del_timer(&info->tx_timer); | ||
1201 | spin_unlock_irqrestore(&info->lock,flags); | ||
1202 | |||
1203 | tty_wakeup(tty); | ||
1204 | } | ||
1205 | |||
1206 | /* throttle (stop) transmitter | ||
1207 | */ | ||
1208 | static void tx_hold(struct tty_struct *tty) | ||
1209 | { | ||
1210 | SLMP_INFO *info = tty->driver_data; | ||
1211 | unsigned long flags; | ||
1212 | |||
1213 | if (sanity_check(info, tty->name, "tx_hold")) | ||
1214 | return; | ||
1215 | |||
1216 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1217 | printk("%s(%d):%s tx_hold()\n", | ||
1218 | __FILE__,__LINE__,info->device_name); | ||
1219 | |||
1220 | spin_lock_irqsave(&info->lock,flags); | ||
1221 | if (info->tx_enabled) | ||
1222 | tx_stop(info); | ||
1223 | spin_unlock_irqrestore(&info->lock,flags); | ||
1224 | } | ||
1225 | |||
1226 | /* release (start) transmitter | ||
1227 | */ | ||
1228 | static void tx_release(struct tty_struct *tty) | ||
1229 | { | ||
1230 | SLMP_INFO *info = tty->driver_data; | ||
1231 | unsigned long flags; | ||
1232 | |||
1233 | if (sanity_check(info, tty->name, "tx_release")) | ||
1234 | return; | ||
1235 | |||
1236 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
1237 | printk("%s(%d):%s tx_release()\n", | ||
1238 | __FILE__,__LINE__,info->device_name); | ||
1239 | |||
1240 | spin_lock_irqsave(&info->lock,flags); | ||
1241 | if (!info->tx_enabled) | ||
1242 | tx_start(info); | ||
1243 | spin_unlock_irqrestore(&info->lock,flags); | ||
1244 | } | ||
1245 | |||
1246 | /* Service an IOCTL request | ||
1247 | * | ||
1248 | * Arguments: | ||
1249 | * | ||
1250 | * tty pointer to tty instance data | ||
1251 | * cmd IOCTL command code | ||
1252 | * arg command argument/context | ||
1253 | * | ||
1254 | * Return Value: 0 if success, otherwise error code | ||
1255 | */ | ||
1256 | static int ioctl(struct tty_struct *tty, | ||
1257 | unsigned int cmd, unsigned long arg) | ||
1258 | { | ||
1259 | SLMP_INFO *info = tty->driver_data; | ||
1260 | void __user *argp = (void __user *)arg; | ||
1261 | |||
1262 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1263 | printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__, | ||
1264 | info->device_name, cmd ); | ||
1265 | |||
1266 | if (sanity_check(info, tty->name, "ioctl")) | ||
1267 | return -ENODEV; | ||
1268 | |||
1269 | if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && | ||
1270 | (cmd != TIOCMIWAIT)) { | ||
1271 | if (tty->flags & (1 << TTY_IO_ERROR)) | ||
1272 | return -EIO; | ||
1273 | } | ||
1274 | |||
1275 | switch (cmd) { | ||
1276 | case MGSL_IOCGPARAMS: | ||
1277 | return get_params(info, argp); | ||
1278 | case MGSL_IOCSPARAMS: | ||
1279 | return set_params(info, argp); | ||
1280 | case MGSL_IOCGTXIDLE: | ||
1281 | return get_txidle(info, argp); | ||
1282 | case MGSL_IOCSTXIDLE: | ||
1283 | return set_txidle(info, (int)arg); | ||
1284 | case MGSL_IOCTXENABLE: | ||
1285 | return tx_enable(info, (int)arg); | ||
1286 | case MGSL_IOCRXENABLE: | ||
1287 | return rx_enable(info, (int)arg); | ||
1288 | case MGSL_IOCTXABORT: | ||
1289 | return tx_abort(info); | ||
1290 | case MGSL_IOCGSTATS: | ||
1291 | return get_stats(info, argp); | ||
1292 | case MGSL_IOCWAITEVENT: | ||
1293 | return wait_mgsl_event(info, argp); | ||
1294 | case MGSL_IOCLOOPTXDONE: | ||
1295 | return 0; // TODO: Not supported, need to document | ||
1296 | /* Wait for modem input (DCD,RI,DSR,CTS) change | ||
1297 | * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) | ||
1298 | */ | ||
1299 | case TIOCMIWAIT: | ||
1300 | return modem_input_wait(info,(int)arg); | ||
1301 | |||
1302 | /* | ||
1303 | * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) | ||
1304 | * Return: write counters to the user passed counter struct | ||
1305 | * NB: both 1->0 and 0->1 transitions are counted except for | ||
1306 | * RI where only 0->1 is counted. | ||
1307 | */ | ||
1308 | default: | ||
1309 | return -ENOIOCTLCMD; | ||
1310 | } | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | static int get_icount(struct tty_struct *tty, | ||
1315 | struct serial_icounter_struct *icount) | ||
1316 | { | ||
1317 | SLMP_INFO *info = tty->driver_data; | ||
1318 | struct mgsl_icount cnow; /* kernel counter temps */ | ||
1319 | unsigned long flags; | ||
1320 | |||
1321 | spin_lock_irqsave(&info->lock,flags); | ||
1322 | cnow = info->icount; | ||
1323 | spin_unlock_irqrestore(&info->lock,flags); | ||
1324 | |||
1325 | icount->cts = cnow.cts; | ||
1326 | icount->dsr = cnow.dsr; | ||
1327 | icount->rng = cnow.rng; | ||
1328 | icount->dcd = cnow.dcd; | ||
1329 | icount->rx = cnow.rx; | ||
1330 | icount->tx = cnow.tx; | ||
1331 | icount->frame = cnow.frame; | ||
1332 | icount->overrun = cnow.overrun; | ||
1333 | icount->parity = cnow.parity; | ||
1334 | icount->brk = cnow.brk; | ||
1335 | icount->buf_overrun = cnow.buf_overrun; | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | /* | ||
1341 | * /proc fs routines.... | ||
1342 | */ | ||
1343 | |||
1344 | static inline void line_info(struct seq_file *m, SLMP_INFO *info) | ||
1345 | { | ||
1346 | char stat_buf[30]; | ||
1347 | unsigned long flags; | ||
1348 | |||
1349 | seq_printf(m, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" | ||
1350 | "\tIRQ=%d MaxFrameSize=%u\n", | ||
1351 | info->device_name, | ||
1352 | info->phys_sca_base, | ||
1353 | info->phys_memory_base, | ||
1354 | info->phys_statctrl_base, | ||
1355 | info->phys_lcr_base, | ||
1356 | info->irq_level, | ||
1357 | info->max_frame_size ); | ||
1358 | |||
1359 | /* output current serial signal states */ | ||
1360 | spin_lock_irqsave(&info->lock,flags); | ||
1361 | get_signals(info); | ||
1362 | spin_unlock_irqrestore(&info->lock,flags); | ||
1363 | |||
1364 | stat_buf[0] = 0; | ||
1365 | stat_buf[1] = 0; | ||
1366 | if (info->serial_signals & SerialSignal_RTS) | ||
1367 | strcat(stat_buf, "|RTS"); | ||
1368 | if (info->serial_signals & SerialSignal_CTS) | ||
1369 | strcat(stat_buf, "|CTS"); | ||
1370 | if (info->serial_signals & SerialSignal_DTR) | ||
1371 | strcat(stat_buf, "|DTR"); | ||
1372 | if (info->serial_signals & SerialSignal_DSR) | ||
1373 | strcat(stat_buf, "|DSR"); | ||
1374 | if (info->serial_signals & SerialSignal_DCD) | ||
1375 | strcat(stat_buf, "|CD"); | ||
1376 | if (info->serial_signals & SerialSignal_RI) | ||
1377 | strcat(stat_buf, "|RI"); | ||
1378 | |||
1379 | if (info->params.mode == MGSL_MODE_HDLC) { | ||
1380 | seq_printf(m, "\tHDLC txok:%d rxok:%d", | ||
1381 | info->icount.txok, info->icount.rxok); | ||
1382 | if (info->icount.txunder) | ||
1383 | seq_printf(m, " txunder:%d", info->icount.txunder); | ||
1384 | if (info->icount.txabort) | ||
1385 | seq_printf(m, " txabort:%d", info->icount.txabort); | ||
1386 | if (info->icount.rxshort) | ||
1387 | seq_printf(m, " rxshort:%d", info->icount.rxshort); | ||
1388 | if (info->icount.rxlong) | ||
1389 | seq_printf(m, " rxlong:%d", info->icount.rxlong); | ||
1390 | if (info->icount.rxover) | ||
1391 | seq_printf(m, " rxover:%d", info->icount.rxover); | ||
1392 | if (info->icount.rxcrc) | ||
1393 | seq_printf(m, " rxlong:%d", info->icount.rxcrc); | ||
1394 | } else { | ||
1395 | seq_printf(m, "\tASYNC tx:%d rx:%d", | ||
1396 | info->icount.tx, info->icount.rx); | ||
1397 | if (info->icount.frame) | ||
1398 | seq_printf(m, " fe:%d", info->icount.frame); | ||
1399 | if (info->icount.parity) | ||
1400 | seq_printf(m, " pe:%d", info->icount.parity); | ||
1401 | if (info->icount.brk) | ||
1402 | seq_printf(m, " brk:%d", info->icount.brk); | ||
1403 | if (info->icount.overrun) | ||
1404 | seq_printf(m, " oe:%d", info->icount.overrun); | ||
1405 | } | ||
1406 | |||
1407 | /* Append serial signal status to end */ | ||
1408 | seq_printf(m, " %s\n", stat_buf+1); | ||
1409 | |||
1410 | seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", | ||
1411 | info->tx_active,info->bh_requested,info->bh_running, | ||
1412 | info->pending_bh); | ||
1413 | } | ||
1414 | |||
1415 | /* Called to print information about devices | ||
1416 | */ | ||
1417 | static int synclinkmp_proc_show(struct seq_file *m, void *v) | ||
1418 | { | ||
1419 | SLMP_INFO *info; | ||
1420 | |||
1421 | seq_printf(m, "synclinkmp driver:%s\n", driver_version); | ||
1422 | |||
1423 | info = synclinkmp_device_list; | ||
1424 | while( info ) { | ||
1425 | line_info(m, info); | ||
1426 | info = info->next_device; | ||
1427 | } | ||
1428 | return 0; | ||
1429 | } | ||
1430 | |||
1431 | static int synclinkmp_proc_open(struct inode *inode, struct file *file) | ||
1432 | { | ||
1433 | return single_open(file, synclinkmp_proc_show, NULL); | ||
1434 | } | ||
1435 | |||
1436 | static const struct file_operations synclinkmp_proc_fops = { | ||
1437 | .owner = THIS_MODULE, | ||
1438 | .open = synclinkmp_proc_open, | ||
1439 | .read = seq_read, | ||
1440 | .llseek = seq_lseek, | ||
1441 | .release = single_release, | ||
1442 | }; | ||
1443 | |||
1444 | /* Return the count of bytes in transmit buffer | ||
1445 | */ | ||
1446 | static int chars_in_buffer(struct tty_struct *tty) | ||
1447 | { | ||
1448 | SLMP_INFO *info = tty->driver_data; | ||
1449 | |||
1450 | if (sanity_check(info, tty->name, "chars_in_buffer")) | ||
1451 | return 0; | ||
1452 | |||
1453 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1454 | printk("%s(%d):%s chars_in_buffer()=%d\n", | ||
1455 | __FILE__, __LINE__, info->device_name, info->tx_count); | ||
1456 | |||
1457 | return info->tx_count; | ||
1458 | } | ||
1459 | |||
1460 | /* Signal remote device to throttle send data (our receive data) | ||
1461 | */ | ||
1462 | static void throttle(struct tty_struct * tty) | ||
1463 | { | ||
1464 | SLMP_INFO *info = tty->driver_data; | ||
1465 | unsigned long flags; | ||
1466 | |||
1467 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1468 | printk("%s(%d):%s throttle() entry\n", | ||
1469 | __FILE__,__LINE__, info->device_name ); | ||
1470 | |||
1471 | if (sanity_check(info, tty->name, "throttle")) | ||
1472 | return; | ||
1473 | |||
1474 | if (I_IXOFF(tty)) | ||
1475 | send_xchar(tty, STOP_CHAR(tty)); | ||
1476 | |||
1477 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1478 | spin_lock_irqsave(&info->lock,flags); | ||
1479 | info->serial_signals &= ~SerialSignal_RTS; | ||
1480 | set_signals(info); | ||
1481 | spin_unlock_irqrestore(&info->lock,flags); | ||
1482 | } | ||
1483 | } | ||
1484 | |||
1485 | /* Signal remote device to stop throttling send data (our receive data) | ||
1486 | */ | ||
1487 | static void unthrottle(struct tty_struct * tty) | ||
1488 | { | ||
1489 | SLMP_INFO *info = tty->driver_data; | ||
1490 | unsigned long flags; | ||
1491 | |||
1492 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1493 | printk("%s(%d):%s unthrottle() entry\n", | ||
1494 | __FILE__,__LINE__, info->device_name ); | ||
1495 | |||
1496 | if (sanity_check(info, tty->name, "unthrottle")) | ||
1497 | return; | ||
1498 | |||
1499 | if (I_IXOFF(tty)) { | ||
1500 | if (info->x_char) | ||
1501 | info->x_char = 0; | ||
1502 | else | ||
1503 | send_xchar(tty, START_CHAR(tty)); | ||
1504 | } | ||
1505 | |||
1506 | if (tty->termios->c_cflag & CRTSCTS) { | ||
1507 | spin_lock_irqsave(&info->lock,flags); | ||
1508 | info->serial_signals |= SerialSignal_RTS; | ||
1509 | set_signals(info); | ||
1510 | spin_unlock_irqrestore(&info->lock,flags); | ||
1511 | } | ||
1512 | } | ||
1513 | |||
1514 | /* set or clear transmit break condition | ||
1515 | * break_state -1=set break condition, 0=clear | ||
1516 | */ | ||
1517 | static int set_break(struct tty_struct *tty, int break_state) | ||
1518 | { | ||
1519 | unsigned char RegValue; | ||
1520 | SLMP_INFO * info = tty->driver_data; | ||
1521 | unsigned long flags; | ||
1522 | |||
1523 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1524 | printk("%s(%d):%s set_break(%d)\n", | ||
1525 | __FILE__,__LINE__, info->device_name, break_state); | ||
1526 | |||
1527 | if (sanity_check(info, tty->name, "set_break")) | ||
1528 | return -EINVAL; | ||
1529 | |||
1530 | spin_lock_irqsave(&info->lock,flags); | ||
1531 | RegValue = read_reg(info, CTL); | ||
1532 | if (break_state == -1) | ||
1533 | RegValue |= BIT3; | ||
1534 | else | ||
1535 | RegValue &= ~BIT3; | ||
1536 | write_reg(info, CTL, RegValue); | ||
1537 | spin_unlock_irqrestore(&info->lock,flags); | ||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | #if SYNCLINK_GENERIC_HDLC | ||
1542 | |||
1543 | /** | ||
1544 | * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) | ||
1545 | * set encoding and frame check sequence (FCS) options | ||
1546 | * | ||
1547 | * dev pointer to network device structure | ||
1548 | * encoding serial encoding setting | ||
1549 | * parity FCS setting | ||
1550 | * | ||
1551 | * returns 0 if success, otherwise error code | ||
1552 | */ | ||
1553 | static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, | ||
1554 | unsigned short parity) | ||
1555 | { | ||
1556 | SLMP_INFO *info = dev_to_port(dev); | ||
1557 | unsigned char new_encoding; | ||
1558 | unsigned short new_crctype; | ||
1559 | |||
1560 | /* return error if TTY interface open */ | ||
1561 | if (info->port.count) | ||
1562 | return -EBUSY; | ||
1563 | |||
1564 | switch (encoding) | ||
1565 | { | ||
1566 | case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; | ||
1567 | case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; | ||
1568 | case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; | ||
1569 | case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; | ||
1570 | case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; | ||
1571 | default: return -EINVAL; | ||
1572 | } | ||
1573 | |||
1574 | switch (parity) | ||
1575 | { | ||
1576 | case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; | ||
1577 | case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; | ||
1578 | case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; | ||
1579 | default: return -EINVAL; | ||
1580 | } | ||
1581 | |||
1582 | info->params.encoding = new_encoding; | ||
1583 | info->params.crc_type = new_crctype; | ||
1584 | |||
1585 | /* if network interface up, reprogram hardware */ | ||
1586 | if (info->netcount) | ||
1587 | program_hw(info); | ||
1588 | |||
1589 | return 0; | ||
1590 | } | ||
1591 | |||
1592 | /** | ||
1593 | * called by generic HDLC layer to send frame | ||
1594 | * | ||
1595 | * skb socket buffer containing HDLC frame | ||
1596 | * dev pointer to network device structure | ||
1597 | */ | ||
1598 | static netdev_tx_t hdlcdev_xmit(struct sk_buff *skb, | ||
1599 | struct net_device *dev) | ||
1600 | { | ||
1601 | SLMP_INFO *info = dev_to_port(dev); | ||
1602 | unsigned long flags; | ||
1603 | |||
1604 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1605 | printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); | ||
1606 | |||
1607 | /* stop sending until this frame completes */ | ||
1608 | netif_stop_queue(dev); | ||
1609 | |||
1610 | /* copy data to device buffers */ | ||
1611 | info->tx_count = skb->len; | ||
1612 | tx_load_dma_buffer(info, skb->data, skb->len); | ||
1613 | |||
1614 | /* update network statistics */ | ||
1615 | dev->stats.tx_packets++; | ||
1616 | dev->stats.tx_bytes += skb->len; | ||
1617 | |||
1618 | /* done with socket buffer, so free it */ | ||
1619 | dev_kfree_skb(skb); | ||
1620 | |||
1621 | /* save start time for transmit timeout detection */ | ||
1622 | dev->trans_start = jiffies; | ||
1623 | |||
1624 | /* start hardware transmitter if necessary */ | ||
1625 | spin_lock_irqsave(&info->lock,flags); | ||
1626 | if (!info->tx_active) | ||
1627 | tx_start(info); | ||
1628 | spin_unlock_irqrestore(&info->lock,flags); | ||
1629 | |||
1630 | return NETDEV_TX_OK; | ||
1631 | } | ||
1632 | |||
1633 | /** | ||
1634 | * called by network layer when interface enabled | ||
1635 | * claim resources and initialize hardware | ||
1636 | * | ||
1637 | * dev pointer to network device structure | ||
1638 | * | ||
1639 | * returns 0 if success, otherwise error code | ||
1640 | */ | ||
1641 | static int hdlcdev_open(struct net_device *dev) | ||
1642 | { | ||
1643 | SLMP_INFO *info = dev_to_port(dev); | ||
1644 | int rc; | ||
1645 | unsigned long flags; | ||
1646 | |||
1647 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1648 | printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); | ||
1649 | |||
1650 | /* generic HDLC layer open processing */ | ||
1651 | if ((rc = hdlc_open(dev))) | ||
1652 | return rc; | ||
1653 | |||
1654 | /* arbitrate between network and tty opens */ | ||
1655 | spin_lock_irqsave(&info->netlock, flags); | ||
1656 | if (info->port.count != 0 || info->netcount != 0) { | ||
1657 | printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); | ||
1658 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1659 | return -EBUSY; | ||
1660 | } | ||
1661 | info->netcount=1; | ||
1662 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1663 | |||
1664 | /* claim resources and init adapter */ | ||
1665 | if ((rc = startup(info)) != 0) { | ||
1666 | spin_lock_irqsave(&info->netlock, flags); | ||
1667 | info->netcount=0; | ||
1668 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1669 | return rc; | ||
1670 | } | ||
1671 | |||
1672 | /* assert DTR and RTS, apply hardware settings */ | ||
1673 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
1674 | program_hw(info); | ||
1675 | |||
1676 | /* enable network layer transmit */ | ||
1677 | dev->trans_start = jiffies; | ||
1678 | netif_start_queue(dev); | ||
1679 | |||
1680 | /* inform generic HDLC layer of current DCD status */ | ||
1681 | spin_lock_irqsave(&info->lock, flags); | ||
1682 | get_signals(info); | ||
1683 | spin_unlock_irqrestore(&info->lock, flags); | ||
1684 | if (info->serial_signals & SerialSignal_DCD) | ||
1685 | netif_carrier_on(dev); | ||
1686 | else | ||
1687 | netif_carrier_off(dev); | ||
1688 | return 0; | ||
1689 | } | ||
1690 | |||
1691 | /** | ||
1692 | * called by network layer when interface is disabled | ||
1693 | * shutdown hardware and release resources | ||
1694 | * | ||
1695 | * dev pointer to network device structure | ||
1696 | * | ||
1697 | * returns 0 if success, otherwise error code | ||
1698 | */ | ||
1699 | static int hdlcdev_close(struct net_device *dev) | ||
1700 | { | ||
1701 | SLMP_INFO *info = dev_to_port(dev); | ||
1702 | unsigned long flags; | ||
1703 | |||
1704 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1705 | printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); | ||
1706 | |||
1707 | netif_stop_queue(dev); | ||
1708 | |||
1709 | /* shutdown adapter and release resources */ | ||
1710 | shutdown(info); | ||
1711 | |||
1712 | hdlc_close(dev); | ||
1713 | |||
1714 | spin_lock_irqsave(&info->netlock, flags); | ||
1715 | info->netcount=0; | ||
1716 | spin_unlock_irqrestore(&info->netlock, flags); | ||
1717 | |||
1718 | return 0; | ||
1719 | } | ||
1720 | |||
1721 | /** | ||
1722 | * called by network layer to process IOCTL call to network device | ||
1723 | * | ||
1724 | * dev pointer to network device structure | ||
1725 | * ifr pointer to network interface request structure | ||
1726 | * cmd IOCTL command code | ||
1727 | * | ||
1728 | * returns 0 if success, otherwise error code | ||
1729 | */ | ||
1730 | static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1731 | { | ||
1732 | const size_t size = sizeof(sync_serial_settings); | ||
1733 | sync_serial_settings new_line; | ||
1734 | sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; | ||
1735 | SLMP_INFO *info = dev_to_port(dev); | ||
1736 | unsigned int flags; | ||
1737 | |||
1738 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1739 | printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); | ||
1740 | |||
1741 | /* return error if TTY interface open */ | ||
1742 | if (info->port.count) | ||
1743 | return -EBUSY; | ||
1744 | |||
1745 | if (cmd != SIOCWANDEV) | ||
1746 | return hdlc_ioctl(dev, ifr, cmd); | ||
1747 | |||
1748 | switch(ifr->ifr_settings.type) { | ||
1749 | case IF_GET_IFACE: /* return current sync_serial_settings */ | ||
1750 | |||
1751 | ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; | ||
1752 | if (ifr->ifr_settings.size < size) { | ||
1753 | ifr->ifr_settings.size = size; /* data size wanted */ | ||
1754 | return -ENOBUFS; | ||
1755 | } | ||
1756 | |||
1757 | flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1758 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1759 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1760 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
1761 | |||
1762 | switch (flags){ | ||
1763 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; | ||
1764 | case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; | ||
1765 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; | ||
1766 | case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; | ||
1767 | default: new_line.clock_type = CLOCK_DEFAULT; | ||
1768 | } | ||
1769 | |||
1770 | new_line.clock_rate = info->params.clock_speed; | ||
1771 | new_line.loopback = info->params.loopback ? 1:0; | ||
1772 | |||
1773 | if (copy_to_user(line, &new_line, size)) | ||
1774 | return -EFAULT; | ||
1775 | return 0; | ||
1776 | |||
1777 | case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ | ||
1778 | |||
1779 | if(!capable(CAP_NET_ADMIN)) | ||
1780 | return -EPERM; | ||
1781 | if (copy_from_user(&new_line, line, size)) | ||
1782 | return -EFAULT; | ||
1783 | |||
1784 | switch (new_line.clock_type) | ||
1785 | { | ||
1786 | case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; | ||
1787 | case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; | ||
1788 | case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; | ||
1789 | case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; | ||
1790 | case CLOCK_DEFAULT: flags = info->params.flags & | ||
1791 | (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1792 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1793 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1794 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; | ||
1795 | default: return -EINVAL; | ||
1796 | } | ||
1797 | |||
1798 | if (new_line.loopback != 0 && new_line.loopback != 1) | ||
1799 | return -EINVAL; | ||
1800 | |||
1801 | info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | | ||
1802 | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | | ||
1803 | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | | ||
1804 | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); | ||
1805 | info->params.flags |= flags; | ||
1806 | |||
1807 | info->params.loopback = new_line.loopback; | ||
1808 | |||
1809 | if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) | ||
1810 | info->params.clock_speed = new_line.clock_rate; | ||
1811 | else | ||
1812 | info->params.clock_speed = 0; | ||
1813 | |||
1814 | /* if network interface up, reprogram hardware */ | ||
1815 | if (info->netcount) | ||
1816 | program_hw(info); | ||
1817 | return 0; | ||
1818 | |||
1819 | default: | ||
1820 | return hdlc_ioctl(dev, ifr, cmd); | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | /** | ||
1825 | * called by network layer when transmit timeout is detected | ||
1826 | * | ||
1827 | * dev pointer to network device structure | ||
1828 | */ | ||
1829 | static void hdlcdev_tx_timeout(struct net_device *dev) | ||
1830 | { | ||
1831 | SLMP_INFO *info = dev_to_port(dev); | ||
1832 | unsigned long flags; | ||
1833 | |||
1834 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1835 | printk("hdlcdev_tx_timeout(%s)\n",dev->name); | ||
1836 | |||
1837 | dev->stats.tx_errors++; | ||
1838 | dev->stats.tx_aborted_errors++; | ||
1839 | |||
1840 | spin_lock_irqsave(&info->lock,flags); | ||
1841 | tx_stop(info); | ||
1842 | spin_unlock_irqrestore(&info->lock,flags); | ||
1843 | |||
1844 | netif_wake_queue(dev); | ||
1845 | } | ||
1846 | |||
1847 | /** | ||
1848 | * called by device driver when transmit completes | ||
1849 | * reenable network layer transmit if stopped | ||
1850 | * | ||
1851 | * info pointer to device instance information | ||
1852 | */ | ||
1853 | static void hdlcdev_tx_done(SLMP_INFO *info) | ||
1854 | { | ||
1855 | if (netif_queue_stopped(info->netdev)) | ||
1856 | netif_wake_queue(info->netdev); | ||
1857 | } | ||
1858 | |||
1859 | /** | ||
1860 | * called by device driver when frame received | ||
1861 | * pass frame to network layer | ||
1862 | * | ||
1863 | * info pointer to device instance information | ||
1864 | * buf pointer to buffer contianing frame data | ||
1865 | * size count of data bytes in buf | ||
1866 | */ | ||
1867 | static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size) | ||
1868 | { | ||
1869 | struct sk_buff *skb = dev_alloc_skb(size); | ||
1870 | struct net_device *dev = info->netdev; | ||
1871 | |||
1872 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
1873 | printk("hdlcdev_rx(%s)\n",dev->name); | ||
1874 | |||
1875 | if (skb == NULL) { | ||
1876 | printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", | ||
1877 | dev->name); | ||
1878 | dev->stats.rx_dropped++; | ||
1879 | return; | ||
1880 | } | ||
1881 | |||
1882 | memcpy(skb_put(skb, size), buf, size); | ||
1883 | |||
1884 | skb->protocol = hdlc_type_trans(skb, dev); | ||
1885 | |||
1886 | dev->stats.rx_packets++; | ||
1887 | dev->stats.rx_bytes += size; | ||
1888 | |||
1889 | netif_rx(skb); | ||
1890 | } | ||
1891 | |||
1892 | static const struct net_device_ops hdlcdev_ops = { | ||
1893 | .ndo_open = hdlcdev_open, | ||
1894 | .ndo_stop = hdlcdev_close, | ||
1895 | .ndo_change_mtu = hdlc_change_mtu, | ||
1896 | .ndo_start_xmit = hdlc_start_xmit, | ||
1897 | .ndo_do_ioctl = hdlcdev_ioctl, | ||
1898 | .ndo_tx_timeout = hdlcdev_tx_timeout, | ||
1899 | }; | ||
1900 | |||
1901 | /** | ||
1902 | * called by device driver when adding device instance | ||
1903 | * do generic HDLC initialization | ||
1904 | * | ||
1905 | * info pointer to device instance information | ||
1906 | * | ||
1907 | * returns 0 if success, otherwise error code | ||
1908 | */ | ||
1909 | static int hdlcdev_init(SLMP_INFO *info) | ||
1910 | { | ||
1911 | int rc; | ||
1912 | struct net_device *dev; | ||
1913 | hdlc_device *hdlc; | ||
1914 | |||
1915 | /* allocate and initialize network and HDLC layer objects */ | ||
1916 | |||
1917 | if (!(dev = alloc_hdlcdev(info))) { | ||
1918 | printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); | ||
1919 | return -ENOMEM; | ||
1920 | } | ||
1921 | |||
1922 | /* for network layer reporting purposes only */ | ||
1923 | dev->mem_start = info->phys_sca_base; | ||
1924 | dev->mem_end = info->phys_sca_base + SCA_BASE_SIZE - 1; | ||
1925 | dev->irq = info->irq_level; | ||
1926 | |||
1927 | /* network layer callbacks and settings */ | ||
1928 | dev->netdev_ops = &hdlcdev_ops; | ||
1929 | dev->watchdog_timeo = 10 * HZ; | ||
1930 | dev->tx_queue_len = 50; | ||
1931 | |||
1932 | /* generic HDLC layer callbacks and settings */ | ||
1933 | hdlc = dev_to_hdlc(dev); | ||
1934 | hdlc->attach = hdlcdev_attach; | ||
1935 | hdlc->xmit = hdlcdev_xmit; | ||
1936 | |||
1937 | /* register objects with HDLC layer */ | ||
1938 | if ((rc = register_hdlc_device(dev))) { | ||
1939 | printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); | ||
1940 | free_netdev(dev); | ||
1941 | return rc; | ||
1942 | } | ||
1943 | |||
1944 | info->netdev = dev; | ||
1945 | return 0; | ||
1946 | } | ||
1947 | |||
1948 | /** | ||
1949 | * called by device driver when removing device instance | ||
1950 | * do generic HDLC cleanup | ||
1951 | * | ||
1952 | * info pointer to device instance information | ||
1953 | */ | ||
1954 | static void hdlcdev_exit(SLMP_INFO *info) | ||
1955 | { | ||
1956 | unregister_hdlc_device(info->netdev); | ||
1957 | free_netdev(info->netdev); | ||
1958 | info->netdev = NULL; | ||
1959 | } | ||
1960 | |||
1961 | #endif /* CONFIG_HDLC */ | ||
1962 | |||
1963 | |||
1964 | /* Return next bottom half action to perform. | ||
1965 | * Return Value: BH action code or 0 if nothing to do. | ||
1966 | */ | ||
1967 | static int bh_action(SLMP_INFO *info) | ||
1968 | { | ||
1969 | unsigned long flags; | ||
1970 | int rc = 0; | ||
1971 | |||
1972 | spin_lock_irqsave(&info->lock,flags); | ||
1973 | |||
1974 | if (info->pending_bh & BH_RECEIVE) { | ||
1975 | info->pending_bh &= ~BH_RECEIVE; | ||
1976 | rc = BH_RECEIVE; | ||
1977 | } else if (info->pending_bh & BH_TRANSMIT) { | ||
1978 | info->pending_bh &= ~BH_TRANSMIT; | ||
1979 | rc = BH_TRANSMIT; | ||
1980 | } else if (info->pending_bh & BH_STATUS) { | ||
1981 | info->pending_bh &= ~BH_STATUS; | ||
1982 | rc = BH_STATUS; | ||
1983 | } | ||
1984 | |||
1985 | if (!rc) { | ||
1986 | /* Mark BH routine as complete */ | ||
1987 | info->bh_running = false; | ||
1988 | info->bh_requested = false; | ||
1989 | } | ||
1990 | |||
1991 | spin_unlock_irqrestore(&info->lock,flags); | ||
1992 | |||
1993 | return rc; | ||
1994 | } | ||
1995 | |||
1996 | /* Perform bottom half processing of work items queued by ISR. | ||
1997 | */ | ||
1998 | static void bh_handler(struct work_struct *work) | ||
1999 | { | ||
2000 | SLMP_INFO *info = container_of(work, SLMP_INFO, task); | ||
2001 | int action; | ||
2002 | |||
2003 | if (!info) | ||
2004 | return; | ||
2005 | |||
2006 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2007 | printk( "%s(%d):%s bh_handler() entry\n", | ||
2008 | __FILE__,__LINE__,info->device_name); | ||
2009 | |||
2010 | info->bh_running = true; | ||
2011 | |||
2012 | while((action = bh_action(info)) != 0) { | ||
2013 | |||
2014 | /* Process work item */ | ||
2015 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2016 | printk( "%s(%d):%s bh_handler() work item action=%d\n", | ||
2017 | __FILE__,__LINE__,info->device_name, action); | ||
2018 | |||
2019 | switch (action) { | ||
2020 | |||
2021 | case BH_RECEIVE: | ||
2022 | bh_receive(info); | ||
2023 | break; | ||
2024 | case BH_TRANSMIT: | ||
2025 | bh_transmit(info); | ||
2026 | break; | ||
2027 | case BH_STATUS: | ||
2028 | bh_status(info); | ||
2029 | break; | ||
2030 | default: | ||
2031 | /* unknown work item ID */ | ||
2032 | printk("%s(%d):%s Unknown work item ID=%08X!\n", | ||
2033 | __FILE__,__LINE__,info->device_name,action); | ||
2034 | break; | ||
2035 | } | ||
2036 | } | ||
2037 | |||
2038 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2039 | printk( "%s(%d):%s bh_handler() exit\n", | ||
2040 | __FILE__,__LINE__,info->device_name); | ||
2041 | } | ||
2042 | |||
2043 | static void bh_receive(SLMP_INFO *info) | ||
2044 | { | ||
2045 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2046 | printk( "%s(%d):%s bh_receive()\n", | ||
2047 | __FILE__,__LINE__,info->device_name); | ||
2048 | |||
2049 | while( rx_get_frame(info) ); | ||
2050 | } | ||
2051 | |||
2052 | static void bh_transmit(SLMP_INFO *info) | ||
2053 | { | ||
2054 | struct tty_struct *tty = info->port.tty; | ||
2055 | |||
2056 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2057 | printk( "%s(%d):%s bh_transmit() entry\n", | ||
2058 | __FILE__,__LINE__,info->device_name); | ||
2059 | |||
2060 | if (tty) | ||
2061 | tty_wakeup(tty); | ||
2062 | } | ||
2063 | |||
2064 | static void bh_status(SLMP_INFO *info) | ||
2065 | { | ||
2066 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
2067 | printk( "%s(%d):%s bh_status() entry\n", | ||
2068 | __FILE__,__LINE__,info->device_name); | ||
2069 | |||
2070 | info->ri_chkcount = 0; | ||
2071 | info->dsr_chkcount = 0; | ||
2072 | info->dcd_chkcount = 0; | ||
2073 | info->cts_chkcount = 0; | ||
2074 | } | ||
2075 | |||
2076 | static void isr_timer(SLMP_INFO * info) | ||
2077 | { | ||
2078 | unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; | ||
2079 | |||
2080 | /* IER2<7..4> = timer<3..0> interrupt enables (0=disabled) */ | ||
2081 | write_reg(info, IER2, 0); | ||
2082 | |||
2083 | /* TMCS, Timer Control/Status Register | ||
2084 | * | ||
2085 | * 07 CMF, Compare match flag (read only) 1=match | ||
2086 | * 06 ECMI, CMF Interrupt Enable: 0=disabled | ||
2087 | * 05 Reserved, must be 0 | ||
2088 | * 04 TME, Timer Enable | ||
2089 | * 03..00 Reserved, must be 0 | ||
2090 | * | ||
2091 | * 0000 0000 | ||
2092 | */ | ||
2093 | write_reg(info, (unsigned char)(timer + TMCS), 0); | ||
2094 | |||
2095 | info->irq_occurred = true; | ||
2096 | |||
2097 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2098 | printk("%s(%d):%s isr_timer()\n", | ||
2099 | __FILE__,__LINE__,info->device_name); | ||
2100 | } | ||
2101 | |||
2102 | static void isr_rxint(SLMP_INFO * info) | ||
2103 | { | ||
2104 | struct tty_struct *tty = info->port.tty; | ||
2105 | struct mgsl_icount *icount = &info->icount; | ||
2106 | unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD); | ||
2107 | unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN; | ||
2108 | |||
2109 | /* clear status bits */ | ||
2110 | if (status) | ||
2111 | write_reg(info, SR1, status); | ||
2112 | |||
2113 | if (status2) | ||
2114 | write_reg(info, SR2, status2); | ||
2115 | |||
2116 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2117 | printk("%s(%d):%s isr_rxint status=%02X %02x\n", | ||
2118 | __FILE__,__LINE__,info->device_name,status,status2); | ||
2119 | |||
2120 | if (info->params.mode == MGSL_MODE_ASYNC) { | ||
2121 | if (status & BRKD) { | ||
2122 | icount->brk++; | ||
2123 | |||
2124 | /* process break detection if tty control | ||
2125 | * is not set to ignore it | ||
2126 | */ | ||
2127 | if ( tty ) { | ||
2128 | if (!(status & info->ignore_status_mask1)) { | ||
2129 | if (info->read_status_mask1 & BRKD) { | ||
2130 | tty_insert_flip_char(tty, 0, TTY_BREAK); | ||
2131 | if (info->port.flags & ASYNC_SAK) | ||
2132 | do_SAK(tty); | ||
2133 | } | ||
2134 | } | ||
2135 | } | ||
2136 | } | ||
2137 | } | ||
2138 | else { | ||
2139 | if (status & (FLGD|IDLD)) { | ||
2140 | if (status & FLGD) | ||
2141 | info->icount.exithunt++; | ||
2142 | else if (status & IDLD) | ||
2143 | info->icount.rxidle++; | ||
2144 | wake_up_interruptible(&info->event_wait_q); | ||
2145 | } | ||
2146 | } | ||
2147 | |||
2148 | if (status & CDCD) { | ||
2149 | /* simulate a common modem status change interrupt | ||
2150 | * for our handler | ||
2151 | */ | ||
2152 | get_signals( info ); | ||
2153 | isr_io_pin(info, | ||
2154 | MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD)); | ||
2155 | } | ||
2156 | } | ||
2157 | |||
2158 | /* | ||
2159 | * handle async rx data interrupts | ||
2160 | */ | ||
2161 | static void isr_rxrdy(SLMP_INFO * info) | ||
2162 | { | ||
2163 | u16 status; | ||
2164 | unsigned char DataByte; | ||
2165 | struct tty_struct *tty = info->port.tty; | ||
2166 | struct mgsl_icount *icount = &info->icount; | ||
2167 | |||
2168 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2169 | printk("%s(%d):%s isr_rxrdy\n", | ||
2170 | __FILE__,__LINE__,info->device_name); | ||
2171 | |||
2172 | while((status = read_reg(info,CST0)) & BIT0) | ||
2173 | { | ||
2174 | int flag = 0; | ||
2175 | bool over = false; | ||
2176 | DataByte = read_reg(info,TRB); | ||
2177 | |||
2178 | icount->rx++; | ||
2179 | |||
2180 | if ( status & (PE + FRME + OVRN) ) { | ||
2181 | printk("%s(%d):%s rxerr=%04X\n", | ||
2182 | __FILE__,__LINE__,info->device_name,status); | ||
2183 | |||
2184 | /* update error statistics */ | ||
2185 | if (status & PE) | ||
2186 | icount->parity++; | ||
2187 | else if (status & FRME) | ||
2188 | icount->frame++; | ||
2189 | else if (status & OVRN) | ||
2190 | icount->overrun++; | ||
2191 | |||
2192 | /* discard char if tty control flags say so */ | ||
2193 | if (status & info->ignore_status_mask2) | ||
2194 | continue; | ||
2195 | |||
2196 | status &= info->read_status_mask2; | ||
2197 | |||
2198 | if ( tty ) { | ||
2199 | if (status & PE) | ||
2200 | flag = TTY_PARITY; | ||
2201 | else if (status & FRME) | ||
2202 | flag = TTY_FRAME; | ||
2203 | if (status & OVRN) { | ||
2204 | /* Overrun is special, since it's | ||
2205 | * reported immediately, and doesn't | ||
2206 | * affect the current character | ||
2207 | */ | ||
2208 | over = true; | ||
2209 | } | ||
2210 | } | ||
2211 | } /* end of if (error) */ | ||
2212 | |||
2213 | if ( tty ) { | ||
2214 | tty_insert_flip_char(tty, DataByte, flag); | ||
2215 | if (over) | ||
2216 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
2217 | } | ||
2218 | } | ||
2219 | |||
2220 | if ( debug_level >= DEBUG_LEVEL_ISR ) { | ||
2221 | printk("%s(%d):%s rx=%d brk=%d parity=%d frame=%d overrun=%d\n", | ||
2222 | __FILE__,__LINE__,info->device_name, | ||
2223 | icount->rx,icount->brk,icount->parity, | ||
2224 | icount->frame,icount->overrun); | ||
2225 | } | ||
2226 | |||
2227 | if ( tty ) | ||
2228 | tty_flip_buffer_push(tty); | ||
2229 | } | ||
2230 | |||
2231 | static void isr_txeom(SLMP_INFO * info, unsigned char status) | ||
2232 | { | ||
2233 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2234 | printk("%s(%d):%s isr_txeom status=%02x\n", | ||
2235 | __FILE__,__LINE__,info->device_name,status); | ||
2236 | |||
2237 | write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ | ||
2238 | write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ | ||
2239 | write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ | ||
2240 | |||
2241 | if (status & UDRN) { | ||
2242 | write_reg(info, CMD, TXRESET); | ||
2243 | write_reg(info, CMD, TXENABLE); | ||
2244 | } else | ||
2245 | write_reg(info, CMD, TXBUFCLR); | ||
2246 | |||
2247 | /* disable and clear tx interrupts */ | ||
2248 | info->ie0_value &= ~TXRDYE; | ||
2249 | info->ie1_value &= ~(IDLE + UDRN); | ||
2250 | write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); | ||
2251 | write_reg(info, SR1, (unsigned char)(UDRN + IDLE)); | ||
2252 | |||
2253 | if ( info->tx_active ) { | ||
2254 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
2255 | if (status & UDRN) | ||
2256 | info->icount.txunder++; | ||
2257 | else if (status & IDLE) | ||
2258 | info->icount.txok++; | ||
2259 | } | ||
2260 | |||
2261 | info->tx_active = false; | ||
2262 | info->tx_count = info->tx_put = info->tx_get = 0; | ||
2263 | |||
2264 | del_timer(&info->tx_timer); | ||
2265 | |||
2266 | if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done ) { | ||
2267 | info->serial_signals &= ~SerialSignal_RTS; | ||
2268 | info->drop_rts_on_tx_done = false; | ||
2269 | set_signals(info); | ||
2270 | } | ||
2271 | |||
2272 | #if SYNCLINK_GENERIC_HDLC | ||
2273 | if (info->netcount) | ||
2274 | hdlcdev_tx_done(info); | ||
2275 | else | ||
2276 | #endif | ||
2277 | { | ||
2278 | if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { | ||
2279 | tx_stop(info); | ||
2280 | return; | ||
2281 | } | ||
2282 | info->pending_bh |= BH_TRANSMIT; | ||
2283 | } | ||
2284 | } | ||
2285 | } | ||
2286 | |||
2287 | |||
2288 | /* | ||
2289 | * handle tx status interrupts | ||
2290 | */ | ||
2291 | static void isr_txint(SLMP_INFO * info) | ||
2292 | { | ||
2293 | unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS); | ||
2294 | |||
2295 | /* clear status bits */ | ||
2296 | write_reg(info, SR1, status); | ||
2297 | |||
2298 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2299 | printk("%s(%d):%s isr_txint status=%02x\n", | ||
2300 | __FILE__,__LINE__,info->device_name,status); | ||
2301 | |||
2302 | if (status & (UDRN + IDLE)) | ||
2303 | isr_txeom(info, status); | ||
2304 | |||
2305 | if (status & CCTS) { | ||
2306 | /* simulate a common modem status change interrupt | ||
2307 | * for our handler | ||
2308 | */ | ||
2309 | get_signals( info ); | ||
2310 | isr_io_pin(info, | ||
2311 | MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS)); | ||
2312 | |||
2313 | } | ||
2314 | } | ||
2315 | |||
2316 | /* | ||
2317 | * handle async tx data interrupts | ||
2318 | */ | ||
2319 | static void isr_txrdy(SLMP_INFO * info) | ||
2320 | { | ||
2321 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2322 | printk("%s(%d):%s isr_txrdy() tx_count=%d\n", | ||
2323 | __FILE__,__LINE__,info->device_name,info->tx_count); | ||
2324 | |||
2325 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
2326 | /* disable TXRDY IRQ, enable IDLE IRQ */ | ||
2327 | info->ie0_value &= ~TXRDYE; | ||
2328 | info->ie1_value |= IDLE; | ||
2329 | write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value)); | ||
2330 | return; | ||
2331 | } | ||
2332 | |||
2333 | if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { | ||
2334 | tx_stop(info); | ||
2335 | return; | ||
2336 | } | ||
2337 | |||
2338 | if ( info->tx_count ) | ||
2339 | tx_load_fifo( info ); | ||
2340 | else { | ||
2341 | info->tx_active = false; | ||
2342 | info->ie0_value &= ~TXRDYE; | ||
2343 | write_reg(info, IE0, info->ie0_value); | ||
2344 | } | ||
2345 | |||
2346 | if (info->tx_count < WAKEUP_CHARS) | ||
2347 | info->pending_bh |= BH_TRANSMIT; | ||
2348 | } | ||
2349 | |||
2350 | static void isr_rxdmaok(SLMP_INFO * info) | ||
2351 | { | ||
2352 | /* BIT7 = EOT (end of transfer) | ||
2353 | * BIT6 = EOM (end of message/frame) | ||
2354 | */ | ||
2355 | unsigned char status = read_reg(info,RXDMA + DSR) & 0xc0; | ||
2356 | |||
2357 | /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ | ||
2358 | write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); | ||
2359 | |||
2360 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2361 | printk("%s(%d):%s isr_rxdmaok(), status=%02x\n", | ||
2362 | __FILE__,__LINE__,info->device_name,status); | ||
2363 | |||
2364 | info->pending_bh |= BH_RECEIVE; | ||
2365 | } | ||
2366 | |||
2367 | static void isr_rxdmaerror(SLMP_INFO * info) | ||
2368 | { | ||
2369 | /* BIT5 = BOF (buffer overflow) | ||
2370 | * BIT4 = COF (counter overflow) | ||
2371 | */ | ||
2372 | unsigned char status = read_reg(info,RXDMA + DSR) & 0x30; | ||
2373 | |||
2374 | /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ | ||
2375 | write_reg(info, RXDMA + DSR, (unsigned char)(status | 1)); | ||
2376 | |||
2377 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2378 | printk("%s(%d):%s isr_rxdmaerror(), status=%02x\n", | ||
2379 | __FILE__,__LINE__,info->device_name,status); | ||
2380 | |||
2381 | info->rx_overflow = true; | ||
2382 | info->pending_bh |= BH_RECEIVE; | ||
2383 | } | ||
2384 | |||
2385 | static void isr_txdmaok(SLMP_INFO * info) | ||
2386 | { | ||
2387 | unsigned char status_reg1 = read_reg(info, SR1); | ||
2388 | |||
2389 | write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */ | ||
2390 | write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */ | ||
2391 | write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ | ||
2392 | |||
2393 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2394 | printk("%s(%d):%s isr_txdmaok(), status=%02x\n", | ||
2395 | __FILE__,__LINE__,info->device_name,status_reg1); | ||
2396 | |||
2397 | /* program TXRDY as FIFO empty flag, enable TXRDY IRQ */ | ||
2398 | write_reg16(info, TRC0, 0); | ||
2399 | info->ie0_value |= TXRDYE; | ||
2400 | write_reg(info, IE0, info->ie0_value); | ||
2401 | } | ||
2402 | |||
2403 | static void isr_txdmaerror(SLMP_INFO * info) | ||
2404 | { | ||
2405 | /* BIT5 = BOF (buffer overflow) | ||
2406 | * BIT4 = COF (counter overflow) | ||
2407 | */ | ||
2408 | unsigned char status = read_reg(info,TXDMA + DSR) & 0x30; | ||
2409 | |||
2410 | /* clear IRQ (BIT0 must be 1 to prevent clearing DE bit) */ | ||
2411 | write_reg(info, TXDMA + DSR, (unsigned char)(status | 1)); | ||
2412 | |||
2413 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2414 | printk("%s(%d):%s isr_txdmaerror(), status=%02x\n", | ||
2415 | __FILE__,__LINE__,info->device_name,status); | ||
2416 | } | ||
2417 | |||
2418 | /* handle input serial signal changes | ||
2419 | */ | ||
2420 | static void isr_io_pin( SLMP_INFO *info, u16 status ) | ||
2421 | { | ||
2422 | struct mgsl_icount *icount; | ||
2423 | |||
2424 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2425 | printk("%s(%d):isr_io_pin status=%04X\n", | ||
2426 | __FILE__,__LINE__,status); | ||
2427 | |||
2428 | if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | | ||
2429 | MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { | ||
2430 | icount = &info->icount; | ||
2431 | /* update input line counters */ | ||
2432 | if (status & MISCSTATUS_RI_LATCHED) { | ||
2433 | icount->rng++; | ||
2434 | if ( status & SerialSignal_RI ) | ||
2435 | info->input_signal_events.ri_up++; | ||
2436 | else | ||
2437 | info->input_signal_events.ri_down++; | ||
2438 | } | ||
2439 | if (status & MISCSTATUS_DSR_LATCHED) { | ||
2440 | icount->dsr++; | ||
2441 | if ( status & SerialSignal_DSR ) | ||
2442 | info->input_signal_events.dsr_up++; | ||
2443 | else | ||
2444 | info->input_signal_events.dsr_down++; | ||
2445 | } | ||
2446 | if (status & MISCSTATUS_DCD_LATCHED) { | ||
2447 | if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { | ||
2448 | info->ie1_value &= ~CDCD; | ||
2449 | write_reg(info, IE1, info->ie1_value); | ||
2450 | } | ||
2451 | icount->dcd++; | ||
2452 | if (status & SerialSignal_DCD) { | ||
2453 | info->input_signal_events.dcd_up++; | ||
2454 | } else | ||
2455 | info->input_signal_events.dcd_down++; | ||
2456 | #if SYNCLINK_GENERIC_HDLC | ||
2457 | if (info->netcount) { | ||
2458 | if (status & SerialSignal_DCD) | ||
2459 | netif_carrier_on(info->netdev); | ||
2460 | else | ||
2461 | netif_carrier_off(info->netdev); | ||
2462 | } | ||
2463 | #endif | ||
2464 | } | ||
2465 | if (status & MISCSTATUS_CTS_LATCHED) | ||
2466 | { | ||
2467 | if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) { | ||
2468 | info->ie1_value &= ~CCTS; | ||
2469 | write_reg(info, IE1, info->ie1_value); | ||
2470 | } | ||
2471 | icount->cts++; | ||
2472 | if ( status & SerialSignal_CTS ) | ||
2473 | info->input_signal_events.cts_up++; | ||
2474 | else | ||
2475 | info->input_signal_events.cts_down++; | ||
2476 | } | ||
2477 | wake_up_interruptible(&info->status_event_wait_q); | ||
2478 | wake_up_interruptible(&info->event_wait_q); | ||
2479 | |||
2480 | if ( (info->port.flags & ASYNC_CHECK_CD) && | ||
2481 | (status & MISCSTATUS_DCD_LATCHED) ) { | ||
2482 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2483 | printk("%s CD now %s...", info->device_name, | ||
2484 | (status & SerialSignal_DCD) ? "on" : "off"); | ||
2485 | if (status & SerialSignal_DCD) | ||
2486 | wake_up_interruptible(&info->port.open_wait); | ||
2487 | else { | ||
2488 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2489 | printk("doing serial hangup..."); | ||
2490 | if (info->port.tty) | ||
2491 | tty_hangup(info->port.tty); | ||
2492 | } | ||
2493 | } | ||
2494 | |||
2495 | if ( (info->port.flags & ASYNC_CTS_FLOW) && | ||
2496 | (status & MISCSTATUS_CTS_LATCHED) ) { | ||
2497 | if ( info->port.tty ) { | ||
2498 | if (info->port.tty->hw_stopped) { | ||
2499 | if (status & SerialSignal_CTS) { | ||
2500 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2501 | printk("CTS tx start..."); | ||
2502 | info->port.tty->hw_stopped = 0; | ||
2503 | tx_start(info); | ||
2504 | info->pending_bh |= BH_TRANSMIT; | ||
2505 | return; | ||
2506 | } | ||
2507 | } else { | ||
2508 | if (!(status & SerialSignal_CTS)) { | ||
2509 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2510 | printk("CTS tx stop..."); | ||
2511 | info->port.tty->hw_stopped = 1; | ||
2512 | tx_stop(info); | ||
2513 | } | ||
2514 | } | ||
2515 | } | ||
2516 | } | ||
2517 | } | ||
2518 | |||
2519 | info->pending_bh |= BH_STATUS; | ||
2520 | } | ||
2521 | |||
2522 | /* Interrupt service routine entry point. | ||
2523 | * | ||
2524 | * Arguments: | ||
2525 | * irq interrupt number that caused interrupt | ||
2526 | * dev_id device ID supplied during interrupt registration | ||
2527 | * regs interrupted processor context | ||
2528 | */ | ||
2529 | static irqreturn_t synclinkmp_interrupt(int dummy, void *dev_id) | ||
2530 | { | ||
2531 | SLMP_INFO *info = dev_id; | ||
2532 | unsigned char status, status0, status1=0; | ||
2533 | unsigned char dmastatus, dmastatus0, dmastatus1=0; | ||
2534 | unsigned char timerstatus0, timerstatus1=0; | ||
2535 | unsigned char shift; | ||
2536 | unsigned int i; | ||
2537 | unsigned short tmp; | ||
2538 | |||
2539 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2540 | printk(KERN_DEBUG "%s(%d): synclinkmp_interrupt(%d)entry.\n", | ||
2541 | __FILE__, __LINE__, info->irq_level); | ||
2542 | |||
2543 | spin_lock(&info->lock); | ||
2544 | |||
2545 | for(;;) { | ||
2546 | |||
2547 | /* get status for SCA0 (ports 0-1) */ | ||
2548 | tmp = read_reg16(info, ISR0); /* get ISR0 and ISR1 in one read */ | ||
2549 | status0 = (unsigned char)tmp; | ||
2550 | dmastatus0 = (unsigned char)(tmp>>8); | ||
2551 | timerstatus0 = read_reg(info, ISR2); | ||
2552 | |||
2553 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2554 | printk(KERN_DEBUG "%s(%d):%s status0=%02x, dmastatus0=%02x, timerstatus0=%02x\n", | ||
2555 | __FILE__, __LINE__, info->device_name, | ||
2556 | status0, dmastatus0, timerstatus0); | ||
2557 | |||
2558 | if (info->port_count == 4) { | ||
2559 | /* get status for SCA1 (ports 2-3) */ | ||
2560 | tmp = read_reg16(info->port_array[2], ISR0); | ||
2561 | status1 = (unsigned char)tmp; | ||
2562 | dmastatus1 = (unsigned char)(tmp>>8); | ||
2563 | timerstatus1 = read_reg(info->port_array[2], ISR2); | ||
2564 | |||
2565 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2566 | printk("%s(%d):%s status1=%02x, dmastatus1=%02x, timerstatus1=%02x\n", | ||
2567 | __FILE__,__LINE__,info->device_name, | ||
2568 | status1,dmastatus1,timerstatus1); | ||
2569 | } | ||
2570 | |||
2571 | if (!status0 && !dmastatus0 && !timerstatus0 && | ||
2572 | !status1 && !dmastatus1 && !timerstatus1) | ||
2573 | break; | ||
2574 | |||
2575 | for(i=0; i < info->port_count ; i++) { | ||
2576 | if (info->port_array[i] == NULL) | ||
2577 | continue; | ||
2578 | if (i < 2) { | ||
2579 | status = status0; | ||
2580 | dmastatus = dmastatus0; | ||
2581 | } else { | ||
2582 | status = status1; | ||
2583 | dmastatus = dmastatus1; | ||
2584 | } | ||
2585 | |||
2586 | shift = i & 1 ? 4 :0; | ||
2587 | |||
2588 | if (status & BIT0 << shift) | ||
2589 | isr_rxrdy(info->port_array[i]); | ||
2590 | if (status & BIT1 << shift) | ||
2591 | isr_txrdy(info->port_array[i]); | ||
2592 | if (status & BIT2 << shift) | ||
2593 | isr_rxint(info->port_array[i]); | ||
2594 | if (status & BIT3 << shift) | ||
2595 | isr_txint(info->port_array[i]); | ||
2596 | |||
2597 | if (dmastatus & BIT0 << shift) | ||
2598 | isr_rxdmaerror(info->port_array[i]); | ||
2599 | if (dmastatus & BIT1 << shift) | ||
2600 | isr_rxdmaok(info->port_array[i]); | ||
2601 | if (dmastatus & BIT2 << shift) | ||
2602 | isr_txdmaerror(info->port_array[i]); | ||
2603 | if (dmastatus & BIT3 << shift) | ||
2604 | isr_txdmaok(info->port_array[i]); | ||
2605 | } | ||
2606 | |||
2607 | if (timerstatus0 & (BIT5 | BIT4)) | ||
2608 | isr_timer(info->port_array[0]); | ||
2609 | if (timerstatus0 & (BIT7 | BIT6)) | ||
2610 | isr_timer(info->port_array[1]); | ||
2611 | if (timerstatus1 & (BIT5 | BIT4)) | ||
2612 | isr_timer(info->port_array[2]); | ||
2613 | if (timerstatus1 & (BIT7 | BIT6)) | ||
2614 | isr_timer(info->port_array[3]); | ||
2615 | } | ||
2616 | |||
2617 | for(i=0; i < info->port_count ; i++) { | ||
2618 | SLMP_INFO * port = info->port_array[i]; | ||
2619 | |||
2620 | /* Request bottom half processing if there's something | ||
2621 | * for it to do and the bh is not already running. | ||
2622 | * | ||
2623 | * Note: startup adapter diags require interrupts. | ||
2624 | * do not request bottom half processing if the | ||
2625 | * device is not open in a normal mode. | ||
2626 | */ | ||
2627 | if ( port && (port->port.count || port->netcount) && | ||
2628 | port->pending_bh && !port->bh_running && | ||
2629 | !port->bh_requested ) { | ||
2630 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2631 | printk("%s(%d):%s queueing bh task.\n", | ||
2632 | __FILE__,__LINE__,port->device_name); | ||
2633 | schedule_work(&port->task); | ||
2634 | port->bh_requested = true; | ||
2635 | } | ||
2636 | } | ||
2637 | |||
2638 | spin_unlock(&info->lock); | ||
2639 | |||
2640 | if ( debug_level >= DEBUG_LEVEL_ISR ) | ||
2641 | printk(KERN_DEBUG "%s(%d):synclinkmp_interrupt(%d)exit.\n", | ||
2642 | __FILE__, __LINE__, info->irq_level); | ||
2643 | return IRQ_HANDLED; | ||
2644 | } | ||
2645 | |||
2646 | /* Initialize and start device. | ||
2647 | */ | ||
2648 | static int startup(SLMP_INFO * info) | ||
2649 | { | ||
2650 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2651 | printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name); | ||
2652 | |||
2653 | if (info->port.flags & ASYNC_INITIALIZED) | ||
2654 | return 0; | ||
2655 | |||
2656 | if (!info->tx_buf) { | ||
2657 | info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); | ||
2658 | if (!info->tx_buf) { | ||
2659 | printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", | ||
2660 | __FILE__,__LINE__,info->device_name); | ||
2661 | return -ENOMEM; | ||
2662 | } | ||
2663 | } | ||
2664 | |||
2665 | info->pending_bh = 0; | ||
2666 | |||
2667 | memset(&info->icount, 0, sizeof(info->icount)); | ||
2668 | |||
2669 | /* program hardware for current parameters */ | ||
2670 | reset_port(info); | ||
2671 | |||
2672 | change_params(info); | ||
2673 | |||
2674 | mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); | ||
2675 | |||
2676 | if (info->port.tty) | ||
2677 | clear_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2678 | |||
2679 | info->port.flags |= ASYNC_INITIALIZED; | ||
2680 | |||
2681 | return 0; | ||
2682 | } | ||
2683 | |||
2684 | /* Called by close() and hangup() to shutdown hardware | ||
2685 | */ | ||
2686 | static void shutdown(SLMP_INFO * info) | ||
2687 | { | ||
2688 | unsigned long flags; | ||
2689 | |||
2690 | if (!(info->port.flags & ASYNC_INITIALIZED)) | ||
2691 | return; | ||
2692 | |||
2693 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2694 | printk("%s(%d):%s synclinkmp_shutdown()\n", | ||
2695 | __FILE__,__LINE__, info->device_name ); | ||
2696 | |||
2697 | /* clear status wait queue because status changes */ | ||
2698 | /* can't happen after shutting down the hardware */ | ||
2699 | wake_up_interruptible(&info->status_event_wait_q); | ||
2700 | wake_up_interruptible(&info->event_wait_q); | ||
2701 | |||
2702 | del_timer(&info->tx_timer); | ||
2703 | del_timer(&info->status_timer); | ||
2704 | |||
2705 | kfree(info->tx_buf); | ||
2706 | info->tx_buf = NULL; | ||
2707 | |||
2708 | spin_lock_irqsave(&info->lock,flags); | ||
2709 | |||
2710 | reset_port(info); | ||
2711 | |||
2712 | if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) { | ||
2713 | info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | ||
2714 | set_signals(info); | ||
2715 | } | ||
2716 | |||
2717 | spin_unlock_irqrestore(&info->lock,flags); | ||
2718 | |||
2719 | if (info->port.tty) | ||
2720 | set_bit(TTY_IO_ERROR, &info->port.tty->flags); | ||
2721 | |||
2722 | info->port.flags &= ~ASYNC_INITIALIZED; | ||
2723 | } | ||
2724 | |||
2725 | static void program_hw(SLMP_INFO *info) | ||
2726 | { | ||
2727 | unsigned long flags; | ||
2728 | |||
2729 | spin_lock_irqsave(&info->lock,flags); | ||
2730 | |||
2731 | rx_stop(info); | ||
2732 | tx_stop(info); | ||
2733 | |||
2734 | info->tx_count = info->tx_put = info->tx_get = 0; | ||
2735 | |||
2736 | if (info->params.mode == MGSL_MODE_HDLC || info->netcount) | ||
2737 | hdlc_mode(info); | ||
2738 | else | ||
2739 | async_mode(info); | ||
2740 | |||
2741 | set_signals(info); | ||
2742 | |||
2743 | info->dcd_chkcount = 0; | ||
2744 | info->cts_chkcount = 0; | ||
2745 | info->ri_chkcount = 0; | ||
2746 | info->dsr_chkcount = 0; | ||
2747 | |||
2748 | info->ie1_value |= (CDCD|CCTS); | ||
2749 | write_reg(info, IE1, info->ie1_value); | ||
2750 | |||
2751 | get_signals(info); | ||
2752 | |||
2753 | if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) ) | ||
2754 | rx_start(info); | ||
2755 | |||
2756 | spin_unlock_irqrestore(&info->lock,flags); | ||
2757 | } | ||
2758 | |||
2759 | /* Reconfigure adapter based on new parameters | ||
2760 | */ | ||
2761 | static void change_params(SLMP_INFO *info) | ||
2762 | { | ||
2763 | unsigned cflag; | ||
2764 | int bits_per_char; | ||
2765 | |||
2766 | if (!info->port.tty || !info->port.tty->termios) | ||
2767 | return; | ||
2768 | |||
2769 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2770 | printk("%s(%d):%s change_params()\n", | ||
2771 | __FILE__,__LINE__, info->device_name ); | ||
2772 | |||
2773 | cflag = info->port.tty->termios->c_cflag; | ||
2774 | |||
2775 | /* if B0 rate (hangup) specified then negate DTR and RTS */ | ||
2776 | /* otherwise assert DTR and RTS */ | ||
2777 | if (cflag & CBAUD) | ||
2778 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
2779 | else | ||
2780 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
2781 | |||
2782 | /* byte size and parity */ | ||
2783 | |||
2784 | switch (cflag & CSIZE) { | ||
2785 | case CS5: info->params.data_bits = 5; break; | ||
2786 | case CS6: info->params.data_bits = 6; break; | ||
2787 | case CS7: info->params.data_bits = 7; break; | ||
2788 | case CS8: info->params.data_bits = 8; break; | ||
2789 | /* Never happens, but GCC is too dumb to figure it out */ | ||
2790 | default: info->params.data_bits = 7; break; | ||
2791 | } | ||
2792 | |||
2793 | if (cflag & CSTOPB) | ||
2794 | info->params.stop_bits = 2; | ||
2795 | else | ||
2796 | info->params.stop_bits = 1; | ||
2797 | |||
2798 | info->params.parity = ASYNC_PARITY_NONE; | ||
2799 | if (cflag & PARENB) { | ||
2800 | if (cflag & PARODD) | ||
2801 | info->params.parity = ASYNC_PARITY_ODD; | ||
2802 | else | ||
2803 | info->params.parity = ASYNC_PARITY_EVEN; | ||
2804 | #ifdef CMSPAR | ||
2805 | if (cflag & CMSPAR) | ||
2806 | info->params.parity = ASYNC_PARITY_SPACE; | ||
2807 | #endif | ||
2808 | } | ||
2809 | |||
2810 | /* calculate number of jiffies to transmit a full | ||
2811 | * FIFO (32 bytes) at specified data rate | ||
2812 | */ | ||
2813 | bits_per_char = info->params.data_bits + | ||
2814 | info->params.stop_bits + 1; | ||
2815 | |||
2816 | /* if port data rate is set to 460800 or less then | ||
2817 | * allow tty settings to override, otherwise keep the | ||
2818 | * current data rate. | ||
2819 | */ | ||
2820 | if (info->params.data_rate <= 460800) { | ||
2821 | info->params.data_rate = tty_get_baud_rate(info->port.tty); | ||
2822 | } | ||
2823 | |||
2824 | if ( info->params.data_rate ) { | ||
2825 | info->timeout = (32*HZ*bits_per_char) / | ||
2826 | info->params.data_rate; | ||
2827 | } | ||
2828 | info->timeout += HZ/50; /* Add .02 seconds of slop */ | ||
2829 | |||
2830 | if (cflag & CRTSCTS) | ||
2831 | info->port.flags |= ASYNC_CTS_FLOW; | ||
2832 | else | ||
2833 | info->port.flags &= ~ASYNC_CTS_FLOW; | ||
2834 | |||
2835 | if (cflag & CLOCAL) | ||
2836 | info->port.flags &= ~ASYNC_CHECK_CD; | ||
2837 | else | ||
2838 | info->port.flags |= ASYNC_CHECK_CD; | ||
2839 | |||
2840 | /* process tty input control flags */ | ||
2841 | |||
2842 | info->read_status_mask2 = OVRN; | ||
2843 | if (I_INPCK(info->port.tty)) | ||
2844 | info->read_status_mask2 |= PE | FRME; | ||
2845 | if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) | ||
2846 | info->read_status_mask1 |= BRKD; | ||
2847 | if (I_IGNPAR(info->port.tty)) | ||
2848 | info->ignore_status_mask2 |= PE | FRME; | ||
2849 | if (I_IGNBRK(info->port.tty)) { | ||
2850 | info->ignore_status_mask1 |= BRKD; | ||
2851 | /* If ignoring parity and break indicators, ignore | ||
2852 | * overruns too. (For real raw support). | ||
2853 | */ | ||
2854 | if (I_IGNPAR(info->port.tty)) | ||
2855 | info->ignore_status_mask2 |= OVRN; | ||
2856 | } | ||
2857 | |||
2858 | program_hw(info); | ||
2859 | } | ||
2860 | |||
2861 | static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount) | ||
2862 | { | ||
2863 | int err; | ||
2864 | |||
2865 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2866 | printk("%s(%d):%s get_params()\n", | ||
2867 | __FILE__,__LINE__, info->device_name); | ||
2868 | |||
2869 | if (!user_icount) { | ||
2870 | memset(&info->icount, 0, sizeof(info->icount)); | ||
2871 | } else { | ||
2872 | mutex_lock(&info->port.mutex); | ||
2873 | COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); | ||
2874 | mutex_unlock(&info->port.mutex); | ||
2875 | if (err) | ||
2876 | return -EFAULT; | ||
2877 | } | ||
2878 | |||
2879 | return 0; | ||
2880 | } | ||
2881 | |||
2882 | static int get_params(SLMP_INFO * info, MGSL_PARAMS __user *user_params) | ||
2883 | { | ||
2884 | int err; | ||
2885 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2886 | printk("%s(%d):%s get_params()\n", | ||
2887 | __FILE__,__LINE__, info->device_name); | ||
2888 | |||
2889 | mutex_lock(&info->port.mutex); | ||
2890 | COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); | ||
2891 | mutex_unlock(&info->port.mutex); | ||
2892 | if (err) { | ||
2893 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2894 | printk( "%s(%d):%s get_params() user buffer copy failed\n", | ||
2895 | __FILE__,__LINE__,info->device_name); | ||
2896 | return -EFAULT; | ||
2897 | } | ||
2898 | |||
2899 | return 0; | ||
2900 | } | ||
2901 | |||
2902 | static int set_params(SLMP_INFO * info, MGSL_PARAMS __user *new_params) | ||
2903 | { | ||
2904 | unsigned long flags; | ||
2905 | MGSL_PARAMS tmp_params; | ||
2906 | int err; | ||
2907 | |||
2908 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2909 | printk("%s(%d):%s set_params\n", | ||
2910 | __FILE__,__LINE__,info->device_name ); | ||
2911 | COPY_FROM_USER(err,&tmp_params, new_params, sizeof(MGSL_PARAMS)); | ||
2912 | if (err) { | ||
2913 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2914 | printk( "%s(%d):%s set_params() user buffer copy failed\n", | ||
2915 | __FILE__,__LINE__,info->device_name); | ||
2916 | return -EFAULT; | ||
2917 | } | ||
2918 | |||
2919 | mutex_lock(&info->port.mutex); | ||
2920 | spin_lock_irqsave(&info->lock,flags); | ||
2921 | memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); | ||
2922 | spin_unlock_irqrestore(&info->lock,flags); | ||
2923 | |||
2924 | change_params(info); | ||
2925 | mutex_unlock(&info->port.mutex); | ||
2926 | |||
2927 | return 0; | ||
2928 | } | ||
2929 | |||
2930 | static int get_txidle(SLMP_INFO * info, int __user *idle_mode) | ||
2931 | { | ||
2932 | int err; | ||
2933 | |||
2934 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2935 | printk("%s(%d):%s get_txidle()=%d\n", | ||
2936 | __FILE__,__LINE__, info->device_name, info->idle_mode); | ||
2937 | |||
2938 | COPY_TO_USER(err,idle_mode, &info->idle_mode, sizeof(int)); | ||
2939 | if (err) { | ||
2940 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
2941 | printk( "%s(%d):%s get_txidle() user buffer copy failed\n", | ||
2942 | __FILE__,__LINE__,info->device_name); | ||
2943 | return -EFAULT; | ||
2944 | } | ||
2945 | |||
2946 | return 0; | ||
2947 | } | ||
2948 | |||
2949 | static int set_txidle(SLMP_INFO * info, int idle_mode) | ||
2950 | { | ||
2951 | unsigned long flags; | ||
2952 | |||
2953 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2954 | printk("%s(%d):%s set_txidle(%d)\n", | ||
2955 | __FILE__,__LINE__,info->device_name, idle_mode ); | ||
2956 | |||
2957 | spin_lock_irqsave(&info->lock,flags); | ||
2958 | info->idle_mode = idle_mode; | ||
2959 | tx_set_idle( info ); | ||
2960 | spin_unlock_irqrestore(&info->lock,flags); | ||
2961 | return 0; | ||
2962 | } | ||
2963 | |||
2964 | static int tx_enable(SLMP_INFO * info, int enable) | ||
2965 | { | ||
2966 | unsigned long flags; | ||
2967 | |||
2968 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2969 | printk("%s(%d):%s tx_enable(%d)\n", | ||
2970 | __FILE__,__LINE__,info->device_name, enable); | ||
2971 | |||
2972 | spin_lock_irqsave(&info->lock,flags); | ||
2973 | if ( enable ) { | ||
2974 | if ( !info->tx_enabled ) { | ||
2975 | tx_start(info); | ||
2976 | } | ||
2977 | } else { | ||
2978 | if ( info->tx_enabled ) | ||
2979 | tx_stop(info); | ||
2980 | } | ||
2981 | spin_unlock_irqrestore(&info->lock,flags); | ||
2982 | return 0; | ||
2983 | } | ||
2984 | |||
2985 | /* abort send HDLC frame | ||
2986 | */ | ||
2987 | static int tx_abort(SLMP_INFO * info) | ||
2988 | { | ||
2989 | unsigned long flags; | ||
2990 | |||
2991 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
2992 | printk("%s(%d):%s tx_abort()\n", | ||
2993 | __FILE__,__LINE__,info->device_name); | ||
2994 | |||
2995 | spin_lock_irqsave(&info->lock,flags); | ||
2996 | if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC ) { | ||
2997 | info->ie1_value &= ~UDRN; | ||
2998 | info->ie1_value |= IDLE; | ||
2999 | write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ | ||
3000 | write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ | ||
3001 | |||
3002 | write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ | ||
3003 | write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ | ||
3004 | |||
3005 | write_reg(info, CMD, TXABORT); | ||
3006 | } | ||
3007 | spin_unlock_irqrestore(&info->lock,flags); | ||
3008 | return 0; | ||
3009 | } | ||
3010 | |||
3011 | static int rx_enable(SLMP_INFO * info, int enable) | ||
3012 | { | ||
3013 | unsigned long flags; | ||
3014 | |||
3015 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3016 | printk("%s(%d):%s rx_enable(%d)\n", | ||
3017 | __FILE__,__LINE__,info->device_name,enable); | ||
3018 | |||
3019 | spin_lock_irqsave(&info->lock,flags); | ||
3020 | if ( enable ) { | ||
3021 | if ( !info->rx_enabled ) | ||
3022 | rx_start(info); | ||
3023 | } else { | ||
3024 | if ( info->rx_enabled ) | ||
3025 | rx_stop(info); | ||
3026 | } | ||
3027 | spin_unlock_irqrestore(&info->lock,flags); | ||
3028 | return 0; | ||
3029 | } | ||
3030 | |||
3031 | /* wait for specified event to occur | ||
3032 | */ | ||
3033 | static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr) | ||
3034 | { | ||
3035 | unsigned long flags; | ||
3036 | int s; | ||
3037 | int rc=0; | ||
3038 | struct mgsl_icount cprev, cnow; | ||
3039 | int events; | ||
3040 | int mask; | ||
3041 | struct _input_signal_events oldsigs, newsigs; | ||
3042 | DECLARE_WAITQUEUE(wait, current); | ||
3043 | |||
3044 | COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int)); | ||
3045 | if (rc) { | ||
3046 | return -EFAULT; | ||
3047 | } | ||
3048 | |||
3049 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3050 | printk("%s(%d):%s wait_mgsl_event(%d)\n", | ||
3051 | __FILE__,__LINE__,info->device_name,mask); | ||
3052 | |||
3053 | spin_lock_irqsave(&info->lock,flags); | ||
3054 | |||
3055 | /* return immediately if state matches requested events */ | ||
3056 | get_signals(info); | ||
3057 | s = info->serial_signals; | ||
3058 | |||
3059 | events = mask & | ||
3060 | ( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) + | ||
3061 | ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) + | ||
3062 | ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) + | ||
3063 | ((s & SerialSignal_RI) ? MgslEvent_RiActive :MgslEvent_RiInactive) ); | ||
3064 | if (events) { | ||
3065 | spin_unlock_irqrestore(&info->lock,flags); | ||
3066 | goto exit; | ||
3067 | } | ||
3068 | |||
3069 | /* save current irq counts */ | ||
3070 | cprev = info->icount; | ||
3071 | oldsigs = info->input_signal_events; | ||
3072 | |||
3073 | /* enable hunt and idle irqs if needed */ | ||
3074 | if (mask & (MgslEvent_ExitHuntMode+MgslEvent_IdleReceived)) { | ||
3075 | unsigned char oldval = info->ie1_value; | ||
3076 | unsigned char newval = oldval + | ||
3077 | (mask & MgslEvent_ExitHuntMode ? FLGD:0) + | ||
3078 | (mask & MgslEvent_IdleReceived ? IDLD:0); | ||
3079 | if ( oldval != newval ) { | ||
3080 | info->ie1_value = newval; | ||
3081 | write_reg(info, IE1, info->ie1_value); | ||
3082 | } | ||
3083 | } | ||
3084 | |||
3085 | set_current_state(TASK_INTERRUPTIBLE); | ||
3086 | add_wait_queue(&info->event_wait_q, &wait); | ||
3087 | |||
3088 | spin_unlock_irqrestore(&info->lock,flags); | ||
3089 | |||
3090 | for(;;) { | ||
3091 | schedule(); | ||
3092 | if (signal_pending(current)) { | ||
3093 | rc = -ERESTARTSYS; | ||
3094 | break; | ||
3095 | } | ||
3096 | |||
3097 | /* get current irq counts */ | ||
3098 | spin_lock_irqsave(&info->lock,flags); | ||
3099 | cnow = info->icount; | ||
3100 | newsigs = info->input_signal_events; | ||
3101 | set_current_state(TASK_INTERRUPTIBLE); | ||
3102 | spin_unlock_irqrestore(&info->lock,flags); | ||
3103 | |||
3104 | /* if no change, wait aborted for some reason */ | ||
3105 | if (newsigs.dsr_up == oldsigs.dsr_up && | ||
3106 | newsigs.dsr_down == oldsigs.dsr_down && | ||
3107 | newsigs.dcd_up == oldsigs.dcd_up && | ||
3108 | newsigs.dcd_down == oldsigs.dcd_down && | ||
3109 | newsigs.cts_up == oldsigs.cts_up && | ||
3110 | newsigs.cts_down == oldsigs.cts_down && | ||
3111 | newsigs.ri_up == oldsigs.ri_up && | ||
3112 | newsigs.ri_down == oldsigs.ri_down && | ||
3113 | cnow.exithunt == cprev.exithunt && | ||
3114 | cnow.rxidle == cprev.rxidle) { | ||
3115 | rc = -EIO; | ||
3116 | break; | ||
3117 | } | ||
3118 | |||
3119 | events = mask & | ||
3120 | ( (newsigs.dsr_up != oldsigs.dsr_up ? MgslEvent_DsrActive:0) + | ||
3121 | (newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) + | ||
3122 | (newsigs.dcd_up != oldsigs.dcd_up ? MgslEvent_DcdActive:0) + | ||
3123 | (newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) + | ||
3124 | (newsigs.cts_up != oldsigs.cts_up ? MgslEvent_CtsActive:0) + | ||
3125 | (newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) + | ||
3126 | (newsigs.ri_up != oldsigs.ri_up ? MgslEvent_RiActive:0) + | ||
3127 | (newsigs.ri_down != oldsigs.ri_down ? MgslEvent_RiInactive:0) + | ||
3128 | (cnow.exithunt != cprev.exithunt ? MgslEvent_ExitHuntMode:0) + | ||
3129 | (cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) ); | ||
3130 | if (events) | ||
3131 | break; | ||
3132 | |||
3133 | cprev = cnow; | ||
3134 | oldsigs = newsigs; | ||
3135 | } | ||
3136 | |||
3137 | remove_wait_queue(&info->event_wait_q, &wait); | ||
3138 | set_current_state(TASK_RUNNING); | ||
3139 | |||
3140 | |||
3141 | if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) { | ||
3142 | spin_lock_irqsave(&info->lock,flags); | ||
3143 | if (!waitqueue_active(&info->event_wait_q)) { | ||
3144 | /* disable enable exit hunt mode/idle rcvd IRQs */ | ||
3145 | info->ie1_value &= ~(FLGD|IDLD); | ||
3146 | write_reg(info, IE1, info->ie1_value); | ||
3147 | } | ||
3148 | spin_unlock_irqrestore(&info->lock,flags); | ||
3149 | } | ||
3150 | exit: | ||
3151 | if ( rc == 0 ) | ||
3152 | PUT_USER(rc, events, mask_ptr); | ||
3153 | |||
3154 | return rc; | ||
3155 | } | ||
3156 | |||
3157 | static int modem_input_wait(SLMP_INFO *info,int arg) | ||
3158 | { | ||
3159 | unsigned long flags; | ||
3160 | int rc; | ||
3161 | struct mgsl_icount cprev, cnow; | ||
3162 | DECLARE_WAITQUEUE(wait, current); | ||
3163 | |||
3164 | /* save current irq counts */ | ||
3165 | spin_lock_irqsave(&info->lock,flags); | ||
3166 | cprev = info->icount; | ||
3167 | add_wait_queue(&info->status_event_wait_q, &wait); | ||
3168 | set_current_state(TASK_INTERRUPTIBLE); | ||
3169 | spin_unlock_irqrestore(&info->lock,flags); | ||
3170 | |||
3171 | for(;;) { | ||
3172 | schedule(); | ||
3173 | if (signal_pending(current)) { | ||
3174 | rc = -ERESTARTSYS; | ||
3175 | break; | ||
3176 | } | ||
3177 | |||
3178 | /* get new irq counts */ | ||
3179 | spin_lock_irqsave(&info->lock,flags); | ||
3180 | cnow = info->icount; | ||
3181 | set_current_state(TASK_INTERRUPTIBLE); | ||
3182 | spin_unlock_irqrestore(&info->lock,flags); | ||
3183 | |||
3184 | /* if no change, wait aborted for some reason */ | ||
3185 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
3186 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { | ||
3187 | rc = -EIO; | ||
3188 | break; | ||
3189 | } | ||
3190 | |||
3191 | /* check for change in caller specified modem input */ | ||
3192 | if ((arg & TIOCM_RNG && cnow.rng != cprev.rng) || | ||
3193 | (arg & TIOCM_DSR && cnow.dsr != cprev.dsr) || | ||
3194 | (arg & TIOCM_CD && cnow.dcd != cprev.dcd) || | ||
3195 | (arg & TIOCM_CTS && cnow.cts != cprev.cts)) { | ||
3196 | rc = 0; | ||
3197 | break; | ||
3198 | } | ||
3199 | |||
3200 | cprev = cnow; | ||
3201 | } | ||
3202 | remove_wait_queue(&info->status_event_wait_q, &wait); | ||
3203 | set_current_state(TASK_RUNNING); | ||
3204 | return rc; | ||
3205 | } | ||
3206 | |||
3207 | /* return the state of the serial control and status signals | ||
3208 | */ | ||
3209 | static int tiocmget(struct tty_struct *tty) | ||
3210 | { | ||
3211 | SLMP_INFO *info = tty->driver_data; | ||
3212 | unsigned int result; | ||
3213 | unsigned long flags; | ||
3214 | |||
3215 | spin_lock_irqsave(&info->lock,flags); | ||
3216 | get_signals(info); | ||
3217 | spin_unlock_irqrestore(&info->lock,flags); | ||
3218 | |||
3219 | result = ((info->serial_signals & SerialSignal_RTS) ? TIOCM_RTS:0) + | ||
3220 | ((info->serial_signals & SerialSignal_DTR) ? TIOCM_DTR:0) + | ||
3221 | ((info->serial_signals & SerialSignal_DCD) ? TIOCM_CAR:0) + | ||
3222 | ((info->serial_signals & SerialSignal_RI) ? TIOCM_RNG:0) + | ||
3223 | ((info->serial_signals & SerialSignal_DSR) ? TIOCM_DSR:0) + | ||
3224 | ((info->serial_signals & SerialSignal_CTS) ? TIOCM_CTS:0); | ||
3225 | |||
3226 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3227 | printk("%s(%d):%s tiocmget() value=%08X\n", | ||
3228 | __FILE__,__LINE__, info->device_name, result ); | ||
3229 | return result; | ||
3230 | } | ||
3231 | |||
3232 | /* set modem control signals (DTR/RTS) | ||
3233 | */ | ||
3234 | static int tiocmset(struct tty_struct *tty, | ||
3235 | unsigned int set, unsigned int clear) | ||
3236 | { | ||
3237 | SLMP_INFO *info = tty->driver_data; | ||
3238 | unsigned long flags; | ||
3239 | |||
3240 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3241 | printk("%s(%d):%s tiocmset(%x,%x)\n", | ||
3242 | __FILE__,__LINE__,info->device_name, set, clear); | ||
3243 | |||
3244 | if (set & TIOCM_RTS) | ||
3245 | info->serial_signals |= SerialSignal_RTS; | ||
3246 | if (set & TIOCM_DTR) | ||
3247 | info->serial_signals |= SerialSignal_DTR; | ||
3248 | if (clear & TIOCM_RTS) | ||
3249 | info->serial_signals &= ~SerialSignal_RTS; | ||
3250 | if (clear & TIOCM_DTR) | ||
3251 | info->serial_signals &= ~SerialSignal_DTR; | ||
3252 | |||
3253 | spin_lock_irqsave(&info->lock,flags); | ||
3254 | set_signals(info); | ||
3255 | spin_unlock_irqrestore(&info->lock,flags); | ||
3256 | |||
3257 | return 0; | ||
3258 | } | ||
3259 | |||
3260 | static int carrier_raised(struct tty_port *port) | ||
3261 | { | ||
3262 | SLMP_INFO *info = container_of(port, SLMP_INFO, port); | ||
3263 | unsigned long flags; | ||
3264 | |||
3265 | spin_lock_irqsave(&info->lock,flags); | ||
3266 | get_signals(info); | ||
3267 | spin_unlock_irqrestore(&info->lock,flags); | ||
3268 | |||
3269 | return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; | ||
3270 | } | ||
3271 | |||
3272 | static void dtr_rts(struct tty_port *port, int on) | ||
3273 | { | ||
3274 | SLMP_INFO *info = container_of(port, SLMP_INFO, port); | ||
3275 | unsigned long flags; | ||
3276 | |||
3277 | spin_lock_irqsave(&info->lock,flags); | ||
3278 | if (on) | ||
3279 | info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; | ||
3280 | else | ||
3281 | info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); | ||
3282 | set_signals(info); | ||
3283 | spin_unlock_irqrestore(&info->lock,flags); | ||
3284 | } | ||
3285 | |||
3286 | /* Block the current process until the specified port is ready to open. | ||
3287 | */ | ||
3288 | static int block_til_ready(struct tty_struct *tty, struct file *filp, | ||
3289 | SLMP_INFO *info) | ||
3290 | { | ||
3291 | DECLARE_WAITQUEUE(wait, current); | ||
3292 | int retval; | ||
3293 | bool do_clocal = false; | ||
3294 | bool extra_count = false; | ||
3295 | unsigned long flags; | ||
3296 | int cd; | ||
3297 | struct tty_port *port = &info->port; | ||
3298 | |||
3299 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3300 | printk("%s(%d):%s block_til_ready()\n", | ||
3301 | __FILE__,__LINE__, tty->driver->name ); | ||
3302 | |||
3303 | if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ | ||
3304 | /* nonblock mode is set or port is not enabled */ | ||
3305 | /* just verify that callout device is not active */ | ||
3306 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3307 | return 0; | ||
3308 | } | ||
3309 | |||
3310 | if (tty->termios->c_cflag & CLOCAL) | ||
3311 | do_clocal = true; | ||
3312 | |||
3313 | /* Wait for carrier detect and the line to become | ||
3314 | * free (i.e., not in use by the callout). While we are in | ||
3315 | * this loop, port->count is dropped by one, so that | ||
3316 | * close() knows when to free things. We restore it upon | ||
3317 | * exit, either normal or abnormal. | ||
3318 | */ | ||
3319 | |||
3320 | retval = 0; | ||
3321 | add_wait_queue(&port->open_wait, &wait); | ||
3322 | |||
3323 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3324 | printk("%s(%d):%s block_til_ready() before block, count=%d\n", | ||
3325 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3326 | |||
3327 | spin_lock_irqsave(&info->lock, flags); | ||
3328 | if (!tty_hung_up_p(filp)) { | ||
3329 | extra_count = true; | ||
3330 | port->count--; | ||
3331 | } | ||
3332 | spin_unlock_irqrestore(&info->lock, flags); | ||
3333 | port->blocked_open++; | ||
3334 | |||
3335 | while (1) { | ||
3336 | if (tty->termios->c_cflag & CBAUD) | ||
3337 | tty_port_raise_dtr_rts(port); | ||
3338 | |||
3339 | set_current_state(TASK_INTERRUPTIBLE); | ||
3340 | |||
3341 | if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){ | ||
3342 | retval = (port->flags & ASYNC_HUP_NOTIFY) ? | ||
3343 | -EAGAIN : -ERESTARTSYS; | ||
3344 | break; | ||
3345 | } | ||
3346 | |||
3347 | cd = tty_port_carrier_raised(port); | ||
3348 | |||
3349 | if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd)) | ||
3350 | break; | ||
3351 | |||
3352 | if (signal_pending(current)) { | ||
3353 | retval = -ERESTARTSYS; | ||
3354 | break; | ||
3355 | } | ||
3356 | |||
3357 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3358 | printk("%s(%d):%s block_til_ready() count=%d\n", | ||
3359 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3360 | |||
3361 | tty_unlock(); | ||
3362 | schedule(); | ||
3363 | tty_lock(); | ||
3364 | } | ||
3365 | |||
3366 | set_current_state(TASK_RUNNING); | ||
3367 | remove_wait_queue(&port->open_wait, &wait); | ||
3368 | |||
3369 | if (extra_count) | ||
3370 | port->count++; | ||
3371 | port->blocked_open--; | ||
3372 | |||
3373 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
3374 | printk("%s(%d):%s block_til_ready() after, count=%d\n", | ||
3375 | __FILE__,__LINE__, tty->driver->name, port->count ); | ||
3376 | |||
3377 | if (!retval) | ||
3378 | port->flags |= ASYNC_NORMAL_ACTIVE; | ||
3379 | |||
3380 | return retval; | ||
3381 | } | ||
3382 | |||
3383 | static int alloc_dma_bufs(SLMP_INFO *info) | ||
3384 | { | ||
3385 | unsigned short BuffersPerFrame; | ||
3386 | unsigned short BufferCount; | ||
3387 | |||
3388 | // Force allocation to start at 64K boundary for each port. | ||
3389 | // This is necessary because *all* buffer descriptors for a port | ||
3390 | // *must* be in the same 64K block. All descriptors on a port | ||
3391 | // share a common 'base' address (upper 8 bits of 24 bits) programmed | ||
3392 | // into the CBP register. | ||
3393 | info->port_array[0]->last_mem_alloc = (SCA_MEM_SIZE/4) * info->port_num; | ||
3394 | |||
3395 | /* Calculate the number of DMA buffers necessary to hold the */ | ||
3396 | /* largest allowable frame size. Note: If the max frame size is */ | ||
3397 | /* not an even multiple of the DMA buffer size then we need to */ | ||
3398 | /* round the buffer count per frame up one. */ | ||
3399 | |||
3400 | BuffersPerFrame = (unsigned short)(info->max_frame_size/SCABUFSIZE); | ||
3401 | if ( info->max_frame_size % SCABUFSIZE ) | ||
3402 | BuffersPerFrame++; | ||
3403 | |||
3404 | /* calculate total number of data buffers (SCABUFSIZE) possible | ||
3405 | * in one ports memory (SCA_MEM_SIZE/4) after allocating memory | ||
3406 | * for the descriptor list (BUFFERLISTSIZE). | ||
3407 | */ | ||
3408 | BufferCount = (SCA_MEM_SIZE/4 - BUFFERLISTSIZE)/SCABUFSIZE; | ||
3409 | |||
3410 | /* limit number of buffers to maximum amount of descriptors */ | ||
3411 | if (BufferCount > BUFFERLISTSIZE/sizeof(SCADESC)) | ||
3412 | BufferCount = BUFFERLISTSIZE/sizeof(SCADESC); | ||
3413 | |||
3414 | /* use enough buffers to transmit one max size frame */ | ||
3415 | info->tx_buf_count = BuffersPerFrame + 1; | ||
3416 | |||
3417 | /* never use more than half the available buffers for transmit */ | ||
3418 | if (info->tx_buf_count > (BufferCount/2)) | ||
3419 | info->tx_buf_count = BufferCount/2; | ||
3420 | |||
3421 | if (info->tx_buf_count > SCAMAXDESC) | ||
3422 | info->tx_buf_count = SCAMAXDESC; | ||
3423 | |||
3424 | /* use remaining buffers for receive */ | ||
3425 | info->rx_buf_count = BufferCount - info->tx_buf_count; | ||
3426 | |||
3427 | if (info->rx_buf_count > SCAMAXDESC) | ||
3428 | info->rx_buf_count = SCAMAXDESC; | ||
3429 | |||
3430 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
3431 | printk("%s(%d):%s Allocating %d TX and %d RX DMA buffers.\n", | ||
3432 | __FILE__,__LINE__, info->device_name, | ||
3433 | info->tx_buf_count,info->rx_buf_count); | ||
3434 | |||
3435 | if ( alloc_buf_list( info ) < 0 || | ||
3436 | alloc_frame_bufs(info, | ||
3437 | info->rx_buf_list, | ||
3438 | info->rx_buf_list_ex, | ||
3439 | info->rx_buf_count) < 0 || | ||
3440 | alloc_frame_bufs(info, | ||
3441 | info->tx_buf_list, | ||
3442 | info->tx_buf_list_ex, | ||
3443 | info->tx_buf_count) < 0 || | ||
3444 | alloc_tmp_rx_buf(info) < 0 ) { | ||
3445 | printk("%s(%d):%s Can't allocate DMA buffer memory\n", | ||
3446 | __FILE__,__LINE__, info->device_name); | ||
3447 | return -ENOMEM; | ||
3448 | } | ||
3449 | |||
3450 | rx_reset_buffers( info ); | ||
3451 | |||
3452 | return 0; | ||
3453 | } | ||
3454 | |||
3455 | /* Allocate DMA buffers for the transmit and receive descriptor lists. | ||
3456 | */ | ||
3457 | static int alloc_buf_list(SLMP_INFO *info) | ||
3458 | { | ||
3459 | unsigned int i; | ||
3460 | |||
3461 | /* build list in adapter shared memory */ | ||
3462 | info->buffer_list = info->memory_base + info->port_array[0]->last_mem_alloc; | ||
3463 | info->buffer_list_phys = info->port_array[0]->last_mem_alloc; | ||
3464 | info->port_array[0]->last_mem_alloc += BUFFERLISTSIZE; | ||
3465 | |||
3466 | memset(info->buffer_list, 0, BUFFERLISTSIZE); | ||
3467 | |||
3468 | /* Save virtual address pointers to the receive and */ | ||
3469 | /* transmit buffer lists. (Receive 1st). These pointers will */ | ||
3470 | /* be used by the processor to access the lists. */ | ||
3471 | info->rx_buf_list = (SCADESC *)info->buffer_list; | ||
3472 | |||
3473 | info->tx_buf_list = (SCADESC *)info->buffer_list; | ||
3474 | info->tx_buf_list += info->rx_buf_count; | ||
3475 | |||
3476 | /* Build links for circular buffer entry lists (tx and rx) | ||
3477 | * | ||
3478 | * Note: links are physical addresses read by the SCA device | ||
3479 | * to determine the next buffer entry to use. | ||
3480 | */ | ||
3481 | |||
3482 | for ( i = 0; i < info->rx_buf_count; i++ ) { | ||
3483 | /* calculate and store physical address of this buffer entry */ | ||
3484 | info->rx_buf_list_ex[i].phys_entry = | ||
3485 | info->buffer_list_phys + (i * sizeof(SCABUFSIZE)); | ||
3486 | |||
3487 | /* calculate and store physical address of */ | ||
3488 | /* next entry in cirular list of entries */ | ||
3489 | info->rx_buf_list[i].next = info->buffer_list_phys; | ||
3490 | if ( i < info->rx_buf_count - 1 ) | ||
3491 | info->rx_buf_list[i].next += (i + 1) * sizeof(SCADESC); | ||
3492 | |||
3493 | info->rx_buf_list[i].length = SCABUFSIZE; | ||
3494 | } | ||
3495 | |||
3496 | for ( i = 0; i < info->tx_buf_count; i++ ) { | ||
3497 | /* calculate and store physical address of this buffer entry */ | ||
3498 | info->tx_buf_list_ex[i].phys_entry = info->buffer_list_phys + | ||
3499 | ((info->rx_buf_count + i) * sizeof(SCADESC)); | ||
3500 | |||
3501 | /* calculate and store physical address of */ | ||
3502 | /* next entry in cirular list of entries */ | ||
3503 | |||
3504 | info->tx_buf_list[i].next = info->buffer_list_phys + | ||
3505 | info->rx_buf_count * sizeof(SCADESC); | ||
3506 | |||
3507 | if ( i < info->tx_buf_count - 1 ) | ||
3508 | info->tx_buf_list[i].next += (i + 1) * sizeof(SCADESC); | ||
3509 | } | ||
3510 | |||
3511 | return 0; | ||
3512 | } | ||
3513 | |||
3514 | /* Allocate the frame DMA buffers used by the specified buffer list. | ||
3515 | */ | ||
3516 | static int alloc_frame_bufs(SLMP_INFO *info, SCADESC *buf_list,SCADESC_EX *buf_list_ex,int count) | ||
3517 | { | ||
3518 | int i; | ||
3519 | unsigned long phys_addr; | ||
3520 | |||
3521 | for ( i = 0; i < count; i++ ) { | ||
3522 | buf_list_ex[i].virt_addr = info->memory_base + info->port_array[0]->last_mem_alloc; | ||
3523 | phys_addr = info->port_array[0]->last_mem_alloc; | ||
3524 | info->port_array[0]->last_mem_alloc += SCABUFSIZE; | ||
3525 | |||
3526 | buf_list[i].buf_ptr = (unsigned short)phys_addr; | ||
3527 | buf_list[i].buf_base = (unsigned char)(phys_addr >> 16); | ||
3528 | } | ||
3529 | |||
3530 | return 0; | ||
3531 | } | ||
3532 | |||
3533 | static void free_dma_bufs(SLMP_INFO *info) | ||
3534 | { | ||
3535 | info->buffer_list = NULL; | ||
3536 | info->rx_buf_list = NULL; | ||
3537 | info->tx_buf_list = NULL; | ||
3538 | } | ||
3539 | |||
3540 | /* allocate buffer large enough to hold max_frame_size. | ||
3541 | * This buffer is used to pass an assembled frame to the line discipline. | ||
3542 | */ | ||
3543 | static int alloc_tmp_rx_buf(SLMP_INFO *info) | ||
3544 | { | ||
3545 | info->tmp_rx_buf = kmalloc(info->max_frame_size, GFP_KERNEL); | ||
3546 | if (info->tmp_rx_buf == NULL) | ||
3547 | return -ENOMEM; | ||
3548 | return 0; | ||
3549 | } | ||
3550 | |||
3551 | static void free_tmp_rx_buf(SLMP_INFO *info) | ||
3552 | { | ||
3553 | kfree(info->tmp_rx_buf); | ||
3554 | info->tmp_rx_buf = NULL; | ||
3555 | } | ||
3556 | |||
3557 | static int claim_resources(SLMP_INFO *info) | ||
3558 | { | ||
3559 | if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) { | ||
3560 | printk( "%s(%d):%s mem addr conflict, Addr=%08X\n", | ||
3561 | __FILE__,__LINE__,info->device_name, info->phys_memory_base); | ||
3562 | info->init_error = DiagStatus_AddressConflict; | ||
3563 | goto errout; | ||
3564 | } | ||
3565 | else | ||
3566 | info->shared_mem_requested = true; | ||
3567 | |||
3568 | if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) { | ||
3569 | printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n", | ||
3570 | __FILE__,__LINE__,info->device_name, info->phys_lcr_base); | ||
3571 | info->init_error = DiagStatus_AddressConflict; | ||
3572 | goto errout; | ||
3573 | } | ||
3574 | else | ||
3575 | info->lcr_mem_requested = true; | ||
3576 | |||
3577 | if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) { | ||
3578 | printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n", | ||
3579 | __FILE__,__LINE__,info->device_name, info->phys_sca_base); | ||
3580 | info->init_error = DiagStatus_AddressConflict; | ||
3581 | goto errout; | ||
3582 | } | ||
3583 | else | ||
3584 | info->sca_base_requested = true; | ||
3585 | |||
3586 | if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) { | ||
3587 | printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n", | ||
3588 | __FILE__,__LINE__,info->device_name, info->phys_statctrl_base); | ||
3589 | info->init_error = DiagStatus_AddressConflict; | ||
3590 | goto errout; | ||
3591 | } | ||
3592 | else | ||
3593 | info->sca_statctrl_requested = true; | ||
3594 | |||
3595 | info->memory_base = ioremap_nocache(info->phys_memory_base, | ||
3596 | SCA_MEM_SIZE); | ||
3597 | if (!info->memory_base) { | ||
3598 | printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", | ||
3599 | __FILE__,__LINE__,info->device_name, info->phys_memory_base ); | ||
3600 | info->init_error = DiagStatus_CantAssignPciResources; | ||
3601 | goto errout; | ||
3602 | } | ||
3603 | |||
3604 | info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE); | ||
3605 | if (!info->lcr_base) { | ||
3606 | printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", | ||
3607 | __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); | ||
3608 | info->init_error = DiagStatus_CantAssignPciResources; | ||
3609 | goto errout; | ||
3610 | } | ||
3611 | info->lcr_base += info->lcr_offset; | ||
3612 | |||
3613 | info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE); | ||
3614 | if (!info->sca_base) { | ||
3615 | printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", | ||
3616 | __FILE__,__LINE__,info->device_name, info->phys_sca_base ); | ||
3617 | info->init_error = DiagStatus_CantAssignPciResources; | ||
3618 | goto errout; | ||
3619 | } | ||
3620 | info->sca_base += info->sca_offset; | ||
3621 | |||
3622 | info->statctrl_base = ioremap_nocache(info->phys_statctrl_base, | ||
3623 | PAGE_SIZE); | ||
3624 | if (!info->statctrl_base) { | ||
3625 | printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", | ||
3626 | __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); | ||
3627 | info->init_error = DiagStatus_CantAssignPciResources; | ||
3628 | goto errout; | ||
3629 | } | ||
3630 | info->statctrl_base += info->statctrl_offset; | ||
3631 | |||
3632 | if ( !memory_test(info) ) { | ||
3633 | printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n", | ||
3634 | __FILE__,__LINE__,info->device_name, info->phys_memory_base ); | ||
3635 | info->init_error = DiagStatus_MemoryError; | ||
3636 | goto errout; | ||
3637 | } | ||
3638 | |||
3639 | return 0; | ||
3640 | |||
3641 | errout: | ||
3642 | release_resources( info ); | ||
3643 | return -ENODEV; | ||
3644 | } | ||
3645 | |||
3646 | static void release_resources(SLMP_INFO *info) | ||
3647 | { | ||
3648 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
3649 | printk( "%s(%d):%s release_resources() entry\n", | ||
3650 | __FILE__,__LINE__,info->device_name ); | ||
3651 | |||
3652 | if ( info->irq_requested ) { | ||
3653 | free_irq(info->irq_level, info); | ||
3654 | info->irq_requested = false; | ||
3655 | } | ||
3656 | |||
3657 | if ( info->shared_mem_requested ) { | ||
3658 | release_mem_region(info->phys_memory_base,SCA_MEM_SIZE); | ||
3659 | info->shared_mem_requested = false; | ||
3660 | } | ||
3661 | if ( info->lcr_mem_requested ) { | ||
3662 | release_mem_region(info->phys_lcr_base + info->lcr_offset,128); | ||
3663 | info->lcr_mem_requested = false; | ||
3664 | } | ||
3665 | if ( info->sca_base_requested ) { | ||
3666 | release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE); | ||
3667 | info->sca_base_requested = false; | ||
3668 | } | ||
3669 | if ( info->sca_statctrl_requested ) { | ||
3670 | release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE); | ||
3671 | info->sca_statctrl_requested = false; | ||
3672 | } | ||
3673 | |||
3674 | if (info->memory_base){ | ||
3675 | iounmap(info->memory_base); | ||
3676 | info->memory_base = NULL; | ||
3677 | } | ||
3678 | |||
3679 | if (info->sca_base) { | ||
3680 | iounmap(info->sca_base - info->sca_offset); | ||
3681 | info->sca_base=NULL; | ||
3682 | } | ||
3683 | |||
3684 | if (info->statctrl_base) { | ||
3685 | iounmap(info->statctrl_base - info->statctrl_offset); | ||
3686 | info->statctrl_base=NULL; | ||
3687 | } | ||
3688 | |||
3689 | if (info->lcr_base){ | ||
3690 | iounmap(info->lcr_base - info->lcr_offset); | ||
3691 | info->lcr_base = NULL; | ||
3692 | } | ||
3693 | |||
3694 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
3695 | printk( "%s(%d):%s release_resources() exit\n", | ||
3696 | __FILE__,__LINE__,info->device_name ); | ||
3697 | } | ||
3698 | |||
3699 | /* Add the specified device instance data structure to the | ||
3700 | * global linked list of devices and increment the device count. | ||
3701 | */ | ||
3702 | static void add_device(SLMP_INFO *info) | ||
3703 | { | ||
3704 | info->next_device = NULL; | ||
3705 | info->line = synclinkmp_device_count; | ||
3706 | sprintf(info->device_name,"ttySLM%dp%d",info->adapter_num,info->port_num); | ||
3707 | |||
3708 | if (info->line < MAX_DEVICES) { | ||
3709 | if (maxframe[info->line]) | ||
3710 | info->max_frame_size = maxframe[info->line]; | ||
3711 | } | ||
3712 | |||
3713 | synclinkmp_device_count++; | ||
3714 | |||
3715 | if ( !synclinkmp_device_list ) | ||
3716 | synclinkmp_device_list = info; | ||
3717 | else { | ||
3718 | SLMP_INFO *current_dev = synclinkmp_device_list; | ||
3719 | while( current_dev->next_device ) | ||
3720 | current_dev = current_dev->next_device; | ||
3721 | current_dev->next_device = info; | ||
3722 | } | ||
3723 | |||
3724 | if ( info->max_frame_size < 4096 ) | ||
3725 | info->max_frame_size = 4096; | ||
3726 | else if ( info->max_frame_size > 65535 ) | ||
3727 | info->max_frame_size = 65535; | ||
3728 | |||
3729 | printk( "SyncLink MultiPort %s: " | ||
3730 | "Mem=(%08x %08X %08x %08X) IRQ=%d MaxFrameSize=%u\n", | ||
3731 | info->device_name, | ||
3732 | info->phys_sca_base, | ||
3733 | info->phys_memory_base, | ||
3734 | info->phys_statctrl_base, | ||
3735 | info->phys_lcr_base, | ||
3736 | info->irq_level, | ||
3737 | info->max_frame_size ); | ||
3738 | |||
3739 | #if SYNCLINK_GENERIC_HDLC | ||
3740 | hdlcdev_init(info); | ||
3741 | #endif | ||
3742 | } | ||
3743 | |||
3744 | static const struct tty_port_operations port_ops = { | ||
3745 | .carrier_raised = carrier_raised, | ||
3746 | .dtr_rts = dtr_rts, | ||
3747 | }; | ||
3748 | |||
3749 | /* Allocate and initialize a device instance structure | ||
3750 | * | ||
3751 | * Return Value: pointer to SLMP_INFO if success, otherwise NULL | ||
3752 | */ | ||
3753 | static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev) | ||
3754 | { | ||
3755 | SLMP_INFO *info; | ||
3756 | |||
3757 | info = kzalloc(sizeof(SLMP_INFO), | ||
3758 | GFP_KERNEL); | ||
3759 | |||
3760 | if (!info) { | ||
3761 | printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n", | ||
3762 | __FILE__,__LINE__, adapter_num, port_num); | ||
3763 | } else { | ||
3764 | tty_port_init(&info->port); | ||
3765 | info->port.ops = &port_ops; | ||
3766 | info->magic = MGSL_MAGIC; | ||
3767 | INIT_WORK(&info->task, bh_handler); | ||
3768 | info->max_frame_size = 4096; | ||
3769 | info->port.close_delay = 5*HZ/10; | ||
3770 | info->port.closing_wait = 30*HZ; | ||
3771 | init_waitqueue_head(&info->status_event_wait_q); | ||
3772 | init_waitqueue_head(&info->event_wait_q); | ||
3773 | spin_lock_init(&info->netlock); | ||
3774 | memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); | ||
3775 | info->idle_mode = HDLC_TXIDLE_FLAGS; | ||
3776 | info->adapter_num = adapter_num; | ||
3777 | info->port_num = port_num; | ||
3778 | |||
3779 | /* Copy configuration info to device instance data */ | ||
3780 | info->irq_level = pdev->irq; | ||
3781 | info->phys_lcr_base = pci_resource_start(pdev,0); | ||
3782 | info->phys_sca_base = pci_resource_start(pdev,2); | ||
3783 | info->phys_memory_base = pci_resource_start(pdev,3); | ||
3784 | info->phys_statctrl_base = pci_resource_start(pdev,4); | ||
3785 | |||
3786 | /* Because veremap only works on page boundaries we must map | ||
3787 | * a larger area than is actually implemented for the LCR | ||
3788 | * memory range. We map a full page starting at the page boundary. | ||
3789 | */ | ||
3790 | info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1); | ||
3791 | info->phys_lcr_base &= ~(PAGE_SIZE-1); | ||
3792 | |||
3793 | info->sca_offset = info->phys_sca_base & (PAGE_SIZE-1); | ||
3794 | info->phys_sca_base &= ~(PAGE_SIZE-1); | ||
3795 | |||
3796 | info->statctrl_offset = info->phys_statctrl_base & (PAGE_SIZE-1); | ||
3797 | info->phys_statctrl_base &= ~(PAGE_SIZE-1); | ||
3798 | |||
3799 | info->bus_type = MGSL_BUS_TYPE_PCI; | ||
3800 | info->irq_flags = IRQF_SHARED; | ||
3801 | |||
3802 | setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info); | ||
3803 | setup_timer(&info->status_timer, status_timeout, | ||
3804 | (unsigned long)info); | ||
3805 | |||
3806 | /* Store the PCI9050 misc control register value because a flaw | ||
3807 | * in the PCI9050 prevents LCR registers from being read if | ||
3808 | * BIOS assigns an LCR base address with bit 7 set. | ||
3809 | * | ||
3810 | * Only the misc control register is accessed for which only | ||
3811 | * write access is needed, so set an initial value and change | ||
3812 | * bits to the device instance data as we write the value | ||
3813 | * to the actual misc control register. | ||
3814 | */ | ||
3815 | info->misc_ctrl_value = 0x087e4546; | ||
3816 | |||
3817 | /* initial port state is unknown - if startup errors | ||
3818 | * occur, init_error will be set to indicate the | ||
3819 | * problem. Once the port is fully initialized, | ||
3820 | * this value will be set to 0 to indicate the | ||
3821 | * port is available. | ||
3822 | */ | ||
3823 | info->init_error = -1; | ||
3824 | } | ||
3825 | |||
3826 | return info; | ||
3827 | } | ||
3828 | |||
3829 | static void device_init(int adapter_num, struct pci_dev *pdev) | ||
3830 | { | ||
3831 | SLMP_INFO *port_array[SCA_MAX_PORTS]; | ||
3832 | int port; | ||
3833 | |||
3834 | /* allocate device instances for up to SCA_MAX_PORTS devices */ | ||
3835 | for ( port = 0; port < SCA_MAX_PORTS; ++port ) { | ||
3836 | port_array[port] = alloc_dev(adapter_num,port,pdev); | ||
3837 | if( port_array[port] == NULL ) { | ||
3838 | for ( --port; port >= 0; --port ) | ||
3839 | kfree(port_array[port]); | ||
3840 | return; | ||
3841 | } | ||
3842 | } | ||
3843 | |||
3844 | /* give copy of port_array to all ports and add to device list */ | ||
3845 | for ( port = 0; port < SCA_MAX_PORTS; ++port ) { | ||
3846 | memcpy(port_array[port]->port_array,port_array,sizeof(port_array)); | ||
3847 | add_device( port_array[port] ); | ||
3848 | spin_lock_init(&port_array[port]->lock); | ||
3849 | } | ||
3850 | |||
3851 | /* Allocate and claim adapter resources */ | ||
3852 | if ( !claim_resources(port_array[0]) ) { | ||
3853 | |||
3854 | alloc_dma_bufs(port_array[0]); | ||
3855 | |||
3856 | /* copy resource information from first port to others */ | ||
3857 | for ( port = 1; port < SCA_MAX_PORTS; ++port ) { | ||
3858 | port_array[port]->lock = port_array[0]->lock; | ||
3859 | port_array[port]->irq_level = port_array[0]->irq_level; | ||
3860 | port_array[port]->memory_base = port_array[0]->memory_base; | ||
3861 | port_array[port]->sca_base = port_array[0]->sca_base; | ||
3862 | port_array[port]->statctrl_base = port_array[0]->statctrl_base; | ||
3863 | port_array[port]->lcr_base = port_array[0]->lcr_base; | ||
3864 | alloc_dma_bufs(port_array[port]); | ||
3865 | } | ||
3866 | |||
3867 | if ( request_irq(port_array[0]->irq_level, | ||
3868 | synclinkmp_interrupt, | ||
3869 | port_array[0]->irq_flags, | ||
3870 | port_array[0]->device_name, | ||
3871 | port_array[0]) < 0 ) { | ||
3872 | printk( "%s(%d):%s Cant request interrupt, IRQ=%d\n", | ||
3873 | __FILE__,__LINE__, | ||
3874 | port_array[0]->device_name, | ||
3875 | port_array[0]->irq_level ); | ||
3876 | } | ||
3877 | else { | ||
3878 | port_array[0]->irq_requested = true; | ||
3879 | adapter_test(port_array[0]); | ||
3880 | } | ||
3881 | } | ||
3882 | } | ||
3883 | |||
3884 | static const struct tty_operations ops = { | ||
3885 | .open = open, | ||
3886 | .close = close, | ||
3887 | .write = write, | ||
3888 | .put_char = put_char, | ||
3889 | .flush_chars = flush_chars, | ||
3890 | .write_room = write_room, | ||
3891 | .chars_in_buffer = chars_in_buffer, | ||
3892 | .flush_buffer = flush_buffer, | ||
3893 | .ioctl = ioctl, | ||
3894 | .throttle = throttle, | ||
3895 | .unthrottle = unthrottle, | ||
3896 | .send_xchar = send_xchar, | ||
3897 | .break_ctl = set_break, | ||
3898 | .wait_until_sent = wait_until_sent, | ||
3899 | .set_termios = set_termios, | ||
3900 | .stop = tx_hold, | ||
3901 | .start = tx_release, | ||
3902 | .hangup = hangup, | ||
3903 | .tiocmget = tiocmget, | ||
3904 | .tiocmset = tiocmset, | ||
3905 | .get_icount = get_icount, | ||
3906 | .proc_fops = &synclinkmp_proc_fops, | ||
3907 | }; | ||
3908 | |||
3909 | |||
3910 | static void synclinkmp_cleanup(void) | ||
3911 | { | ||
3912 | int rc; | ||
3913 | SLMP_INFO *info; | ||
3914 | SLMP_INFO *tmp; | ||
3915 | |||
3916 | printk("Unloading %s %s\n", driver_name, driver_version); | ||
3917 | |||
3918 | if (serial_driver) { | ||
3919 | if ((rc = tty_unregister_driver(serial_driver))) | ||
3920 | printk("%s(%d) failed to unregister tty driver err=%d\n", | ||
3921 | __FILE__,__LINE__,rc); | ||
3922 | put_tty_driver(serial_driver); | ||
3923 | } | ||
3924 | |||
3925 | /* reset devices */ | ||
3926 | info = synclinkmp_device_list; | ||
3927 | while(info) { | ||
3928 | reset_port(info); | ||
3929 | info = info->next_device; | ||
3930 | } | ||
3931 | |||
3932 | /* release devices */ | ||
3933 | info = synclinkmp_device_list; | ||
3934 | while(info) { | ||
3935 | #if SYNCLINK_GENERIC_HDLC | ||
3936 | hdlcdev_exit(info); | ||
3937 | #endif | ||
3938 | free_dma_bufs(info); | ||
3939 | free_tmp_rx_buf(info); | ||
3940 | if ( info->port_num == 0 ) { | ||
3941 | if (info->sca_base) | ||
3942 | write_reg(info, LPR, 1); /* set low power mode */ | ||
3943 | release_resources(info); | ||
3944 | } | ||
3945 | tmp = info; | ||
3946 | info = info->next_device; | ||
3947 | kfree(tmp); | ||
3948 | } | ||
3949 | |||
3950 | pci_unregister_driver(&synclinkmp_pci_driver); | ||
3951 | } | ||
3952 | |||
3953 | /* Driver initialization entry point. | ||
3954 | */ | ||
3955 | |||
3956 | static int __init synclinkmp_init(void) | ||
3957 | { | ||
3958 | int rc; | ||
3959 | |||
3960 | if (break_on_load) { | ||
3961 | synclinkmp_get_text_ptr(); | ||
3962 | BREAKPOINT(); | ||
3963 | } | ||
3964 | |||
3965 | printk("%s %s\n", driver_name, driver_version); | ||
3966 | |||
3967 | if ((rc = pci_register_driver(&synclinkmp_pci_driver)) < 0) { | ||
3968 | printk("%s:failed to register PCI driver, error=%d\n",__FILE__,rc); | ||
3969 | return rc; | ||
3970 | } | ||
3971 | |||
3972 | serial_driver = alloc_tty_driver(128); | ||
3973 | if (!serial_driver) { | ||
3974 | rc = -ENOMEM; | ||
3975 | goto error; | ||
3976 | } | ||
3977 | |||
3978 | /* Initialize the tty_driver structure */ | ||
3979 | |||
3980 | serial_driver->owner = THIS_MODULE; | ||
3981 | serial_driver->driver_name = "synclinkmp"; | ||
3982 | serial_driver->name = "ttySLM"; | ||
3983 | serial_driver->major = ttymajor; | ||
3984 | serial_driver->minor_start = 64; | ||
3985 | serial_driver->type = TTY_DRIVER_TYPE_SERIAL; | ||
3986 | serial_driver->subtype = SERIAL_TYPE_NORMAL; | ||
3987 | serial_driver->init_termios = tty_std_termios; | ||
3988 | serial_driver->init_termios.c_cflag = | ||
3989 | B9600 | CS8 | CREAD | HUPCL | CLOCAL; | ||
3990 | serial_driver->init_termios.c_ispeed = 9600; | ||
3991 | serial_driver->init_termios.c_ospeed = 9600; | ||
3992 | serial_driver->flags = TTY_DRIVER_REAL_RAW; | ||
3993 | tty_set_operations(serial_driver, &ops); | ||
3994 | if ((rc = tty_register_driver(serial_driver)) < 0) { | ||
3995 | printk("%s(%d):Couldn't register serial driver\n", | ||
3996 | __FILE__,__LINE__); | ||
3997 | put_tty_driver(serial_driver); | ||
3998 | serial_driver = NULL; | ||
3999 | goto error; | ||
4000 | } | ||
4001 | |||
4002 | printk("%s %s, tty major#%d\n", | ||
4003 | driver_name, driver_version, | ||
4004 | serial_driver->major); | ||
4005 | |||
4006 | return 0; | ||
4007 | |||
4008 | error: | ||
4009 | synclinkmp_cleanup(); | ||
4010 | return rc; | ||
4011 | } | ||
4012 | |||
4013 | static void __exit synclinkmp_exit(void) | ||
4014 | { | ||
4015 | synclinkmp_cleanup(); | ||
4016 | } | ||
4017 | |||
4018 | module_init(synclinkmp_init); | ||
4019 | module_exit(synclinkmp_exit); | ||
4020 | |||
4021 | /* Set the port for internal loopback mode. | ||
4022 | * The TxCLK and RxCLK signals are generated from the BRG and | ||
4023 | * the TxD is looped back to the RxD internally. | ||
4024 | */ | ||
4025 | static void enable_loopback(SLMP_INFO *info, int enable) | ||
4026 | { | ||
4027 | if (enable) { | ||
4028 | /* MD2 (Mode Register 2) | ||
4029 | * 01..00 CNCT<1..0> Channel Connection 11=Local Loopback | ||
4030 | */ | ||
4031 | write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) | (BIT1 + BIT0))); | ||
4032 | |||
4033 | /* degate external TxC clock source */ | ||
4034 | info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); | ||
4035 | write_control_reg(info); | ||
4036 | |||
4037 | /* RXS/TXS (Rx/Tx clock source) | ||
4038 | * 07 Reserved, must be 0 | ||
4039 | * 06..04 Clock Source, 100=BRG | ||
4040 | * 03..00 Clock Divisor, 0000=1 | ||
4041 | */ | ||
4042 | write_reg(info, RXS, 0x40); | ||
4043 | write_reg(info, TXS, 0x40); | ||
4044 | |||
4045 | } else { | ||
4046 | /* MD2 (Mode Register 2) | ||
4047 | * 01..00 CNCT<1..0> Channel connection, 0=normal | ||
4048 | */ | ||
4049 | write_reg(info, MD2, (unsigned char)(read_reg(info, MD2) & ~(BIT1 + BIT0))); | ||
4050 | |||
4051 | /* RXS/TXS (Rx/Tx clock source) | ||
4052 | * 07 Reserved, must be 0 | ||
4053 | * 06..04 Clock Source, 000=RxC/TxC Pin | ||
4054 | * 03..00 Clock Divisor, 0000=1 | ||
4055 | */ | ||
4056 | write_reg(info, RXS, 0x00); | ||
4057 | write_reg(info, TXS, 0x00); | ||
4058 | } | ||
4059 | |||
4060 | /* set LinkSpeed if available, otherwise default to 2Mbps */ | ||
4061 | if (info->params.clock_speed) | ||
4062 | set_rate(info, info->params.clock_speed); | ||
4063 | else | ||
4064 | set_rate(info, 3686400); | ||
4065 | } | ||
4066 | |||
4067 | /* Set the baud rate register to the desired speed | ||
4068 | * | ||
4069 | * data_rate data rate of clock in bits per second | ||
4070 | * A data rate of 0 disables the AUX clock. | ||
4071 | */ | ||
4072 | static void set_rate( SLMP_INFO *info, u32 data_rate ) | ||
4073 | { | ||
4074 | u32 TMCValue; | ||
4075 | unsigned char BRValue; | ||
4076 | u32 Divisor=0; | ||
4077 | |||
4078 | /* fBRG = fCLK/(TMC * 2^BR) | ||
4079 | */ | ||
4080 | if (data_rate != 0) { | ||
4081 | Divisor = 14745600/data_rate; | ||
4082 | if (!Divisor) | ||
4083 | Divisor = 1; | ||
4084 | |||
4085 | TMCValue = Divisor; | ||
4086 | |||
4087 | BRValue = 0; | ||
4088 | if (TMCValue != 1 && TMCValue != 2) { | ||
4089 | /* BRValue of 0 provides 50/50 duty cycle *only* when | ||
4090 | * TMCValue is 1 or 2. BRValue of 1 to 9 always provides | ||
4091 | * 50/50 duty cycle. | ||
4092 | */ | ||
4093 | BRValue = 1; | ||
4094 | TMCValue >>= 1; | ||
4095 | } | ||
4096 | |||
4097 | /* while TMCValue is too big for TMC register, divide | ||
4098 | * by 2 and increment BR exponent. | ||
4099 | */ | ||
4100 | for(; TMCValue > 256 && BRValue < 10; BRValue++) | ||
4101 | TMCValue >>= 1; | ||
4102 | |||
4103 | write_reg(info, TXS, | ||
4104 | (unsigned char)((read_reg(info, TXS) & 0xf0) | BRValue)); | ||
4105 | write_reg(info, RXS, | ||
4106 | (unsigned char)((read_reg(info, RXS) & 0xf0) | BRValue)); | ||
4107 | write_reg(info, TMC, (unsigned char)TMCValue); | ||
4108 | } | ||
4109 | else { | ||
4110 | write_reg(info, TXS,0); | ||
4111 | write_reg(info, RXS,0); | ||
4112 | write_reg(info, TMC, 0); | ||
4113 | } | ||
4114 | } | ||
4115 | |||
4116 | /* Disable receiver | ||
4117 | */ | ||
4118 | static void rx_stop(SLMP_INFO *info) | ||
4119 | { | ||
4120 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
4121 | printk("%s(%d):%s rx_stop()\n", | ||
4122 | __FILE__,__LINE__, info->device_name ); | ||
4123 | |||
4124 | write_reg(info, CMD, RXRESET); | ||
4125 | |||
4126 | info->ie0_value &= ~RXRDYE; | ||
4127 | write_reg(info, IE0, info->ie0_value); /* disable Rx data interrupts */ | ||
4128 | |||
4129 | write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ | ||
4130 | write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ | ||
4131 | write_reg(info, RXDMA + DIR, 0); /* disable Rx DMA interrupts */ | ||
4132 | |||
4133 | info->rx_enabled = false; | ||
4134 | info->rx_overflow = false; | ||
4135 | } | ||
4136 | |||
4137 | /* enable the receiver | ||
4138 | */ | ||
4139 | static void rx_start(SLMP_INFO *info) | ||
4140 | { | ||
4141 | int i; | ||
4142 | |||
4143 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
4144 | printk("%s(%d):%s rx_start()\n", | ||
4145 | __FILE__,__LINE__, info->device_name ); | ||
4146 | |||
4147 | write_reg(info, CMD, RXRESET); | ||
4148 | |||
4149 | if ( info->params.mode == MGSL_MODE_HDLC ) { | ||
4150 | /* HDLC, disabe IRQ on rxdata */ | ||
4151 | info->ie0_value &= ~RXRDYE; | ||
4152 | write_reg(info, IE0, info->ie0_value); | ||
4153 | |||
4154 | /* Reset all Rx DMA buffers and program rx dma */ | ||
4155 | write_reg(info, RXDMA + DSR, 0); /* disable Rx DMA */ | ||
4156 | write_reg(info, RXDMA + DCMD, SWABORT); /* reset/init Rx DMA */ | ||
4157 | |||
4158 | for (i = 0; i < info->rx_buf_count; i++) { | ||
4159 | info->rx_buf_list[i].status = 0xff; | ||
4160 | |||
4161 | // throttle to 4 shared memory writes at a time to prevent | ||
4162 | // hogging local bus (keep latency time for DMA requests low). | ||
4163 | if (!(i % 4)) | ||
4164 | read_status_reg(info); | ||
4165 | } | ||
4166 | info->current_rx_buf = 0; | ||
4167 | |||
4168 | /* set current/1st descriptor address */ | ||
4169 | write_reg16(info, RXDMA + CDA, | ||
4170 | info->rx_buf_list_ex[0].phys_entry); | ||
4171 | |||
4172 | /* set new last rx descriptor address */ | ||
4173 | write_reg16(info, RXDMA + EDA, | ||
4174 | info->rx_buf_list_ex[info->rx_buf_count - 1].phys_entry); | ||
4175 | |||
4176 | /* set buffer length (shared by all rx dma data buffers) */ | ||
4177 | write_reg16(info, RXDMA + BFL, SCABUFSIZE); | ||
4178 | |||
4179 | write_reg(info, RXDMA + DIR, 0x60); /* enable Rx DMA interrupts (EOM/BOF) */ | ||
4180 | write_reg(info, RXDMA + DSR, 0xf2); /* clear Rx DMA IRQs, enable Rx DMA */ | ||
4181 | } else { | ||
4182 | /* async, enable IRQ on rxdata */ | ||
4183 | info->ie0_value |= RXRDYE; | ||
4184 | write_reg(info, IE0, info->ie0_value); | ||
4185 | } | ||
4186 | |||
4187 | write_reg(info, CMD, RXENABLE); | ||
4188 | |||
4189 | info->rx_overflow = false; | ||
4190 | info->rx_enabled = true; | ||
4191 | } | ||
4192 | |||
4193 | /* Enable the transmitter and send a transmit frame if | ||
4194 | * one is loaded in the DMA buffers. | ||
4195 | */ | ||
4196 | static void tx_start(SLMP_INFO *info) | ||
4197 | { | ||
4198 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
4199 | printk("%s(%d):%s tx_start() tx_count=%d\n", | ||
4200 | __FILE__,__LINE__, info->device_name,info->tx_count ); | ||
4201 | |||
4202 | if (!info->tx_enabled ) { | ||
4203 | write_reg(info, CMD, TXRESET); | ||
4204 | write_reg(info, CMD, TXENABLE); | ||
4205 | info->tx_enabled = true; | ||
4206 | } | ||
4207 | |||
4208 | if ( info->tx_count ) { | ||
4209 | |||
4210 | /* If auto RTS enabled and RTS is inactive, then assert */ | ||
4211 | /* RTS and set a flag indicating that the driver should */ | ||
4212 | /* negate RTS when the transmission completes. */ | ||
4213 | |||
4214 | info->drop_rts_on_tx_done = false; | ||
4215 | |||
4216 | if (info->params.mode != MGSL_MODE_ASYNC) { | ||
4217 | |||
4218 | if ( info->params.flags & HDLC_FLAG_AUTO_RTS ) { | ||
4219 | get_signals( info ); | ||
4220 | if ( !(info->serial_signals & SerialSignal_RTS) ) { | ||
4221 | info->serial_signals |= SerialSignal_RTS; | ||
4222 | set_signals( info ); | ||
4223 | info->drop_rts_on_tx_done = true; | ||
4224 | } | ||
4225 | } | ||
4226 | |||
4227 | write_reg16(info, TRC0, | ||
4228 | (unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level)); | ||
4229 | |||
4230 | write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ | ||
4231 | write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ | ||
4232 | |||
4233 | /* set TX CDA (current descriptor address) */ | ||
4234 | write_reg16(info, TXDMA + CDA, | ||
4235 | info->tx_buf_list_ex[0].phys_entry); | ||
4236 | |||
4237 | /* set TX EDA (last descriptor address) */ | ||
4238 | write_reg16(info, TXDMA + EDA, | ||
4239 | info->tx_buf_list_ex[info->last_tx_buf].phys_entry); | ||
4240 | |||
4241 | /* enable underrun IRQ */ | ||
4242 | info->ie1_value &= ~IDLE; | ||
4243 | info->ie1_value |= UDRN; | ||
4244 | write_reg(info, IE1, info->ie1_value); | ||
4245 | write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); | ||
4246 | |||
4247 | write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */ | ||
4248 | write_reg(info, TXDMA + DSR, 0xf2); /* clear Tx DMA IRQs, enable Tx DMA */ | ||
4249 | |||
4250 | mod_timer(&info->tx_timer, jiffies + | ||
4251 | msecs_to_jiffies(5000)); | ||
4252 | } | ||
4253 | else { | ||
4254 | tx_load_fifo(info); | ||
4255 | /* async, enable IRQ on txdata */ | ||
4256 | info->ie0_value |= TXRDYE; | ||
4257 | write_reg(info, IE0, info->ie0_value); | ||
4258 | } | ||
4259 | |||
4260 | info->tx_active = true; | ||
4261 | } | ||
4262 | } | ||
4263 | |||
4264 | /* stop the transmitter and DMA | ||
4265 | */ | ||
4266 | static void tx_stop( SLMP_INFO *info ) | ||
4267 | { | ||
4268 | if (debug_level >= DEBUG_LEVEL_ISR) | ||
4269 | printk("%s(%d):%s tx_stop()\n", | ||
4270 | __FILE__,__LINE__, info->device_name ); | ||
4271 | |||
4272 | del_timer(&info->tx_timer); | ||
4273 | |||
4274 | write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */ | ||
4275 | write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */ | ||
4276 | |||
4277 | write_reg(info, CMD, TXRESET); | ||
4278 | |||
4279 | info->ie1_value &= ~(UDRN + IDLE); | ||
4280 | write_reg(info, IE1, info->ie1_value); /* disable tx status interrupts */ | ||
4281 | write_reg(info, SR1, (unsigned char)(IDLE + UDRN)); /* clear pending */ | ||
4282 | |||
4283 | info->ie0_value &= ~TXRDYE; | ||
4284 | write_reg(info, IE0, info->ie0_value); /* disable tx data interrupts */ | ||
4285 | |||
4286 | info->tx_enabled = false; | ||
4287 | info->tx_active = false; | ||
4288 | } | ||
4289 | |||
4290 | /* Fill the transmit FIFO until the FIFO is full or | ||
4291 | * there is no more data to load. | ||
4292 | */ | ||
4293 | static void tx_load_fifo(SLMP_INFO *info) | ||
4294 | { | ||
4295 | u8 TwoBytes[2]; | ||
4296 | |||
4297 | /* do nothing is now tx data available and no XON/XOFF pending */ | ||
4298 | |||
4299 | if ( !info->tx_count && !info->x_char ) | ||
4300 | return; | ||
4301 | |||
4302 | /* load the Transmit FIFO until FIFOs full or all data sent */ | ||
4303 | |||
4304 | while( info->tx_count && (read_reg(info,SR0) & BIT1) ) { | ||
4305 | |||
4306 | /* there is more space in the transmit FIFO and */ | ||
4307 | /* there is more data in transmit buffer */ | ||
4308 | |||
4309 | if ( (info->tx_count > 1) && !info->x_char ) { | ||
4310 | /* write 16-bits */ | ||
4311 | TwoBytes[0] = info->tx_buf[info->tx_get++]; | ||
4312 | if (info->tx_get >= info->max_frame_size) | ||
4313 | info->tx_get -= info->max_frame_size; | ||
4314 | TwoBytes[1] = info->tx_buf[info->tx_get++]; | ||
4315 | if (info->tx_get >= info->max_frame_size) | ||
4316 | info->tx_get -= info->max_frame_size; | ||
4317 | |||
4318 | write_reg16(info, TRB, *((u16 *)TwoBytes)); | ||
4319 | |||
4320 | info->tx_count -= 2; | ||
4321 | info->icount.tx += 2; | ||
4322 | } else { | ||
4323 | /* only 1 byte left to transmit or 1 FIFO slot left */ | ||
4324 | |||
4325 | if (info->x_char) { | ||
4326 | /* transmit pending high priority char */ | ||
4327 | write_reg(info, TRB, info->x_char); | ||
4328 | info->x_char = 0; | ||
4329 | } else { | ||
4330 | write_reg(info, TRB, info->tx_buf[info->tx_get++]); | ||
4331 | if (info->tx_get >= info->max_frame_size) | ||
4332 | info->tx_get -= info->max_frame_size; | ||
4333 | info->tx_count--; | ||
4334 | } | ||
4335 | info->icount.tx++; | ||
4336 | } | ||
4337 | } | ||
4338 | } | ||
4339 | |||
4340 | /* Reset a port to a known state | ||
4341 | */ | ||
4342 | static void reset_port(SLMP_INFO *info) | ||
4343 | { | ||
4344 | if (info->sca_base) { | ||
4345 | |||
4346 | tx_stop(info); | ||
4347 | rx_stop(info); | ||
4348 | |||
4349 | info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); | ||
4350 | set_signals(info); | ||
4351 | |||
4352 | /* disable all port interrupts */ | ||
4353 | info->ie0_value = 0; | ||
4354 | info->ie1_value = 0; | ||
4355 | info->ie2_value = 0; | ||
4356 | write_reg(info, IE0, info->ie0_value); | ||
4357 | write_reg(info, IE1, info->ie1_value); | ||
4358 | write_reg(info, IE2, info->ie2_value); | ||
4359 | |||
4360 | write_reg(info, CMD, CHRESET); | ||
4361 | } | ||
4362 | } | ||
4363 | |||
4364 | /* Reset all the ports to a known state. | ||
4365 | */ | ||
4366 | static void reset_adapter(SLMP_INFO *info) | ||
4367 | { | ||
4368 | int i; | ||
4369 | |||
4370 | for ( i=0; i < SCA_MAX_PORTS; ++i) { | ||
4371 | if (info->port_array[i]) | ||
4372 | reset_port(info->port_array[i]); | ||
4373 | } | ||
4374 | } | ||
4375 | |||
4376 | /* Program port for asynchronous communications. | ||
4377 | */ | ||
4378 | static void async_mode(SLMP_INFO *info) | ||
4379 | { | ||
4380 | |||
4381 | unsigned char RegValue; | ||
4382 | |||
4383 | tx_stop(info); | ||
4384 | rx_stop(info); | ||
4385 | |||
4386 | /* MD0, Mode Register 0 | ||
4387 | * | ||
4388 | * 07..05 PRCTL<2..0>, Protocol Mode, 000=async | ||
4389 | * 04 AUTO, Auto-enable (RTS/CTS/DCD) | ||
4390 | * 03 Reserved, must be 0 | ||
4391 | * 02 CRCCC, CRC Calculation, 0=disabled | ||
4392 | * 01..00 STOP<1..0> Stop bits (00=1,10=2) | ||
4393 | * | ||
4394 | * 0000 0000 | ||
4395 | */ | ||
4396 | RegValue = 0x00; | ||
4397 | if (info->params.stop_bits != 1) | ||
4398 | RegValue |= BIT1; | ||
4399 | write_reg(info, MD0, RegValue); | ||
4400 | |||
4401 | /* MD1, Mode Register 1 | ||
4402 | * | ||
4403 | * 07..06 BRATE<1..0>, bit rate, 00=1/1 01=1/16 10=1/32 11=1/64 | ||
4404 | * 05..04 TXCHR<1..0>, tx char size, 00=8 bits,01=7,10=6,11=5 | ||
4405 | * 03..02 RXCHR<1..0>, rx char size | ||
4406 | * 01..00 PMPM<1..0>, Parity mode, 00=none 10=even 11=odd | ||
4407 | * | ||
4408 | * 0100 0000 | ||
4409 | */ | ||
4410 | RegValue = 0x40; | ||
4411 | switch (info->params.data_bits) { | ||
4412 | case 7: RegValue |= BIT4 + BIT2; break; | ||
4413 | case 6: RegValue |= BIT5 + BIT3; break; | ||
4414 | case 5: RegValue |= BIT5 + BIT4 + BIT3 + BIT2; break; | ||
4415 | } | ||
4416 | if (info->params.parity != ASYNC_PARITY_NONE) { | ||
4417 | RegValue |= BIT1; | ||
4418 | if (info->params.parity == ASYNC_PARITY_ODD) | ||
4419 | RegValue |= BIT0; | ||
4420 | } | ||
4421 | write_reg(info, MD1, RegValue); | ||
4422 | |||
4423 | /* MD2, Mode Register 2 | ||
4424 | * | ||
4425 | * 07..02 Reserved, must be 0 | ||
4426 | * 01..00 CNCT<1..0> Channel connection, 00=normal 11=local loopback | ||
4427 | * | ||
4428 | * 0000 0000 | ||
4429 | */ | ||
4430 | RegValue = 0x00; | ||
4431 | if (info->params.loopback) | ||
4432 | RegValue |= (BIT1 + BIT0); | ||
4433 | write_reg(info, MD2, RegValue); | ||
4434 | |||
4435 | /* RXS, Receive clock source | ||
4436 | * | ||
4437 | * 07 Reserved, must be 0 | ||
4438 | * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL | ||
4439 | * 03..00 RXBR<3..0>, rate divisor, 0000=1 | ||
4440 | */ | ||
4441 | RegValue=BIT6; | ||
4442 | write_reg(info, RXS, RegValue); | ||
4443 | |||
4444 | /* TXS, Transmit clock source | ||
4445 | * | ||
4446 | * 07 Reserved, must be 0 | ||
4447 | * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock | ||
4448 | * 03..00 RXBR<3..0>, rate divisor, 0000=1 | ||
4449 | */ | ||
4450 | RegValue=BIT6; | ||
4451 | write_reg(info, TXS, RegValue); | ||
4452 | |||
4453 | /* Control Register | ||
4454 | * | ||
4455 | * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out | ||
4456 | */ | ||
4457 | info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); | ||
4458 | write_control_reg(info); | ||
4459 | |||
4460 | tx_set_idle(info); | ||
4461 | |||
4462 | /* RRC Receive Ready Control 0 | ||
4463 | * | ||
4464 | * 07..05 Reserved, must be 0 | ||
4465 | * 04..00 RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte | ||
4466 | */ | ||
4467 | write_reg(info, RRC, 0x00); | ||
4468 | |||
4469 | /* TRC0 Transmit Ready Control 0 | ||
4470 | * | ||
4471 | * 07..05 Reserved, must be 0 | ||
4472 | * 04..00 TRC<4..0> Tx FIFO trigger active 0x10 = 16 bytes | ||
4473 | */ | ||
4474 | write_reg(info, TRC0, 0x10); | ||
4475 | |||
4476 | /* TRC1 Transmit Ready Control 1 | ||
4477 | * | ||
4478 | * 07..05 Reserved, must be 0 | ||
4479 | * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1e = 31 bytes (full-1) | ||
4480 | */ | ||
4481 | write_reg(info, TRC1, 0x1e); | ||
4482 | |||
4483 | /* CTL, MSCI control register | ||
4484 | * | ||
4485 | * 07..06 Reserved, set to 0 | ||
4486 | * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) | ||
4487 | * 04 IDLC, idle control, 0=mark 1=idle register | ||
4488 | * 03 BRK, break, 0=off 1 =on (async) | ||
4489 | * 02 SYNCLD, sync char load enable (BSC) 1=enabled | ||
4490 | * 01 GOP, go active on poll (LOOP mode) 1=enabled | ||
4491 | * 00 RTS, RTS output control, 0=active 1=inactive | ||
4492 | * | ||
4493 | * 0001 0001 | ||
4494 | */ | ||
4495 | RegValue = 0x10; | ||
4496 | if (!(info->serial_signals & SerialSignal_RTS)) | ||
4497 | RegValue |= 0x01; | ||
4498 | write_reg(info, CTL, RegValue); | ||
4499 | |||
4500 | /* enable status interrupts */ | ||
4501 | info->ie0_value |= TXINTE + RXINTE; | ||
4502 | write_reg(info, IE0, info->ie0_value); | ||
4503 | |||
4504 | /* enable break detect interrupt */ | ||
4505 | info->ie1_value = BRKD; | ||
4506 | write_reg(info, IE1, info->ie1_value); | ||
4507 | |||
4508 | /* enable rx overrun interrupt */ | ||
4509 | info->ie2_value = OVRN; | ||
4510 | write_reg(info, IE2, info->ie2_value); | ||
4511 | |||
4512 | set_rate( info, info->params.data_rate * 16 ); | ||
4513 | } | ||
4514 | |||
4515 | /* Program the SCA for HDLC communications. | ||
4516 | */ | ||
4517 | static void hdlc_mode(SLMP_INFO *info) | ||
4518 | { | ||
4519 | unsigned char RegValue; | ||
4520 | u32 DpllDivisor; | ||
4521 | |||
4522 | // Can't use DPLL because SCA outputs recovered clock on RxC when | ||
4523 | // DPLL mode selected. This causes output contention with RxC receiver. | ||
4524 | // Use of DPLL would require external hardware to disable RxC receiver | ||
4525 | // when DPLL mode selected. | ||
4526 | info->params.flags &= ~(HDLC_FLAG_TXC_DPLL + HDLC_FLAG_RXC_DPLL); | ||
4527 | |||
4528 | /* disable DMA interrupts */ | ||
4529 | write_reg(info, TXDMA + DIR, 0); | ||
4530 | write_reg(info, RXDMA + DIR, 0); | ||
4531 | |||
4532 | /* MD0, Mode Register 0 | ||
4533 | * | ||
4534 | * 07..05 PRCTL<2..0>, Protocol Mode, 100=HDLC | ||
4535 | * 04 AUTO, Auto-enable (RTS/CTS/DCD) | ||
4536 | * 03 Reserved, must be 0 | ||
4537 | * 02 CRCCC, CRC Calculation, 1=enabled | ||
4538 | * 01 CRC1, CRC selection, 0=CRC-16,1=CRC-CCITT-16 | ||
4539 | * 00 CRC0, CRC initial value, 1 = all 1s | ||
4540 | * | ||
4541 | * 1000 0001 | ||
4542 | */ | ||
4543 | RegValue = 0x81; | ||
4544 | if (info->params.flags & HDLC_FLAG_AUTO_CTS) | ||
4545 | RegValue |= BIT4; | ||
4546 | if (info->params.flags & HDLC_FLAG_AUTO_DCD) | ||
4547 | RegValue |= BIT4; | ||
4548 | if (info->params.crc_type == HDLC_CRC_16_CCITT) | ||
4549 | RegValue |= BIT2 + BIT1; | ||
4550 | write_reg(info, MD0, RegValue); | ||
4551 | |||
4552 | /* MD1, Mode Register 1 | ||
4553 | * | ||
4554 | * 07..06 ADDRS<1..0>, Address detect, 00=no addr check | ||
4555 | * 05..04 TXCHR<1..0>, tx char size, 00=8 bits | ||
4556 | * 03..02 RXCHR<1..0>, rx char size, 00=8 bits | ||
4557 | * 01..00 PMPM<1..0>, Parity mode, 00=no parity | ||
4558 | * | ||
4559 | * 0000 0000 | ||
4560 | */ | ||
4561 | RegValue = 0x00; | ||
4562 | write_reg(info, MD1, RegValue); | ||
4563 | |||
4564 | /* MD2, Mode Register 2 | ||
4565 | * | ||
4566 | * 07 NRZFM, 0=NRZ, 1=FM | ||
4567 | * 06..05 CODE<1..0> Encoding, 00=NRZ | ||
4568 | * 04..03 DRATE<1..0> DPLL Divisor, 00=8 | ||
4569 | * 02 Reserved, must be 0 | ||
4570 | * 01..00 CNCT<1..0> Channel connection, 0=normal | ||
4571 | * | ||
4572 | * 0000 0000 | ||
4573 | */ | ||
4574 | RegValue = 0x00; | ||
4575 | switch(info->params.encoding) { | ||
4576 | case HDLC_ENCODING_NRZI: RegValue |= BIT5; break; | ||
4577 | case HDLC_ENCODING_BIPHASE_MARK: RegValue |= BIT7 + BIT5; break; /* aka FM1 */ | ||
4578 | case HDLC_ENCODING_BIPHASE_SPACE: RegValue |= BIT7 + BIT6; break; /* aka FM0 */ | ||
4579 | case HDLC_ENCODING_BIPHASE_LEVEL: RegValue |= BIT7; break; /* aka Manchester */ | ||
4580 | #if 0 | ||
4581 | case HDLC_ENCODING_NRZB: /* not supported */ | ||
4582 | case HDLC_ENCODING_NRZI_MARK: /* not supported */ | ||
4583 | case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: /* not supported */ | ||
4584 | #endif | ||
4585 | } | ||
4586 | if ( info->params.flags & HDLC_FLAG_DPLL_DIV16 ) { | ||
4587 | DpllDivisor = 16; | ||
4588 | RegValue |= BIT3; | ||
4589 | } else if ( info->params.flags & HDLC_FLAG_DPLL_DIV8 ) { | ||
4590 | DpllDivisor = 8; | ||
4591 | } else { | ||
4592 | DpllDivisor = 32; | ||
4593 | RegValue |= BIT4; | ||
4594 | } | ||
4595 | write_reg(info, MD2, RegValue); | ||
4596 | |||
4597 | |||
4598 | /* RXS, Receive clock source | ||
4599 | * | ||
4600 | * 07 Reserved, must be 0 | ||
4601 | * 06..04 RXCS<2..0>, clock source, 000=RxC Pin, 100=BRG, 110=DPLL | ||
4602 | * 03..00 RXBR<3..0>, rate divisor, 0000=1 | ||
4603 | */ | ||
4604 | RegValue=0; | ||
4605 | if (info->params.flags & HDLC_FLAG_RXC_BRG) | ||
4606 | RegValue |= BIT6; | ||
4607 | if (info->params.flags & HDLC_FLAG_RXC_DPLL) | ||
4608 | RegValue |= BIT6 + BIT5; | ||
4609 | write_reg(info, RXS, RegValue); | ||
4610 | |||
4611 | /* TXS, Transmit clock source | ||
4612 | * | ||
4613 | * 07 Reserved, must be 0 | ||
4614 | * 06..04 RXCS<2..0>, clock source, 000=TxC Pin, 100=BRG, 110=Receive Clock | ||
4615 | * 03..00 RXBR<3..0>, rate divisor, 0000=1 | ||
4616 | */ | ||
4617 | RegValue=0; | ||
4618 | if (info->params.flags & HDLC_FLAG_TXC_BRG) | ||
4619 | RegValue |= BIT6; | ||
4620 | if (info->params.flags & HDLC_FLAG_TXC_DPLL) | ||
4621 | RegValue |= BIT6 + BIT5; | ||
4622 | write_reg(info, TXS, RegValue); | ||
4623 | |||
4624 | if (info->params.flags & HDLC_FLAG_RXC_DPLL) | ||
4625 | set_rate(info, info->params.clock_speed * DpllDivisor); | ||
4626 | else | ||
4627 | set_rate(info, info->params.clock_speed); | ||
4628 | |||
4629 | /* GPDATA (General Purpose I/O Data Register) | ||
4630 | * | ||
4631 | * 6,4,2,0 CLKSEL<3..0>, 0 = TcCLK in, 1 = Auxclk out | ||
4632 | */ | ||
4633 | if (info->params.flags & HDLC_FLAG_TXC_BRG) | ||
4634 | info->port_array[0]->ctrlreg_value |= (BIT0 << (info->port_num * 2)); | ||
4635 | else | ||
4636 | info->port_array[0]->ctrlreg_value &= ~(BIT0 << (info->port_num * 2)); | ||
4637 | write_control_reg(info); | ||
4638 | |||
4639 | /* RRC Receive Ready Control 0 | ||
4640 | * | ||
4641 | * 07..05 Reserved, must be 0 | ||
4642 | * 04..00 RRC<4..0> Rx FIFO trigger active | ||
4643 | */ | ||
4644 | write_reg(info, RRC, rx_active_fifo_level); | ||
4645 | |||
4646 | /* TRC0 Transmit Ready Control 0 | ||
4647 | * | ||
4648 | * 07..05 Reserved, must be 0 | ||
4649 | * 04..00 TRC<4..0> Tx FIFO trigger active | ||
4650 | */ | ||
4651 | write_reg(info, TRC0, tx_active_fifo_level); | ||
4652 | |||
4653 | /* TRC1 Transmit Ready Control 1 | ||
4654 | * | ||
4655 | * 07..05 Reserved, must be 0 | ||
4656 | * 04..00 TRC<4..0> Tx FIFO trigger inactive 0x1f = 32 bytes (full) | ||
4657 | */ | ||
4658 | write_reg(info, TRC1, (unsigned char)(tx_negate_fifo_level - 1)); | ||
4659 | |||
4660 | /* DMR, DMA Mode Register | ||
4661 | * | ||
4662 | * 07..05 Reserved, must be 0 | ||
4663 | * 04 TMOD, Transfer Mode: 1=chained-block | ||
4664 | * 03 Reserved, must be 0 | ||
4665 | * 02 NF, Number of Frames: 1=multi-frame | ||
4666 | * 01 CNTE, Frame End IRQ Counter enable: 0=disabled | ||
4667 | * 00 Reserved, must be 0 | ||
4668 | * | ||
4669 | * 0001 0100 | ||
4670 | */ | ||
4671 | write_reg(info, TXDMA + DMR, 0x14); | ||
4672 | write_reg(info, RXDMA + DMR, 0x14); | ||
4673 | |||
4674 | /* Set chain pointer base (upper 8 bits of 24 bit addr) */ | ||
4675 | write_reg(info, RXDMA + CPB, | ||
4676 | (unsigned char)(info->buffer_list_phys >> 16)); | ||
4677 | |||
4678 | /* Set chain pointer base (upper 8 bits of 24 bit addr) */ | ||
4679 | write_reg(info, TXDMA + CPB, | ||
4680 | (unsigned char)(info->buffer_list_phys >> 16)); | ||
4681 | |||
4682 | /* enable status interrupts. other code enables/disables | ||
4683 | * the individual sources for these two interrupt classes. | ||
4684 | */ | ||
4685 | info->ie0_value |= TXINTE + RXINTE; | ||
4686 | write_reg(info, IE0, info->ie0_value); | ||
4687 | |||
4688 | /* CTL, MSCI control register | ||
4689 | * | ||
4690 | * 07..06 Reserved, set to 0 | ||
4691 | * 05 UDRNC, underrun control, 0=abort 1=CRC+flag (HDLC/BSC) | ||
4692 | * 04 IDLC, idle control, 0=mark 1=idle register | ||
4693 | * 03 BRK, break, 0=off 1 =on (async) | ||
4694 | * 02 SYNCLD, sync char load enable (BSC) 1=enabled | ||
4695 | * 01 GOP, go active on poll (LOOP mode) 1=enabled | ||
4696 | * 00 RTS, RTS output control, 0=active 1=inactive | ||
4697 | * | ||
4698 | * 0001 0001 | ||
4699 | */ | ||
4700 | RegValue = 0x10; | ||
4701 | if (!(info->serial_signals & SerialSignal_RTS)) | ||
4702 | RegValue |= 0x01; | ||
4703 | write_reg(info, CTL, RegValue); | ||
4704 | |||
4705 | /* preamble not supported ! */ | ||
4706 | |||
4707 | tx_set_idle(info); | ||
4708 | tx_stop(info); | ||
4709 | rx_stop(info); | ||
4710 | |||
4711 | set_rate(info, info->params.clock_speed); | ||
4712 | |||
4713 | if (info->params.loopback) | ||
4714 | enable_loopback(info,1); | ||
4715 | } | ||
4716 | |||
4717 | /* Set the transmit HDLC idle mode | ||
4718 | */ | ||
4719 | static void tx_set_idle(SLMP_INFO *info) | ||
4720 | { | ||
4721 | unsigned char RegValue = 0xff; | ||
4722 | |||
4723 | /* Map API idle mode to SCA register bits */ | ||
4724 | switch(info->idle_mode) { | ||
4725 | case HDLC_TXIDLE_FLAGS: RegValue = 0x7e; break; | ||
4726 | case HDLC_TXIDLE_ALT_ZEROS_ONES: RegValue = 0xaa; break; | ||
4727 | case HDLC_TXIDLE_ZEROS: RegValue = 0x00; break; | ||
4728 | case HDLC_TXIDLE_ONES: RegValue = 0xff; break; | ||
4729 | case HDLC_TXIDLE_ALT_MARK_SPACE: RegValue = 0xaa; break; | ||
4730 | case HDLC_TXIDLE_SPACE: RegValue = 0x00; break; | ||
4731 | case HDLC_TXIDLE_MARK: RegValue = 0xff; break; | ||
4732 | } | ||
4733 | |||
4734 | write_reg(info, IDL, RegValue); | ||
4735 | } | ||
4736 | |||
4737 | /* Query the adapter for the state of the V24 status (input) signals. | ||
4738 | */ | ||
4739 | static void get_signals(SLMP_INFO *info) | ||
4740 | { | ||
4741 | u16 status = read_reg(info, SR3); | ||
4742 | u16 gpstatus = read_status_reg(info); | ||
4743 | u16 testbit; | ||
4744 | |||
4745 | /* clear all serial signals except DTR and RTS */ | ||
4746 | info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; | ||
4747 | |||
4748 | /* set serial signal bits to reflect MISR */ | ||
4749 | |||
4750 | if (!(status & BIT3)) | ||
4751 | info->serial_signals |= SerialSignal_CTS; | ||
4752 | |||
4753 | if ( !(status & BIT2)) | ||
4754 | info->serial_signals |= SerialSignal_DCD; | ||
4755 | |||
4756 | testbit = BIT1 << (info->port_num * 2); // Port 0..3 RI is GPDATA<1,3,5,7> | ||
4757 | if (!(gpstatus & testbit)) | ||
4758 | info->serial_signals |= SerialSignal_RI; | ||
4759 | |||
4760 | testbit = BIT0 << (info->port_num * 2); // Port 0..3 DSR is GPDATA<0,2,4,6> | ||
4761 | if (!(gpstatus & testbit)) | ||
4762 | info->serial_signals |= SerialSignal_DSR; | ||
4763 | } | ||
4764 | |||
4765 | /* Set the state of DTR and RTS based on contents of | ||
4766 | * serial_signals member of device context. | ||
4767 | */ | ||
4768 | static void set_signals(SLMP_INFO *info) | ||
4769 | { | ||
4770 | unsigned char RegValue; | ||
4771 | u16 EnableBit; | ||
4772 | |||
4773 | RegValue = read_reg(info, CTL); | ||
4774 | if (info->serial_signals & SerialSignal_RTS) | ||
4775 | RegValue &= ~BIT0; | ||
4776 | else | ||
4777 | RegValue |= BIT0; | ||
4778 | write_reg(info, CTL, RegValue); | ||
4779 | |||
4780 | // Port 0..3 DTR is ctrl reg <1,3,5,7> | ||
4781 | EnableBit = BIT1 << (info->port_num*2); | ||
4782 | if (info->serial_signals & SerialSignal_DTR) | ||
4783 | info->port_array[0]->ctrlreg_value &= ~EnableBit; | ||
4784 | else | ||
4785 | info->port_array[0]->ctrlreg_value |= EnableBit; | ||
4786 | write_control_reg(info); | ||
4787 | } | ||
4788 | |||
4789 | /*******************/ | ||
4790 | /* DMA Buffer Code */ | ||
4791 | /*******************/ | ||
4792 | |||
4793 | /* Set the count for all receive buffers to SCABUFSIZE | ||
4794 | * and set the current buffer to the first buffer. This effectively | ||
4795 | * makes all buffers free and discards any data in buffers. | ||
4796 | */ | ||
4797 | static void rx_reset_buffers(SLMP_INFO *info) | ||
4798 | { | ||
4799 | rx_free_frame_buffers(info, 0, info->rx_buf_count - 1); | ||
4800 | } | ||
4801 | |||
4802 | /* Free the buffers used by a received frame | ||
4803 | * | ||
4804 | * info pointer to device instance data | ||
4805 | * first index of 1st receive buffer of frame | ||
4806 | * last index of last receive buffer of frame | ||
4807 | */ | ||
4808 | static void rx_free_frame_buffers(SLMP_INFO *info, unsigned int first, unsigned int last) | ||
4809 | { | ||
4810 | bool done = false; | ||
4811 | |||
4812 | while(!done) { | ||
4813 | /* reset current buffer for reuse */ | ||
4814 | info->rx_buf_list[first].status = 0xff; | ||
4815 | |||
4816 | if (first == last) { | ||
4817 | done = true; | ||
4818 | /* set new last rx descriptor address */ | ||
4819 | write_reg16(info, RXDMA + EDA, info->rx_buf_list_ex[first].phys_entry); | ||
4820 | } | ||
4821 | |||
4822 | first++; | ||
4823 | if (first == info->rx_buf_count) | ||
4824 | first = 0; | ||
4825 | } | ||
4826 | |||
4827 | /* set current buffer to next buffer after last buffer of frame */ | ||
4828 | info->current_rx_buf = first; | ||
4829 | } | ||
4830 | |||
4831 | /* Return a received frame from the receive DMA buffers. | ||
4832 | * Only frames received without errors are returned. | ||
4833 | * | ||
4834 | * Return Value: true if frame returned, otherwise false | ||
4835 | */ | ||
4836 | static bool rx_get_frame(SLMP_INFO *info) | ||
4837 | { | ||
4838 | unsigned int StartIndex, EndIndex; /* index of 1st and last buffers of Rx frame */ | ||
4839 | unsigned short status; | ||
4840 | unsigned int framesize = 0; | ||
4841 | bool ReturnCode = false; | ||
4842 | unsigned long flags; | ||
4843 | struct tty_struct *tty = info->port.tty; | ||
4844 | unsigned char addr_field = 0xff; | ||
4845 | SCADESC *desc; | ||
4846 | SCADESC_EX *desc_ex; | ||
4847 | |||
4848 | CheckAgain: | ||
4849 | /* assume no frame returned, set zero length */ | ||
4850 | framesize = 0; | ||
4851 | addr_field = 0xff; | ||
4852 | |||
4853 | /* | ||
4854 | * current_rx_buf points to the 1st buffer of the next available | ||
4855 | * receive frame. To find the last buffer of the frame look for | ||
4856 | * a non-zero status field in the buffer entries. (The status | ||
4857 | * field is set by the 16C32 after completing a receive frame. | ||
4858 | */ | ||
4859 | StartIndex = EndIndex = info->current_rx_buf; | ||
4860 | |||
4861 | for ( ;; ) { | ||
4862 | desc = &info->rx_buf_list[EndIndex]; | ||
4863 | desc_ex = &info->rx_buf_list_ex[EndIndex]; | ||
4864 | |||
4865 | if (desc->status == 0xff) | ||
4866 | goto Cleanup; /* current desc still in use, no frames available */ | ||
4867 | |||
4868 | if (framesize == 0 && info->params.addr_filter != 0xff) | ||
4869 | addr_field = desc_ex->virt_addr[0]; | ||
4870 | |||
4871 | framesize += desc->length; | ||
4872 | |||
4873 | /* Status != 0 means last buffer of frame */ | ||
4874 | if (desc->status) | ||
4875 | break; | ||
4876 | |||
4877 | EndIndex++; | ||
4878 | if (EndIndex == info->rx_buf_count) | ||
4879 | EndIndex = 0; | ||
4880 | |||
4881 | if (EndIndex == info->current_rx_buf) { | ||
4882 | /* all buffers have been 'used' but none mark */ | ||
4883 | /* the end of a frame. Reset buffers and receiver. */ | ||
4884 | if ( info->rx_enabled ){ | ||
4885 | spin_lock_irqsave(&info->lock,flags); | ||
4886 | rx_start(info); | ||
4887 | spin_unlock_irqrestore(&info->lock,flags); | ||
4888 | } | ||
4889 | goto Cleanup; | ||
4890 | } | ||
4891 | |||
4892 | } | ||
4893 | |||
4894 | /* check status of receive frame */ | ||
4895 | |||
4896 | /* frame status is byte stored after frame data | ||
4897 | * | ||
4898 | * 7 EOM (end of msg), 1 = last buffer of frame | ||
4899 | * 6 Short Frame, 1 = short frame | ||
4900 | * 5 Abort, 1 = frame aborted | ||
4901 | * 4 Residue, 1 = last byte is partial | ||
4902 | * 3 Overrun, 1 = overrun occurred during frame reception | ||
4903 | * 2 CRC, 1 = CRC error detected | ||
4904 | * | ||
4905 | */ | ||
4906 | status = desc->status; | ||
4907 | |||
4908 | /* ignore CRC bit if not using CRC (bit is undefined) */ | ||
4909 | /* Note:CRC is not save to data buffer */ | ||
4910 | if (info->params.crc_type == HDLC_CRC_NONE) | ||
4911 | status &= ~BIT2; | ||
4912 | |||
4913 | if (framesize == 0 || | ||
4914 | (addr_field != 0xff && addr_field != info->params.addr_filter)) { | ||
4915 | /* discard 0 byte frames, this seems to occur sometime | ||
4916 | * when remote is idling flags. | ||
4917 | */ | ||
4918 | rx_free_frame_buffers(info, StartIndex, EndIndex); | ||
4919 | goto CheckAgain; | ||
4920 | } | ||
4921 | |||
4922 | if (framesize < 2) | ||
4923 | status |= BIT6; | ||
4924 | |||
4925 | if (status & (BIT6+BIT5+BIT3+BIT2)) { | ||
4926 | /* received frame has errors, | ||
4927 | * update counts and mark frame size as 0 | ||
4928 | */ | ||
4929 | if (status & BIT6) | ||
4930 | info->icount.rxshort++; | ||
4931 | else if (status & BIT5) | ||
4932 | info->icount.rxabort++; | ||
4933 | else if (status & BIT3) | ||
4934 | info->icount.rxover++; | ||
4935 | else | ||
4936 | info->icount.rxcrc++; | ||
4937 | |||
4938 | framesize = 0; | ||
4939 | #if SYNCLINK_GENERIC_HDLC | ||
4940 | { | ||
4941 | info->netdev->stats.rx_errors++; | ||
4942 | info->netdev->stats.rx_frame_errors++; | ||
4943 | } | ||
4944 | #endif | ||
4945 | } | ||
4946 | |||
4947 | if ( debug_level >= DEBUG_LEVEL_BH ) | ||
4948 | printk("%s(%d):%s rx_get_frame() status=%04X size=%d\n", | ||
4949 | __FILE__,__LINE__,info->device_name,status,framesize); | ||
4950 | |||
4951 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
4952 | trace_block(info,info->rx_buf_list_ex[StartIndex].virt_addr, | ||
4953 | min_t(int, framesize,SCABUFSIZE),0); | ||
4954 | |||
4955 | if (framesize) { | ||
4956 | if (framesize > info->max_frame_size) | ||
4957 | info->icount.rxlong++; | ||
4958 | else { | ||
4959 | /* copy dma buffer(s) to contiguous intermediate buffer */ | ||
4960 | int copy_count = framesize; | ||
4961 | int index = StartIndex; | ||
4962 | unsigned char *ptmp = info->tmp_rx_buf; | ||
4963 | info->tmp_rx_buf_count = framesize; | ||
4964 | |||
4965 | info->icount.rxok++; | ||
4966 | |||
4967 | while(copy_count) { | ||
4968 | int partial_count = min(copy_count,SCABUFSIZE); | ||
4969 | memcpy( ptmp, | ||
4970 | info->rx_buf_list_ex[index].virt_addr, | ||
4971 | partial_count ); | ||
4972 | ptmp += partial_count; | ||
4973 | copy_count -= partial_count; | ||
4974 | |||
4975 | if ( ++index == info->rx_buf_count ) | ||
4976 | index = 0; | ||
4977 | } | ||
4978 | |||
4979 | #if SYNCLINK_GENERIC_HDLC | ||
4980 | if (info->netcount) | ||
4981 | hdlcdev_rx(info,info->tmp_rx_buf,framesize); | ||
4982 | else | ||
4983 | #endif | ||
4984 | ldisc_receive_buf(tty,info->tmp_rx_buf, | ||
4985 | info->flag_buf, framesize); | ||
4986 | } | ||
4987 | } | ||
4988 | /* Free the buffers used by this frame. */ | ||
4989 | rx_free_frame_buffers( info, StartIndex, EndIndex ); | ||
4990 | |||
4991 | ReturnCode = true; | ||
4992 | |||
4993 | Cleanup: | ||
4994 | if ( info->rx_enabled && info->rx_overflow ) { | ||
4995 | /* Receiver is enabled, but needs to restarted due to | ||
4996 | * rx buffer overflow. If buffers are empty, restart receiver. | ||
4997 | */ | ||
4998 | if (info->rx_buf_list[EndIndex].status == 0xff) { | ||
4999 | spin_lock_irqsave(&info->lock,flags); | ||
5000 | rx_start(info); | ||
5001 | spin_unlock_irqrestore(&info->lock,flags); | ||
5002 | } | ||
5003 | } | ||
5004 | |||
5005 | return ReturnCode; | ||
5006 | } | ||
5007 | |||
5008 | /* load the transmit DMA buffer with data | ||
5009 | */ | ||
5010 | static void tx_load_dma_buffer(SLMP_INFO *info, const char *buf, unsigned int count) | ||
5011 | { | ||
5012 | unsigned short copy_count; | ||
5013 | unsigned int i = 0; | ||
5014 | SCADESC *desc; | ||
5015 | SCADESC_EX *desc_ex; | ||
5016 | |||
5017 | if ( debug_level >= DEBUG_LEVEL_DATA ) | ||
5018 | trace_block(info,buf, min_t(int, count,SCABUFSIZE), 1); | ||
5019 | |||
5020 | /* Copy source buffer to one or more DMA buffers, starting with | ||
5021 | * the first transmit dma buffer. | ||
5022 | */ | ||
5023 | for(i=0;;) | ||
5024 | { | ||
5025 | copy_count = min_t(unsigned short,count,SCABUFSIZE); | ||
5026 | |||
5027 | desc = &info->tx_buf_list[i]; | ||
5028 | desc_ex = &info->tx_buf_list_ex[i]; | ||
5029 | |||
5030 | load_pci_memory(info, desc_ex->virt_addr,buf,copy_count); | ||
5031 | |||
5032 | desc->length = copy_count; | ||
5033 | desc->status = 0; | ||
5034 | |||
5035 | buf += copy_count; | ||
5036 | count -= copy_count; | ||
5037 | |||
5038 | if (!count) | ||
5039 | break; | ||
5040 | |||
5041 | i++; | ||
5042 | if (i >= info->tx_buf_count) | ||
5043 | i = 0; | ||
5044 | } | ||
5045 | |||
5046 | info->tx_buf_list[i].status = 0x81; /* set EOM and EOT status */ | ||
5047 | info->last_tx_buf = ++i; | ||
5048 | } | ||
5049 | |||
5050 | static bool register_test(SLMP_INFO *info) | ||
5051 | { | ||
5052 | static unsigned char testval[] = {0x00, 0xff, 0xaa, 0x55, 0x69, 0x96}; | ||
5053 | static unsigned int count = ARRAY_SIZE(testval); | ||
5054 | unsigned int i; | ||
5055 | bool rc = true; | ||
5056 | unsigned long flags; | ||
5057 | |||
5058 | spin_lock_irqsave(&info->lock,flags); | ||
5059 | reset_port(info); | ||
5060 | |||
5061 | /* assume failure */ | ||
5062 | info->init_error = DiagStatus_AddressFailure; | ||
5063 | |||
5064 | /* Write bit patterns to various registers but do it out of */ | ||
5065 | /* sync, then read back and verify values. */ | ||
5066 | |||
5067 | for (i = 0 ; i < count ; i++) { | ||
5068 | write_reg(info, TMC, testval[i]); | ||
5069 | write_reg(info, IDL, testval[(i+1)%count]); | ||
5070 | write_reg(info, SA0, testval[(i+2)%count]); | ||
5071 | write_reg(info, SA1, testval[(i+3)%count]); | ||
5072 | |||
5073 | if ( (read_reg(info, TMC) != testval[i]) || | ||
5074 | (read_reg(info, IDL) != testval[(i+1)%count]) || | ||
5075 | (read_reg(info, SA0) != testval[(i+2)%count]) || | ||
5076 | (read_reg(info, SA1) != testval[(i+3)%count]) ) | ||
5077 | { | ||
5078 | rc = false; | ||
5079 | break; | ||
5080 | } | ||
5081 | } | ||
5082 | |||
5083 | reset_port(info); | ||
5084 | spin_unlock_irqrestore(&info->lock,flags); | ||
5085 | |||
5086 | return rc; | ||
5087 | } | ||
5088 | |||
5089 | static bool irq_test(SLMP_INFO *info) | ||
5090 | { | ||
5091 | unsigned long timeout; | ||
5092 | unsigned long flags; | ||
5093 | |||
5094 | unsigned char timer = (info->port_num & 1) ? TIMER2 : TIMER0; | ||
5095 | |||
5096 | spin_lock_irqsave(&info->lock,flags); | ||
5097 | reset_port(info); | ||
5098 | |||
5099 | /* assume failure */ | ||
5100 | info->init_error = DiagStatus_IrqFailure; | ||
5101 | info->irq_occurred = false; | ||
5102 | |||
5103 | /* setup timer0 on SCA0 to interrupt */ | ||
5104 | |||
5105 | /* IER2<7..4> = timer<3..0> interrupt enables (1=enabled) */ | ||
5106 | write_reg(info, IER2, (unsigned char)((info->port_num & 1) ? BIT6 : BIT4)); | ||
5107 | |||
5108 | write_reg(info, (unsigned char)(timer + TEPR), 0); /* timer expand prescale */ | ||
5109 | write_reg16(info, (unsigned char)(timer + TCONR), 1); /* timer constant */ | ||
5110 | |||
5111 | |||
5112 | /* TMCS, Timer Control/Status Register | ||
5113 | * | ||
5114 | * 07 CMF, Compare match flag (read only) 1=match | ||
5115 | * 06 ECMI, CMF Interrupt Enable: 1=enabled | ||
5116 | * 05 Reserved, must be 0 | ||
5117 | * 04 TME, Timer Enable | ||
5118 | * 03..00 Reserved, must be 0 | ||
5119 | * | ||
5120 | * 0101 0000 | ||
5121 | */ | ||
5122 | write_reg(info, (unsigned char)(timer + TMCS), 0x50); | ||
5123 | |||
5124 | spin_unlock_irqrestore(&info->lock,flags); | ||
5125 | |||
5126 | timeout=100; | ||
5127 | while( timeout-- && !info->irq_occurred ) { | ||
5128 | msleep_interruptible(10); | ||
5129 | } | ||
5130 | |||
5131 | spin_lock_irqsave(&info->lock,flags); | ||
5132 | reset_port(info); | ||
5133 | spin_unlock_irqrestore(&info->lock,flags); | ||
5134 | |||
5135 | return info->irq_occurred; | ||
5136 | } | ||
5137 | |||
5138 | /* initialize individual SCA device (2 ports) | ||
5139 | */ | ||
5140 | static bool sca_init(SLMP_INFO *info) | ||
5141 | { | ||
5142 | /* set wait controller to single mem partition (low), no wait states */ | ||
5143 | write_reg(info, PABR0, 0); /* wait controller addr boundary 0 */ | ||
5144 | write_reg(info, PABR1, 0); /* wait controller addr boundary 1 */ | ||
5145 | write_reg(info, WCRL, 0); /* wait controller low range */ | ||
5146 | write_reg(info, WCRM, 0); /* wait controller mid range */ | ||
5147 | write_reg(info, WCRH, 0); /* wait controller high range */ | ||
5148 | |||
5149 | /* DPCR, DMA Priority Control | ||
5150 | * | ||
5151 | * 07..05 Not used, must be 0 | ||
5152 | * 04 BRC, bus release condition: 0=all transfers complete | ||
5153 | * 03 CCC, channel change condition: 0=every cycle | ||
5154 | * 02..00 PR<2..0>, priority 100=round robin | ||
5155 | * | ||
5156 | * 00000100 = 0x04 | ||
5157 | */ | ||
5158 | write_reg(info, DPCR, dma_priority); | ||
5159 | |||
5160 | /* DMA Master Enable, BIT7: 1=enable all channels */ | ||
5161 | write_reg(info, DMER, 0x80); | ||
5162 | |||
5163 | /* enable all interrupt classes */ | ||
5164 | write_reg(info, IER0, 0xff); /* TxRDY,RxRDY,TxINT,RxINT (ports 0-1) */ | ||
5165 | write_reg(info, IER1, 0xff); /* DMIB,DMIA (channels 0-3) */ | ||
5166 | write_reg(info, IER2, 0xf0); /* TIRQ (timers 0-3) */ | ||
5167 | |||
5168 | /* ITCR, interrupt control register | ||
5169 | * 07 IPC, interrupt priority, 0=MSCI->DMA | ||
5170 | * 06..05 IAK<1..0>, Acknowledge cycle, 00=non-ack cycle | ||
5171 | * 04 VOS, Vector Output, 0=unmodified vector | ||
5172 | * 03..00 Reserved, must be 0 | ||
5173 | */ | ||
5174 | write_reg(info, ITCR, 0); | ||
5175 | |||
5176 | return true; | ||
5177 | } | ||
5178 | |||
5179 | /* initialize adapter hardware | ||
5180 | */ | ||
5181 | static bool init_adapter(SLMP_INFO *info) | ||
5182 | { | ||
5183 | int i; | ||
5184 | |||
5185 | /* Set BIT30 of Local Control Reg 0x50 to reset SCA */ | ||
5186 | volatile u32 *MiscCtrl = (u32 *)(info->lcr_base + 0x50); | ||
5187 | u32 readval; | ||
5188 | |||
5189 | info->misc_ctrl_value |= BIT30; | ||
5190 | *MiscCtrl = info->misc_ctrl_value; | ||
5191 | |||
5192 | /* | ||
5193 | * Force at least 170ns delay before clearing | ||
5194 | * reset bit. Each read from LCR takes at least | ||
5195 | * 30ns so 10 times for 300ns to be safe. | ||
5196 | */ | ||
5197 | for(i=0;i<10;i++) | ||
5198 | readval = *MiscCtrl; | ||
5199 | |||
5200 | info->misc_ctrl_value &= ~BIT30; | ||
5201 | *MiscCtrl = info->misc_ctrl_value; | ||
5202 | |||
5203 | /* init control reg (all DTRs off, all clksel=input) */ | ||
5204 | info->ctrlreg_value = 0xaa; | ||
5205 | write_control_reg(info); | ||
5206 | |||
5207 | { | ||
5208 | volatile u32 *LCR1BRDR = (u32 *)(info->lcr_base + 0x2c); | ||
5209 | lcr1_brdr_value &= ~(BIT5 + BIT4 + BIT3); | ||
5210 | |||
5211 | switch(read_ahead_count) | ||
5212 | { | ||
5213 | case 16: | ||
5214 | lcr1_brdr_value |= BIT5 + BIT4 + BIT3; | ||
5215 | break; | ||
5216 | case 8: | ||
5217 | lcr1_brdr_value |= BIT5 + BIT4; | ||
5218 | break; | ||
5219 | case 4: | ||
5220 | lcr1_brdr_value |= BIT5 + BIT3; | ||
5221 | break; | ||
5222 | case 0: | ||
5223 | lcr1_brdr_value |= BIT5; | ||
5224 | break; | ||
5225 | } | ||
5226 | |||
5227 | *LCR1BRDR = lcr1_brdr_value; | ||
5228 | *MiscCtrl = misc_ctrl_value; | ||
5229 | } | ||
5230 | |||
5231 | sca_init(info->port_array[0]); | ||
5232 | sca_init(info->port_array[2]); | ||
5233 | |||
5234 | return true; | ||
5235 | } | ||
5236 | |||
5237 | /* Loopback an HDLC frame to test the hardware | ||
5238 | * interrupt and DMA functions. | ||
5239 | */ | ||
5240 | static bool loopback_test(SLMP_INFO *info) | ||
5241 | { | ||
5242 | #define TESTFRAMESIZE 20 | ||
5243 | |||
5244 | unsigned long timeout; | ||
5245 | u16 count = TESTFRAMESIZE; | ||
5246 | unsigned char buf[TESTFRAMESIZE]; | ||
5247 | bool rc = false; | ||
5248 | unsigned long flags; | ||
5249 | |||
5250 | struct tty_struct *oldtty = info->port.tty; | ||
5251 | u32 speed = info->params.clock_speed; | ||
5252 | |||
5253 | info->params.clock_speed = 3686400; | ||
5254 | info->port.tty = NULL; | ||
5255 | |||
5256 | /* assume failure */ | ||
5257 | info->init_error = DiagStatus_DmaFailure; | ||
5258 | |||
5259 | /* build and send transmit frame */ | ||
5260 | for (count = 0; count < TESTFRAMESIZE;++count) | ||
5261 | buf[count] = (unsigned char)count; | ||
5262 | |||
5263 | memset(info->tmp_rx_buf,0,TESTFRAMESIZE); | ||
5264 | |||
5265 | /* program hardware for HDLC and enabled receiver */ | ||
5266 | spin_lock_irqsave(&info->lock,flags); | ||
5267 | hdlc_mode(info); | ||
5268 | enable_loopback(info,1); | ||
5269 | rx_start(info); | ||
5270 | info->tx_count = count; | ||
5271 | tx_load_dma_buffer(info,buf,count); | ||
5272 | tx_start(info); | ||
5273 | spin_unlock_irqrestore(&info->lock,flags); | ||
5274 | |||
5275 | /* wait for receive complete */ | ||
5276 | /* Set a timeout for waiting for interrupt. */ | ||
5277 | for ( timeout = 100; timeout; --timeout ) { | ||
5278 | msleep_interruptible(10); | ||
5279 | |||
5280 | if (rx_get_frame(info)) { | ||
5281 | rc = true; | ||
5282 | break; | ||
5283 | } | ||
5284 | } | ||
5285 | |||
5286 | /* verify received frame length and contents */ | ||
5287 | if (rc && | ||
5288 | ( info->tmp_rx_buf_count != count || | ||
5289 | memcmp(buf, info->tmp_rx_buf,count))) { | ||
5290 | rc = false; | ||
5291 | } | ||
5292 | |||
5293 | spin_lock_irqsave(&info->lock,flags); | ||
5294 | reset_adapter(info); | ||
5295 | spin_unlock_irqrestore(&info->lock,flags); | ||
5296 | |||
5297 | info->params.clock_speed = speed; | ||
5298 | info->port.tty = oldtty; | ||
5299 | |||
5300 | return rc; | ||
5301 | } | ||
5302 | |||
5303 | /* Perform diagnostics on hardware | ||
5304 | */ | ||
5305 | static int adapter_test( SLMP_INFO *info ) | ||
5306 | { | ||
5307 | unsigned long flags; | ||
5308 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
5309 | printk( "%s(%d):Testing device %s\n", | ||
5310 | __FILE__,__LINE__,info->device_name ); | ||
5311 | |||
5312 | spin_lock_irqsave(&info->lock,flags); | ||
5313 | init_adapter(info); | ||
5314 | spin_unlock_irqrestore(&info->lock,flags); | ||
5315 | |||
5316 | info->port_array[0]->port_count = 0; | ||
5317 | |||
5318 | if ( register_test(info->port_array[0]) && | ||
5319 | register_test(info->port_array[1])) { | ||
5320 | |||
5321 | info->port_array[0]->port_count = 2; | ||
5322 | |||
5323 | if ( register_test(info->port_array[2]) && | ||
5324 | register_test(info->port_array[3]) ) | ||
5325 | info->port_array[0]->port_count += 2; | ||
5326 | } | ||
5327 | else { | ||
5328 | printk( "%s(%d):Register test failure for device %s Addr=%08lX\n", | ||
5329 | __FILE__,__LINE__,info->device_name, (unsigned long)(info->phys_sca_base)); | ||
5330 | return -ENODEV; | ||
5331 | } | ||
5332 | |||
5333 | if ( !irq_test(info->port_array[0]) || | ||
5334 | !irq_test(info->port_array[1]) || | ||
5335 | (info->port_count == 4 && !irq_test(info->port_array[2])) || | ||
5336 | (info->port_count == 4 && !irq_test(info->port_array[3]))) { | ||
5337 | printk( "%s(%d):Interrupt test failure for device %s IRQ=%d\n", | ||
5338 | __FILE__,__LINE__,info->device_name, (unsigned short)(info->irq_level) ); | ||
5339 | return -ENODEV; | ||
5340 | } | ||
5341 | |||
5342 | if (!loopback_test(info->port_array[0]) || | ||
5343 | !loopback_test(info->port_array[1]) || | ||
5344 | (info->port_count == 4 && !loopback_test(info->port_array[2])) || | ||
5345 | (info->port_count == 4 && !loopback_test(info->port_array[3]))) { | ||
5346 | printk( "%s(%d):DMA test failure for device %s\n", | ||
5347 | __FILE__,__LINE__,info->device_name); | ||
5348 | return -ENODEV; | ||
5349 | } | ||
5350 | |||
5351 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
5352 | printk( "%s(%d):device %s passed diagnostics\n", | ||
5353 | __FILE__,__LINE__,info->device_name ); | ||
5354 | |||
5355 | info->port_array[0]->init_error = 0; | ||
5356 | info->port_array[1]->init_error = 0; | ||
5357 | if ( info->port_count > 2 ) { | ||
5358 | info->port_array[2]->init_error = 0; | ||
5359 | info->port_array[3]->init_error = 0; | ||
5360 | } | ||
5361 | |||
5362 | return 0; | ||
5363 | } | ||
5364 | |||
5365 | /* Test the shared memory on a PCI adapter. | ||
5366 | */ | ||
5367 | static bool memory_test(SLMP_INFO *info) | ||
5368 | { | ||
5369 | static unsigned long testval[] = { 0x0, 0x55555555, 0xaaaaaaaa, | ||
5370 | 0x66666666, 0x99999999, 0xffffffff, 0x12345678 }; | ||
5371 | unsigned long count = ARRAY_SIZE(testval); | ||
5372 | unsigned long i; | ||
5373 | unsigned long limit = SCA_MEM_SIZE/sizeof(unsigned long); | ||
5374 | unsigned long * addr = (unsigned long *)info->memory_base; | ||
5375 | |||
5376 | /* Test data lines with test pattern at one location. */ | ||
5377 | |||
5378 | for ( i = 0 ; i < count ; i++ ) { | ||
5379 | *addr = testval[i]; | ||
5380 | if ( *addr != testval[i] ) | ||
5381 | return false; | ||
5382 | } | ||
5383 | |||
5384 | /* Test address lines with incrementing pattern over */ | ||
5385 | /* entire address range. */ | ||
5386 | |||
5387 | for ( i = 0 ; i < limit ; i++ ) { | ||
5388 | *addr = i * 4; | ||
5389 | addr++; | ||
5390 | } | ||
5391 | |||
5392 | addr = (unsigned long *)info->memory_base; | ||
5393 | |||
5394 | for ( i = 0 ; i < limit ; i++ ) { | ||
5395 | if ( *addr != i * 4 ) | ||
5396 | return false; | ||
5397 | addr++; | ||
5398 | } | ||
5399 | |||
5400 | memset( info->memory_base, 0, SCA_MEM_SIZE ); | ||
5401 | return true; | ||
5402 | } | ||
5403 | |||
5404 | /* Load data into PCI adapter shared memory. | ||
5405 | * | ||
5406 | * The PCI9050 releases control of the local bus | ||
5407 | * after completing the current read or write operation. | ||
5408 | * | ||
5409 | * While the PCI9050 write FIFO not empty, the | ||
5410 | * PCI9050 treats all of the writes as a single transaction | ||
5411 | * and does not release the bus. This causes DMA latency problems | ||
5412 | * at high speeds when copying large data blocks to the shared memory. | ||
5413 | * | ||
5414 | * This function breaks a write into multiple transations by | ||
5415 | * interleaving a read which flushes the write FIFO and 'completes' | ||
5416 | * the write transation. This allows any pending DMA request to gain control | ||
5417 | * of the local bus in a timely fasion. | ||
5418 | */ | ||
5419 | static void load_pci_memory(SLMP_INFO *info, char* dest, const char* src, unsigned short count) | ||
5420 | { | ||
5421 | /* A load interval of 16 allows for 4 32-bit writes at */ | ||
5422 | /* 136ns each for a maximum latency of 542ns on the local bus.*/ | ||
5423 | |||
5424 | unsigned short interval = count / sca_pci_load_interval; | ||
5425 | unsigned short i; | ||
5426 | |||
5427 | for ( i = 0 ; i < interval ; i++ ) | ||
5428 | { | ||
5429 | memcpy(dest, src, sca_pci_load_interval); | ||
5430 | read_status_reg(info); | ||
5431 | dest += sca_pci_load_interval; | ||
5432 | src += sca_pci_load_interval; | ||
5433 | } | ||
5434 | |||
5435 | memcpy(dest, src, count % sca_pci_load_interval); | ||
5436 | } | ||
5437 | |||
5438 | static void trace_block(SLMP_INFO *info,const char* data, int count, int xmit) | ||
5439 | { | ||
5440 | int i; | ||
5441 | int linecount; | ||
5442 | if (xmit) | ||
5443 | printk("%s tx data:\n",info->device_name); | ||
5444 | else | ||
5445 | printk("%s rx data:\n",info->device_name); | ||
5446 | |||
5447 | while(count) { | ||
5448 | if (count > 16) | ||
5449 | linecount = 16; | ||
5450 | else | ||
5451 | linecount = count; | ||
5452 | |||
5453 | for(i=0;i<linecount;i++) | ||
5454 | printk("%02X ",(unsigned char)data[i]); | ||
5455 | for(;i<17;i++) | ||
5456 | printk(" "); | ||
5457 | for(i=0;i<linecount;i++) { | ||
5458 | if (data[i]>=040 && data[i]<=0176) | ||
5459 | printk("%c",data[i]); | ||
5460 | else | ||
5461 | printk("."); | ||
5462 | } | ||
5463 | printk("\n"); | ||
5464 | |||
5465 | data += linecount; | ||
5466 | count -= linecount; | ||
5467 | } | ||
5468 | } /* end of trace_block() */ | ||
5469 | |||
5470 | /* called when HDLC frame times out | ||
5471 | * update stats and do tx completion processing | ||
5472 | */ | ||
5473 | static void tx_timeout(unsigned long context) | ||
5474 | { | ||
5475 | SLMP_INFO *info = (SLMP_INFO*)context; | ||
5476 | unsigned long flags; | ||
5477 | |||
5478 | if ( debug_level >= DEBUG_LEVEL_INFO ) | ||
5479 | printk( "%s(%d):%s tx_timeout()\n", | ||
5480 | __FILE__,__LINE__,info->device_name); | ||
5481 | if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) { | ||
5482 | info->icount.txtimeout++; | ||
5483 | } | ||
5484 | spin_lock_irqsave(&info->lock,flags); | ||
5485 | info->tx_active = false; | ||
5486 | info->tx_count = info->tx_put = info->tx_get = 0; | ||
5487 | |||
5488 | spin_unlock_irqrestore(&info->lock,flags); | ||
5489 | |||
5490 | #if SYNCLINK_GENERIC_HDLC | ||
5491 | if (info->netcount) | ||
5492 | hdlcdev_tx_done(info); | ||
5493 | else | ||
5494 | #endif | ||
5495 | bh_transmit(info); | ||
5496 | } | ||
5497 | |||
5498 | /* called to periodically check the DSR/RI modem signal input status | ||
5499 | */ | ||
5500 | static void status_timeout(unsigned long context) | ||
5501 | { | ||
5502 | u16 status = 0; | ||
5503 | SLMP_INFO *info = (SLMP_INFO*)context; | ||
5504 | unsigned long flags; | ||
5505 | unsigned char delta; | ||
5506 | |||
5507 | |||
5508 | spin_lock_irqsave(&info->lock,flags); | ||
5509 | get_signals(info); | ||
5510 | spin_unlock_irqrestore(&info->lock,flags); | ||
5511 | |||
5512 | /* check for DSR/RI state change */ | ||
5513 | |||
5514 | delta = info->old_signals ^ info->serial_signals; | ||
5515 | info->old_signals = info->serial_signals; | ||
5516 | |||
5517 | if (delta & SerialSignal_DSR) | ||
5518 | status |= MISCSTATUS_DSR_LATCHED|(info->serial_signals&SerialSignal_DSR); | ||
5519 | |||
5520 | if (delta & SerialSignal_RI) | ||
5521 | status |= MISCSTATUS_RI_LATCHED|(info->serial_signals&SerialSignal_RI); | ||
5522 | |||
5523 | if (delta & SerialSignal_DCD) | ||
5524 | status |= MISCSTATUS_DCD_LATCHED|(info->serial_signals&SerialSignal_DCD); | ||
5525 | |||
5526 | if (delta & SerialSignal_CTS) | ||
5527 | status |= MISCSTATUS_CTS_LATCHED|(info->serial_signals&SerialSignal_CTS); | ||
5528 | |||
5529 | if (status) | ||
5530 | isr_io_pin(info,status); | ||
5531 | |||
5532 | mod_timer(&info->status_timer, jiffies + msecs_to_jiffies(10)); | ||
5533 | } | ||
5534 | |||
5535 | |||
5536 | /* Register Access Routines - | ||
5537 | * All registers are memory mapped | ||
5538 | */ | ||
5539 | #define CALC_REGADDR() \ | ||
5540 | unsigned char * RegAddr = (unsigned char*)(info->sca_base + Addr); \ | ||
5541 | if (info->port_num > 1) \ | ||
5542 | RegAddr += 256; /* port 0-1 SCA0, 2-3 SCA1 */ \ | ||
5543 | if ( info->port_num & 1) { \ | ||
5544 | if (Addr > 0x7f) \ | ||
5545 | RegAddr += 0x40; /* DMA access */ \ | ||
5546 | else if (Addr > 0x1f && Addr < 0x60) \ | ||
5547 | RegAddr += 0x20; /* MSCI access */ \ | ||
5548 | } | ||
5549 | |||
5550 | |||
5551 | static unsigned char read_reg(SLMP_INFO * info, unsigned char Addr) | ||
5552 | { | ||
5553 | CALC_REGADDR(); | ||
5554 | return *RegAddr; | ||
5555 | } | ||
5556 | static void write_reg(SLMP_INFO * info, unsigned char Addr, unsigned char Value) | ||
5557 | { | ||
5558 | CALC_REGADDR(); | ||
5559 | *RegAddr = Value; | ||
5560 | } | ||
5561 | |||
5562 | static u16 read_reg16(SLMP_INFO * info, unsigned char Addr) | ||
5563 | { | ||
5564 | CALC_REGADDR(); | ||
5565 | return *((u16 *)RegAddr); | ||
5566 | } | ||
5567 | |||
5568 | static void write_reg16(SLMP_INFO * info, unsigned char Addr, u16 Value) | ||
5569 | { | ||
5570 | CALC_REGADDR(); | ||
5571 | *((u16 *)RegAddr) = Value; | ||
5572 | } | ||
5573 | |||
5574 | static unsigned char read_status_reg(SLMP_INFO * info) | ||
5575 | { | ||
5576 | unsigned char *RegAddr = (unsigned char *)info->statctrl_base; | ||
5577 | return *RegAddr; | ||
5578 | } | ||
5579 | |||
5580 | static void write_control_reg(SLMP_INFO * info) | ||
5581 | { | ||
5582 | unsigned char *RegAddr = (unsigned char *)info->statctrl_base; | ||
5583 | *RegAddr = info->port_array[0]->ctrlreg_value; | ||
5584 | } | ||
5585 | |||
5586 | |||
5587 | static int __devinit synclinkmp_init_one (struct pci_dev *dev, | ||
5588 | const struct pci_device_id *ent) | ||
5589 | { | ||
5590 | if (pci_enable_device(dev)) { | ||
5591 | printk("error enabling pci device %p\n", dev); | ||
5592 | return -EIO; | ||
5593 | } | ||
5594 | device_init( ++synclinkmp_adapter_count, dev ); | ||
5595 | return 0; | ||
5596 | } | ||
5597 | |||
5598 | static void __devexit synclinkmp_remove_one (struct pci_dev *dev) | ||
5599 | { | ||
5600 | } | ||
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 8e0dd254eb11..81f13958e751 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c | |||
@@ -571,6 +571,7 @@ struct sysrq_state { | |||
571 | unsigned int alt_use; | 571 | unsigned int alt_use; |
572 | bool active; | 572 | bool active; |
573 | bool need_reinject; | 573 | bool need_reinject; |
574 | bool reinjecting; | ||
574 | }; | 575 | }; |
575 | 576 | ||
576 | static void sysrq_reinject_alt_sysrq(struct work_struct *work) | 577 | static void sysrq_reinject_alt_sysrq(struct work_struct *work) |
@@ -581,6 +582,10 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) | |||
581 | unsigned int alt_code = sysrq->alt_use; | 582 | unsigned int alt_code = sysrq->alt_use; |
582 | 583 | ||
583 | if (sysrq->need_reinject) { | 584 | if (sysrq->need_reinject) { |
585 | /* we do not want the assignment to be reordered */ | ||
586 | sysrq->reinjecting = true; | ||
587 | mb(); | ||
588 | |||
584 | /* Simulate press and release of Alt + SysRq */ | 589 | /* Simulate press and release of Alt + SysRq */ |
585 | input_inject_event(handle, EV_KEY, alt_code, 1); | 590 | input_inject_event(handle, EV_KEY, alt_code, 1); |
586 | input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1); | 591 | input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1); |
@@ -589,6 +594,9 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work) | |||
589 | input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0); | 594 | input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0); |
590 | input_inject_event(handle, EV_KEY, alt_code, 0); | 595 | input_inject_event(handle, EV_KEY, alt_code, 0); |
591 | input_inject_event(handle, EV_SYN, SYN_REPORT, 1); | 596 | input_inject_event(handle, EV_SYN, SYN_REPORT, 1); |
597 | |||
598 | mb(); | ||
599 | sysrq->reinjecting = false; | ||
592 | } | 600 | } |
593 | } | 601 | } |
594 | 602 | ||
@@ -599,6 +607,13 @@ static bool sysrq_filter(struct input_handle *handle, | |||
599 | bool was_active = sysrq->active; | 607 | bool was_active = sysrq->active; |
600 | bool suppress; | 608 | bool suppress; |
601 | 609 | ||
610 | /* | ||
611 | * Do not filter anything if we are in the process of re-injecting | ||
612 | * Alt+SysRq combination. | ||
613 | */ | ||
614 | if (sysrq->reinjecting) | ||
615 | return false; | ||
616 | |||
602 | switch (type) { | 617 | switch (type) { |
603 | 618 | ||
604 | case EV_SYN: | 619 | case EV_SYN: |
@@ -629,7 +644,7 @@ static bool sysrq_filter(struct input_handle *handle, | |||
629 | sysrq->alt_use = sysrq->alt; | 644 | sysrq->alt_use = sysrq->alt; |
630 | /* | 645 | /* |
631 | * If nothing else will be pressed we'll need | 646 | * If nothing else will be pressed we'll need |
632 | * to * re-inject Alt-SysRq keysroke. | 647 | * to re-inject Alt-SysRq keysroke. |
633 | */ | 648 | */ |
634 | sysrq->need_reinject = true; | 649 | sysrq->need_reinject = true; |
635 | } | 650 | } |
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index f64582b0f623..7c5866920622 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c | |||
@@ -95,8 +95,10 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, | |||
95 | { | 95 | { |
96 | if (buf->valid == 0) | 96 | if (buf->valid == 0) |
97 | return; | 97 | return; |
98 | if (audit_enabled == 0) | 98 | if (audit_enabled == 0) { |
99 | buf->valid = 0; | ||
99 | return; | 100 | return; |
101 | } | ||
100 | tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor, | 102 | tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor, |
101 | buf->data, buf->valid); | 103 | buf->data, buf->valid); |
102 | buf->valid = 0; | 104 | buf->valid = 0; |
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 0065da4b11c1..936a4ead6c21 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
@@ -90,7 +90,6 @@ | |||
90 | #include <linux/proc_fs.h> | 90 | #include <linux/proc_fs.h> |
91 | #include <linux/init.h> | 91 | #include <linux/init.h> |
92 | #include <linux/module.h> | 92 | #include <linux/module.h> |
93 | #include <linux/smp_lock.h> | ||
94 | #include <linux/device.h> | 93 | #include <linux/device.h> |
95 | #include <linux/wait.h> | 94 | #include <linux/wait.h> |
96 | #include <linux/bitops.h> | 95 | #include <linux/bitops.h> |
@@ -2465,12 +2464,12 @@ out: | |||
2465 | * Locking: none (up to the driver) | 2464 | * Locking: none (up to the driver) |
2466 | */ | 2465 | */ |
2467 | 2466 | ||
2468 | static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) | 2467 | static int tty_tiocmget(struct tty_struct *tty, int __user *p) |
2469 | { | 2468 | { |
2470 | int retval = -EINVAL; | 2469 | int retval = -EINVAL; |
2471 | 2470 | ||
2472 | if (tty->ops->tiocmget) { | 2471 | if (tty->ops->tiocmget) { |
2473 | retval = tty->ops->tiocmget(tty, file); | 2472 | retval = tty->ops->tiocmget(tty); |
2474 | 2473 | ||
2475 | if (retval >= 0) | 2474 | if (retval >= 0) |
2476 | retval = put_user(retval, p); | 2475 | retval = put_user(retval, p); |
@@ -2481,7 +2480,6 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p | |||
2481 | /** | 2480 | /** |
2482 | * tty_tiocmset - set modem status | 2481 | * tty_tiocmset - set modem status |
2483 | * @tty: tty device | 2482 | * @tty: tty device |
2484 | * @file: user file pointer | ||
2485 | * @cmd: command - clear bits, set bits or set all | 2483 | * @cmd: command - clear bits, set bits or set all |
2486 | * @p: pointer to desired bits | 2484 | * @p: pointer to desired bits |
2487 | * | 2485 | * |
@@ -2491,7 +2489,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p | |||
2491 | * Locking: none (up to the driver) | 2489 | * Locking: none (up to the driver) |
2492 | */ | 2490 | */ |
2493 | 2491 | ||
2494 | static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, | 2492 | static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, |
2495 | unsigned __user *p) | 2493 | unsigned __user *p) |
2496 | { | 2494 | { |
2497 | int retval; | 2495 | int retval; |
@@ -2518,7 +2516,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int | |||
2518 | } | 2516 | } |
2519 | set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; | 2517 | set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; |
2520 | clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; | 2518 | clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; |
2521 | return tty->ops->tiocmset(tty, file, set, clear); | 2519 | return tty->ops->tiocmset(tty, set, clear); |
2522 | } | 2520 | } |
2523 | 2521 | ||
2524 | static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) | 2522 | static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) |
@@ -2627,6 +2625,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2627 | return put_user(tty->ldisc->ops->num, (int __user *)p); | 2625 | return put_user(tty->ldisc->ops->num, (int __user *)p); |
2628 | case TIOCSETD: | 2626 | case TIOCSETD: |
2629 | return tiocsetd(tty, p); | 2627 | return tiocsetd(tty, p); |
2628 | case TIOCVHANGUP: | ||
2629 | if (!capable(CAP_SYS_ADMIN)) | ||
2630 | return -EPERM; | ||
2631 | tty_vhangup(tty); | ||
2632 | return 0; | ||
2630 | case TIOCGDEV: | 2633 | case TIOCGDEV: |
2631 | { | 2634 | { |
2632 | unsigned int ret = new_encode_dev(tty_devnum(real_tty)); | 2635 | unsigned int ret = new_encode_dev(tty_devnum(real_tty)); |
@@ -2655,11 +2658,11 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2655 | return send_break(tty, arg ? arg*100 : 250); | 2658 | return send_break(tty, arg ? arg*100 : 250); |
2656 | 2659 | ||
2657 | case TIOCMGET: | 2660 | case TIOCMGET: |
2658 | return tty_tiocmget(tty, file, p); | 2661 | return tty_tiocmget(tty, p); |
2659 | case TIOCMSET: | 2662 | case TIOCMSET: |
2660 | case TIOCMBIC: | 2663 | case TIOCMBIC: |
2661 | case TIOCMBIS: | 2664 | case TIOCMBIS: |
2662 | return tty_tiocmset(tty, file, cmd, p); | 2665 | return tty_tiocmset(tty, cmd, p); |
2663 | case TIOCGICOUNT: | 2666 | case TIOCGICOUNT: |
2664 | retval = tty_tiocgicount(tty, p); | 2667 | retval = tty_tiocgicount(tty, p); |
2665 | /* For the moment allow fall through to the old method */ | 2668 | /* For the moment allow fall through to the old method */ |
@@ -2677,7 +2680,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
2677 | break; | 2680 | break; |
2678 | } | 2681 | } |
2679 | if (tty->ops->ioctl) { | 2682 | if (tty->ops->ioctl) { |
2680 | retval = (tty->ops->ioctl)(tty, file, cmd, arg); | 2683 | retval = (tty->ops->ioctl)(tty, cmd, arg); |
2681 | if (retval != -ENOIOCTLCMD) | 2684 | if (retval != -ENOIOCTLCMD) |
2682 | return retval; | 2685 | return retval; |
2683 | } | 2686 | } |
@@ -2705,7 +2708,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, | |||
2705 | return -EINVAL; | 2708 | return -EINVAL; |
2706 | 2709 | ||
2707 | if (tty->ops->compat_ioctl) { | 2710 | if (tty->ops->compat_ioctl) { |
2708 | retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg); | 2711 | retval = (tty->ops->compat_ioctl)(tty, cmd, arg); |
2709 | if (retval != -ENOIOCTLCMD) | 2712 | if (retval != -ENOIOCTLCMD) |
2710 | return retval; | 2713 | return retval; |
2711 | } | 2714 | } |
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 0c1889971459..1a1135d580a2 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c | |||
@@ -486,7 +486,7 @@ int tty_termios_hw_change(struct ktermios *a, struct ktermios *b) | |||
486 | EXPORT_SYMBOL(tty_termios_hw_change); | 486 | EXPORT_SYMBOL(tty_termios_hw_change); |
487 | 487 | ||
488 | /** | 488 | /** |
489 | * change_termios - update termios values | 489 | * tty_set_termios - update termios values |
490 | * @tty: tty to update | 490 | * @tty: tty to update |
491 | * @new_termios: desired new value | 491 | * @new_termios: desired new value |
492 | * | 492 | * |
@@ -497,7 +497,7 @@ EXPORT_SYMBOL(tty_termios_hw_change); | |||
497 | * Locking: termios_mutex | 497 | * Locking: termios_mutex |
498 | */ | 498 | */ |
499 | 499 | ||
500 | static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | 500 | int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) |
501 | { | 501 | { |
502 | struct ktermios old_termios; | 502 | struct ktermios old_termios; |
503 | struct tty_ldisc *ld; | 503 | struct tty_ldisc *ld; |
@@ -553,7 +553,9 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
553 | tty_ldisc_deref(ld); | 553 | tty_ldisc_deref(ld); |
554 | } | 554 | } |
555 | mutex_unlock(&tty->termios_mutex); | 555 | mutex_unlock(&tty->termios_mutex); |
556 | return 0; | ||
556 | } | 557 | } |
558 | EXPORT_SYMBOL_GPL(tty_set_termios); | ||
557 | 559 | ||
558 | /** | 560 | /** |
559 | * set_termios - set termios values for a tty | 561 | * set_termios - set termios values for a tty |
@@ -562,7 +564,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) | |||
562 | * @opt: option information | 564 | * @opt: option information |
563 | * | 565 | * |
564 | * Helper function to prepare termios data and run necessary other | 566 | * Helper function to prepare termios data and run necessary other |
565 | * functions before using change_termios to do the actual changes. | 567 | * functions before using tty_set_termios to do the actual changes. |
566 | * | 568 | * |
567 | * Locking: | 569 | * Locking: |
568 | * Called functions take ldisc and termios_mutex locks | 570 | * Called functions take ldisc and termios_mutex locks |
@@ -620,7 +622,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) | |||
620 | return -EINTR; | 622 | return -EINTR; |
621 | } | 623 | } |
622 | 624 | ||
623 | change_termios(tty, &tmp_termios); | 625 | tty_set_termios(tty, &tmp_termios); |
624 | 626 | ||
625 | /* FIXME: Arguably if tmp_termios == tty->termios AND the | 627 | /* FIXME: Arguably if tmp_termios == tty->termios AND the |
626 | actual requested termios was not tmp_termios then we may | 628 | actual requested termios was not tmp_termios then we may |
@@ -797,7 +799,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) | |||
797 | termios.c_ospeed); | 799 | termios.c_ospeed); |
798 | #endif | 800 | #endif |
799 | mutex_unlock(&tty->termios_mutex); | 801 | mutex_unlock(&tty->termios_mutex); |
800 | change_termios(tty, &termios); | 802 | tty_set_termios(tty, &termios); |
801 | return 0; | 803 | return 0; |
802 | } | 804 | } |
803 | #endif | 805 | #endif |
@@ -951,6 +953,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, | |||
951 | int ret = 0; | 953 | int ret = 0; |
952 | struct ktermios kterm; | 954 | struct ktermios kterm; |
953 | 955 | ||
956 | BUG_ON(file == NULL); | ||
957 | |||
954 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && | 958 | if (tty->driver->type == TTY_DRIVER_TYPE_PTY && |
955 | tty->driver->subtype == PTY_TYPE_MASTER) | 959 | tty->driver->subtype == PTY_TYPE_MASTER) |
956 | real_tty = tty->link; | 960 | real_tty = tty->link; |
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 4214d58276f7..0fc564a97706 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -34,8 +34,6 @@ | |||
34 | #include <linux/vt_kern.h> | 34 | #include <linux/vt_kern.h> |
35 | #include <linux/selection.h> | 35 | #include <linux/selection.h> |
36 | 36 | ||
37 | #include <linux/smp_lock.h> /* For the moment */ | ||
38 | |||
39 | #include <linux/kmod.h> | 37 | #include <linux/kmod.h> |
40 | #include <linux/nsproxy.h> | 38 | #include <linux/nsproxy.h> |
41 | 39 | ||
@@ -535,6 +533,19 @@ static int tty_ldisc_halt(struct tty_struct *tty) | |||
535 | } | 533 | } |
536 | 534 | ||
537 | /** | 535 | /** |
536 | * tty_ldisc_flush_works - flush all works of a tty | ||
537 | * @tty: tty device to flush works for | ||
538 | * | ||
539 | * Sync flush all works belonging to @tty. | ||
540 | */ | ||
541 | static void tty_ldisc_flush_works(struct tty_struct *tty) | ||
542 | { | ||
543 | flush_work_sync(&tty->hangup_work); | ||
544 | flush_work_sync(&tty->SAK_work); | ||
545 | flush_delayed_work_sync(&tty->buf.work); | ||
546 | } | ||
547 | |||
548 | /** | ||
538 | * tty_ldisc_wait_idle - wait for the ldisc to become idle | 549 | * tty_ldisc_wait_idle - wait for the ldisc to become idle |
539 | * @tty: tty to wait for | 550 | * @tty: tty to wait for |
540 | * | 551 | * |
@@ -653,7 +664,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
653 | 664 | ||
654 | mutex_unlock(&tty->ldisc_mutex); | 665 | mutex_unlock(&tty->ldisc_mutex); |
655 | 666 | ||
656 | flush_scheduled_work(); | 667 | tty_ldisc_flush_works(tty); |
657 | 668 | ||
658 | retval = tty_ldisc_wait_idle(tty); | 669 | retval = tty_ldisc_wait_idle(tty); |
659 | 670 | ||
@@ -905,7 +916,7 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
905 | 916 | ||
906 | tty_unlock(); | 917 | tty_unlock(); |
907 | tty_ldisc_halt(tty); | 918 | tty_ldisc_halt(tty); |
908 | flush_scheduled_work(); | 919 | tty_ldisc_flush_works(tty); |
909 | tty_lock(); | 920 | tty_lock(); |
910 | 921 | ||
911 | mutex_lock(&tty->ldisc_mutex); | 922 | mutex_lock(&tty->ldisc_mutex); |
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index e95d7876ca6b..6dd3c68c13ad 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
@@ -654,7 +654,8 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag) | |||
654 | if (value >= ARRAY_SIZE(fn_handler)) | 654 | if (value >= ARRAY_SIZE(fn_handler)) |
655 | return; | 655 | return; |
656 | if ((kbd->kbdmode == VC_RAW || | 656 | if ((kbd->kbdmode == VC_RAW || |
657 | kbd->kbdmode == VC_MEDIUMRAW) && | 657 | kbd->kbdmode == VC_MEDIUMRAW || |
658 | kbd->kbdmode == VC_OFF) && | ||
658 | value != KVAL(K_SAK)) | 659 | value != KVAL(K_SAK)) |
659 | return; /* SAK is allowed even in raw mode */ | 660 | return; /* SAK is allowed even in raw mode */ |
660 | fn_handler[value](vc); | 661 | fn_handler[value](vc); |
@@ -1295,7 +1296,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1295 | if (rc == NOTIFY_STOP) | 1296 | if (rc == NOTIFY_STOP) |
1296 | return; | 1297 | return; |
1297 | 1298 | ||
1298 | if (raw_mode && type != KT_SPEC && type != KT_SHIFT) | 1299 | if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT) |
1299 | return; | 1300 | return; |
1300 | 1301 | ||
1301 | (*k_handler[type])(vc, keysym & 0xff, !down); | 1302 | (*k_handler[type])(vc, keysym & 0xff, !down); |
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index c956ed6c83a3..adf0ad2a8851 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/selection.h> | 26 | #include <linux/selection.h> |
27 | #include <linux/tiocl.h> | 27 | #include <linux/tiocl.h> |
28 | #include <linux/console.h> | 28 | #include <linux/console.h> |
29 | #include <linux/smp_lock.h> | ||
30 | 29 | ||
31 | /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ | 30 | /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ |
32 | #define isspace(c) ((c) == ' ') | 31 | #define isspace(c) ((c) == ' ') |
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index a672ed192d33..1564261e80c8 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c | |||
@@ -28,13 +28,11 @@ | |||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/mutex.h> | ||
32 | #include <linux/vt_kern.h> | 31 | #include <linux/vt_kern.h> |
33 | #include <linux/selection.h> | 32 | #include <linux/selection.h> |
34 | #include <linux/kbd_kern.h> | 33 | #include <linux/kbd_kern.h> |
35 | #include <linux/console.h> | 34 | #include <linux/console.h> |
36 | #include <linux/device.h> | 35 | #include <linux/device.h> |
37 | #include <linux/smp_lock.h> | ||
38 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
39 | #include <linux/fs.h> | 37 | #include <linux/fs.h> |
40 | #include <linux/poll.h> | 38 | #include <linux/poll.h> |
@@ -51,6 +49,8 @@ | |||
51 | #undef addr | 49 | #undef addr |
52 | #define HEADER_SIZE 4 | 50 | #define HEADER_SIZE 4 |
53 | 51 | ||
52 | #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) | ||
53 | |||
54 | struct vcs_poll_data { | 54 | struct vcs_poll_data { |
55 | struct notifier_block notifier; | 55 | struct notifier_block notifier; |
56 | unsigned int cons_num; | 56 | unsigned int cons_num; |
@@ -131,21 +131,45 @@ vcs_poll_data_get(struct file *file) | |||
131 | return poll; | 131 | return poll; |
132 | } | 132 | } |
133 | 133 | ||
134 | /* | ||
135 | * Returns VC for inode. | ||
136 | * Must be called with console_lock. | ||
137 | */ | ||
138 | static struct vc_data* | ||
139 | vcs_vc(struct inode *inode, int *viewed) | ||
140 | { | ||
141 | unsigned int currcons = iminor(inode) & 127; | ||
142 | |||
143 | WARN_CONSOLE_UNLOCKED(); | ||
144 | |||
145 | if (currcons == 0) { | ||
146 | currcons = fg_console; | ||
147 | if (viewed) | ||
148 | *viewed = 1; | ||
149 | } else { | ||
150 | currcons--; | ||
151 | if (viewed) | ||
152 | *viewed = 0; | ||
153 | } | ||
154 | return vc_cons[currcons].d; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Returns size for VC carried by inode. | ||
159 | * Must be called with console_lock. | ||
160 | */ | ||
134 | static int | 161 | static int |
135 | vcs_size(struct inode *inode) | 162 | vcs_size(struct inode *inode) |
136 | { | 163 | { |
137 | int size; | 164 | int size; |
138 | int minor = iminor(inode); | 165 | int minor = iminor(inode); |
139 | int currcons = minor & 127; | ||
140 | struct vc_data *vc; | 166 | struct vc_data *vc; |
141 | 167 | ||
142 | if (currcons == 0) | 168 | WARN_CONSOLE_UNLOCKED(); |
143 | currcons = fg_console; | 169 | |
144 | else | 170 | vc = vcs_vc(inode, NULL); |
145 | currcons--; | 171 | if (!vc) |
146 | if (!vc_cons_allocated(currcons)) | ||
147 | return -ENXIO; | 172 | return -ENXIO; |
148 | vc = vc_cons[currcons].d; | ||
149 | 173 | ||
150 | size = vc->vc_rows * vc->vc_cols; | 174 | size = vc->vc_rows * vc->vc_cols; |
151 | 175 | ||
@@ -158,11 +182,13 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) | |||
158 | { | 182 | { |
159 | int size; | 183 | int size; |
160 | 184 | ||
161 | mutex_lock(&con_buf_mtx); | 185 | console_lock(); |
162 | size = vcs_size(file->f_path.dentry->d_inode); | 186 | size = vcs_size(file->f_path.dentry->d_inode); |
187 | console_unlock(); | ||
188 | if (size < 0) | ||
189 | return size; | ||
163 | switch (orig) { | 190 | switch (orig) { |
164 | default: | 191 | default: |
165 | mutex_unlock(&con_buf_mtx); | ||
166 | return -EINVAL; | 192 | return -EINVAL; |
167 | case 2: | 193 | case 2: |
168 | offset += size; | 194 | offset += size; |
@@ -173,11 +199,9 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig) | |||
173 | break; | 199 | break; |
174 | } | 200 | } |
175 | if (offset < 0 || offset > size) { | 201 | if (offset < 0 || offset > size) { |
176 | mutex_unlock(&con_buf_mtx); | ||
177 | return -EINVAL; | 202 | return -EINVAL; |
178 | } | 203 | } |
179 | file->f_pos = offset; | 204 | file->f_pos = offset; |
180 | mutex_unlock(&con_buf_mtx); | ||
181 | return file->f_pos; | 205 | return file->f_pos; |
182 | } | 206 | } |
183 | 207 | ||
@@ -190,12 +214,15 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
190 | struct vc_data *vc; | 214 | struct vc_data *vc; |
191 | struct vcs_poll_data *poll; | 215 | struct vcs_poll_data *poll; |
192 | long pos; | 216 | long pos; |
193 | long viewed, attr, read; | 217 | long attr, read; |
194 | int col, maxcol; | 218 | int col, maxcol, viewed; |
195 | unsigned short *org = NULL; | 219 | unsigned short *org = NULL; |
196 | ssize_t ret; | 220 | ssize_t ret; |
221 | char *con_buf; | ||
197 | 222 | ||
198 | mutex_lock(&con_buf_mtx); | 223 | con_buf = (char *) __get_free_page(GFP_KERNEL); |
224 | if (!con_buf) | ||
225 | return -ENOMEM; | ||
199 | 226 | ||
200 | pos = *ppos; | 227 | pos = *ppos; |
201 | 228 | ||
@@ -205,18 +232,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
205 | console_lock(); | 232 | console_lock(); |
206 | 233 | ||
207 | attr = (currcons & 128); | 234 | attr = (currcons & 128); |
208 | currcons = (currcons & 127); | ||
209 | if (currcons == 0) { | ||
210 | currcons = fg_console; | ||
211 | viewed = 1; | ||
212 | } else { | ||
213 | currcons--; | ||
214 | viewed = 0; | ||
215 | } | ||
216 | ret = -ENXIO; | 235 | ret = -ENXIO; |
217 | if (!vc_cons_allocated(currcons)) | 236 | vc = vcs_vc(inode, &viewed); |
237 | if (!vc) | ||
218 | goto unlock_out; | 238 | goto unlock_out; |
219 | vc = vc_cons[currcons].d; | ||
220 | 239 | ||
221 | ret = -EINVAL; | 240 | ret = -EINVAL; |
222 | if (pos < 0) | 241 | if (pos < 0) |
@@ -237,6 +256,12 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
237 | * could sleep. | 256 | * could sleep. |
238 | */ | 257 | */ |
239 | size = vcs_size(inode); | 258 | size = vcs_size(inode); |
259 | if (size < 0) { | ||
260 | if (read) | ||
261 | break; | ||
262 | ret = size; | ||
263 | goto unlock_out; | ||
264 | } | ||
240 | if (pos >= size) | 265 | if (pos >= size) |
241 | break; | 266 | break; |
242 | if (count > size - pos) | 267 | if (count > size - pos) |
@@ -355,7 +380,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
355 | ret = read; | 380 | ret = read; |
356 | unlock_out: | 381 | unlock_out: |
357 | console_unlock(); | 382 | console_unlock(); |
358 | mutex_unlock(&con_buf_mtx); | 383 | free_page((unsigned long) con_buf); |
359 | return ret; | 384 | return ret; |
360 | } | 385 | } |
361 | 386 | ||
@@ -366,13 +391,16 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
366 | unsigned int currcons = iminor(inode); | 391 | unsigned int currcons = iminor(inode); |
367 | struct vc_data *vc; | 392 | struct vc_data *vc; |
368 | long pos; | 393 | long pos; |
369 | long viewed, attr, size, written; | 394 | long attr, size, written; |
370 | char *con_buf0; | 395 | char *con_buf0; |
371 | int col, maxcol; | 396 | int col, maxcol, viewed; |
372 | u16 *org0 = NULL, *org = NULL; | 397 | u16 *org0 = NULL, *org = NULL; |
373 | size_t ret; | 398 | size_t ret; |
399 | char *con_buf; | ||
374 | 400 | ||
375 | mutex_lock(&con_buf_mtx); | 401 | con_buf = (char *) __get_free_page(GFP_KERNEL); |
402 | if (!con_buf) | ||
403 | return -ENOMEM; | ||
376 | 404 | ||
377 | pos = *ppos; | 405 | pos = *ppos; |
378 | 406 | ||
@@ -382,19 +410,10 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
382 | console_lock(); | 410 | console_lock(); |
383 | 411 | ||
384 | attr = (currcons & 128); | 412 | attr = (currcons & 128); |
385 | currcons = (currcons & 127); | ||
386 | |||
387 | if (currcons == 0) { | ||
388 | currcons = fg_console; | ||
389 | viewed = 1; | ||
390 | } else { | ||
391 | currcons--; | ||
392 | viewed = 0; | ||
393 | } | ||
394 | ret = -ENXIO; | 413 | ret = -ENXIO; |
395 | if (!vc_cons_allocated(currcons)) | 414 | vc = vcs_vc(inode, &viewed); |
415 | if (!vc) | ||
396 | goto unlock_out; | 416 | goto unlock_out; |
397 | vc = vc_cons[currcons].d; | ||
398 | 417 | ||
399 | size = vcs_size(inode); | 418 | size = vcs_size(inode); |
400 | ret = -EINVAL; | 419 | ret = -EINVAL; |
@@ -436,6 +455,12 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
436 | * Return data written up to now on failure. | 455 | * Return data written up to now on failure. |
437 | */ | 456 | */ |
438 | size = vcs_size(inode); | 457 | size = vcs_size(inode); |
458 | if (size < 0) { | ||
459 | if (written) | ||
460 | break; | ||
461 | ret = size; | ||
462 | goto unlock_out; | ||
463 | } | ||
439 | if (pos >= size) | 464 | if (pos >= size) |
440 | break; | 465 | break; |
441 | if (this_round > size - pos) | 466 | if (this_round > size - pos) |
@@ -543,9 +568,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
543 | 568 | ||
544 | unlock_out: | 569 | unlock_out: |
545 | console_unlock(); | 570 | console_unlock(); |
546 | 571 | free_page((unsigned long) con_buf); | |
547 | mutex_unlock(&con_buf_mtx); | ||
548 | |||
549 | return ret; | 572 | return ret; |
550 | } | 573 | } |
551 | 574 | ||
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 147ede3423df..c83cdfb56fcc 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c | |||
@@ -89,7 +89,6 @@ | |||
89 | #include <linux/mutex.h> | 89 | #include <linux/mutex.h> |
90 | #include <linux/vt_kern.h> | 90 | #include <linux/vt_kern.h> |
91 | #include <linux/selection.h> | 91 | #include <linux/selection.h> |
92 | #include <linux/smp_lock.h> | ||
93 | #include <linux/tiocl.h> | 92 | #include <linux/tiocl.h> |
94 | #include <linux/kbd_kern.h> | 93 | #include <linux/kbd_kern.h> |
95 | #include <linux/consolemap.h> | 94 | #include <linux/consolemap.h> |
@@ -2068,18 +2067,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | |||
2068 | } | 2067 | } |
2069 | } | 2068 | } |
2070 | 2069 | ||
2071 | /* This is a temporary buffer used to prepare a tty console write | ||
2072 | * so that we can easily avoid touching user space while holding the | ||
2073 | * console spinlock. It is allocated in con_init and is shared by | ||
2074 | * this code and the vc_screen read/write tty calls. | ||
2075 | * | ||
2076 | * We have to allocate this statically in the kernel data section | ||
2077 | * since console_init (and thus con_init) are called before any | ||
2078 | * kernel memory allocation is available. | ||
2079 | */ | ||
2080 | char con_buf[CON_BUF_SIZE]; | ||
2081 | DEFINE_MUTEX(con_buf_mtx); | ||
2082 | |||
2083 | /* is_double_width() is based on the wcwidth() implementation by | 2070 | /* is_double_width() is based on the wcwidth() implementation by |
2084 | * Markus Kuhn -- 2007-05-26 (Unicode 5.0) | 2071 | * Markus Kuhn -- 2007-05-26 (Unicode 5.0) |
2085 | * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c | 2072 | * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c |
@@ -2157,10 +2144,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co | |||
2157 | 2144 | ||
2158 | currcons = vc->vc_num; | 2145 | currcons = vc->vc_num; |
2159 | if (!vc_cons_allocated(currcons)) { | 2146 | if (!vc_cons_allocated(currcons)) { |
2160 | /* could this happen? */ | 2147 | /* could this happen? */ |
2161 | printk_once("con_write: tty %d not allocated\n", currcons+1); | 2148 | pr_warn_once("con_write: tty %d not allocated\n", currcons+1); |
2162 | console_unlock(); | 2149 | console_unlock(); |
2163 | return 0; | 2150 | return 0; |
2164 | } | 2151 | } |
2165 | 2152 | ||
2166 | himask = vc->vc_hi_font_mask; | 2153 | himask = vc->vc_hi_font_mask; |
@@ -2940,7 +2927,7 @@ static int __init con_init(void) | |||
2940 | gotoxy(vc, vc->vc_x, vc->vc_y); | 2927 | gotoxy(vc, vc->vc_x, vc->vc_y); |
2941 | csi_J(vc, 0); | 2928 | csi_J(vc, 0); |
2942 | update_screen(vc); | 2929 | update_screen(vc); |
2943 | printk("Console: %s %s %dx%d", | 2930 | pr_info("Console: %s %s %dx%d", |
2944 | vc->vc_can_do_color ? "colour" : "mono", | 2931 | vc->vc_can_do_color ? "colour" : "mono", |
2945 | display_desc, vc->vc_cols, vc->vc_rows); | 2932 | display_desc, vc->vc_cols, vc->vc_rows); |
2946 | printable = 1; | 2933 | printable = 1; |
@@ -3103,7 +3090,7 @@ static int bind_con_driver(const struct consw *csw, int first, int last, | |||
3103 | clear_buffer_attributes(vc); | 3090 | clear_buffer_attributes(vc); |
3104 | } | 3091 | } |
3105 | 3092 | ||
3106 | printk("Console: switching "); | 3093 | pr_info("Console: switching "); |
3107 | if (!deflt) | 3094 | if (!deflt) |
3108 | printk("consoles %d-%d ", first+1, last+1); | 3095 | printk("consoles %d-%d ", first+1, last+1); |
3109 | if (j >= 0) { | 3096 | if (j >= 0) { |
@@ -3809,7 +3796,8 @@ void do_unblank_screen(int leaving_gfx) | |||
3809 | return; | 3796 | return; |
3810 | if (!vc_cons_allocated(fg_console)) { | 3797 | if (!vc_cons_allocated(fg_console)) { |
3811 | /* impossible */ | 3798 | /* impossible */ |
3812 | printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); | 3799 | pr_warning("unblank_screen: tty %d not allocated ??\n", |
3800 | fg_console+1); | ||
3813 | return; | 3801 | return; |
3814 | } | 3802 | } |
3815 | vc = vc_cons[fg_console].d; | 3803 | vc = vc_cons[fg_console].d; |
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 1235ebda6e1c..937d17219984 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
28 | #include <linux/consolemap.h> | 28 | #include <linux/consolemap.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/smp_lock.h> | ||
31 | #include <linux/timex.h> | 30 | #include <linux/timex.h> |
32 | 31 | ||
33 | #include <asm/io.h> | 32 | #include <asm/io.h> |
@@ -495,7 +494,7 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_ | |||
495 | * We handle the console-specific ioctl's here. We allow the | 494 | * We handle the console-specific ioctl's here. We allow the |
496 | * capability to modify any console, not just the fg_console. | 495 | * capability to modify any console, not just the fg_console. |
497 | */ | 496 | */ |
498 | int vt_ioctl(struct tty_struct *tty, struct file * file, | 497 | int vt_ioctl(struct tty_struct *tty, |
499 | unsigned int cmd, unsigned long arg) | 498 | unsigned int cmd, unsigned long arg) |
500 | { | 499 | { |
501 | struct vc_data *vc = tty->driver_data; | 500 | struct vc_data *vc = tty->driver_data; |
@@ -688,6 +687,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
688 | kbd->kbdmode = VC_UNICODE; | 687 | kbd->kbdmode = VC_UNICODE; |
689 | compute_shiftstate(); | 688 | compute_shiftstate(); |
690 | break; | 689 | break; |
690 | case K_OFF: | ||
691 | kbd->kbdmode = VC_OFF; | ||
692 | break; | ||
691 | default: | 693 | default: |
692 | ret = -EINVAL; | 694 | ret = -EINVAL; |
693 | goto out; | 695 | goto out; |
@@ -1007,8 +1009,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
1007 | if (ret) | 1009 | if (ret) |
1008 | break; | 1010 | break; |
1009 | /* Commence switch and lock */ | 1011 | /* Commence switch and lock */ |
1010 | set_console(arg); | 1012 | set_console(vsa.console); |
1011 | } | 1013 | } |
1014 | break; | ||
1012 | } | 1015 | } |
1013 | 1016 | ||
1014 | /* | 1017 | /* |
@@ -1491,7 +1494,7 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud, | |||
1491 | return 0; | 1494 | return 0; |
1492 | } | 1495 | } |
1493 | 1496 | ||
1494 | long vt_compat_ioctl(struct tty_struct *tty, struct file * file, | 1497 | long vt_compat_ioctl(struct tty_struct *tty, |
1495 | unsigned int cmd, unsigned long arg) | 1498 | unsigned int cmd, unsigned long arg) |
1496 | { | 1499 | { |
1497 | struct vc_data *vc = tty->driver_data; | 1500 | struct vc_data *vc = tty->driver_data; |
@@ -1577,7 +1580,7 @@ out: | |||
1577 | 1580 | ||
1578 | fallback: | 1581 | fallback: |
1579 | tty_unlock(); | 1582 | tty_unlock(); |
1580 | return vt_ioctl(tty, file, cmd, arg); | 1583 | return vt_ioctl(tty, cmd, arg); |
1581 | } | 1584 | } |
1582 | 1585 | ||
1583 | 1586 | ||