blob: 31bc8e41587ebee601a8fb490aeac60d47f84e95 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08004static char rcsid[] = "$Revision: 2.3.2.20 $$Date: 2004/02/25 18:14:16 $";
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6/*
7 * linux/drivers/char/cyclades.c
8 *
9 * This file contains the driver for the Cyclades async multiport
10 * serial boards.
11 *
12 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
13 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
14 * Currently maintained by Cyclades team <async@cyclades.com>.
15 *
16 * For Technical support and installation problems, please send e-mail
17 * to support@cyclades.com.
18 *
19 * Much of the design and some of the code came from serial.c
20 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
21 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
22 * and then fixed as suggested by Michael K. Johnson 12/12/92.
23 *
24 * This version supports shared IRQ's (only for PCI boards).
25 *
26 * $Log: cyclades.c,v $
27 * Prevent users from opening non-existing Z ports.
28 *
29 * Revision 2.3.2.8 2000/07/06 18:14:16 ivan
30 * Fixed the PCI detection function to work properly on Alpha systems.
31 * Implemented support for TIOCSERGETLSR ioctl.
32 * Implemented full support for non-standard baud rates.
33 *
34 * Revision 2.3.2.7 2000/06/01 18:26:34 ivan
35 * Request PLX I/O region, although driver doesn't use it, to avoid
36 * problems with other drivers accessing it.
37 * Removed count for on-board buffer characters in cy_chars_in_buffer
38 * (Cyclades-Z only).
39 *
40 * Revision 2.3.2.6 2000/05/05 13:56:05 ivan
41 * Driver now reports physical instead of virtual memory addresses.
42 * Masks were added to some Cyclades-Z read accesses.
43 * Implemented workaround for PLX9050 bug that would cause a system lockup
44 * in certain systems, depending on the MMIO addresses allocated to the
45 * board.
46 * Changed the Tx interrupt programming in the CD1400 chips to boost up
47 * performance (Cyclom-Y only).
48 * Code is now compliant with the new module interface (module_[init|exit]).
49 * Make use of the PCI helper functions to access PCI resources.
50 * Did some code "housekeeping".
51 *
52 * Revision 2.3.2.5 2000/01/19 14:35:33 ivan
53 * Fixed bug in cy_set_termios on CRTSCTS flag turnoff.
54 *
55 * Revision 2.3.2.4 2000/01/17 09:19:40 ivan
56 * Fixed SMP locking in Cyclom-Y interrupt handler.
57 *
58 * Revision 2.3.2.3 1999/12/28 12:11:39 ivan
59 * Added a new cyclades_card field called nports to allow the driver to
60 * know the exact number of ports found by the Z firmware after its load;
61 * RX buffer contention prevention logic on interrupt op mode revisited
62 * (Cyclades-Z only);
63 * Revisited printk's for Z debug;
64 * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
65 *
66 * Revision 2.3.2.2 1999/10/01 11:27:43 ivan
67 * Fixed bug in cyz_poll that would make all ports but port 0
68 * unable to transmit/receive data (Cyclades-Z only);
69 * Implemented logic to prevent the RX buffer from being stuck with data
70 * due to a driver / firmware race condition in interrupt op mode
71 * (Cyclades-Z only);
72 * Fixed bug in block_til_ready logic that would lead to a system crash;
73 * Revisited cy_close spinlock usage;
74 *
75 * Revision 2.3.2.1 1999/09/28 11:01:22 ivan
76 * Revisited CONFIG_PCI conditional compilation for PCI board support;
77 * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support;
78 * _Major_ cleanup on the Cyclades-Z interrupt support code / logic;
79 * Removed CTS handling from the driver -- this is now completely handled
80 * by the firmware (Cyclades-Z only);
81 * Flush RX on-board buffers on a port open (Cyclades-Z only);
82 * Fixed handling of ASYNC_SPD_* TTY flags;
83 * Module unload now unmaps all memory area allocated by ioremap;
84 *
85 * Revision 2.3.1.1 1999/07/15 16:45:53 ivan
86 * Removed CY_PROC conditional compilation;
87 * Implemented SMP-awareness for the driver;
88 * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
89 * functions;
90 * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
91 * (irq=NN) as parameters (only for ISA boards);
92 * Fixed bug in set_line_char that would prevent the Cyclades-Z
93 * ports from being configured at speeds above 115.2Kbps;
94 * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
95 * switching from working properly;
96 * The driver now only prints IRQ info for the Cyclades-Z if it's
97 * configured to work in interrupt mode;
98 *
99 * Revision 2.2.2.3 1999/06/28 11:13:29 ivan
100 * Added support for interrupt mode operation for the Z cards;
101 * Removed the driver inactivity control for the Z;
102 * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
103 * the Z firmware is not loaded yet;
104 * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
105 * same functionality;
106 * Implemented workaround for IRQ setting loss on the PCI configuration
107 * registers after a PCI bridge EEPROM reload (affects PLX9060 only);
108 *
109 * Revision 2.2.2.2 1999/05/14 17:18:15 ivan
110 * /proc entry location changed to /proc/tty/driver/cyclades;
111 * Added support to shared IRQ's (only for PCI boards);
112 * Added support for Cobalt Qube2 systems;
113 * IRQ [de]allocation scheme revisited;
114 * BREAK implementation changed in order to make use of the 'break_ctl'
115 * TTY facility;
116 * Fixed typo in TTY structure field 'driver_name';
117 * Included a PCI bridge reset and EEPROM reload in the board
118 * initialization code (for both Y and Z series).
119 *
120 * Revision 2.2.2.1 1999/04/08 16:17:43 ivan
121 * Fixed a bug in cy_wait_until_sent that was preventing the port to be
122 * closed properly after a SIGINT;
123 * Module usage counter scheme revisited;
124 * Added support to the upcoming Y PCI boards (i.e., support to additional
125 * PCI Device ID's).
126 *
127 * Revision 2.2.1.10 1999/01/20 16:14:29 ivan
128 * Removed all unnecessary page-alignement operations in ioremap calls
129 * (ioremap is currently safe for these operations).
130 *
131 * Revision 2.2.1.9 1998/12/30 18:18:30 ivan
132 * Changed access to PLX PCI bridge registers from I/O to MMIO, in
133 * order to make PLX9050-based boards work with certain motherboards.
134 *
135 * Revision 2.2.1.8 1998/11/13 12:46:20 ivan
136 * cy_close function now resets (correctly) the tty->closing flag;
137 * JIFFIES_DIFF macro fixed.
138 *
139 * Revision 2.2.1.7 1998/09/03 12:07:28 ivan
140 * Fixed bug in cy_close function, which was not informing HW of
141 * which port should have the reception disabled before doing so;
142 * fixed Cyclom-8YoP hardware detection bug.
143 *
144 * Revision 2.2.1.6 1998/08/20 17:15:39 ivan
145 * Fixed bug in cy_close function, which causes malfunction
146 * of one of the first 4 ports when a higher port is closed
147 * (Cyclom-Y only).
148 *
149 * Revision 2.2.1.5 1998/08/10 18:10:28 ivan
150 * Fixed Cyclom-4Yo hardware detection bug.
151 *
152 * Revision 2.2.1.4 1998/08/04 11:02:50 ivan
153 * /proc/cyclades implementation with great collaboration of
154 * Marc Lewis <marc@blarg.net>;
155 * cyy_interrupt was changed to avoid occurrence of kernel oopses
156 * during PPP operation.
157 *
158 * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
159 * General code review in order to comply with 2.1 kernel standards;
160 * data loss prevention for slow devices revisited (cy_wait_until_sent
161 * was created);
162 * removed conditional compilation for new/old PCI structure support
163 * (now the driver only supports the new PCI structure).
164 *
165 * Revision 2.2.1.1 1998/03/19 16:43:12 ivan
166 * added conditional compilation for new/old PCI structure support;
167 * removed kernel series (2.0.x / 2.1.x) conditional compilation.
168 *
169 * Revision 2.1.1.3 1998/03/16 18:01:12 ivan
170 * cleaned up the data loss fix;
171 * fixed XON/XOFF handling once more (Cyclades-Z);
172 * general review of the driver routines;
173 * introduction of a mechanism to prevent data loss with slow
174 * printers, by forcing a delay before closing the port.
175 *
176 * Revision 2.1.1.2 1998/02/17 16:50:00 ivan
177 * fixed detection/handling of new CD1400 in Ye boards;
178 * fixed XON/XOFF handling (Cyclades-Z);
179 * fixed data loss caused by a premature port close;
180 * introduction of a flag that holds the CD1400 version ID per port
181 * (used by the CYGETCD1400VER new ioctl).
182 *
183 * Revision 2.1.1.1 1997/12/03 17:31:19 ivan
184 * Code review for the module cleanup routine;
185 * fixed RTS and DTR status report for new CD1400's in get_modem_info;
186 * includes anonymous changes regarding signal_pending.
187 *
188 * Revision 2.1 1997/11/01 17:42:41 ivan
189 * Changes in the driver to support Alpha systems (except 8Zo V_1);
190 * BREAK fix for the Cyclades-Z boards;
191 * driver inactivity control by FW implemented;
192 * introduction of flag that allows driver to take advantage of
193 * a special CD1400 feature related to HW flow control;
194 * added support for the CD1400 rev. J (Cyclom-Y boards);
195 * introduction of ioctls to:
196 * - control the rtsdtr_inv flag (Cyclom-Y);
197 * - control the rflow flag (Cyclom-Y);
198 * - adjust the polling interval (Cyclades-Z);
199 *
200 * Revision 1.36.4.33 1997/06/27 19:00:00 ivan
201 * Fixes related to kernel version conditional
202 * compilation.
203 *
204 * Revision 1.36.4.32 1997/06/14 19:30:00 ivan
205 * Compatibility issues between kernels 2.0.x and
206 * 2.1.x (mainly related to clear_bit function).
207 *
208 * Revision 1.36.4.31 1997/06/03 15:30:00 ivan
209 * Changes to define the memory window according to the
210 * board type.
211 *
212 * Revision 1.36.4.30 1997/05/16 15:30:00 daniel
213 * Changes to support new cycladesZ boards.
214 *
215 * Revision 1.36.4.29 1997/05/12 11:30:00 daniel
216 * Merge of Bentson's and Daniel's version 1.36.4.28.
217 * Corrects bug in cy_detect_pci: check if there are more
218 * ports than the number of static structs allocated.
219 * Warning message during initialization if this driver is
220 * used with the new generation of cycladesZ boards. Those
221 * will be supported only in next release of the driver.
222 * Corrects bug in cy_detect_pci and cy_detect_isa that
223 * returned wrong number of VALID boards, when a cyclomY
224 * was found with no serial modules connected.
225 * Changes to use current (2.1.x) kernel subroutine names
226 * and created macros for compilation with 2.0.x kernel,
227 * instead of the other way around.
228 *
229 * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson
230 * Change queue_task_irq_off to queue_task_irq.
231 * The inline function queue_task_irq_off (tqueue.h)
232 * was removed from latest releases of 2.1.x kernel.
233 * Use of macro __init to mark the initialization
234 * routines, so memory can be reused.
235 * Also incorporate implementation of critical region
236 * in function cleanup_module() created by anonymous
237 * linuxer.
238 *
239 * Revision 1.36.4.28 1997/04/25 16:00:00 daniel
240 * Change to support new firmware that solves DCD problem:
241 * application could fail to receive SIGHUP signal when DCD
242 * varying too fast.
243 *
244 * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
245 * Changed for support linux versions 2.1.X.
246 * Backward compatible with linux versions 2.0.X.
247 * Corrected illegal use of filler field in
248 * CH_CTRL struct.
249 * Deleted some debug messages.
250 *
251 * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
252 * Included check for NULL tty pointer in cyz_poll.
253 *
254 * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
255 * Bill Foster at Blarg! Online services noticed that
256 * some of the switch elements of -Z modem control
257 * lacked a closing "break;"
258 *
259 * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
260 * Changed low water threshold for buffer xmit_buf
261 *
262 * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
263 * Marcio provided fix to modem status fetch for -Z
264 *
265 * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
266 * improve mapping of -Z control page (thanks to Steve
267 * Price <stevep@fa.tdktca.com> for help on this)
268 *
269 * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
270 * shift from CPU-bound to memcopy in cyz_polling operation
271 *
272 * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
273 * Added support to set and report higher speeds.
274 *
275 * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
276 * Some fixes in the HW flow control for the BETA release.
277 * Don't try to register the IRQ.
278 *
279 * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
280 * make sure "cyc" appears in all kernel messages; all soft interrupts
281 * handled by same routine; recognize out-of-band reception; comment
282 * out some diagnostic messages; leave RTS/CTS flow control to hardware;
Jean Delvare33430dc2005-10-30 15:02:20 -0800283 * fix race condition in -Z buffer management; only -Y needs to explicitly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 * flush chars; tidy up some startup messages;
285 *
286 * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
287 * shift MOD_INC_USE_COUNT location to match
288 * serial.c; purge some diagnostic messages;
289 *
290 * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
291 * enable modem status messages and fetch & process them; note
292 * time of last activity type for each port; set_line_char now
293 * supports more than line 0 and treats 0 baud correctly;
294 * get_modem_info senses rs_status;
295 *
296 * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
297 * barely works--now's time to turn on
298 * more features 'til it breaks
299 *
300 * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
301 * check more -Z board status; shorten boot message
302 *
303 * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
304 * fix reference to ch_ctrl in startup; verify return
305 * values from cyz_issue_cmd and cyz_update_channel;
306 * more stuff to get modem control correct;
307 *
308 * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
309 * more -Z stuff folded in; re-order changes to put -Z stuff
310 * after -Y stuff (to make changes clearer)
311 *
312 * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
313 * Add code to poll Cyclades-Z. Add code to get & set RS-232 control.
314 * Add code to send break. Clear firmware ID word at startup (so
315 * that other code won't talk to inactive board).
316 *
317 * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
318 * add code for -Z in set_line_char
319 *
320 * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
321 * fold more -Z stuff (or in some cases, error messages)
322 * into driver; add text to "don't know what to do" messages.
323 *
324 * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
325 * moved compile-time flags near top of file; cosmetic changes
326 * to narrow text (to allow 2-up printing); changed many declarations
327 * to "static" to limit external symbols; shuffled code order to
328 * coalesce -Y and -Z specific code, also to put internal functions
329 * in order of tty_driver structure; added code to recognize -Z
330 * ports (and for moment, do nothing or report error); add cy_startup
331 * to parse boot command line for extra base addresses for ISA probes;
332 *
333 * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
334 * reorder some code, fix types of some vars (int vs. long),
335 * add cy_setup to support user declared ISA addresses
336 *
337 * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
338 * dump ioctl based firmware load (it's now a user level
339 * program); ensure uninitialzed ports cannot be used
340 *
341 * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
342 * rename vars and restructure some code
343 *
344 * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
345 * get right status back after boot load
346 *
347 * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
348 * successfully loads firmware
349 *
350 * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
351 * add more of the code for the boot/load ioctls
352 *
353 * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
354 * start to add Z functionality--starting with ioctl
355 * for loading firmware
356 *
357 * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
358 * added code to recognize Z/PCI card at initialization; report
359 * presence, but card is not initialized (because firmware needs
360 * to be loaded)
361 *
362 * Revision 1.36.3.8 1996/06/07 16:29:00 bentson
363 * starting minor number at zero; added missing verify_area
364 * as noted by Heiko Eissfeldt <heiko@colossus.escape.de>
365 *
366 * Revision 1.36.3.7 1996/04/19 21:06:18 bentson
367 * remove unneeded boot message & fix CLOCAL hardware flow
368 * control (Miquel van Smoorenburg <miquels@Q.cistron.nl>);
369 * remove unused diagnostic statements; minor 0 is first;
370 *
371 * Revision 1.36.3.6 1996/03/13 13:21:17 marcio
372 * The kernel function vremap (available only in later 1.3.xx kernels)
373 * allows the access to memory addresses above the RAM. This revision
374 * of the driver supports PCI boards below 1Mb (device id 0x100) and
375 * above 1Mb (device id 0x101).
376 *
377 * Revision 1.36.3.5 1996/03/07 15:20:17 bentson
378 * Some global changes to interrupt handling spilled into
379 * this driver--mostly unused arguments in system function
380 * calls. Also added change by Marcio Saito which should
381 * reduce lost interrupts at startup by fast processors.
382 *
383 * Revision 1.36.3.4 1995/11/13 20:45:10 bentson
384 * Changes by Corey Minyard <minyard@wf-rch.cirr.com> distributed
385 * in 1.3.41 kernel to remove a possible race condition, extend
386 * some error messages, and let the driver run as a loadable module
387 * Change by Alan Wendt <alan@ez0.ezlink.com> to remove a
388 * possible race condition.
389 * Change by Marcio Saito <marcio@cyclades.com> to fix PCI addressing.
390 *
391 * Revision 1.36.3.3 1995/11/13 19:44:48 bentson
392 * Changes by Linus Torvalds in 1.3.33 kernel distribution
393 * required due to reordering of driver initialization.
394 * Drivers are now initialized *after* memory management.
395 *
396 * Revision 1.36.3.2 1995/09/08 22:07:14 bentson
397 * remove printk from ISR; fix typo
398 *
399 * Revision 1.36.3.1 1995/09/01 12:00:42 marcio
400 * Minor fixes in the PCI board support. PCI function calls in
401 * conditional compilation (CONFIG_PCI). Thanks to Jim Duncan
402 * <duncan@okay.com>. "bad serial count" message removed.
403 *
404 * Revision 1.36.3 1995/08/22 09:19:42 marcio
405 * Cyclom-Y/PCI support added. Changes in the cy_init routine and
406 * board initialization. Changes in the boot messages. The driver
407 * supports up to 4 boards and 64 ports by default.
408 *
409 * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
410 * disambiguate between Cyclom-16Y and Cyclom-32Ye;
411 *
412 * Revision 1.36.1.3 1995/03/23 22:15:35 bentson
413 * add missing break in modem control block in ioctl switch statement
414 * (discovered by Michael Edward Chastain <mec@jobe.shell.portal.com>);
415 *
416 * Revision 1.36.1.2 1995/03/22 19:16:22 bentson
417 * make sure CTS flow control is set as soon as possible (thanks
418 * to note from David Lambert <lambert@chesapeake.rps.slb.com>);
419 *
420 * Revision 1.36.1.1 1995/03/13 15:44:43 bentson
421 * initialize defaults for receive threshold and stale data timeout;
422 * cosmetic changes;
423 *
424 * Revision 1.36 1995/03/10 23:33:53 bentson
425 * added support of chips 4-7 in 32 port Cyclom-Ye;
426 * fix cy_interrupt pointer dereference problem
427 * (Joe Portman <baron@aa.net>);
428 * give better error response if open is attempted on non-existent port
429 * (Zachariah Vaum <jchryslr@netcom.com>);
430 * correct command timeout (Kenneth Lerman <lerman@@seltd.newnet.com>);
431 * conditional compilation for -16Y on systems with fast, noisy bus;
432 * comment out diagnostic print function;
433 * cleaned up table of base addresses;
434 * set receiver time-out period register to correct value,
435 * set receive threshold to better default values,
436 * set chip timer to more accurate 200 Hz ticking,
437 * add code to monitor and modify receive parameters
438 * (Rik Faith <faith@cs.unc.edu> Nick Simicich
439 * <njs@scifi.emi.net>);
440 *
441 * Revision 1.35 1994/12/16 13:54:18 steffen
442 * additional patch by Marcio Saito for board detection
443 * Accidently left out in 1.34
444 *
445 * Revision 1.34 1994/12/10 12:37:12 steffen
446 * This is the corrected version as suggested by Marcio Saito
447 *
448 * Revision 1.33 1994/12/01 22:41:18 bentson
449 * add hooks to support more high speeds directly; add tytso
450 * patch regarding CLOCAL wakeups
451 *
452 * Revision 1.32 1994/11/23 19:50:04 bentson
453 * allow direct kernel control of higher signalling rates;
454 * look for cards at additional locations
455 *
456 * Revision 1.31 1994/11/16 04:33:28 bentson
457 * ANOTHER fix from Corey Minyard, minyard@wf-rch.cirr.com--
458 * a problem in chars_in_buffer has been resolved by some
459 * small changes; this should yield smoother output
460 *
461 * Revision 1.30 1994/11/16 04:28:05 bentson
462 * Fix from Corey Minyard, Internet: minyard@metronet.com,
463 * UUCP: minyard@wf-rch.cirr.com, WORK: minyardbnr.ca, to
464 * cy_hangup that appears to clear up much (all?) of the
465 * DTR glitches; also he's added/cleaned-up diagnostic messages
466 *
467 * Revision 1.29 1994/11/16 04:16:07 bentson
468 * add change proposed by Ralph Sims, ralphs@halcyon.com, to
469 * operate higher speeds in same way as other serial ports;
470 * add more serial ports (for up to two 16-port muxes).
471 *
472 * Revision 1.28 1994/11/04 00:13:16 root
473 * turn off diagnostic messages
474 *
475 * Revision 1.27 1994/11/03 23:46:37 root
476 * bunch of changes to bring driver into greater conformance
477 * with the serial.c driver (looking for missed fixes)
478 *
479 * Revision 1.26 1994/11/03 22:40:36 root
480 * automatic interrupt probing fixed.
481 *
482 * Revision 1.25 1994/11/03 20:17:02 root
483 * start to implement auto-irq
484 *
485 * Revision 1.24 1994/11/03 18:01:55 root
486 * still working on modem signals--trying not to drop DTR
487 * during the getty/login processes
488 *
489 * Revision 1.23 1994/11/03 17:51:36 root
490 * extend baud rate support; set receive threshold as function
491 * of baud rate; fix some problems with RTS/CTS;
492 *
493 * Revision 1.22 1994/11/02 18:05:35 root
494 * changed arguments to udelay to type long to get
495 * delays to be of correct duration
496 *
497 * Revision 1.21 1994/11/02 17:37:30 root
498 * employ udelay (after calibrating loops_per_second earlier
499 * in init/main.c) instead of using home-grown delay routines
500 *
501 * Revision 1.20 1994/11/02 03:11:38 root
502 * cy_chars_in_buffer forces a return value of 0 to let
503 * login work (don't know why it does); some functions
504 * that were returning EFAULT, now executes the code;
505 * more work on deciding when to disable xmit interrupts;
506 *
507 * Revision 1.19 1994/11/01 20:10:14 root
508 * define routine to start transmission interrupts (by enabling
509 * transmit interrupts); directly enable/disable modem interrupts;
510 *
511 * Revision 1.18 1994/11/01 18:40:45 bentson
512 * Don't always enable transmit interrupts in startup; interrupt on
513 * TxMpty instead of TxRdy to help characters get out before shutdown;
514 * restructure xmit interrupt to check for chars first and quit if
515 * none are ready to go; modem status (MXVRx) is upright, _not_ inverted
516 * (to my view);
517 *
518 * Revision 1.17 1994/10/30 04:39:45 bentson
519 * rename serial_driver and callout_driver to cy_serial_driver and
520 * cy_callout_driver to avoid linkage interference; initialize
521 * info->type to PORT_CIRRUS; ruggedize paranoia test; elide ->port
522 * from cyclades_port structure; add paranoia check to cy_close;
523 *
524 * Revision 1.16 1994/10/30 01:14:33 bentson
525 * change major numbers; add some _early_ return statements;
526 *
527 * Revision 1.15 1994/10/29 06:43:15 bentson
528 * final tidying up for clean compile; enable some error reporting
529 *
530 * Revision 1.14 1994/10/28 20:30:22 Bentson
531 * lots of changes to drag the driver towards the new tty_io
532 * structures and operation. not expected to work, but may
533 * compile cleanly.
534 *
535 * Revision 1.13 1994/07/21 23:08:57 Bentson
536 * add some diagnostic cruft; support 24 lines (for testing
537 * both -8Y and -16Y cards; be more thorough in servicing all
538 * chips during interrupt; add "volatile" a few places to
539 * circumvent compiler optimizations; fix base & offset
540 * computations in block_til_ready (was causing chip 0 to
541 * stop operation)
542 *
543 * Revision 1.12 1994/07/19 16:42:11 Bentson
544 * add some hackery for kernel version 1.1.8; expand
545 * error messages; refine timing for delay loops and
546 * declare loop params volatile
547 *
548 * Revision 1.11 1994/06/11 21:53:10 bentson
549 * get use of save_car right in transmit interrupt service
550 *
551 * Revision 1.10.1.1 1994/06/11 21:31:18 bentson
552 * add some diagnostic printing; try to fix save_car stuff
553 *
554 * Revision 1.10 1994/06/11 20:36:08 bentson
555 * clean up compiler warnings
556 *
557 * Revision 1.9 1994/06/11 19:42:46 bentson
558 * added a bunch of code to support modem signalling
559 *
560 * Revision 1.8 1994/06/11 17:57:07 bentson
561 * recognize break & parity error
562 *
563 * Revision 1.7 1994/06/05 05:51:34 bentson
564 * Reorder baud table to be monotonic; add cli to CP; discard
565 * incoming characters and status if the line isn't open; start to
566 * fold code into cy_throttle; start to port get_serial_info,
567 * set_serial_info, get_modem_info, set_modem_info, and send_break
568 * from serial.c; expand cy_ioctl; relocate and expand config_setup;
569 * get flow control characters from tty struct; invalidate ports w/o
570 * hardware;
571 *
572 * Revision 1.6 1994/05/31 18:42:21 bentson
573 * add a loop-breaker in the interrupt service routine;
574 * note when port is initialized so that it can be shut
575 * down under the right conditions; receive works without
576 * any obvious errors
577 *
578 * Revision 1.5 1994/05/30 00:55:02 bentson
579 * transmit works without obvious errors
580 *
581 * Revision 1.4 1994/05/27 18:46:27 bentson
582 * incorporated more code from lib_y.c; can now print short
583 * strings under interrupt control to port zero; seems to
584 * select ports/channels/lines correctly
585 *
586 * Revision 1.3 1994/05/25 22:12:44 bentson
587 * shifting from multi-port on a card to proper multiplexor
588 * data structures; added skeletons of most routines
589 *
590 * Revision 1.2 1994/05/19 13:21:43 bentson
591 * start to crib from other sources
592 *
593 */
594
595/* If you need to install more boards than NR_CARDS, change the constant
596 in the definition below. No other change is necessary to support up to
597 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
598
Jiri Slaby02f11752006-12-08 02:39:28 -0800599#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601/*
602 If the total number of ports is larger than NR_PORTS, change this
603 constant in the definition below. No other change is necessary to
604 support more boards/ports. */
605
Jiri Slaby02f11752006-12-08 02:39:28 -0800606#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608#define ZE_V1_NPORTS 64
609#define ZO_V1 0
610#define ZO_V2 1
611#define ZE_V1 2
612
613#define SERIAL_PARANOIA_CHECK
614#undef CY_DEBUG_OPEN
615#undef CY_DEBUG_THROTTLE
616#undef CY_DEBUG_OTHER
617#undef CY_DEBUG_IO
618#undef CY_DEBUG_COUNT
619#undef CY_DEBUG_DTR
620#undef CY_DEBUG_WAIT_UNTIL_SENT
621#undef CY_DEBUG_INTERRUPTS
622#undef CY_16Y_HACK
623#undef CY_ENABLE_MONITORING
624#undef CY_PCI_DEBUG
625
626#if 0
627#define PAUSE __asm__("nop");
628#else
629#define PAUSE ;
630#endif
631
632/*
633 * Include section
634 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635#include <linux/module.h>
636#include <linux/errno.h>
637#include <linux/signal.h>
638#include <linux/sched.h>
639#include <linux/timer.h>
640#include <linux/interrupt.h>
641#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -0800642#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643#include <linux/serial.h>
644#include <linux/major.h>
645#include <linux/string.h>
646#include <linux/fcntl.h>
647#include <linux/ptrace.h>
648#include <linux/cyclades.h>
649#include <linux/mm.h>
650#include <linux/ioport.h>
651#include <linux/init.h>
652#include <linux/delay.h>
653#include <linux/spinlock.h>
654#include <linux/bitops.h>
655
656#include <asm/system.h>
657#include <asm/io.h>
658#include <asm/irq.h>
659#include <asm/uaccess.h>
660
661#define CY_LOCK(info,flags) \
662 do { \
663 spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
664 } while (0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666#define CY_UNLOCK(info,flags) \
667 do { \
668 spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
669 } while (0)
670
671#include <linux/types.h>
672#include <linux/kernel.h>
673#include <linux/pci.h>
674
675#include <linux/stat.h>
676#include <linux/proc_fs.h>
677
Jiri Slaby02f11752006-12-08 02:39:28 -0800678static void cy_throttle(struct tty_struct *tty);
679static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681#define IS_CYC_Z(card) ((card).num_chips == -1)
682
683#define Z_FPGA_CHECK(card) \
Jiri Slaby02f11752006-12-08 02:39:28 -0800684 ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
685 ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
688 ((card).ctl_addr))->mail_box_0)) || \
689 Z_FPGA_CHECK(card)) && \
690 (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \
691 ((card).base_addr+ID_ADDRESS))->signature)))
692
693#ifndef SERIAL_XMIT_SIZE
694#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
695#endif
696#define WAKEUP_CHARS 256
697
698#define STD_COM_FLAGS (0)
699
700#define JIFFIES_DIFF(n, j) ((j) - (n))
701
702static struct tty_driver *cy_serial_driver;
703
704#ifdef CONFIG_ISA
705/* This is the address lookup table. The driver will probe for
706 Cyclom-Y/ISA boards at all addresses in here. If you want the
707 driver to probe addresses at a different address, add it to
708 this table. If the driver is probing some other board and
709 causing problems, remove the offending address from this table.
710 The cy_setup function extracts additional addresses from the
711 boot options line. The form is "cyclades=address,address..."
712*/
713
714static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800715 0xD0000,
716 0xD2000,
717 0xD4000,
718 0xD6000,
719 0xD8000,
720 0xDA000,
721 0xDC000,
722 0xDE000,
723 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724};
Jiri Slaby02f11752006-12-08 02:39:28 -0800725
Tobias Klauserfe971072006-01-09 20:54:02 -0800726#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728#ifdef MODULE
729static long maddr[NR_CARDS] = { 0, };
Jiri Slaby02f11752006-12-08 02:39:28 -0800730static int irq[NR_CARDS] = { 0, };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732module_param_array(maddr, long, NULL, 0);
733module_param_array(irq, int, NULL, 0);
734#endif
735
Jiri Slaby02f11752006-12-08 02:39:28 -0800736#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738/* This is the per-card data structure containing address, irq, number of
739 channels, etc. This driver supports a maximum of NR_CARDS cards.
740*/
741static struct cyclades_card cy_card[NR_CARDS];
742
743/* This is the per-channel data structure containing pointers, flags
744 and variables for the port. This driver supports a maximum of NR_PORTS.
745*/
746static struct cyclades_port cy_port[NR_PORTS];
747
Jiri Slaby02f11752006-12-08 02:39:28 -0800748static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 * This is used to look up the divisor speeds and the timeouts
752 * We're normally limited to 15 distinct baud rates. The extra
753 * are accessed via settings in info->flags.
754 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
755 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
756 * HI VHI
757 * 20
758 */
759static int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800760 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
761 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
762 230400, 0
763};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Jiri Slaby02f11752006-12-08 02:39:28 -0800765static char baud_co_25[] = { /* 25 MHz clock option table */
766 /* value => 00 01 02 03 04 */
767 /* divide by 8 32 128 512 2048 */
768 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
769 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
770};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Jiri Slaby02f11752006-12-08 02:39:28 -0800772static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
773 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
774 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
775};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Jiri Slaby02f11752006-12-08 02:39:28 -0800777static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
778 /* value => 00 01 02 03 04 */
779 /* divide by 8 32 128 512 2048 */
780 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
781 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00
783};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Jiri Slaby02f11752006-12-08 02:39:28 -0800785static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
786 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
787 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
788 0x21
789};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Jiri Slaby02f11752006-12-08 02:39:28 -0800791static char baud_cor3[] = { /* receive threshold */
792 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
793 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
794 0x07
795};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797/*
798 * The Cyclades driver implements HW flow control as any serial driver.
799 * The cyclades_port structure member rflow and the vector rflow_thr
800 * allows us to take advantage of a special feature in the CD1400 to avoid
801 * data loss even when the system interrupt latency is too high. These flags
802 * are to be used only with very special applications. Setting these flags
803 * requires the use of a special cable (DTR and RTS reversed). In the new
804 * CD1400-based boards (rev. 6.00 or later), there is no need for special
805 * cables.
806 */
807
Jiri Slaby02f11752006-12-08 02:39:28 -0800808static char rflow_thr[] = { /* rflow threshold */
809 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
811 0x0a
812};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814/* The Cyclom-Ye has placed the sequential chips in non-sequential
815 * address order. This look-up table overcomes that problem.
816 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800817static int cy_chip_offset[] = { 0x0000,
818 0x0400,
819 0x0800,
820 0x0C00,
821 0x0200,
822 0x0600,
823 0x0A00,
824 0x0E00
825};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
827/* PCI related definitions */
828
Jiri Slaby02f11752006-12-08 02:39:28 -0800829static unsigned short cy_pci_nboard;
830static unsigned short cy_isa_nboard;
831static unsigned short cy_nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -0800833static unsigned short cy_pci_dev_id[] = {
834 PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */
835 PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */
836 PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */
837 PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */
838 PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */
839 PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */
840 PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */
841 PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */
842 0 /* end of table */
843};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#endif
845
846static void cy_start(struct tty_struct *);
847static void set_line_char(struct cyclades_port *);
848static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
849#ifdef CONFIG_ISA
850static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800851#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Jiri Slaby02f11752006-12-08 02:39:28 -0800853static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855#ifndef CONFIG_CYZ_INTR
856static void cyz_poll(unsigned long);
857
858/* The Cyclades-Z polling cycle is defined by this variable */
859static long cyz_polling_cycle = CZ_DEF_POLL;
860
861static int cyz_timeron = 0;
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700862static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Jiri Slaby02f11752006-12-08 02:39:28 -0800864#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865static void cyz_rx_restart(unsigned long);
866static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800867#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Jiri Slaby02f11752006-12-08 02:39:28 -0800869static inline int serial_paranoia_check(struct cyclades_port *info,
870 char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
872#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800873 static const char *badmagic =
874 "cyc Warning: bad magic number for serial struct (%s) in %s\n";
875 static const char *badinfo =
876 "cyc Warning: null cyclades_port for (%s) in %s\n";
877 static const char *badrange =
878 "cyc Warning: cyclades_port out of range for (%s) in %s\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Jiri Slaby02f11752006-12-08 02:39:28 -0800880 if (!info) {
881 printk(badinfo, name, routine);
882 return 1;
883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Jiri Slaby02f11752006-12-08 02:39:28 -0800885 if ((long)info < (long)(&cy_port[0]) ||
886 (long)(&cy_port[NR_PORTS]) < (long)info) {
887 printk(badrange, name, routine);
888 return 1;
889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Jiri Slaby02f11752006-12-08 02:39:28 -0800891 if (info->magic != CYCLADES_MAGIC) {
892 printk(badmagic, name, routine);
893 return 1;
894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800896 return 0;
897} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899/*
900 * This routine is used by the interrupt handler to schedule
901 * processing in the software interrupt portion of the driver
902 * (also known as the "bottom half"). This can be called any
903 * number of times for any channel without harm.
904 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800905static inline void cy_sched_event(struct cyclades_port *info, int event)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
Jiri Slaby02f11752006-12-08 02:39:28 -0800907 info->event |= 1 << event; /* remember what kind of event and who */
908 schedule_work(&info->tqueue);
909} /* cy_sched_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911/*
912 * This routine is used to handle the "bottom half" processing for the
913 * serial driver, known also the "software interrupt" processing.
914 * This processing is done at the kernel interrupt level, after the
915 * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
916 * is where time-consuming activities which can not be done in the
917 * interrupt driver proper are done; the interrupt driver schedules
918 * them using cy_sched_event(), and they get done here.
919 *
920 * This is done through one level of indirection--the task queue.
921 * When a hardware interrupt service routine wants service by the
922 * driver's bottom half, it enqueues the appropriate tq_struct (one
923 * per port) to the keventd work queue and sets a request flag
924 * that the work queue be processed.
925 *
926 * Although this may seem unwieldy, it gives the system a way to
927 * pass an argument (in this case the pointer to the cyclades_port
928 * structure) to the bottom half of the driver. Previous kernels
929 * had to poll every port to see if that port needed servicing.
930 */
931static void
David Howellsc4028952006-11-22 14:57:56 +0000932do_softint(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
David Howellsc4028952006-11-22 14:57:56 +0000934 struct cyclades_port *info =
935 container_of(work, struct cyclades_port, tqueue);
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Jiri Slaby02f11752006-12-08 02:39:28 -0800938 tty = info->tty;
939 if (!tty)
940 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Jiri Slaby02f11752006-12-08 02:39:28 -0800942 if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
943 tty_hangup(info->tty);
944 wake_up_interruptible(&info->open_wait);
945 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800947 if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
948 wake_up_interruptible(&info->open_wait);
949#ifdef CONFIG_CYZ_INTR
950 if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
951 if (cyz_rx_full_timer[info->line].function == NULL) {
952 cyz_rx_full_timer[info->line].expires = jiffies + 1;
953 cyz_rx_full_timer[info->line].function = cyz_rx_restart;
954 cyz_rx_full_timer[info->line].data =
955 (unsigned long)info;
956 add_timer(&cyz_rx_full_timer[info->line]);
957 }
958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800960 if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
961 wake_up_interruptible(&info->delta_msr_wait);
962 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#ifdef Z_WAKE
Jiri Slaby02f11752006-12-08 02:39:28 -0800964 if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
965 wake_up_interruptible(&info->shutdown_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966#endif
967} /* do_softint */
968
969
970/***********************************************************/
971/********* Start of block of Cyclom-Y specific code ********/
972
973/* This routine waits up to 1000 micro-seconds for the previous
974 command to the Cirrus chip to complete and then issues the
975 new command. An error is returned if the previous command
976 didn't finish within the time limit.
977
978 This function is only called from inside spinlock-protected code.
979 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800980static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
Jiri Slaby02f11752006-12-08 02:39:28 -0800982 volatile int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Jiri Slaby02f11752006-12-08 02:39:28 -0800984 /* Check to see that the previous command has completed */
985 for (i = 0; i < 100; i++) {
986 if (cy_readb(base_addr + (CyCCR << index)) == 0) {
987 break;
988 }
989 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800991 /* if the CCR never cleared, the previous command
992 didn't finish within the "reasonable time" */
993 if (i == 100)
994 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Jiri Slaby02f11752006-12-08 02:39:28 -0800996 /* Issue the new command */
997 cy_writeb(base_addr + (CyCCR << index), cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
Jiri Slaby02f11752006-12-08 02:39:28 -0800999 return (0);
1000} /* cyy_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002#ifdef CONFIG_ISA
1003/* ISA interrupt detection code */
Jiri Slaby02f11752006-12-08 02:39:28 -08001004static unsigned detect_isa_irq(void __iomem * address)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
Jiri Slaby02f11752006-12-08 02:39:28 -08001006 int irq;
1007 unsigned long irqs, flags;
1008 int save_xir, save_car;
1009 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Jiri Slaby02f11752006-12-08 02:39:28 -08001011 /* forget possible initially masked and pending IRQ */
1012 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Jiri Slaby02f11752006-12-08 02:39:28 -08001014 /* Clear interrupts on the board first */
1015 cy_writeb(address + (Cy_ClrIntr << index), 0);
1016 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Jiri Slaby02f11752006-12-08 02:39:28 -08001018 irqs = probe_irq_on();
1019 /* Wait ... */
1020 udelay(5000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Jiri Slaby02f11752006-12-08 02:39:28 -08001022 /* Enable the Tx interrupts on the CD1400 */
1023 local_irq_save(flags);
1024 cy_writeb(address + (CyCAR << index), 0);
1025 cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Jiri Slaby02f11752006-12-08 02:39:28 -08001027 cy_writeb(address + (CyCAR << index), 0);
1028 cy_writeb(address + (CySRER << index),
1029 cy_readb(address + (CySRER << index)) | CyTxRdy);
1030 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Jiri Slaby02f11752006-12-08 02:39:28 -08001032 /* Wait ... */
1033 udelay(5000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Jiri Slaby02f11752006-12-08 02:39:28 -08001035 /* Check which interrupt is in use */
1036 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Jiri Slaby02f11752006-12-08 02:39:28 -08001038 /* Clean up */
1039 save_xir = (u_char) cy_readb(address + (CyTIR << index));
1040 save_car = cy_readb(address + (CyCAR << index));
1041 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
1042 cy_writeb(address + (CySRER << index),
1043 cy_readb(address + (CySRER << index)) & ~CyTxRdy);
1044 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
1045 cy_writeb(address + (CyCAR << index), (save_car));
1046 cy_writeb(address + (Cy_ClrIntr << index), 0);
1047 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Jiri Slaby02f11752006-12-08 02:39:28 -08001049 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050}
Jiri Slaby02f11752006-12-08 02:39:28 -08001051#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Jiri Slabye9410272006-12-08 02:39:28 -08001053static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
Jiri Slaby02f11752006-12-08 02:39:28 -08001054 void __iomem * base_addr, int status, int index)
Jiri Slabye9410272006-12-08 02:39:28 -08001055{
1056 struct cyclades_port *info;
1057 struct tty_struct *tty;
1058 volatile int char_count;
1059 int i, j, len, mdm_change, mdm_status, outch;
1060 int save_xir, channel, save_car;
1061 char data;
1062
Jiri Slaby02f11752006-12-08 02:39:28 -08001063 if (status & CySRReceive) { /* reception interrupt */
Jiri Slabye9410272006-12-08 02:39:28 -08001064#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby02f11752006-12-08 02:39:28 -08001065 printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
Jiri Slabye9410272006-12-08 02:39:28 -08001066#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001067 /* determine the channel & change to that context */
1068 spin_lock(&cinfo->card_lock);
1069 save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
1070 channel = (u_short) (save_xir & CyIRChannel);
1071 i = channel + chip * 4 + cinfo->first_line;
1072 info = &cy_port[i];
1073 info->last_active = jiffies;
1074 save_car = cy_readb(base_addr + (CyCAR << index));
1075 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001076
Jiri Slaby02f11752006-12-08 02:39:28 -08001077 /* if there is nowhere to put the data, discard it */
1078 if (info->tty == 0) {
1079 j = (cy_readb(base_addr + (CyRIVR << index)) &
1080 CyIVRMask);
1081 if (j == CyIVRRxEx) { /* exception */
1082 data = cy_readb(base_addr + (CyRDSR << index));
1083 } else { /* normal character reception */
1084 char_count = cy_readb(base_addr +
1085 (CyRDCR << index));
1086 while (char_count--) {
1087 data = cy_readb(base_addr +
1088 (CyRDSR << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001089 }
Jiri Slabye9410272006-12-08 02:39:28 -08001090 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001091 } else { /* there is an open port for this data */
1092 tty = info->tty;
1093 j = (cy_readb(base_addr + (CyRIVR << index)) &
1094 CyIVRMask);
1095 if (j == CyIVRRxEx) { /* exception */
1096 data = cy_readb(base_addr + (CyRDSR << index));
1097
1098 /* For statistics only */
1099 if (data & CyBREAK)
1100 info->icount.brk++;
1101 else if (data & CyFRAME)
1102 info->icount.frame++;
1103 else if (data & CyPARITY)
1104 info->icount.parity++;
1105 else if (data & CyOVERRUN)
1106 info->icount.overrun++;
1107
1108 if (data & info->ignore_status_mask) {
1109 info->icount.rx++;
1110 return;
1111 }
1112 if (tty_buffer_request_room(tty, 1)) {
1113 if (data & info->read_status_mask) {
1114 if (data & CyBREAK) {
1115 tty_insert_flip_char(
1116 tty,
1117 cy_readb(
1118 base_addr +
1119 (CyRDSR <<
1120 index)),
1121 TTY_BREAK);
1122 info->icount.rx++;
1123 if (info->flags &
1124 ASYNC_SAK) {
1125 do_SAK(tty);
1126 }
1127 } else if (data & CyFRAME) {
1128 tty_insert_flip_char(
1129 tty,
1130 cy_readb(
1131 base_addr +
1132 (CyRDSR <<
1133 index)),
1134 TTY_FRAME);
1135 info->icount.rx++;
1136 info->idle_stats.
1137 frame_errs++;
1138 } else if (data & CyPARITY) {
1139 /* Pieces of seven... */
1140 tty_insert_flip_char(
1141 tty,
1142 cy_readb(
1143 base_addr +
1144 (CyRDSR <<
1145 index)),
1146 TTY_PARITY);
1147 info->icount.rx++;
1148 info->idle_stats.
1149 parity_errs++;
1150 } else if (data & CyOVERRUN) {
1151 tty_insert_flip_char(
1152 tty, 0,
1153 TTY_OVERRUN);
1154 info->icount.rx++;
1155 /* If the flip buffer itself is
1156 overflowing, we still lose
1157 the next incoming character.
1158 */
1159 tty_insert_flip_char(
1160 tty,
1161 cy_readb(
1162 base_addr +
1163 (CyRDSR <<
1164 index)),
1165 TTY_FRAME);
1166 info->icount.rx++;
1167 info->idle_stats.
1168 overruns++;
1169 /* These two conditions may imply */
1170 /* a normal read should be done. */
1171 /* }else if(data & CyTIMEOUT){ */
1172 /* }else if(data & CySPECHAR){ */
1173 } else {
1174 tty_insert_flip_char(
1175 tty, 0,
1176 TTY_NORMAL);
1177 info->icount.rx++;
1178 }
1179 } else {
1180 tty_insert_flip_char(tty, 0,
1181 TTY_NORMAL);
1182 info->icount.rx++;
1183 }
1184 } else {
1185 /* there was a software buffer
1186 overrun and nothing could be
1187 done about it!!! */
1188 info->icount.buf_overrun++;
1189 info->idle_stats.overruns++;
1190 }
1191 } else { /* normal character reception */
1192 /* load # chars available from the chip */
1193 char_count = cy_readb(base_addr +
1194 (CyRDCR << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001195
1196#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -08001197 ++info->mon.int_count;
1198 info->mon.char_count += char_count;
1199 if (char_count > info->mon.char_max)
1200 info->mon.char_max = char_count;
1201 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -08001202#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001203 len = tty_buffer_request_room(tty, char_count);
1204 while (len--) {
1205 data = cy_readb(base_addr +
1206 (CyRDSR << index));
1207 tty_insert_flip_char(tty, data,
1208 TTY_NORMAL);
1209 info->idle_stats.recv_bytes++;
1210 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -08001211#ifdef CY_16Y_HACK
Jiri Slaby02f11752006-12-08 02:39:28 -08001212 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -08001213#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001214 }
1215 info->idle_stats.recv_idle = jiffies;
1216 }
1217 tty_schedule_flip(tty);
Jiri Slabye9410272006-12-08 02:39:28 -08001218 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001219 /* end of service */
1220 cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
1221 cy_writeb(base_addr + (CyCAR << index), (save_car));
1222 spin_unlock(&cinfo->card_lock);
Jiri Slabye9410272006-12-08 02:39:28 -08001223 }
1224
Jiri Slaby02f11752006-12-08 02:39:28 -08001225 if (status & CySRTransmit) { /* transmission interrupt */
1226 /* Since we only get here when the transmit buffer
1227 is empty, we know we can always stuff a dozen
1228 characters. */
Jiri Slabye9410272006-12-08 02:39:28 -08001229#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby02f11752006-12-08 02:39:28 -08001230 printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
Jiri Slabye9410272006-12-08 02:39:28 -08001231#endif
1232
Jiri Slaby02f11752006-12-08 02:39:28 -08001233 /* determine the channel & change to that context */
1234 spin_lock(&cinfo->card_lock);
1235 save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
1236 channel = (u_short) (save_xir & CyIRChannel);
1237 i = channel + chip * 4 + cinfo->first_line;
1238 save_car = cy_readb(base_addr + (CyCAR << index));
1239 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001240
Jiri Slaby02f11752006-12-08 02:39:28 -08001241 /* validate the port# (as configured and open) */
1242 if ((i < 0) || (NR_PORTS <= i)) {
1243 cy_writeb(base_addr + (CySRER << index),
1244 cy_readb(base_addr + (CySRER << index)) &
1245 ~CyTxRdy);
1246 goto txend;
1247 }
1248 info = &cy_port[i];
1249 info->last_active = jiffies;
1250 if (info->tty == 0) {
1251 cy_writeb(base_addr + (CySRER << index),
1252 cy_readb(base_addr + (CySRER << index)) &
1253 ~CyTxRdy);
1254 goto txdone;
1255 }
Jiri Slabye9410272006-12-08 02:39:28 -08001256
Jiri Slaby02f11752006-12-08 02:39:28 -08001257 /* load the on-chip space for outbound data */
1258 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -08001259
Jiri Slaby02f11752006-12-08 02:39:28 -08001260 if (info->x_char) { /* send special char */
1261 outch = info->x_char;
1262 cy_writeb(base_addr + (CyTDR << index), outch);
Jiri Slabye9410272006-12-08 02:39:28 -08001263 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -08001264 info->icount.tx++;
1265 info->x_char = 0;
Jiri Slabye9410272006-12-08 02:39:28 -08001266 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001267
1268 if (info->breakon || info->breakoff) {
1269 if (info->breakon) {
1270 cy_writeb(base_addr + (CyTDR << index), 0);
1271 cy_writeb(base_addr + (CyTDR << index), 0x81);
1272 info->breakon = 0;
1273 char_count -= 2;
1274 }
1275 if (info->breakoff) {
1276 cy_writeb(base_addr + (CyTDR << index), 0);
1277 cy_writeb(base_addr + (CyTDR << index), 0x83);
1278 info->breakoff = 0;
1279 char_count -= 2;
1280 }
1281 }
1282
1283 while (char_count-- > 0) {
1284 if (!info->xmit_cnt) {
1285 if (cy_readb(base_addr + (CySRER << index)) &
1286 CyTxMpty) {
1287 cy_writeb(base_addr + (CySRER << index),
1288 cy_readb(base_addr +
1289 (CySRER << index)) &
1290 ~CyTxMpty);
1291 } else {
1292 cy_writeb(base_addr + (CySRER << index),
1293 (cy_readb(base_addr +
1294 (CySRER << index)) &
1295 ~CyTxRdy) | CyTxMpty);
1296 }
1297 goto txdone;
1298 }
1299 if (info->xmit_buf == 0) {
1300 cy_writeb(base_addr + (CySRER << index),
1301 cy_readb(base_addr + (CySRER << index))&
1302 ~CyTxRdy);
1303 goto txdone;
1304 }
1305 if (info->tty->stopped || info->tty->hw_stopped) {
1306 cy_writeb(base_addr + (CySRER << index),
1307 cy_readb(base_addr + (CySRER << index))&
1308 ~CyTxRdy);
1309 goto txdone;
1310 }
1311 /* Because the Embedded Transmit Commands have
1312 been enabled, we must check to see if the
1313 escape character, NULL, is being sent. If it
1314 is, we must ensure that there is room for it
1315 to be doubled in the output stream. Therefore
1316 we no longer advance the pointer when the
1317 character is fetched, but rather wait until
1318 after the check for a NULL output character.
1319 This is necessary because there may not be
1320 room for the two chars needed to send a NULL.)
1321 */
1322 outch = info->xmit_buf[info->xmit_tail];
1323 if (outch) {
1324 info->xmit_cnt--;
1325 info->xmit_tail = (info->xmit_tail + 1) &
1326 (SERIAL_XMIT_SIZE - 1);
1327 cy_writeb(base_addr + (CyTDR << index), outch);
1328 info->icount.tx++;
1329 } else {
1330 if (char_count > 1) {
1331 info->xmit_cnt--;
1332 info->xmit_tail = (info->xmit_tail + 1)&
1333 (SERIAL_XMIT_SIZE - 1);
1334 cy_writeb(base_addr + (CyTDR << index),
1335 outch);
1336 cy_writeb(base_addr + (CyTDR << index),
1337 0);
1338 info->icount.tx++;
1339 char_count--;
1340 } else {
1341 }
1342 }
1343 }
Jiri Slabye9410272006-12-08 02:39:28 -08001344
1345txdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001346 if (info->xmit_cnt < WAKEUP_CHARS) {
1347 cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
1348 }
Jiri Slabye9410272006-12-08 02:39:28 -08001349txend:
Jiri Slaby02f11752006-12-08 02:39:28 -08001350 /* end of service */
1351 cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
1352 cy_writeb(base_addr + (CyCAR << index), (save_car));
1353 spin_unlock(&cinfo->card_lock);
Jiri Slabye9410272006-12-08 02:39:28 -08001354 }
1355
Jiri Slaby02f11752006-12-08 02:39:28 -08001356 if (status & CySRModem) { /* modem interrupt */
Jiri Slabye9410272006-12-08 02:39:28 -08001357
Jiri Slaby02f11752006-12-08 02:39:28 -08001358 /* determine the channel & change to that context */
1359 spin_lock(&cinfo->card_lock);
1360 save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
1361 channel = (u_short) (save_xir & CyIRChannel);
1362 info = &cy_port[channel + chip * 4 + cinfo->first_line];
1363 info->last_active = jiffies;
1364 save_car = cy_readb(base_addr + (CyCAR << index));
1365 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001366
Jiri Slaby02f11752006-12-08 02:39:28 -08001367 mdm_change = cy_readb(base_addr + (CyMISR << index));
1368 mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001369
Jiri Slaby02f11752006-12-08 02:39:28 -08001370 if (info->tty == 0) { /* no place for data, ignore it */
1371 ;
1372 } else {
1373 if (mdm_change & CyANY_DELTA) {
1374 /* For statistics only */
1375 if (mdm_change & CyDCD)
1376 info->icount.dcd++;
1377 if (mdm_change & CyCTS)
1378 info->icount.cts++;
1379 if (mdm_change & CyDSR)
1380 info->icount.dsr++;
1381 if (mdm_change & CyRI)
1382 info->icount.rng++;
Jiri Slabye9410272006-12-08 02:39:28 -08001383
Jiri Slaby02f11752006-12-08 02:39:28 -08001384 cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
Jiri Slabye9410272006-12-08 02:39:28 -08001385 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001386
1387 if ((mdm_change & CyDCD) &&
1388 (info->flags & ASYNC_CHECK_CD)) {
1389 if (mdm_status & CyDCD) {
1390 cy_sched_event(info,
1391 Cy_EVENT_OPEN_WAKEUP);
1392 } else {
1393 cy_sched_event(info, Cy_EVENT_HANGUP);
1394 }
Jiri Slabye9410272006-12-08 02:39:28 -08001395 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001396 if ((mdm_change & CyCTS) &&
1397 (info->flags & ASYNC_CTS_FLOW)) {
1398 if (info->tty->hw_stopped) {
1399 if (mdm_status & CyCTS) {
1400 /* cy_start isn't used
1401 because... !!! */
1402 info->tty->hw_stopped = 0;
1403 cy_writeb(base_addr +
1404 (CySRER << index),
1405 cy_readb(base_addr +
1406 (CySRER <<
1407 index))|
1408 CyTxRdy);
1409 cy_sched_event(info,
1410 Cy_EVENT_WRITE_WAKEUP);
1411 }
1412 } else {
1413 if (!(mdm_status & CyCTS)) {
1414 /* cy_stop isn't used
1415 because ... !!! */
1416 info->tty->hw_stopped = 1;
1417 cy_writeb(base_addr +
1418 (CySRER << index),
1419 cy_readb(base_addr +
1420 (CySRER <<
1421 index)) &
1422 ~CyTxRdy);
1423 }
1424 }
1425 }
1426 if (mdm_change & CyDSR) {
1427 }
1428 if (mdm_change & CyRI) {
1429 }
Jiri Slabye9410272006-12-08 02:39:28 -08001430 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001431 /* end of service */
1432 cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
1433 cy_writeb(base_addr + (CyCAR << index), save_car);
1434 spin_unlock(&cinfo->card_lock);
Jiri Slabye9410272006-12-08 02:39:28 -08001435 }
1436}
1437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438/* The real interrupt service routine is called
1439 whenever the card wants its hand held--chars
1440 received, out buffer empty, modem change, etc.
1441 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001442static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
Jiri Slaby02f11752006-12-08 02:39:28 -08001444 int status;
1445 struct cyclades_card *cinfo;
1446 void __iomem *base_addr, *card_base_addr;
1447 int chip;
1448 int index;
1449 int too_many;
1450 int had_work;
Jiri Slabye9410272006-12-08 02:39:28 -08001451
Jiri Slaby02f11752006-12-08 02:39:28 -08001452 if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby02f11752006-12-08 02:39:28 -08001454 printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001456 return IRQ_NONE; /* spurious interrupt */
1457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Jiri Slaby02f11752006-12-08 02:39:28 -08001459 card_base_addr = cinfo->base_addr;
1460 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Jiri Slaby02f11752006-12-08 02:39:28 -08001462 /* This loop checks all chips in the card. Make a note whenever
1463 _any_ chip had some work to do, as this is considered an
1464 indication that there will be more to do. Only when no chip
1465 has any work does this outermost loop exit.
1466 */
1467 do {
1468 had_work = 0;
1469 for (chip = 0; chip < cinfo->num_chips; chip++) {
1470 base_addr = cinfo->base_addr +
1471 (cy_chip_offset[chip] << index);
1472 too_many = 0;
1473 while ((status = cy_readb(base_addr +
1474 (CySVRR << index))) != 0x00) {
1475 had_work++;
1476 /* The purpose of the following test is to ensure that
1477 no chip can monopolize the driver. This forces the
1478 chips to be checked in a round-robin fashion (after
1479 draining each of a bunch (1000) of characters).
1480 */
1481 if (1000 < too_many++) {
1482 break;
1483 }
1484 cyy_intr_chip(cinfo, chip, base_addr, status,
1485 index);
1486 }
1487 }
1488 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Jiri Slaby02f11752006-12-08 02:39:28 -08001490 /* clear interrupts */
1491 spin_lock(&cinfo->card_lock);
1492 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
1493 /* Cy_ClrIntr is 0x1800 */
1494 spin_unlock(&cinfo->card_lock);
1495 return IRQ_HANDLED;
1496} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
1498/***********************************************************/
1499/********* End of block of Cyclom-Y specific code **********/
1500/******** Start of block of Cyclades-Z specific code *********/
1501/***********************************************************/
1502
1503static int
Jiri Slaby02f11752006-12-08 02:39:28 -08001504cyz_fetch_msg(struct cyclades_card *cinfo,
1505 uclong * channel, ucchar * cmd, uclong * param)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
Jiri Slaby02f11752006-12-08 02:39:28 -08001507 struct FIRM_ID __iomem *firm_id;
1508 struct ZFW_CTRL __iomem *zfw_ctrl;
1509 struct BOARD_CTRL __iomem *board_ctrl;
1510 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Jiri Slaby02f11752006-12-08 02:39:28 -08001512 firm_id = cinfo->base_addr + ID_ADDRESS;
1513 if (!ISZLOADED(*cinfo)) {
1514 return (-1);
1515 }
1516 zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
1517 0xfffff);
1518 board_ctrl = &zfw_ctrl->board_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Jiri Slaby02f11752006-12-08 02:39:28 -08001520 loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
1521 (cinfo->ctl_addr))->loc_doorbell);
1522 if (loc_doorbell) {
1523 *cmd = (char)(0xff & loc_doorbell);
1524 *channel = cy_readl(&board_ctrl->fwcmd_channel);
1525 *param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
1526 cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
1527 loc_doorbell, 0xffffffff);
1528 return 1;
1529 }
1530 return 0;
1531} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533static int
Jiri Slaby02f11752006-12-08 02:39:28 -08001534cyz_issue_cmd(struct cyclades_card *cinfo,
1535 uclong channel, ucchar cmd, uclong param)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
Jiri Slaby02f11752006-12-08 02:39:28 -08001537 struct FIRM_ID __iomem *firm_id;
1538 struct ZFW_CTRL __iomem *zfw_ctrl;
1539 struct BOARD_CTRL __iomem *board_ctrl;
1540 unsigned long __iomem *pci_doorbell;
1541 int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Jiri Slaby02f11752006-12-08 02:39:28 -08001543 firm_id = cinfo->base_addr + ID_ADDRESS;
1544 if (!ISZLOADED(*cinfo)) {
1545 return (-1);
1546 }
1547 zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
1548 0xfffff);
1549 board_ctrl = &zfw_ctrl->board_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Jiri Slaby02f11752006-12-08 02:39:28 -08001551 index = 0;
1552 pci_doorbell =
1553 &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
1554 while ((cy_readl(pci_doorbell) & 0xff) != 0) {
1555 if (index++ == 1000) {
1556 return ((int)(cy_readl(pci_doorbell) & 0xff));
1557 }
1558 udelay(50L);
1559 }
1560 cy_writel(&board_ctrl->hcmd_channel, channel);
1561 cy_writel(&board_ctrl->hcmd_param, param);
1562 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
Jiri Slaby02f11752006-12-08 02:39:28 -08001564 return (0);
1565} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567static void
1568cyz_handle_rx(struct cyclades_port *info,
Jiri Slaby02f11752006-12-08 02:39:28 -08001569 volatile struct CH_CTRL __iomem * ch_ctrl,
1570 volatile struct BUF_CTRL __iomem * buf_ctrl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
Jiri Slaby02f11752006-12-08 02:39:28 -08001572 struct cyclades_card *cinfo = &cy_card[info->card];
1573 struct tty_struct *tty = info->tty;
1574 volatile int char_count;
1575 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001577 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578#else
Jiri Slaby02f11752006-12-08 02:39:28 -08001579 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001581 volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Jiri Slaby02f11752006-12-08 02:39:28 -08001583 rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
1584 rx_put = cy_readl(&buf_ctrl->rx_put);
1585 rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
1586 rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
1587 if (rx_put >= rx_get)
1588 char_count = rx_put - rx_get;
1589 else
1590 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Jiri Slaby02f11752006-12-08 02:39:28 -08001592 if (char_count) {
1593 info->last_active = jiffies;
1594 info->jiffies[1] = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -08001597 info->mon.int_count++;
1598 info->mon.char_count += char_count;
1599 if (char_count > info->mon.char_max)
1600 info->mon.char_max = char_count;
1601 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001603 if (tty == 0) {
1604 /* flush received characters */
1605 new_rx_get = (new_rx_get + char_count) &
1606 (rx_bufsize - 1);
1607 info->rflush_count++;
1608 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001610 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
1611 for performance, but because of buffer boundaries, there
1612 may be several steps to the operation */
1613 while (0 < (small_count = min_t(unsigned int,
1614 rx_bufsize - new_rx_get,
1615 min_t(unsigned int, TTY_FLIPBUF_SIZE -
1616 tty->flip.count, char_count)))){
1617 memcpy_fromio(tty->flip.char_buf_ptr,
1618 (char *)(cinfo->base_addr + rx_bufaddr +
1619 new_rx_get),
1620 small_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Jiri Slaby02f11752006-12-08 02:39:28 -08001622 tty->flip.char_buf_ptr += small_count;
1623 memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
1624 small_count);
1625 tty->flip.flag_buf_ptr += small_count;
1626 new_rx_get = (new_rx_get + small_count) &
1627 (rx_bufsize - 1);
1628 char_count -= small_count;
1629 info->icount.rx += small_count;
1630 info->idle_stats.recv_bytes += small_count;
1631 tty->flip.count += small_count;
1632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633#else
Jiri Slaby02f11752006-12-08 02:39:28 -08001634 len = tty_buffer_request_room(tty, char_count);
1635 while (len--) {
1636 data = cy_readb(cinfo->base_addr + rx_bufaddr +
1637 new_rx_get);
1638 new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
1639 tty_insert_flip_char(tty, data, TTY_NORMAL);
1640 info->idle_stats.recv_bytes++;
1641 info->icount.rx++;
1642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643#endif
1644#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001645 /* Recalculate the number of chars in the RX buffer and issue
1646 a cmd in case it's higher than the RX high water mark */
1647 rx_put = cy_readl(&buf_ctrl->rx_put);
1648 if (rx_put >= rx_get)
1649 char_count = rx_put - rx_get;
1650 else
1651 char_count = rx_put - rx_get + rx_bufsize;
1652 if (char_count >= cy_readl(&buf_ctrl->rx_threshold)) {
1653 cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
1654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001656 info->idle_stats.recv_idle = jiffies;
1657 tty_schedule_flip(tty);
1658 }
1659 /* Update rx_get */
1660 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662}
1663
1664static void
1665cyz_handle_tx(struct cyclades_port *info,
Jiri Slaby02f11752006-12-08 02:39:28 -08001666 volatile struct CH_CTRL __iomem * ch_ctrl,
1667 volatile struct BUF_CTRL __iomem * buf_ctrl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668{
Jiri Slaby02f11752006-12-08 02:39:28 -08001669 struct cyclades_card *cinfo = &cy_card[info->card];
1670 struct tty_struct *tty = info->tty;
1671 char data;
1672 volatile int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001674 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001676 volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Jiri Slaby02f11752006-12-08 02:39:28 -08001678 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1679 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Jiri Slaby02f11752006-12-08 02:39:28 -08001681 tx_get = cy_readl(&buf_ctrl->tx_get);
1682 tx_put = cy_readl(&buf_ctrl->tx_put);
1683 tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
1684 tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
1685 if (tx_put >= tx_get)
1686 char_count = tx_get - tx_put - 1 + tx_bufsize;
1687 else
1688 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Jiri Slaby02f11752006-12-08 02:39:28 -08001690 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
Jiri Slaby02f11752006-12-08 02:39:28 -08001692 if (tty == 0) {
1693 goto ztxdone;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001695
1696 if (info->x_char) { /* send special char */
1697 data = info->x_char;
1698
1699 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1700 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1701 info->x_char = 0;
1702 char_count--;
1703 info->icount.tx++;
1704 info->last_active = jiffies;
1705 info->jiffies[2] = jiffies;
1706 }
1707#ifdef BLOCKMOVE
1708 while (0 < (small_count = min_t(unsigned int,
1709 tx_bufsize - tx_put, min_t(unsigned int,
1710 (SERIAL_XMIT_SIZE - info->xmit_tail),
1711 min_t(unsigned int, info->xmit_cnt,
1712 char_count))))) {
1713
1714 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1715 tx_put),
1716 &info->xmit_buf[info->xmit_tail],
1717 small_count);
1718
1719 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1720 char_count -= small_count;
1721 info->icount.tx += small_count;
1722 info->xmit_cnt -= small_count;
1723 info->xmit_tail = (info->xmit_tail + small_count) &
1724 (SERIAL_XMIT_SIZE - 1);
1725 info->last_active = jiffies;
1726 info->jiffies[2] = jiffies;
1727 }
1728#else
1729 while (info->xmit_cnt && char_count) {
1730 data = info->xmit_buf[info->xmit_tail];
1731 info->xmit_cnt--;
1732 info->xmit_tail = (info->xmit_tail + 1) &
1733 (SERIAL_XMIT_SIZE - 1);
1734
1735 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1736 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1737 char_count--;
1738 info->icount.tx++;
1739 info->last_active = jiffies;
1740 info->jiffies[2] = jiffies;
1741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001743ztxdone:
1744 if (info->xmit_cnt < WAKEUP_CHARS) {
1745 cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
1746 }
1747 /* Update tx_put */
1748 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750}
1751
Jiri Slaby02f11752006-12-08 02:39:28 -08001752static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753{
Jiri Slaby02f11752006-12-08 02:39:28 -08001754 struct tty_struct *tty;
1755 struct cyclades_port *info;
1756 static volatile struct FIRM_ID __iomem *firm_id;
1757 static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
1758 static volatile struct BOARD_CTRL __iomem *board_ctrl;
1759 static volatile struct CH_CTRL __iomem *ch_ctrl;
1760 static volatile struct BUF_CTRL __iomem *buf_ctrl;
1761 uclong channel;
1762 ucchar cmd;
1763 uclong param;
1764 uclong hw_ver, fw_ver;
1765 int special_count;
1766 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 firm_id = cinfo->base_addr + ID_ADDRESS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001769 zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
1770 0xfffff);
1771 board_ctrl = &zfw_ctrl->board_ctrl;
1772 fw_ver = cy_readl(&board_ctrl->fw_version);
1773 hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
1774 mail_box_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
Jiri Slaby02f11752006-12-08 02:39:28 -08001776 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1777 special_count = 0;
1778 delta_count = 0;
1779 info = &cy_port[channel + cinfo->first_line];
1780 if ((tty = info->tty) == 0) {
1781 continue;
1782 }
1783 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
1784 buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
1785
1786 switch (cmd) {
1787 case C_CM_PR_ERROR:
1788 tty_insert_flip_char(tty, 0, TTY_PARITY);
1789 info->icount.rx++;
1790 special_count++;
1791 break;
1792 case C_CM_FR_ERROR:
1793 tty_insert_flip_char(tty, 0, TTY_FRAME);
1794 info->icount.rx++;
1795 special_count++;
1796 break;
1797 case C_CM_RXBRK:
1798 tty_insert_flip_char(tty, 0, TTY_BREAK);
1799 info->icount.rx++;
1800 special_count++;
1801 break;
1802 case C_CM_MDCD:
1803 info->icount.dcd++;
1804 delta_count++;
1805 if (info->flags & ASYNC_CHECK_CD) {
1806 if ((fw_ver > 241 ? ((u_long) param) :
1807 cy_readl(&ch_ctrl->rs_status)) &
1808 C_RS_DCD) {
1809 cy_sched_event(info,
1810 Cy_EVENT_OPEN_WAKEUP);
1811 } else {
1812 cy_sched_event(info, Cy_EVENT_HANGUP);
1813 }
1814 }
1815 break;
1816 case C_CM_MCTS:
1817 info->icount.cts++;
1818 delta_count++;
1819 break;
1820 case C_CM_MRI:
1821 info->icount.rng++;
1822 delta_count++;
1823 break;
1824 case C_CM_MDSR:
1825 info->icount.dsr++;
1826 delta_count++;
1827 break;
1828#ifdef Z_WAKE
1829 case C_CM_IOCTLW:
1830 cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
1831 break;
1832#endif
1833#ifdef CONFIG_CYZ_INTR
1834 case C_CM_RXHIWM:
1835 case C_CM_RXNNDT:
1836 case C_CM_INTBACK2:
1837 /* Reception Interrupt */
1838#ifdef CY_DEBUG_INTERRUPTS
1839 printk("cyz_interrupt: rcvd intr, card %d, "
1840 "port %ld\n\r", info->card, channel);
1841#endif
1842 cyz_handle_rx(info, ch_ctrl, buf_ctrl);
1843 break;
1844 case C_CM_TXBEMPTY:
1845 case C_CM_TXLOWWM:
1846 case C_CM_INTBACK:
1847 /* Transmission Interrupt */
1848#ifdef CY_DEBUG_INTERRUPTS
1849 printk("cyz_interrupt: xmit intr, card %d, "
1850 "port %ld\n\r", info->card, channel);
1851#endif
1852 cyz_handle_tx(info, ch_ctrl, buf_ctrl);
1853 break;
1854#endif /* CONFIG_CYZ_INTR */
1855 case C_CM_FATAL:
1856 /* should do something with this !!! */
1857 break;
1858 default:
1859 break;
1860 }
1861 if (delta_count)
1862 cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
1863 if (special_count)
1864 tty_schedule_flip(tty);
1865 }
1866}
1867
1868#ifdef CONFIG_CYZ_INTR
1869static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1870{
1871 struct cyclades_card *cinfo;
1872
1873 if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
1874#ifdef CY_DEBUG_INTERRUPTS
1875 printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
1876#endif
1877 return IRQ_NONE; /* spurious interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 }
1879
Jiri Slaby02f11752006-12-08 02:39:28 -08001880 if (!ISZLOADED(*cinfo)) {
1881#ifdef CY_DEBUG_INTERRUPTS
1882 printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
1883#endif
1884 return IRQ_NONE;
1885 }
1886
1887 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 cyz_handle_cmd(cinfo);
1889
Jiri Slaby02f11752006-12-08 02:39:28 -08001890 return IRQ_HANDLED;
1891} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
Jiri Slaby02f11752006-12-08 02:39:28 -08001893static void cyz_rx_restart(unsigned long arg)
1894{
1895 struct cyclades_port *info = (struct cyclades_port *)arg;
1896 int retval;
1897 int card = info->card;
1898 uclong channel = (info->line) - (cy_card[card].first_line);
1899 unsigned long flags;
1900
1901 CY_LOCK(info, flags);
1902 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
1903 if (retval != 0) {
1904 printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
1905 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 cyz_rx_full_timer[info->line].function = NULL;
1908 CY_UNLOCK(info, flags);
1909}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
Jiri Slaby02f11752006-12-08 02:39:28 -08001911#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Jiri Slaby02f11752006-12-08 02:39:28 -08001913static void cyz_poll(unsigned long arg)
1914{
1915 struct cyclades_card *cinfo;
1916 struct cyclades_port *info;
1917 struct tty_struct *tty;
1918 static volatile struct FIRM_ID *firm_id;
1919 static volatile struct ZFW_CTRL *zfw_ctrl;
1920 static volatile struct BOARD_CTRL *board_ctrl;
1921 static volatile struct CH_CTRL *ch_ctrl;
1922 static volatile struct BUF_CTRL *buf_ctrl;
1923 int card, port;
1924
1925 cyz_timerlist.expires = jiffies + (HZ);
1926 for (card = 0; card < NR_CARDS; card++) {
1927 cinfo = &cy_card[card];
1928
1929 if (!IS_CYC_Z(*cinfo))
1930 continue;
1931 if (!ISZLOADED(*cinfo))
1932 continue;
1933
1934 firm_id = cinfo->base_addr + ID_ADDRESS;
1935 zfw_ctrl = cinfo->base_addr +
1936 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
1937 board_ctrl = &(zfw_ctrl->board_ctrl);
1938
1939 /* Skip first polling cycle to avoid racing conditions with the FW */
1940 if (!cinfo->intr_enabled) {
1941 cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
1942 cinfo->intr_enabled = 1;
1943 continue;
1944 }
1945
1946 cyz_handle_cmd(cinfo);
1947
1948 for (port = 0; port < cinfo->nports; port++) {
1949 info = &cy_port[port + cinfo->first_line];
1950 tty = info->tty;
1951 ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
1952 buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
1953
1954 if (!info->throttle)
1955 cyz_handle_rx(info, ch_ctrl, buf_ctrl);
1956 cyz_handle_tx(info, ch_ctrl, buf_ctrl);
1957 }
1958 /* poll every 'cyz_polling_cycle' period */
1959 cyz_timerlist.expires = jiffies + cyz_polling_cycle;
1960 }
1961 add_timer(&cyz_timerlist);
1962
1963 return;
1964} /* cyz_poll */
1965
1966#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
1968/********** End of block of Cyclades-Z specific code *********/
1969/***********************************************************/
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971/* This is called whenever a port becomes active;
1972 interrupts are enabled and DTR & RTS are turned on.
1973 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001974static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975{
Jiri Slaby02f11752006-12-08 02:39:28 -08001976 unsigned long flags;
1977 int retval = 0;
1978 void __iomem *base_addr;
1979 int card, chip, channel, index;
1980 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
Jiri Slaby02f11752006-12-08 02:39:28 -08001982 card = info->card;
1983 channel = (info->line) - (cy_card[card].first_line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Jiri Slaby02f11752006-12-08 02:39:28 -08001985 page = get_zeroed_page(GFP_KERNEL);
1986 if (!page)
1987 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989 CY_LOCK(info, flags);
1990
Jiri Slaby02f11752006-12-08 02:39:28 -08001991 if (info->flags & ASYNC_INITIALIZED) {
1992 free_page(page);
1993 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001995
1996 if (!info->type) {
1997 if (info->tty) {
1998 set_bit(TTY_IO_ERROR, &info->tty->flags);
1999 }
2000 free_page(page);
2001 goto errout;
2002 }
2003
2004 if (info->xmit_buf)
2005 free_page(page);
2006 else
2007 info->xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
2009 CY_UNLOCK(info, flags);
2010
Jiri Slaby02f11752006-12-08 02:39:28 -08002011 set_line_char(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Jiri Slaby02f11752006-12-08 02:39:28 -08002013 if (!IS_CYC_Z(cy_card[card])) {
2014 chip = channel >> 2;
2015 channel &= 0x03;
2016 index = cy_card[card].bus_index;
2017 base_addr = cy_card[card].base_addr +
2018 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
2020#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002021 printk("cyc startup card %d, chip %d, channel %d, "
2022 "base_addr %lx\n",
2023 card, chip, channel, (long)base_addr);
2024 /**/
2025#endif
2026 CY_LOCK(info, flags);
2027
2028 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2029
2030 cy_writeb(base_addr + (CyRTPR << index),
2031 (info->default_timeout ? info->default_timeout : 0x02));
2032 /* 10ms rx timeout */
2033
2034 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
2035 index);
2036
2037 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2038 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
2039 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
2040
2041#ifdef CY_DEBUG_DTR
2042 printk("cyc:startup raising DTR\n");
2043 printk(" status: 0x%x, 0x%x\n",
2044 cy_readb(base_addr + (CyMSVR1 << index)),
2045 cy_readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046#endif
2047
Jiri Slaby02f11752006-12-08 02:39:28 -08002048 cy_writeb(base_addr + (CySRER << index),
2049 cy_readb(base_addr + (CySRER << index)) | CyRxData);
2050 info->flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
Jiri Slaby02f11752006-12-08 02:39:28 -08002052 if (info->tty) {
2053 clear_bit(TTY_IO_ERROR, &info->tty->flags);
2054 }
2055 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
2056 info->breakon = info->breakoff = 0;
2057 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
2058 info->idle_stats.in_use =
2059 info->idle_stats.recv_idle =
2060 info->idle_stats.xmit_idle = jiffies;
2061
2062 CY_UNLOCK(info, flags);
2063
2064 } else {
2065 struct FIRM_ID __iomem *firm_id;
2066 struct ZFW_CTRL __iomem *zfw_ctrl;
2067 struct BOARD_CTRL __iomem *board_ctrl;
2068 struct CH_CTRL __iomem *ch_ctrl;
2069 int retval;
2070
2071 base_addr = cy_card[card].base_addr;
2072
2073 firm_id = base_addr + ID_ADDRESS;
2074 if (!ISZLOADED(cy_card[card])) {
2075 return -ENODEV;
2076 }
2077
2078 zfw_ctrl = cy_card[card].base_addr +
2079 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
2080 board_ctrl = &zfw_ctrl->board_ctrl;
2081 ch_ctrl = zfw_ctrl->ch_ctrl;
2082
2083#ifdef CY_DEBUG_OPEN
2084 printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
2085 card, channel, (long)base_addr);
2086 /**/
2087#endif
2088 CY_LOCK(info, flags);
2089
2090 cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091#ifdef Z_WAKE
2092#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002093 cy_writel(&ch_ctrl[channel].intr_enable,
2094 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
2095 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096#else
Jiri Slaby02f11752006-12-08 02:39:28 -08002097 cy_writel(&ch_ctrl[channel].intr_enable,
2098 C_IN_IOCTLW | C_IN_MDCD);
2099#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100#else
2101#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002102 cy_writel(&ch_ctrl[channel].intr_enable,
2103 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
2104 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105#else
Jiri Slaby02f11752006-12-08 02:39:28 -08002106 cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
2107#endif /* CONFIG_CYZ_INTR */
2108#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
Jiri Slaby02f11752006-12-08 02:39:28 -08002110 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
2111 if (retval != 0) {
2112 printk("cyc:startup(1) retval on ttyC%d was %x\n",
2113 info->line, retval);
2114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Jiri Slaby02f11752006-12-08 02:39:28 -08002116 /* Flush RX buffers before raising DTR and RTS */
2117 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
2118 0L);
2119 if (retval != 0) {
2120 printk("cyc:startup(2) retval on ttyC%d was %x\n",
2121 info->line, retval);
2122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Jiri Slaby02f11752006-12-08 02:39:28 -08002124 /* set timeout !!! */
2125 /* set RTS and DTR !!! */
2126 cy_writel(&ch_ctrl[channel].rs_control,
2127 cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
2128 C_RS_DTR);
2129 retval = cyz_issue_cmd(&cy_card[info->card], channel,
2130 C_CM_IOCTLM, 0L);
2131 if (retval != 0) {
2132 printk("cyc:startup(3) retval on ttyC%d was %x\n",
2133 info->line, retval);
2134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002136 printk("cyc:startup raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137#endif
2138
Jiri Slaby02f11752006-12-08 02:39:28 -08002139 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Jiri Slaby02f11752006-12-08 02:39:28 -08002141 info->flags |= ASYNC_INITIALIZED;
2142 if (info->tty) {
2143 clear_bit(TTY_IO_ERROR, &info->tty->flags);
2144 }
2145 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
2146 info->breakon = info->breakoff = 0;
2147 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
2148 info->idle_stats.in_use =
2149 info->idle_stats.recv_idle =
2150 info->idle_stats.xmit_idle = jiffies;
2151
2152 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155#ifdef CY_DEBUG_OPEN
2156 printk(" cyc startup done\n");
2157#endif
2158 return 0;
2159
2160errout:
2161 CY_UNLOCK(info, flags);
2162 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002163} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Jiri Slaby02f11752006-12-08 02:39:28 -08002165static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166{
Jiri Slaby02f11752006-12-08 02:39:28 -08002167 unsigned long flags;
2168 void __iomem *base_addr;
2169 int card, chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Jiri Slaby02f11752006-12-08 02:39:28 -08002171 card = info->card;
2172 channel = (info->line) - (cy_card[card].first_line);
2173 if (!IS_CYC_Z(cy_card[card])) {
2174 chip = channel >> 2;
2175 channel &= 0x03;
2176 index = cy_card[card].bus_index;
2177 base_addr = cy_card[card].base_addr +
2178 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Jiri Slaby02f11752006-12-08 02:39:28 -08002180 CY_LOCK(info, flags);
2181 cy_writeb(base_addr + (CyCAR << index), channel);
2182 cy_writeb(base_addr + (CySRER << index),
2183 cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
2184 CY_UNLOCK(info, flags);
2185 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002187 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Jiri Slaby02f11752006-12-08 02:39:28 -08002189 CY_LOCK(info, flags);
2190 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
2191 0L);
2192 if (retval != 0) {
2193 printk("cyc:start_xmit retval on ttyC%d was %x\n",
2194 info->line, retval);
2195 }
2196 CY_UNLOCK(info, flags);
2197#else /* CONFIG_CYZ_INTR */
2198 /* Don't have to do anything at this time */
2199#endif /* CONFIG_CYZ_INTR */
2200 }
2201} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
2203/*
2204 * This routine shuts down a serial port; interrupts are disabled,
2205 * and DTR is dropped if the hangup on close termio flag is on.
2206 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002207static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208{
Jiri Slaby02f11752006-12-08 02:39:28 -08002209 unsigned long flags;
2210 void __iomem *base_addr;
2211 int card, chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Jiri Slaby02f11752006-12-08 02:39:28 -08002213 if (!(info->flags & ASYNC_INITIALIZED)) {
2214 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 }
2216
Jiri Slaby02f11752006-12-08 02:39:28 -08002217 card = info->card;
2218 channel = info->line - cy_card[card].first_line;
2219 if (!IS_CYC_Z(cy_card[card])) {
2220 chip = channel >> 2;
2221 channel &= 0x03;
2222 index = cy_card[card].bus_index;
2223 base_addr = cy_card[card].base_addr +
2224 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
2226#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002227 printk("cyc shutdown Y card %d, chip %d, channel %d, "
2228 "base_addr %lx\n",
2229 card, chip, channel, (long)base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Jiri Slaby02f11752006-12-08 02:39:28 -08002232 CY_LOCK(info, flags);
2233
2234 /* Clear delta_msr_wait queue to avoid mem leaks. */
2235 wake_up_interruptible(&info->delta_msr_wait);
2236
2237 if (info->xmit_buf) {
2238 unsigned char *temp;
2239 temp = info->xmit_buf;
2240 info->xmit_buf = NULL;
2241 free_page((unsigned long)temp);
2242 }
2243 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2244 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
2245 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
2246 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
2247#ifdef CY_DEBUG_DTR
2248 printk("cyc shutdown dropping DTR\n");
2249 printk(" status: 0x%x, 0x%x\n",
2250 cy_readb(base_addr + (CyMSVR1 << index)),
2251 cy_readb(base_addr + (CyMSVR2 << index)));
2252#endif
2253 }
2254 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
2255 /* it may be appropriate to clear _XMIT at
2256 some later date (after testing)!!! */
2257
2258 if (info->tty) {
2259 set_bit(TTY_IO_ERROR, &info->tty->flags);
2260 }
2261 info->flags &= ~ASYNC_INITIALIZED;
2262 CY_UNLOCK(info, flags);
2263 } else {
2264 struct FIRM_ID __iomem *firm_id;
2265 struct ZFW_CTRL __iomem *zfw_ctrl;
2266 struct BOARD_CTRL __iomem *board_ctrl;
2267 struct CH_CTRL __iomem *ch_ctrl;
2268 int retval;
2269
2270 base_addr = cy_card[card].base_addr;
2271#ifdef CY_DEBUG_OPEN
2272 printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
2273 card, channel, (long)base_addr);
2274#endif
2275
2276 firm_id = base_addr + ID_ADDRESS;
2277 if (!ISZLOADED(cy_card[card])) {
2278 return;
2279 }
2280
2281 zfw_ctrl = cy_card[card].base_addr +
2282 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
2283 board_ctrl = &zfw_ctrl->board_ctrl;
2284 ch_ctrl = zfw_ctrl->ch_ctrl;
2285
2286 CY_LOCK(info, flags);
2287
2288 if (info->xmit_buf) {
2289 unsigned char *temp;
2290 temp = info->xmit_buf;
2291 info->xmit_buf = NULL;
2292 free_page((unsigned long)temp);
2293 }
2294
2295 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
2296 cy_writel(&ch_ctrl[channel].rs_control,
2297 (uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
2298 ~(C_RS_RTS | C_RS_DTR)));
2299 retval = cyz_issue_cmd(&cy_card[info->card], channel,
2300 C_CM_IOCTLM, 0L);
2301 if (retval != 0) {
2302 printk("cyc:shutdown retval on ttyC%d was %x\n",
2303 info->line, retval);
2304 }
2305#ifdef CY_DEBUG_DTR
2306 printk("cyc:shutdown dropping Z DTR\n");
2307#endif
2308 }
2309
2310 if (info->tty) {
2311 set_bit(TTY_IO_ERROR, &info->tty->flags);
2312 }
2313 info->flags &= ~ASYNC_INITIALIZED;
2314
2315 CY_UNLOCK(info, flags);
2316 }
2317
2318#ifdef CY_DEBUG_OPEN
2319 printk(" cyc shutdown done\n");
2320#endif
2321 return;
2322} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
2324/*
2325 * ------------------------------------------------------------
2326 * cy_open() and friends
2327 * ------------------------------------------------------------
2328 */
2329
2330static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002331block_til_ready(struct tty_struct *tty, struct file *filp,
2332 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333{
Jiri Slaby02f11752006-12-08 02:39:28 -08002334 DECLARE_WAITQUEUE(wait, current);
2335 struct cyclades_card *cinfo;
2336 unsigned long flags;
2337 int chip, channel, index;
2338 int retval;
2339 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Jiri Slaby02f11752006-12-08 02:39:28 -08002341 cinfo = &cy_card[info->card];
2342 channel = info->line - cinfo->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
Jiri Slaby02f11752006-12-08 02:39:28 -08002344 /*
2345 * If the device is in the middle of being closed, then block
2346 * until it's done, and then try again.
2347 */
2348 if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
2349 if (info->flags & ASYNC_CLOSING) {
2350 interruptible_sleep_on(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002352 return ((info->
2353 flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
2354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
Jiri Slaby02f11752006-12-08 02:39:28 -08002356 /*
2357 * If non-blocking mode is set, then make the check up front
2358 * and then exit.
2359 */
2360 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
2361 info->flags |= ASYNC_NORMAL_ACTIVE;
2362 return 0;
2363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
Jiri Slaby02f11752006-12-08 02:39:28 -08002365 /*
2366 * Block waiting for the carrier detect and the line to become
2367 * free (i.e., not in use by the callout). While we are in
2368 * this loop, info->count is dropped by one, so that
2369 * cy_close() knows when to free things. We restore it upon
2370 * exit, either normal or abnormal.
2371 */
2372 retval = 0;
2373 add_wait_queue(&info->open_wait, &wait);
2374#ifdef CY_DEBUG_OPEN
2375 printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
2376 info->line, info->count);
2377 /**/
2378#endif
2379 CY_LOCK(info, flags);
2380 if (!tty_hung_up_p(filp))
2381 info->count--;
2382 CY_UNLOCK(info, flags);
2383#ifdef CY_DEBUG_COUNT
2384 printk("cyc block_til_ready: (%d): decrementing count to %d\n",
2385 current->pid, info->count);
2386#endif
2387 info->blocked_open++;
2388
2389 if (!IS_CYC_Z(*cinfo)) {
2390 chip = channel >> 2;
2391 channel &= 0x03;
2392 index = cinfo->bus_index;
2393 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
2394
2395 while (1) {
2396 CY_LOCK(info, flags);
2397 if ((tty->termios->c_cflag & CBAUD)) {
2398 cy_writeb(base_addr + (CyCAR << index),
2399 (u_char) channel);
2400 cy_writeb(base_addr + (CyMSVR1 << index),
2401 CyRTS);
2402 cy_writeb(base_addr + (CyMSVR2 << index),
2403 CyDTR);
2404#ifdef CY_DEBUG_DTR
2405 printk("cyc:block_til_ready raising DTR\n");
2406 printk(" status: 0x%x, 0x%x\n",
2407 cy_readb(base_addr +
2408 (CyMSVR1 << index)),
2409 cy_readb(base_addr +
2410 (CyMSVR2 << index)));
2411#endif
2412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
Jiri Slaby02f11752006-12-08 02:39:28 -08002415 set_current_state(TASK_INTERRUPTIBLE);
2416 if (tty_hung_up_p(filp) ||
2417 !(info->flags & ASYNC_INITIALIZED)) {
2418 retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
2419 -EAGAIN : -ERESTARTSYS);
2420 break;
2421 }
2422
2423 CY_LOCK(info, flags);
2424 cy_writeb(base_addr + (CyCAR << index),
2425 (u_char) channel);
2426 if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
2427 (cy_readb(base_addr +
2428 (CyMSVR1 << index)) & CyDCD))) {
2429 CY_UNLOCK(info, flags);
2430 break;
2431 }
2432 CY_UNLOCK(info, flags);
2433
2434 if (signal_pending(current)) {
2435 retval = -ERESTARTSYS;
2436 break;
2437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002439 printk("cyc block_til_ready blocking: ttyC%d, "
2440 "count = %d\n",
2441 info->line, info->count);
2442 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002444 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002446 } else {
2447 struct FIRM_ID __iomem *firm_id;
2448 struct ZFW_CTRL __iomem *zfw_ctrl;
2449 struct BOARD_CTRL __iomem *board_ctrl;
2450 struct CH_CTRL __iomem *ch_ctrl;
2451 int retval;
2452
2453 base_addr = cinfo->base_addr;
2454 firm_id = base_addr + ID_ADDRESS;
2455 if (!ISZLOADED(*cinfo)) {
2456 current->state = TASK_RUNNING;
2457 remove_wait_queue(&info->open_wait, &wait);
2458 return -EINVAL;
2459 }
2460
2461 zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
2462 0xfffff);
2463 board_ctrl = &zfw_ctrl->board_ctrl;
2464 ch_ctrl = zfw_ctrl->ch_ctrl;
2465
2466 while (1) {
2467 if ((tty->termios->c_cflag & CBAUD)) {
2468 cy_writel(&ch_ctrl[channel].rs_control,
2469 cy_readl(&ch_ctrl[channel].
2470 rs_control) | (C_RS_RTS |
2471 C_RS_DTR));
2472 retval = cyz_issue_cmd(&cy_card[info->card],
2473 channel, C_CM_IOCTLM, 0L);
2474 if (retval != 0) {
2475 printk("cyc:block_til_ready retval on "
2476 "ttyC%d was %x\n",
2477 info->line, retval);
2478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002480 printk("cyc:block_til_ready raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
Jiri Slaby02f11752006-12-08 02:39:28 -08002484 set_current_state(TASK_INTERRUPTIBLE);
2485 if (tty_hung_up_p(filp) ||
2486 !(info->flags & ASYNC_INITIALIZED)) {
2487 retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
2488 -EAGAIN : -ERESTARTSYS);
2489 break;
2490 }
2491 if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
2492 (cy_readl(&ch_ctrl[channel].rs_status) &
2493 C_RS_DCD))) {
2494 break;
2495 }
2496 if (signal_pending(current)) {
2497 retval = -ERESTARTSYS;
2498 break;
2499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002501 printk("cyc block_til_ready blocking: ttyC%d, "
2502 "count = %d\n",
2503 info->line, info->count);
2504 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002506 schedule();
2507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002509 current->state = TASK_RUNNING;
2510 remove_wait_queue(&info->open_wait, &wait);
2511 if (!tty_hung_up_p(filp)) {
2512 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513#ifdef CY_DEBUG_COUNT
Jiri Slaby02f11752006-12-08 02:39:28 -08002514 printk("cyc:block_til_ready (%d): incrementing count to %d\n",
2515 current->pid, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002517 }
2518 info->blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002520 printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
2521 info->line, info->count);
2522 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002524 if (retval)
2525 return retval;
2526 info->flags |= ASYNC_NORMAL_ACTIVE;
2527 return 0;
2528} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530/*
2531 * This routine is called whenever a serial port is opened. It
2532 * performs the serial-specific initialization for the tty structure.
2533 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002534static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
Jiri Slaby02f11752006-12-08 02:39:28 -08002536 struct cyclades_port *info;
2537 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Jiri Slaby02f11752006-12-08 02:39:28 -08002539 line = tty->index;
2540 if ((line < 0) || (NR_PORTS <= line)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08002542 }
2543 info = &cy_port[line];
2544 if (info->line < 0) {
2545 return -ENODEV;
2546 }
2547
2548 /* If the card's firmware hasn't been loaded,
2549 treat it as absent from the system. This
2550 will make the user pay attention.
2551 */
2552 if (IS_CYC_Z(cy_card[info->card])) {
2553 struct cyclades_card *cinfo = &cy_card[info->card];
2554 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
2555
2556 if (!ISZLOADED(*cinfo)) {
2557 if (((ZE_V1 == cy_readl(
2558 &((struct RUNTIME_9060 __iomem *)
2559 (cinfo->ctl_addr))->mail_box_0)) &&
2560 Z_FPGA_CHECK(*cinfo)) &&
2561 (ZFIRM_HLT == cy_readl(
2562 &firm_id->signature))) {
2563 printk("cyc:Cyclades-Z Error: you need an "
2564 "external power supply for this number "
2565 "of ports.\n\rFirmware halted.\r\n");
2566 } else {
2567 printk("cyc:Cyclades-Z firmware not yet "
2568 "loaded\n");
2569 }
2570 return -ENODEV;
2571 }
2572#ifdef CONFIG_CYZ_INTR
2573 else {
2574 /* In case this Z board is operating in interrupt mode, its
2575 interrupts should be enabled as soon as the first open
2576 happens to one of its ports. */
2577 if (!cinfo->intr_enabled) {
2578 struct ZFW_CTRL __iomem *zfw_ctrl;
2579 struct BOARD_CTRL __iomem *board_ctrl;
2580
2581 zfw_ctrl = cinfo->base_addr +
2582 (cy_readl(&firm_id->zfwctrl_addr) &
2583 0xfffff);
2584
2585 board_ctrl = &zfw_ctrl->board_ctrl;
2586
2587 /* Enable interrupts on the PLX chip */
2588 cy_writew(cinfo->ctl_addr + 0x68,
2589 cy_readw(cinfo->ctl_addr +
2590 0x68) | 0x0900);
2591 /* Enable interrupts on the FW */
2592 retval = cyz_issue_cmd(cinfo, 0,
2593 C_CM_IRQ_ENBL, 0L);
2594 if (retval != 0) {
2595 printk("cyc:IRQ enable retval was %x\n",
2596 retval);
2597 }
2598 cinfo->nports =
2599 (int)cy_readl(&board_ctrl->n_channel);
2600 cinfo->intr_enabled = 1;
2601 }
2602 }
2603#endif /* CONFIG_CYZ_INTR */
2604 /* Make sure this Z port really exists in hardware */
2605 if (info->line > (cinfo->first_line + cinfo->nports - 1))
2606 return -ENODEV;
2607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08002609 printk("cyc:cy_open ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002611 tty->driver_data = info;
2612 info->tty = tty;
2613 if (serial_paranoia_check(info, tty->name, "cy_open")) {
2614 return -ENODEV;
2615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002617 printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
2618 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002620 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621#ifdef CY_DEBUG_COUNT
Jiri Slaby02f11752006-12-08 02:39:28 -08002622 printk("cyc:cy_open (%d): incrementing count to %d\n",
2623 current->pid, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Jiri Slaby02f11752006-12-08 02:39:28 -08002626 /*
2627 * If the port is the middle of closing, bail out now
2628 */
2629 if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
2630 if (info->flags & ASYNC_CLOSING)
2631 interruptible_sleep_on(&info->close_wait);
2632 return ((info->
2633 flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
2634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Jiri Slaby02f11752006-12-08 02:39:28 -08002636 /*
2637 * Start up serial port
2638 */
2639 retval = startup(info);
2640 if (retval) {
2641 return retval;
2642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
Jiri Slaby02f11752006-12-08 02:39:28 -08002644 retval = block_til_ready(tty, filp, info);
2645 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002647 printk("cyc:cy_open returning after block_til_ready with %d\n",
2648 retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002650 return retval;
2651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Jiri Slaby02f11752006-12-08 02:39:28 -08002653 info->throttle = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655#ifdef CY_DEBUG_OPEN
Jiri Slaby02f11752006-12-08 02:39:28 -08002656 printk(" cyc:cy_open done\n");
2657 /**/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002659 return 0;
2660} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
2662/*
2663 * cy_wait_until_sent() --- wait until the transmitter is empty
2664 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002665static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666{
Jiri Slaby02f11752006-12-08 02:39:28 -08002667 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2668 void __iomem *base_addr;
2669 int card, chip, channel, index;
2670 unsigned long orig_jiffies;
2671 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
Jiri Slaby02f11752006-12-08 02:39:28 -08002673 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
2674 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
Jiri Slaby02f11752006-12-08 02:39:28 -08002676 if (info->xmit_fifo_size == 0)
2677 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
Jiri Slaby02f11752006-12-08 02:39:28 -08002679 orig_jiffies = jiffies;
2680 /*
2681 * Set the check interval to be 1/5 of the estimated time to
2682 * send a single character, and make it at least 1. The check
2683 * interval should also be less than the timeout.
2684 *
2685 * Note: we have to use pretty tight timings here to satisfy
2686 * the NIST-PCTS.
2687 */
2688 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
2689 char_time = char_time / 5;
2690 if (char_time <= 0)
2691 char_time = 1;
2692 if (timeout < 0)
2693 timeout = 0;
2694 if (timeout)
2695 char_time = min(char_time, timeout);
2696 /*
2697 * If the transmitter hasn't cleared in twice the approximate
2698 * amount of time to send the entire FIFO, it probably won't
2699 * ever clear. This assumes the UART isn't doing flow
2700 * control, which is currently the case. Hence, if it ever
2701 * takes longer than info->timeout, this is probably due to a
2702 * UART bug of some kind. So, we clamp the timeout parameter at
2703 * 2*info->timeout.
2704 */
2705 if (!timeout || timeout > 2 * info->timeout)
2706 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
2709 printk("jiff=%lu...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002711 card = info->card;
2712 channel = (info->line) - (cy_card[card].first_line);
2713 if (!IS_CYC_Z(cy_card[card])) {
2714 chip = channel >> 2;
2715 channel &= 0x03;
2716 index = cy_card[card].bus_index;
2717 base_addr =
2718 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
2719 while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby02f11752006-12-08 02:39:28 -08002721 printk("Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002723 if (msleep_interruptible(jiffies_to_msecs(char_time)))
2724 break;
2725 if (timeout && time_after(jiffies, orig_jiffies +
2726 timeout))
2727 break;
2728 }
2729 } else {
2730 // Nothing to do!
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002732 /* Run one more char cycle */
2733 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby02f11752006-12-08 02:39:28 -08002735 printk("Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736#endif
2737}
2738
2739/*
2740 * This routine is called when a particular tty device is closed.
2741 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002742static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743{
Jiri Slaby02f11752006-12-08 02:39:28 -08002744 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2745 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
2747#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08002748 printk("cyc:cy_close ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749#endif
2750
Jiri Slaby02f11752006-12-08 02:39:28 -08002751 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
2752 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 CY_LOCK(info, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002756 /* If the TTY is being hung up, nothing to do */
2757 if (tty_hung_up_p(filp)) {
2758 CY_UNLOCK(info, flags);
2759 return;
2760 }
2761#ifdef CY_DEBUG_OPEN
2762 printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
2763#endif
2764 if ((tty->count == 1) && (info->count != 1)) {
2765 /*
2766 * Uh, oh. tty->count is 1, which means that the tty
2767 * structure will be freed. Info->count should always
2768 * be one in these conditions. If it's greater than
2769 * one, we've got real problems, since it means the
2770 * serial port won't be shutdown.
2771 */
2772 printk("cyc:cy_close: bad serial port count; tty->count is 1, "
2773 "info->count is %d\n", info->count);
2774 info->count = 1;
2775 }
2776#ifdef CY_DEBUG_COUNT
2777 printk("cyc:cy_close at (%d): decrementing count to %d\n",
2778 current->pid, info->count - 1);
2779#endif
2780 if (--info->count < 0) {
2781#ifdef CY_DEBUG_COUNT
2782 printk("cyc:cyc_close setting count to 0\n");
2783#endif
2784 info->count = 0;
2785 }
2786 if (info->count) {
2787 CY_UNLOCK(info, flags);
2788 return;
2789 }
2790 info->flags |= ASYNC_CLOSING;
2791
2792 /*
2793 * Now we wait for the transmit buffer to clear; and we notify
2794 * the line discipline to only process XON/XOFF characters.
2795 */
2796 tty->closing = 1;
2797 CY_UNLOCK(info, flags);
2798 if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
2799 tty_wait_until_sent(tty, info->closing_wait);
2800 }
2801 CY_LOCK(info, flags);
2802
2803 if (!IS_CYC_Z(cy_card[info->card])) {
2804 int channel = info->line - cy_card[info->card].first_line;
2805 int index = cy_card[info->card].bus_index;
2806 void __iomem *base_addr = cy_card[info->card].base_addr +
2807 (cy_chip_offset[channel >> 2] << index);
2808 /* Stop accepting input */
2809 channel &= 0x03;
2810 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2811 cy_writeb(base_addr + (CySRER << index),
2812 cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
2813 if (info->flags & ASYNC_INITIALIZED) {
2814 /* Waiting for on-board buffers to be empty before closing
2815 the port */
2816 CY_UNLOCK(info, flags);
2817 cy_wait_until_sent(tty, info->timeout);
2818 CY_LOCK(info, flags);
2819 }
2820 } else {
2821#ifdef Z_WAKE
2822 /* Waiting for on-board buffers to be empty before closing the port */
2823 void __iomem *base_addr = cy_card[info->card].base_addr;
2824 struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
2825 struct ZFW_CTRL __iomem *zfw_ctrl =
2826 base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
2827 struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
2828 int channel = info->line - cy_card[info->card].first_line;
2829 int retval;
2830
2831 if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
2832 retval = cyz_issue_cmd(&cy_card[info->card], channel,
2833 C_CM_IOCTLW, 0L);
2834 if (retval != 0) {
2835 printk("cyc:cy_close retval on ttyC%d was %x\n",
2836 info->line, retval);
2837 }
2838 CY_UNLOCK(info, flags);
2839 interruptible_sleep_on(&info->shutdown_wait);
2840 CY_LOCK(info, flags);
2841 }
2842#endif
2843 }
2844
2845 CY_UNLOCK(info, flags);
2846 shutdown(info);
2847 if (tty->driver->flush_buffer)
2848 tty->driver->flush_buffer(tty);
2849 tty_ldisc_flush(tty);
2850 CY_LOCK(info, flags);
2851
2852 tty->closing = 0;
2853 info->event = 0;
2854 info->tty = NULL;
2855 if (info->blocked_open) {
2856 CY_UNLOCK(info, flags);
2857 if (info->close_delay) {
2858 msleep_interruptible(jiffies_to_msecs
2859 (info->close_delay));
2860 }
2861 wake_up_interruptible(&info->open_wait);
2862 CY_LOCK(info, flags);
2863 }
2864 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
2865 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
2867#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08002868 printk(" cyc:cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869#endif
2870
Jiri Slaby02f11752006-12-08 02:39:28 -08002871 CY_UNLOCK(info, flags);
2872 return;
2873} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875/* This routine gets called when tty_write has put something into
2876 * the write_queue. The characters may come from user space or
2877 * kernel space.
2878 *
2879 * This routine will return the number of characters actually
2880 * accepted for writing.
2881 *
2882 * If the port is not already transmitting stuff, start it off by
2883 * enabling interrupts. The interrupt service routine will then
2884 * ensure that the characters are sent.
2885 * If the port is already active, there is no need to kick it.
2886 *
2887 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002888static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
Jiri Slaby02f11752006-12-08 02:39:28 -08002890 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2891 unsigned long flags;
2892 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08002895 printk("cyc:cy_write ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896#endif
2897
Jiri Slaby02f11752006-12-08 02:39:28 -08002898 if (serial_paranoia_check(info, tty->name, "cy_write")) {
2899 return 0;
2900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Jiri Slaby02f11752006-12-08 02:39:28 -08002902 if (!info->xmit_buf)
2903 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Jiri Slaby02f11752006-12-08 02:39:28 -08002905 CY_LOCK(info, flags);
2906 while (1) {
2907 c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
2908 (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
Jiri Slaby02f11752006-12-08 02:39:28 -08002910 if (c <= 0)
2911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
Jiri Slaby02f11752006-12-08 02:39:28 -08002913 memcpy(info->xmit_buf + info->xmit_head, buf, c);
2914 info->xmit_head = (info->xmit_head + c) &
2915 (SERIAL_XMIT_SIZE - 1);
2916 info->xmit_cnt += c;
2917 buf += c;
2918 count -= c;
2919 ret += c;
2920 }
2921 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
Jiri Slaby02f11752006-12-08 02:39:28 -08002923 info->idle_stats.xmit_bytes += ret;
2924 info->idle_stats.xmit_idle = jiffies;
2925
2926 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
2927 start_xmit(info);
2928 }
2929 return ret;
2930} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
2932/*
2933 * This routine is called by the kernel to write a single
2934 * character to the tty device. If the kernel uses this routine,
2935 * it must call the flush_chars() routine (if defined) when it is
2936 * done stuffing characters into the driver. If there is no room
2937 * in the queue, the character is ignored.
2938 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002939static void cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940{
Jiri Slaby02f11752006-12-08 02:39:28 -08002941 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2942 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08002945 printk("cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946#endif
2947
Jiri Slaby02f11752006-12-08 02:39:28 -08002948 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
2949 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Jiri Slaby02f11752006-12-08 02:39:28 -08002951 if (!info->xmit_buf)
2952 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Jiri Slaby02f11752006-12-08 02:39:28 -08002954 CY_LOCK(info, flags);
2955 if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
2956 CY_UNLOCK(info, flags);
2957 return;
2958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
Jiri Slaby02f11752006-12-08 02:39:28 -08002960 info->xmit_buf[info->xmit_head++] = ch;
2961 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
2962 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 info->idle_stats.xmit_bytes++;
2964 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby02f11752006-12-08 02:39:28 -08002965 CY_UNLOCK(info, flags);
2966} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
2968/*
2969 * This routine is called by the kernel after it has written a
2970 * series of characters to the tty device using put_char().
2971 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002972static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973{
Jiri Slaby02f11752006-12-08 02:39:28 -08002974 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2975
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08002977 printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978#endif
2979
Jiri Slaby02f11752006-12-08 02:39:28 -08002980 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
2981 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
Jiri Slaby02f11752006-12-08 02:39:28 -08002983 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
2984 !info->xmit_buf)
2985 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
Jiri Slaby02f11752006-12-08 02:39:28 -08002987 start_xmit(info);
2988} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
2990/*
2991 * This routine returns the numbers of characters the tty driver
2992 * will accept for queuing to be written. This number is subject
2993 * to change as output buffers get emptied, or if the output flow
2994 * control is activated.
2995 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002996static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997{
Jiri Slaby02f11752006-12-08 02:39:28 -08002998 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
2999 int ret;
3000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08003002 printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003#endif
3004
Jiri Slaby02f11752006-12-08 02:39:28 -08003005 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
3006 return 0;
3007 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
3008 if (ret < 0)
3009 ret = 0;
3010 return ret;
3011} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012
Jiri Slaby02f11752006-12-08 02:39:28 -08003013static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014{
Jiri Slaby02f11752006-12-08 02:39:28 -08003015 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
3016 int card, channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
Jiri Slaby02f11752006-12-08 02:39:28 -08003018 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
3019 return 0;
3020
3021 card = info->card;
3022 channel = (info->line) - (cy_card[card].first_line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
3024#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08003025 if (!IS_CYC_Z(cy_card[card])) {
3026#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08003028 printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003030 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08003032 } else {
3033 static volatile struct FIRM_ID *firm_id;
3034 static volatile struct ZFW_CTRL *zfw_ctrl;
3035 static volatile struct CH_CTRL *ch_ctrl;
3036 static volatile struct BUF_CTRL *buf_ctrl;
3037 int char_count;
3038 volatile uclong tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
Jiri Slaby02f11752006-12-08 02:39:28 -08003040 firm_id = cy_card[card].base_addr + ID_ADDRESS;
3041 zfw_ctrl = cy_card[card].base_addr +
3042 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
3043 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
3044 buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
Jiri Slaby02f11752006-12-08 02:39:28 -08003046 tx_get = cy_readl(&buf_ctrl->tx_get);
3047 tx_put = cy_readl(&buf_ctrl->tx_put);
3048 tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
3049 if (tx_put >= tx_get)
3050 char_count = tx_put - tx_get;
3051 else
3052 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053#ifdef CY_DEBUG_IO
Jiri Slaby02f11752006-12-08 02:39:28 -08003054 printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003056 return (info->xmit_cnt + char_count);
3057 }
3058#endif /* Z_EXT_CHARS_IN_BUFFER */
3059} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
3061/*
3062 * ------------------------------------------------------------
3063 * cy_ioctl() and friends
3064 * ------------------------------------------------------------
3065 */
3066
Jiri Slaby02f11752006-12-08 02:39:28 -08003067static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068{
Jiri Slaby02f11752006-12-08 02:39:28 -08003069 int co, co_val, bpr;
3070 uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
3071 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
Jiri Slaby02f11752006-12-08 02:39:28 -08003073 if (baud == 0) {
3074 info->tbpr = info->tco = info->rbpr = info->rco = 0;
3075 return;
3076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Jiri Slaby02f11752006-12-08 02:39:28 -08003078 /* determine which prescaler to use */
3079 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
3080 if (cy_clock / co_val / baud > 63)
3081 break;
3082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
Jiri Slaby02f11752006-12-08 02:39:28 -08003084 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
3085 if (bpr > 255)
3086 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
Jiri Slaby02f11752006-12-08 02:39:28 -08003088 info->tbpr = info->rbpr = bpr;
3089 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090}
3091
3092/*
3093 * This routine finds or computes the various line characteristics.
3094 * It used to be called config_setup
3095 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003096static void set_line_char(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097{
Jiri Slaby02f11752006-12-08 02:39:28 -08003098 unsigned long flags;
3099 void __iomem *base_addr;
3100 int card, chip, channel, index;
3101 unsigned cflag, iflag;
3102 unsigned short chip_number;
3103 int baud, baud_rate = 0;
3104 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
Jiri Slaby02f11752006-12-08 02:39:28 -08003106 if (!info->tty || !info->tty->termios) {
3107 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003109 if (info->line == -1) {
3110 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003112 cflag = info->tty->termios->c_cflag;
3113 iflag = info->tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
Jiri Slaby02f11752006-12-08 02:39:28 -08003115 /*
3116 * Set up the tty->alt_speed kludge
3117 */
3118 if (info->tty) {
3119 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
3120 info->tty->alt_speed = 57600;
3121 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
3122 info->tty->alt_speed = 115200;
3123 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
3124 info->tty->alt_speed = 230400;
3125 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
3126 info->tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Jiri Slaby02f11752006-12-08 02:39:28 -08003129 card = info->card;
3130 channel = (info->line) - (cy_card[card].first_line);
3131 chip_number = channel / 4;
3132
3133 if (!IS_CYC_Z(cy_card[card])) {
3134
3135 index = cy_card[card].bus_index;
3136
3137 /* baud rate */
3138 baud = tty_get_baud_rate(info->tty);
3139 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3140 ASYNC_SPD_CUST) {
3141 if (info->custom_divisor)
3142 baud_rate = info->baud / info->custom_divisor;
3143 else
3144 baud_rate = info->baud;
3145 } else if (baud > CD1400_MAX_SPEED) {
3146 baud = CD1400_MAX_SPEED;
3147 }
3148 /* find the baud index */
3149 for (i = 0; i < 20; i++) {
3150 if (baud == baud_table[i]) {
3151 break;
3152 }
3153 }
3154 if (i == 20) {
3155 i = 19; /* CD1400_MAX_SPEED */
3156 }
3157
3158 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3159 ASYNC_SPD_CUST) {
3160 cyy_baud_calc(info, baud_rate);
3161 } else {
3162 if (info->chip_rev >= CD1400_REV_J) {
3163 /* It is a CD1400 rev. J or later */
3164 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
3165 info->tco = baud_co_60[i]; /* Tx CO */
3166 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
3167 info->rco = baud_co_60[i]; /* Rx CO */
3168 } else {
3169 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
3170 info->tco = baud_co_25[i]; /* Tx CO */
3171 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
3172 info->rco = baud_co_25[i]; /* Rx CO */
3173 }
3174 }
3175 if (baud_table[i] == 134) {
3176 /* get it right for 134.5 baud */
3177 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
3178 2;
3179 } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3180 ASYNC_SPD_CUST) {
3181 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3182 baud_rate) + 2;
3183 } else if (baud_table[i]) {
3184 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3185 baud_table[i]) + 2;
3186 /* this needs to be propagated into the card info */
3187 } else {
3188 info->timeout = 0;
3189 }
3190 /* By tradition (is it a standard?) a baud rate of zero
3191 implies the line should be/has been closed. A bit
3192 later in this routine such a test is performed. */
3193
3194 /* byte size and parity */
3195 info->cor5 = 0;
3196 info->cor4 = 0;
3197 /* receive threshold */
3198 info->cor3 = (info->default_threshold ?
3199 info->default_threshold : baud_cor3[i]);
3200 info->cor2 = CyETC;
3201 switch (cflag & CSIZE) {
3202 case CS5:
3203 info->cor1 = Cy_5_BITS;
3204 break;
3205 case CS6:
3206 info->cor1 = Cy_6_BITS;
3207 break;
3208 case CS7:
3209 info->cor1 = Cy_7_BITS;
3210 break;
3211 case CS8:
3212 info->cor1 = Cy_8_BITS;
3213 break;
3214 }
3215 if (cflag & CSTOPB) {
3216 info->cor1 |= Cy_2_STOP;
3217 }
3218 if (cflag & PARENB) {
3219 if (cflag & PARODD) {
3220 info->cor1 |= CyPARITY_O;
3221 } else {
3222 info->cor1 |= CyPARITY_E;
3223 }
3224 } else {
3225 info->cor1 |= CyPARITY_NONE;
3226 }
3227
3228 /* CTS flow control flag */
3229 if (cflag & CRTSCTS) {
3230 info->flags |= ASYNC_CTS_FLOW;
3231 info->cor2 |= CyCtsAE;
3232 } else {
3233 info->flags &= ~ASYNC_CTS_FLOW;
3234 info->cor2 &= ~CyCtsAE;
3235 }
3236 if (cflag & CLOCAL)
3237 info->flags &= ~ASYNC_CHECK_CD;
3238 else
3239 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
3241 /***********************************************
3242 The hardware option, CyRtsAO, presents RTS when
3243 the chip has characters to send. Since most modems
3244 use RTS as reverse (inbound) flow control, this
3245 option is not used. If inbound flow control is
3246 necessary, DTR can be programmed to provide the
3247 appropriate signals for use with a non-standard
3248 cable. Contact Marcio Saito for details.
3249 ***********************************************/
3250
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 chip = channel >> 2;
3252 channel &= 0x03;
3253 base_addr = cy_card[card].base_addr +
3254 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Jiri Slaby02f11752006-12-08 02:39:28 -08003256 CY_LOCK(info, flags);
3257 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Jiri Slaby02f11752006-12-08 02:39:28 -08003259 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
Jiri Slaby02f11752006-12-08 02:39:28 -08003261 cy_writeb(base_addr + (CyTCOR << index), info->tco);
3262 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
3263 cy_writeb(base_addr + (CyRCOR << index), info->rco);
3264 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Jiri Slaby02f11752006-12-08 02:39:28 -08003266 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
Jiri Slaby02f11752006-12-08 02:39:28 -08003268 cy_writeb(base_addr + (CySCHR1 << index),
3269 START_CHAR(info->tty));
3270 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty));
3271 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
3272 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
3273 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
3274 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
3275 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
Jiri Slaby02f11752006-12-08 02:39:28 -08003277 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
3278 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
Jiri Slaby02f11752006-12-08 02:39:28 -08003280 cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
3281 cy_writeb(base_addr + (CyRTPR << index),
3282 (info->default_timeout ? info->default_timeout : 0x02));
3283 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
Jiri Slaby02f11752006-12-08 02:39:28 -08003285 if (C_CLOCAL(info->tty)) {
3286 /* without modem intr */
3287 cy_writeb(base_addr + (CySRER << index),
3288 cy_readb(base_addr +
3289 (CySRER << index)) | CyMdmCh);
3290 /* act on 1->0 modem transitions */
3291 if ((cflag & CRTSCTS) && info->rflow) {
3292 cy_writeb(base_addr + (CyMCOR1 << index),
3293 (CyCTS | rflow_thr[i]));
3294 } else {
3295 cy_writeb(base_addr + (CyMCOR1 << index),
3296 CyCTS);
3297 }
3298 /* act on 0->1 modem transitions */
3299 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08003301 /* without modem intr */
3302 cy_writeb(base_addr + (CySRER << index),
3303 cy_readb(base_addr +
3304 (CySRER << index)) | CyMdmCh);
3305 /* act on 1->0 modem transitions */
3306 if ((cflag & CRTSCTS) && info->rflow) {
3307 cy_writeb(base_addr + (CyMCOR1 << index),
3308 (CyDSR | CyCTS | CyRI | CyDCD |
3309 rflow_thr[i]));
3310 } else {
3311 cy_writeb(base_addr + (CyMCOR1 << index),
3312 CyDSR | CyCTS | CyRI | CyDCD);
3313 }
3314 /* act on 0->1 modem transitions */
3315 cy_writeb(base_addr + (CyMCOR2 << index),
3316 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003318
3319 if (i == 0) { /* baud rate is zero, turn off line */
3320 if (info->rtsdtr_inv) {
3321 cy_writeb(base_addr + (CyMSVR1 << index),
3322 ~CyRTS);
3323 } else {
3324 cy_writeb(base_addr + (CyMSVR2 << index),
3325 ~CyDTR);
3326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003328 printk("cyc:set_line_char dropping DTR\n");
3329 printk(" status: 0x%x, 0x%x\n",
3330 cy_readb(base_addr + (CyMSVR1 << index)),
3331 cy_readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003333 } else {
3334 if (info->rtsdtr_inv) {
3335 cy_writeb(base_addr + (CyMSVR1 << index),
3336 CyRTS);
3337 } else {
3338 cy_writeb(base_addr + (CyMSVR2 << index),
3339 CyDTR);
3340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003342 printk("cyc:set_line_char raising DTR\n");
3343 printk(" status: 0x%x, 0x%x\n",
3344 cy_readb(base_addr + (CyMSVR1 << index)),
3345 cy_readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
Jiri Slaby02f11752006-12-08 02:39:28 -08003349 if (info->tty) {
3350 clear_bit(TTY_IO_ERROR, &info->tty->flags);
3351 }
3352 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08003355 struct FIRM_ID __iomem *firm_id;
3356 struct ZFW_CTRL __iomem *zfw_ctrl;
3357 struct BOARD_CTRL __iomem *board_ctrl;
3358 struct CH_CTRL __iomem *ch_ctrl;
3359 struct BUF_CTRL __iomem *buf_ctrl;
3360 uclong sw_flow;
3361 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Jiri Slaby02f11752006-12-08 02:39:28 -08003363 firm_id = cy_card[card].base_addr + ID_ADDRESS;
3364 if (!ISZLOADED(cy_card[card])) {
3365 return;
3366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
Jiri Slaby02f11752006-12-08 02:39:28 -08003368 zfw_ctrl = cy_card[card].base_addr +
3369 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
3370 board_ctrl = &zfw_ctrl->board_ctrl;
3371 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
3372 buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373
Jiri Slaby02f11752006-12-08 02:39:28 -08003374 /* baud rate */
3375 baud = tty_get_baud_rate(info->tty);
3376 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3377 ASYNC_SPD_CUST) {
3378 if (info->custom_divisor)
3379 baud_rate = info->baud / info->custom_divisor;
3380 else
3381 baud_rate = info->baud;
3382 } else if (baud > CYZ_MAX_SPEED) {
3383 baud = CYZ_MAX_SPEED;
3384 }
3385 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
Jiri Slaby02f11752006-12-08 02:39:28 -08003387 if (baud == 134) {
3388 /* get it right for 134.5 baud */
3389 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
3390 2;
3391 } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3392 ASYNC_SPD_CUST) {
3393 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3394 baud_rate) + 2;
3395 } else if (baud) {
3396 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3397 baud) + 2;
3398 /* this needs to be propagated into the card info */
3399 } else {
3400 info->timeout = 0;
3401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402
Jiri Slaby02f11752006-12-08 02:39:28 -08003403 /* byte size and parity */
3404 switch (cflag & CSIZE) {
3405 case CS5:
3406 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
3407 break;
3408 case CS6:
3409 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
3410 break;
3411 case CS7:
3412 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
3413 break;
3414 case CS8:
3415 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
3416 break;
3417 }
3418 if (cflag & CSTOPB) {
3419 cy_writel(&ch_ctrl->comm_data_l,
3420 cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
3421 } else {
3422 cy_writel(&ch_ctrl->comm_data_l,
3423 cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
3424 }
3425 if (cflag & PARENB) {
3426 if (cflag & PARODD) {
3427 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
3428 } else {
3429 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
3430 }
3431 } else {
3432 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
3433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434
Jiri Slaby02f11752006-12-08 02:39:28 -08003435 /* CTS flow control flag */
3436 if (cflag & CRTSCTS) {
3437 cy_writel(&ch_ctrl->hw_flow,
3438 cy_readl(&ch_ctrl->
3439 hw_flow) | C_RS_CTS | C_RS_RTS);
3440 } else {
3441 cy_writel(&ch_ctrl->hw_flow,
3442 cy_readl(&ch_ctrl->
3443 hw_flow) & ~(C_RS_CTS | C_RS_RTS));
3444 }
3445 /* As the HW flow control is done in firmware, the driver
3446 doesn't need to care about it */
3447 info->flags &= ~ASYNC_CTS_FLOW;
3448
3449 /* XON/XOFF/XANY flow control flags */
3450 sw_flow = 0;
3451 if (iflag & IXON) {
3452 sw_flow |= C_FL_OXX;
3453 if (iflag & IXANY)
3454 sw_flow |= C_FL_OIXANY;
3455 }
3456 cy_writel(&ch_ctrl->sw_flow, sw_flow);
3457
3458 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
3459 if (retval != 0) {
3460 printk("cyc:set_line_char retval on ttyC%d was %x\n",
3461 info->line, retval);
3462 }
3463
3464 /* CD sensitivity */
3465 if (cflag & CLOCAL) {
3466 info->flags &= ~ASYNC_CHECK_CD;
3467 } else {
3468 info->flags |= ASYNC_CHECK_CD;
3469 }
3470
3471 if (baud == 0) { /* baud rate is zero, turn off line */
3472 cy_writel(&ch_ctrl->rs_control,
3473 cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003475 printk("cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003477 } else {
3478 cy_writel(&ch_ctrl->rs_control,
3479 cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003481 printk("cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
Jiri Slaby02f11752006-12-08 02:39:28 -08003485 retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
3486 if (retval != 0) {
3487 printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
3488 info->line, retval);
3489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Jiri Slaby02f11752006-12-08 02:39:28 -08003491 if (info->tty) {
3492 clear_bit(TTY_IO_ERROR, &info->tty->flags);
3493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003495} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
3497static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003498get_serial_info(struct cyclades_port *info,
3499 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500{
Jiri Slaby02f11752006-12-08 02:39:28 -08003501 struct serial_struct tmp;
3502 struct cyclades_card *cinfo = &cy_card[info->card];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
Jiri Slaby02f11752006-12-08 02:39:28 -08003504 if (!retinfo)
3505 return -EFAULT;
3506 memset(&tmp, 0, sizeof(tmp));
3507 tmp.type = info->type;
3508 tmp.line = info->line;
3509 tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
3510 tmp.irq = cinfo->irq;
3511 tmp.flags = info->flags;
3512 tmp.close_delay = info->close_delay;
3513 tmp.baud_base = info->baud;
3514 tmp.custom_divisor = info->custom_divisor;
3515 tmp.hub6 = 0; /*!!! */
3516 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
3517} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003520set_serial_info(struct cyclades_port *info,
3521 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522{
Jiri Slaby02f11752006-12-08 02:39:28 -08003523 struct serial_struct new_serial;
3524 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Jiri Slaby02f11752006-12-08 02:39:28 -08003526 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
3527 return -EFAULT;
3528 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
Jiri Slaby02f11752006-12-08 02:39:28 -08003530 if (!capable(CAP_SYS_ADMIN)) {
3531 if (new_serial.close_delay != info->close_delay ||
3532 new_serial.baud_base != info->baud ||
3533 (new_serial.flags & ASYNC_FLAGS &
3534 ~ASYNC_USR_MASK) !=
3535 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
3536 return -EPERM;
3537 info->flags = (info->flags & ~ASYNC_USR_MASK) |
3538 (new_serial.flags & ASYNC_USR_MASK);
3539 info->baud = new_serial.baud_base;
3540 info->custom_divisor = new_serial.custom_divisor;
3541 goto check_and_exit;
3542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
Jiri Slaby02f11752006-12-08 02:39:28 -08003544 /*
3545 * OK, past this point, all the error checking has been done.
3546 * At this point, we start making changes.....
3547 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548
Jiri Slaby02f11752006-12-08 02:39:28 -08003549 info->baud = new_serial.baud_base;
3550 info->custom_divisor = new_serial.custom_divisor;
3551 info->flags = (info->flags & ~ASYNC_FLAGS) |
3552 (new_serial.flags & ASYNC_FLAGS);
3553 info->close_delay = new_serial.close_delay * HZ / 100;
3554 info->closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
3556check_and_exit:
Jiri Slaby02f11752006-12-08 02:39:28 -08003557 if (info->flags & ASYNC_INITIALIZED) {
3558 set_line_char(info);
3559 return 0;
3560 } else {
3561 return startup(info);
3562 }
3563} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
3565/*
3566 * get_lsr_info - get line status register info
3567 *
3568 * Purpose: Let user call ioctl() to get info when the UART physically
3569 * is emptied. On bus types like RS485, the transmitter must
3570 * release the bus after transmitting. This must be done when
3571 * the transmit shift register is empty, not be done when the
3572 * transmit holding register is empty. This functionality
3573 * allows an RS485 driver to be written in user space.
3574 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003575static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576{
Jiri Slaby02f11752006-12-08 02:39:28 -08003577 int card, chip, channel, index;
3578 unsigned char status;
3579 unsigned int result;
3580 unsigned long flags;
3581 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Jiri Slaby02f11752006-12-08 02:39:28 -08003583 card = info->card;
3584 channel = (info->line) - (cy_card[card].first_line);
3585 if (!IS_CYC_Z(cy_card[card])) {
3586 chip = channel >> 2;
3587 channel &= 0x03;
3588 index = cy_card[card].bus_index;
3589 base_addr =
3590 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
Jiri Slaby02f11752006-12-08 02:39:28 -08003592 CY_LOCK(info, flags);
3593 status = cy_readb(base_addr + (CySRER << index)) &
3594 (CyTxRdy | CyTxMpty);
3595 CY_UNLOCK(info, flags);
3596 result = (status ? 0 : TIOCSER_TEMT);
3597 } else {
3598 /* Not supported yet */
3599 return -EINVAL;
3600 }
3601 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602}
3603
Jiri Slaby02f11752006-12-08 02:39:28 -08003604static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
Jiri Slaby02f11752006-12-08 02:39:28 -08003606 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
3607 int card, chip, channel, index;
3608 void __iomem *base_addr;
3609 unsigned long flags;
3610 unsigned char status;
3611 unsigned long lstatus;
3612 unsigned int result;
3613 struct FIRM_ID __iomem *firm_id;
3614 struct ZFW_CTRL __iomem *zfw_ctrl;
3615 struct BOARD_CTRL __iomem *board_ctrl;
3616 struct CH_CTRL __iomem *ch_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617
Jiri Slaby02f11752006-12-08 02:39:28 -08003618 if (serial_paranoia_check(info, tty->name, __FUNCTION__))
3619 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
Jiri Slaby02f11752006-12-08 02:39:28 -08003621 card = info->card;
3622 channel = (info->line) - (cy_card[card].first_line);
3623 if (!IS_CYC_Z(cy_card[card])) {
3624 chip = channel >> 2;
3625 channel &= 0x03;
3626 index = cy_card[card].bus_index;
3627 base_addr =
3628 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
Jiri Slaby02f11752006-12-08 02:39:28 -08003630 CY_LOCK(info, flags);
3631 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
3632 status = cy_readb(base_addr + (CyMSVR1 << index));
3633 status |= cy_readb(base_addr + (CyMSVR2 << index));
3634 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635
Jiri Slaby02f11752006-12-08 02:39:28 -08003636 if (info->rtsdtr_inv) {
3637 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
3638 ((status & CyDTR) ? TIOCM_RTS : 0);
3639 } else {
3640 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
3641 ((status & CyDTR) ? TIOCM_DTR : 0);
3642 }
3643 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
3644 ((status & CyRI) ? TIOCM_RNG : 0) |
3645 ((status & CyDSR) ? TIOCM_DSR : 0) |
3646 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08003648 base_addr = cy_card[card].base_addr;
3649
3650 if (cy_card[card].num_chips != -1) {
3651 return -EINVAL;
3652 }
3653
3654 firm_id = cy_card[card].base_addr + ID_ADDRESS;
3655 if (ISZLOADED(cy_card[card])) {
3656 zfw_ctrl = cy_card[card].base_addr +
3657 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
3658 board_ctrl = &zfw_ctrl->board_ctrl;
3659 ch_ctrl = zfw_ctrl->ch_ctrl;
3660 lstatus = cy_readl(&ch_ctrl[channel].rs_status);
3661 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
3662 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
3663 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
3664 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
3665 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
3666 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
3667 } else {
3668 result = 0;
3669 return -ENODEV;
3670 }
3671
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003673 return result;
3674} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
3676static int
3677cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08003678 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679{
Jiri Slaby02f11752006-12-08 02:39:28 -08003680 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
3681 int card, chip, channel, index;
3682 void __iomem *base_addr;
3683 unsigned long flags;
3684 struct FIRM_ID __iomem *firm_id;
3685 struct ZFW_CTRL __iomem *zfw_ctrl;
3686 struct BOARD_CTRL __iomem *board_ctrl;
3687 struct CH_CTRL __iomem *ch_ctrl;
3688 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689
Jiri Slaby02f11752006-12-08 02:39:28 -08003690 if (serial_paranoia_check(info, tty->name, __FUNCTION__))
3691 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
Jiri Slaby02f11752006-12-08 02:39:28 -08003693 card = info->card;
3694 channel = (info->line) - (cy_card[card].first_line);
3695 if (!IS_CYC_Z(cy_card[card])) {
3696 chip = channel >> 2;
3697 channel &= 0x03;
3698 index = cy_card[card].bus_index;
3699 base_addr =
3700 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Jiri Slaby02f11752006-12-08 02:39:28 -08003702 if (set & TIOCM_RTS) {
3703 CY_LOCK(info, flags);
3704 cy_writeb(base_addr + (CyCAR << index),
3705 (u_char) channel);
3706 if (info->rtsdtr_inv) {
3707 cy_writeb(base_addr + (CyMSVR2 << index),
3708 CyDTR);
3709 } else {
3710 cy_writeb(base_addr + (CyMSVR1 << index),
3711 CyRTS);
3712 }
3713 CY_UNLOCK(info, flags);
3714 }
3715 if (clear & TIOCM_RTS) {
3716 CY_LOCK(info, flags);
3717 cy_writeb(base_addr + (CyCAR << index),
3718 (u_char) channel);
3719 if (info->rtsdtr_inv) {
3720 cy_writeb(base_addr + (CyMSVR2 << index),
3721 ~CyDTR);
3722 } else {
3723 cy_writeb(base_addr + (CyMSVR1 << index),
3724 ~CyRTS);
3725 }
3726 CY_UNLOCK(info, flags);
3727 }
3728 if (set & TIOCM_DTR) {
3729 CY_LOCK(info, flags);
3730 cy_writeb(base_addr + (CyCAR << index),
3731 (u_char) channel);
3732 if (info->rtsdtr_inv) {
3733 cy_writeb(base_addr + (CyMSVR1 << index),
3734 CyRTS);
3735 } else {
3736 cy_writeb(base_addr + (CyMSVR2 << index),
3737 CyDTR);
3738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003740 printk("cyc:set_modem_info raising DTR\n");
3741 printk(" status: 0x%x, 0x%x\n",
3742 cy_readb(base_addr + (CyMSVR1 << index)),
3743 cy_readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003745 CY_UNLOCK(info, flags);
3746 }
3747 if (clear & TIOCM_DTR) {
3748 CY_LOCK(info, flags);
3749 cy_writeb(base_addr + (CyCAR << index),
3750 (u_char) channel);
3751 if (info->rtsdtr_inv) {
3752 cy_writeb(base_addr + (CyMSVR1 << index),
3753 ~CyRTS);
3754 } else {
3755 cy_writeb(base_addr + (CyMSVR2 << index),
3756 ~CyDTR);
3757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
3759#ifdef CY_DEBUG_DTR
Jiri Slaby02f11752006-12-08 02:39:28 -08003760 printk("cyc:set_modem_info dropping DTR\n");
3761 printk(" status: 0x%x, 0x%x\n",
3762 cy_readb(base_addr + (CyMSVR1 << index)),
3763 cy_readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003765 CY_UNLOCK(info, flags);
3766 }
3767 } else {
3768 base_addr = cy_card[card].base_addr;
3769
3770 firm_id = cy_card[card].base_addr + ID_ADDRESS;
3771 if (ISZLOADED(cy_card[card])) {
3772 zfw_ctrl = cy_card[card].base_addr +
3773 (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
3774 board_ctrl = &zfw_ctrl->board_ctrl;
3775 ch_ctrl = zfw_ctrl->ch_ctrl;
3776
3777 if (set & TIOCM_RTS) {
3778 CY_LOCK(info, flags);
3779 cy_writel(&ch_ctrl[channel].rs_control,
3780 cy_readl(&ch_ctrl[channel].
3781 rs_control) | C_RS_RTS);
3782 CY_UNLOCK(info, flags);
3783 }
3784 if (clear & TIOCM_RTS) {
3785 CY_LOCK(info, flags);
3786 cy_writel(&ch_ctrl[channel].rs_control,
3787 cy_readl(&ch_ctrl[channel].
3788 rs_control) & ~C_RS_RTS);
3789 CY_UNLOCK(info, flags);
3790 }
3791 if (set & TIOCM_DTR) {
3792 CY_LOCK(info, flags);
3793 cy_writel(&ch_ctrl[channel].rs_control,
3794 cy_readl(&ch_ctrl[channel].
3795 rs_control) | C_RS_DTR);
3796#ifdef CY_DEBUG_DTR
3797 printk("cyc:set_modem_info raising Z DTR\n");
3798#endif
3799 CY_UNLOCK(info, flags);
3800 }
3801 if (clear & TIOCM_DTR) {
3802 CY_LOCK(info, flags);
3803 cy_writel(&ch_ctrl[channel].rs_control,
3804 cy_readl(&ch_ctrl[channel].
3805 rs_control) & ~C_RS_DTR);
3806#ifdef CY_DEBUG_DTR
3807 printk("cyc:set_modem_info clearing Z DTR\n");
3808#endif
3809 CY_UNLOCK(info, flags);
3810 }
3811 } else {
3812 return -ENODEV;
3813 }
3814 CY_LOCK(info, flags);
3815 retval = cyz_issue_cmd(&cy_card[info->card],
3816 channel, C_CM_IOCTLM, 0L);
3817 if (retval != 0) {
3818 printk("cyc:set_modem_info retval on ttyC%d was %x\n",
3819 info->line, retval);
3820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 CY_UNLOCK(info, flags);
3822 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003823 return 0;
3824} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826/*
3827 * cy_break() --- routine which turns the break handling on or off
3828 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003829static void cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
Jiri Slaby02f11752006-12-08 02:39:28 -08003831 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
3832 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Jiri Slaby02f11752006-12-08 02:39:28 -08003834 if (serial_paranoia_check(info, tty->name, "cy_break"))
3835 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836
3837 CY_LOCK(info, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003838 if (!IS_CYC_Z(cy_card[info->card])) {
3839 /* Let the transmit ISR take care of this (since it
3840 requires stuffing characters into the output stream).
3841 */
3842 if (break_state == -1) {
3843 if (!info->breakon) {
3844 info->breakon = 1;
3845 if (!info->xmit_cnt) {
3846 CY_UNLOCK(info, flags);
3847 start_xmit(info);
3848 CY_LOCK(info, flags);
3849 }
3850 }
3851 } else {
3852 if (!info->breakoff) {
3853 info->breakoff = 1;
3854 if (!info->xmit_cnt) {
3855 CY_UNLOCK(info, flags);
3856 start_xmit(info);
3857 CY_LOCK(info, flags);
3858 }
3859 }
3860 }
3861 } else {
3862 int retval;
3863
3864 if (break_state == -1) {
3865 retval = cyz_issue_cmd(&cy_card[info->card],
3866 info->line - cy_card[info->card].first_line,
3867 C_CM_SET_BREAK, 0L);
3868 if (retval != 0) {
3869 printk("cyc:cy_break (set) retval on ttyC%d "
3870 "was %x\n", info->line, retval);
3871 }
3872 } else {
3873 retval = cyz_issue_cmd(&cy_card[info->card],
3874 info->line - cy_card[info->card].first_line,
3875 C_CM_CLR_BREAK, 0L);
3876 if (retval != 0) {
3877 printk("cyc:cy_break (clr) retval on ttyC%d "
3878 "was %x\n", info->line, retval);
3879 }
3880 }
3881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 CY_UNLOCK(info, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003883} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884
3885static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003886get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
Jiri Slaby02f11752006-12-08 02:39:28 -08003889 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
3890 return -EFAULT;
3891 info->mon.int_count = 0;
3892 info->mon.char_count = 0;
3893 info->mon.char_max = 0;
3894 info->mon.char_last = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003896} /* get_mon_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
Jiri Slaby02f11752006-12-08 02:39:28 -08003898static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899{
Jiri Slaby02f11752006-12-08 02:39:28 -08003900 void __iomem *base_addr;
3901 int card, channel, chip, index;
3902 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
Jiri Slaby02f11752006-12-08 02:39:28 -08003904 card = info->card;
3905 channel = info->line - cy_card[card].first_line;
3906 if (!IS_CYC_Z(cy_card[card])) {
3907 chip = channel >> 2;
3908 channel &= 0x03;
3909 index = cy_card[card].bus_index;
3910 base_addr =
3911 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912
Jiri Slaby02f11752006-12-08 02:39:28 -08003913 info->cor3 &= ~CyREC_FIFO;
3914 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Jiri Slaby02f11752006-12-08 02:39:28 -08003916 CY_LOCK(info, flags);
3917 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
3918 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
3919 CY_UNLOCK(info, flags);
3920 } else {
3921 // Nothing to do!
3922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003924} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
3926static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003927get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928{
Jiri Slaby02f11752006-12-08 02:39:28 -08003929 void __iomem *base_addr;
3930 int card, channel, chip, index;
3931 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
Jiri Slaby02f11752006-12-08 02:39:28 -08003933 card = info->card;
3934 channel = info->line - cy_card[card].first_line;
3935 if (!IS_CYC_Z(cy_card[card])) {
3936 chip = channel >> 2;
3937 channel &= 0x03;
3938 index = cy_card[card].bus_index;
3939 base_addr =
3940 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
3941
3942 tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
3943 return put_user(tmp, value);
3944 } else {
3945 // Nothing to do!
3946 return 0;
3947 }
3948} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
3950static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003951set_default_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952{
Jiri Slaby02f11752006-12-08 02:39:28 -08003953 info->default_threshold = value & 0x0f;
3954 return 0;
3955} /* set_default_threshold */
3956
3957static int
3958get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
3959{
3960 return put_user(info->default_threshold, value);
3961} /* get_default_threshold */
3962
3963static int set_timeout(struct cyclades_port *info, unsigned long value)
3964{
3965 void __iomem *base_addr;
3966 int card, channel, chip, index;
3967 unsigned long flags;
3968
3969 card = info->card;
3970 channel = info->line - cy_card[card].first_line;
3971 if (!IS_CYC_Z(cy_card[card])) {
3972 chip = channel >> 2;
3973 channel &= 0x03;
3974 index = cy_card[card].bus_index;
3975 base_addr =
3976 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
3977
3978 CY_LOCK(info, flags);
3979 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
3980 CY_UNLOCK(info, flags);
3981 } else {
3982 // Nothing to do!
3983 }
3984 return 0;
3985} /* set_timeout */
3986
3987static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
3988{
3989 void __iomem *base_addr;
3990 int card, channel, chip, index;
3991 unsigned long tmp;
3992
3993 card = info->card;
3994 channel = info->line - cy_card[card].first_line;
3995 if (!IS_CYC_Z(cy_card[card])) {
3996 chip = channel >> 2;
3997 channel &= 0x03;
3998 index = cy_card[card].bus_index;
3999 base_addr =
4000 cy_card[card].base_addr + (cy_chip_offset[chip] << index);
4001
4002 tmp = cy_readb(base_addr + (CyRTPR << index));
4003 return put_user(tmp, value);
4004 } else {
4005 // Nothing to do!
4006 return 0;
4007 }
4008} /* get_timeout */
4009
4010static int set_default_timeout(struct cyclades_port *info, unsigned long value)
4011{
4012 info->default_timeout = value & 0xff;
4013 return 0;
4014} /* set_default_timeout */
4015
4016static int
4017get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
4018{
4019 return put_user(info->default_timeout, value);
4020} /* get_default_timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022/*
4023 * This routine allows the tty driver to implement device-
4024 * specific ioctl's. If the ioctl number passed in cmd is
4025 * not recognized by the driver, it should return ENOIOCTLCMD.
4026 */
4027static int
Jiri Slaby02f11752006-12-08 02:39:28 -08004028cy_ioctl(struct tty_struct *tty, struct file *file,
4029 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030{
Jiri Slaby02f11752006-12-08 02:39:28 -08004031 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4032 struct cyclades_icount cprev, cnow; /* kernel counter temps */
4033 struct serial_icounter_struct __user *p_cuser; /* user space */
4034 int ret_val = 0;
4035 unsigned long flags;
4036 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
Jiri Slaby02f11752006-12-08 02:39:28 -08004038 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
4039 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08004042 printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043#endif
4044
Jiri Slaby02f11752006-12-08 02:39:28 -08004045 switch (cmd) {
4046 case CYGETMON:
4047 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08004049 case CYGETTHRESH:
4050 ret_val = get_threshold(info, argp);
4051 break;
4052 case CYSETTHRESH:
4053 ret_val = set_threshold(info, arg);
4054 break;
4055 case CYGETDEFTHRESH:
4056 ret_val = get_default_threshold(info, argp);
4057 break;
4058 case CYSETDEFTHRESH:
4059 ret_val = set_default_threshold(info, arg);
4060 break;
4061 case CYGETTIMEOUT:
4062 ret_val = get_timeout(info, argp);
4063 break;
4064 case CYSETTIMEOUT:
4065 ret_val = set_timeout(info, arg);
4066 break;
4067 case CYGETDEFTIMEOUT:
4068 ret_val = get_default_timeout(info, argp);
4069 break;
4070 case CYSETDEFTIMEOUT:
4071 ret_val = set_default_timeout(info, arg);
4072 break;
4073 case CYSETRFLOW:
4074 info->rflow = (int)arg;
4075 ret_val = 0;
4076 break;
4077 case CYGETRFLOW:
4078 ret_val = info->rflow;
4079 break;
4080 case CYSETRTSDTR_INV:
4081 info->rtsdtr_inv = (int)arg;
4082 ret_val = 0;
4083 break;
4084 case CYGETRTSDTR_INV:
4085 ret_val = info->rtsdtr_inv;
4086 break;
4087 case CYGETCARDINFO:
4088 if (copy_to_user(argp, &cy_card[info->card],
4089 sizeof(struct cyclades_card))) {
4090 ret_val = -EFAULT;
4091 break;
4092 }
4093 ret_val = 0;
4094 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08004096 ret_val = info->chip_rev;
4097 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098#ifndef CONFIG_CYZ_INTR
4099 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08004100 cyz_polling_cycle = (arg * HZ) / 1000;
4101 ret_val = 0;
4102 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08004104 ret_val = (cyz_polling_cycle * 1000) / HZ;
4105 break;
4106#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 case CYSETWAIT:
Jiri Slaby02f11752006-12-08 02:39:28 -08004108 info->closing_wait = (unsigned short)arg *HZ / 100;
4109 ret_val = 0;
4110 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 case CYGETWAIT:
Jiri Slaby02f11752006-12-08 02:39:28 -08004112 ret_val = info->closing_wait / (HZ / 100);
4113 break;
4114 case TIOCGSERIAL:
4115 ret_val = get_serial_info(info, argp);
4116 break;
4117 case TIOCSSERIAL:
4118 ret_val = set_serial_info(info, argp);
4119 break;
4120 case TIOCSERGETLSR: /* Get line status register */
4121 ret_val = get_lsr_info(info, argp);
4122 break;
4123 /*
4124 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
4125 * - mask passed in arg for lines of interest
4126 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
4127 * Caller should use TIOCGICOUNT to see which one it was
4128 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 case TIOCMIWAIT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 CY_LOCK(info, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004131 /* note the counters on entry */
4132 cprev = info->icount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 CY_UNLOCK(info, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004134 while (1) {
4135 interruptible_sleep_on(&info->delta_msr_wait);
4136 /* see if a signal did it */
4137 if (signal_pending(current)) {
4138 return -ERESTARTSYS;
4139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Jiri Slaby02f11752006-12-08 02:39:28 -08004141 CY_LOCK(info, flags);
4142 cnow = info->icount; /* atomic copy */
4143 CY_UNLOCK(info, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144
Jiri Slaby02f11752006-12-08 02:39:28 -08004145 if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
4146 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
4147 return -EIO; /* no change => error */
4148 }
4149 if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
4150 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
4151 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
4152 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
4153 return 0;
4154 }
4155 cprev = cnow;
4156 }
4157 /* NOTREACHED */
4158
4159 /*
4160 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
4161 * Return: write counters to the user passed counter struct
4162 * NB: both 1->0 and 0->1 transitions are counted except for
4163 * RI where only 0->1 is counted.
4164 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 case TIOCGICOUNT:
Jiri Slaby02f11752006-12-08 02:39:28 -08004166 CY_LOCK(info, flags);
4167 cnow = info->icount;
4168 CY_UNLOCK(info, flags);
4169 p_cuser = argp;
4170 ret_val = put_user(cnow.cts, &p_cuser->cts);
4171 if (ret_val)
4172 return ret_val;
4173 ret_val = put_user(cnow.dsr, &p_cuser->dsr);
4174 if (ret_val)
4175 return ret_val;
4176 ret_val = put_user(cnow.rng, &p_cuser->rng);
4177 if (ret_val)
4178 return ret_val;
4179 ret_val = put_user(cnow.dcd, &p_cuser->dcd);
4180 if (ret_val)
4181 return ret_val;
4182 ret_val = put_user(cnow.rx, &p_cuser->rx);
4183 if (ret_val)
4184 return ret_val;
4185 ret_val = put_user(cnow.tx, &p_cuser->tx);
4186 if (ret_val)
4187 return ret_val;
4188 ret_val = put_user(cnow.frame, &p_cuser->frame);
4189 if (ret_val)
4190 return ret_val;
4191 ret_val = put_user(cnow.overrun, &p_cuser->overrun);
4192 if (ret_val)
4193 return ret_val;
4194 ret_val = put_user(cnow.parity, &p_cuser->parity);
4195 if (ret_val)
4196 return ret_val;
4197 ret_val = put_user(cnow.brk, &p_cuser->brk);
4198 if (ret_val)
4199 return ret_val;
4200 ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
4201 if (ret_val)
4202 return ret_val;
4203 ret_val = 0;
4204 break;
4205 default:
4206 ret_val = -ENOIOCTLCMD;
4207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208
4209#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08004210 printk(" cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211#endif
4212
Jiri Slaby02f11752006-12-08 02:39:28 -08004213 return ret_val;
4214} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
4216/*
4217 * This routine allows the tty driver to be notified when
4218 * device's termios settings have changed. Note that a
4219 * well-designed tty driver should be prepared to accept the case
4220 * where old == NULL, and try to do something rational.
4221 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004222static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223{
Jiri Slaby02f11752006-12-08 02:39:28 -08004224 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
4226#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08004227 printk("cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228#endif
4229
Jiri Slaby02f11752006-12-08 02:39:28 -08004230 if (tty->termios->c_cflag == old_termios->c_cflag &&
4231 (tty->termios->c_iflag & (IXON | IXANY)) ==
4232 (old_termios->c_iflag & (IXON | IXANY)))
4233 return;
4234 set_line_char(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Jiri Slaby02f11752006-12-08 02:39:28 -08004236 if ((old_termios->c_cflag & CRTSCTS) &&
4237 !(tty->termios->c_cflag & CRTSCTS)) {
4238 tty->hw_stopped = 0;
4239 cy_start(tty);
4240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08004242 /*
4243 * No need to wake up processes in open wait, since they
4244 * sample the CLOCAL flag once, and don't recheck it.
4245 * XXX It's not clear whether the current behavior is correct
4246 * or not. Hence, this may change.....
4247 */
4248 if (!(old_termios->c_cflag & CLOCAL) &&
4249 (tty->termios->c_cflag & CLOCAL))
4250 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251#endif
4252
Jiri Slaby02f11752006-12-08 02:39:28 -08004253 return;
4254} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
4256/* This function is used to send a high-priority XON/XOFF character to
4257 the device.
4258*/
Jiri Slaby02f11752006-12-08 02:39:28 -08004259static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260{
Jiri Slaby02f11752006-12-08 02:39:28 -08004261 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 int card, channel;
4263
Jiri Slaby02f11752006-12-08 02:39:28 -08004264 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 return;
4266
Jiri Slaby02f11752006-12-08 02:39:28 -08004267 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268
4269 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08004270 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
4272 card = info->card;
4273 channel = info->line - cy_card[card].first_line;
4274
Jiri Slaby02f11752006-12-08 02:39:28 -08004275 if (IS_CYC_Z(cy_card[card])) {
4276 if (ch == STOP_CHAR(tty))
4277 cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
4278 0L);
4279 else if (ch == START_CHAR(tty))
4280 cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
4281 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 }
4283}
4284
4285/* This routine is called by the upper-layer tty layer to signal
4286 that incoming characters should be throttled because the input
4287 buffers are close to full.
4288 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004289static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290{
Jiri Slaby02f11752006-12-08 02:39:28 -08004291 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4292 unsigned long flags;
4293 void __iomem *base_addr;
4294 int card, chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295
4296#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08004297 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Jiri Slaby02f11752006-12-08 02:39:28 -08004299 printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
4300 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301#endif
4302
Jiri Slaby02f11752006-12-08 02:39:28 -08004303 if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
4304 return;
4305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
Jiri Slaby02f11752006-12-08 02:39:28 -08004307 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
Jiri Slaby02f11752006-12-08 02:39:28 -08004309 if (I_IXOFF(tty)) {
4310 if (!IS_CYC_Z(cy_card[card]))
4311 cy_send_xchar(tty, STOP_CHAR(tty));
4312 else
4313 info->throttle = 1;
4314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315
Jiri Slaby02f11752006-12-08 02:39:28 -08004316 if (tty->termios->c_cflag & CRTSCTS) {
4317 channel = info->line - cy_card[card].first_line;
4318 if (!IS_CYC_Z(cy_card[card])) {
4319 chip = channel >> 2;
4320 channel &= 0x03;
4321 index = cy_card[card].bus_index;
4322 base_addr = cy_card[card].base_addr +
4323 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Jiri Slaby02f11752006-12-08 02:39:28 -08004325 CY_LOCK(info, flags);
4326 cy_writeb(base_addr + (CyCAR << index),
4327 (u_char) channel);
4328 if (info->rtsdtr_inv) {
4329 cy_writeb(base_addr + (CyMSVR2 << index),
4330 ~CyDTR);
4331 } else {
4332 cy_writeb(base_addr + (CyMSVR1 << index),
4333 ~CyRTS);
4334 }
4335 CY_UNLOCK(info, flags);
4336 } else {
4337 info->throttle = 1;
4338 }
4339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Jiri Slaby02f11752006-12-08 02:39:28 -08004341 return;
4342} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
4344/*
4345 * This routine notifies the tty driver that it should signal
4346 * that characters can now be sent to the tty without fear of
4347 * overrunning the input buffers of the line disciplines.
4348 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004349static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350{
Jiri Slaby02f11752006-12-08 02:39:28 -08004351 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4352 unsigned long flags;
4353 void __iomem *base_addr;
4354 int card, chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
4356#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08004357 char buf[64];
4358
4359 printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
4360 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361#endif
4362
Jiri Slaby02f11752006-12-08 02:39:28 -08004363 if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
4364 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366
Jiri Slaby02f11752006-12-08 02:39:28 -08004367 if (I_IXOFF(tty)) {
4368 if (info->x_char)
4369 info->x_char = 0;
4370 else
4371 cy_send_xchar(tty, START_CHAR(tty));
4372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
Jiri Slaby02f11752006-12-08 02:39:28 -08004374 if (tty->termios->c_cflag & CRTSCTS) {
4375 card = info->card;
4376 channel = info->line - cy_card[card].first_line;
4377 if (!IS_CYC_Z(cy_card[card])) {
4378 chip = channel >> 2;
4379 channel &= 0x03;
4380 index = cy_card[card].bus_index;
4381 base_addr = cy_card[card].base_addr +
4382 (cy_chip_offset[chip] << index);
4383
4384 CY_LOCK(info, flags);
4385 cy_writeb(base_addr + (CyCAR << index),
4386 (u_char) channel);
4387 if (info->rtsdtr_inv) {
4388 cy_writeb(base_addr + (CyMSVR2 << index),
4389 CyDTR);
4390 } else {
4391 cy_writeb(base_addr + (CyMSVR1 << index),
4392 CyRTS);
4393 }
4394 CY_UNLOCK(info, flags);
4395 } else {
4396 info->throttle = 0;
4397 }
4398 }
4399
4400 return;
4401} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402
4403/* cy_start and cy_stop provide software output flow control as a
4404 function of XON/XOFF, software CTS, and other such stuff.
4405*/
Jiri Slaby02f11752006-12-08 02:39:28 -08004406static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407{
Jiri Slaby02f11752006-12-08 02:39:28 -08004408 struct cyclades_card *cinfo;
4409 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4410 void __iomem *base_addr;
4411 int chip, channel, index;
4412 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413
4414#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08004415 printk("cyc:cy_stop ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416#endif
4417
Jiri Slaby02f11752006-12-08 02:39:28 -08004418 if (serial_paranoia_check(info, tty->name, "cy_stop"))
4419 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420
Jiri Slaby02f11752006-12-08 02:39:28 -08004421 cinfo = &cy_card[info->card];
4422 channel = info->line - cinfo->first_line;
4423 if (!IS_CYC_Z(*cinfo)) {
4424 index = cinfo->bus_index;
4425 chip = channel >> 2;
4426 channel &= 0x03;
4427 base_addr = cy_card[info->card].base_addr +
4428 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
Jiri Slaby02f11752006-12-08 02:39:28 -08004430 CY_LOCK(info, flags);
4431 cy_writeb(base_addr + (CyCAR << index),
4432 (u_char)(channel & 0x0003)); /* index channel */
4433 cy_writeb(base_addr + (CySRER << index),
4434 cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
4435 CY_UNLOCK(info, flags);
4436 } else {
4437 // Nothing to do!
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
Jiri Slaby02f11752006-12-08 02:39:28 -08004440 return;
4441} /* cy_stop */
4442
4443static void cy_start(struct tty_struct *tty)
4444{
4445 struct cyclades_card *cinfo;
4446 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4447 void __iomem *base_addr;
4448 int chip, channel, index;
4449 unsigned long flags;
4450
4451#ifdef CY_DEBUG_OTHER
4452 printk("cyc:cy_start ttyC%d\n", info->line); /* */
4453#endif
4454
4455 if (serial_paranoia_check(info, tty->name, "cy_start"))
4456 return;
4457
4458 cinfo = &cy_card[info->card];
4459 channel = info->line - cinfo->first_line;
4460 index = cinfo->bus_index;
4461 if (!IS_CYC_Z(*cinfo)) {
4462 chip = channel >> 2;
4463 channel &= 0x03;
4464 base_addr = cy_card[info->card].base_addr +
4465 (cy_chip_offset[chip] << index);
4466
4467 CY_LOCK(info, flags);
4468 cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
4469 cy_writeb(base_addr + (CySRER << index),
4470 cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
4471 CY_UNLOCK(info, flags);
4472 } else {
4473 // Nothing to do!
4474 }
4475
4476 return;
4477} /* cy_start */
4478
4479static void cy_flush_buffer(struct tty_struct *tty)
4480{
4481 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4482 int card, channel, retval;
4483 unsigned long flags;
4484
4485#ifdef CY_DEBUG_IO
4486 printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
4487#endif
4488
4489 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
4490 return;
4491
4492 card = info->card;
4493 channel = (info->line) - (cy_card[card].first_line);
4494
4495 CY_LOCK(info, flags);
4496 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
4497 CY_UNLOCK(info, flags);
4498
4499 if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
4500 buffers as well */
4501 CY_LOCK(info, flags);
4502 retval =
4503 cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
4504 if (retval != 0) {
4505 printk("cyc: flush_buffer retval on ttyC%d was %x\n",
4506 info->line, retval);
4507 }
4508 CY_UNLOCK(info, flags);
4509 }
4510 tty_wakeup(tty);
4511 wake_up_interruptible(&tty->write_wait);
4512} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
4514/*
4515 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
4516 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004517static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518{
Jiri Slaby02f11752006-12-08 02:39:28 -08004519 struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
4520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521#ifdef CY_DEBUG_OTHER
Jiri Slaby02f11752006-12-08 02:39:28 -08004522 printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523#endif
4524
Jiri Slaby02f11752006-12-08 02:39:28 -08004525 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
4526 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527
Jiri Slaby02f11752006-12-08 02:39:28 -08004528 cy_flush_buffer(tty);
4529 shutdown(info);
4530 info->event = 0;
4531 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532#ifdef CY_DEBUG_COUNT
Jiri Slaby02f11752006-12-08 02:39:28 -08004533 printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004535 info->tty = NULL;
4536 info->flags &= ~ASYNC_NORMAL_ACTIVE;
4537 wake_up_interruptible(&info->open_wait);
4538} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539
4540/*
4541 * ---------------------------------------------------------------------
4542 * cy_init() and friends
4543 *
4544 * cy_init() is called at boot-time to initialize the serial driver.
4545 * ---------------------------------------------------------------------
4546 */
4547
4548/* initialize chips on Cyclom-Y card -- return number of valid
4549 chips (which is number of ports/4) */
4550static unsigned short __init
Jiri Slaby02f11752006-12-08 02:39:28 -08004551cyy_init_card(void __iomem * true_base_addr, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
Jiri Slaby02f11752006-12-08 02:39:28 -08004553 unsigned int chip_number;
4554 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Jiri Slaby02f11752006-12-08 02:39:28 -08004556 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
4557 /* Cy_HwReset is 0x1400 */
4558 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
4559 /* Cy_ClrIntr is 0x1800 */
4560 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561
Jiri Slaby02f11752006-12-08 02:39:28 -08004562 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
4563 base_addr =
4564 true_base_addr + (cy_chip_offset[chip_number] << index);
4565 mdelay(1);
4566 if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
4567 /*************
4568 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
4569 chip_number, (unsigned long)base_addr);
4570 *************/
4571 return chip_number;
4572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
Jiri Slaby02f11752006-12-08 02:39:28 -08004574 cy_writeb(base_addr + (CyGFRCR << index), 0);
4575 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576
Jiri Slaby02f11752006-12-08 02:39:28 -08004577 /* The Cyclom-16Y does not decode address bit 9 and therefore
4578 cannot distinguish between references to chip 0 and a non-
4579 existent chip 4. If the preceding clearing of the supposed
4580 chip 4 GFRCR register appears at chip 0, there is no chip 4
4581 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
4582 */
4583 if (chip_number == 4 && cy_readb(true_base_addr +
4584 (cy_chip_offset[0] << index) +
4585 (CyGFRCR << index)) == 0) {
4586 return chip_number;
4587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Jiri Slaby02f11752006-12-08 02:39:28 -08004589 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
4590 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
Jiri Slaby02f11752006-12-08 02:39:28 -08004592 if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
4593 /*
4594 printk(" chip #%d at %#6lx is not responding ",
4595 chip_number, (unsigned long)base_addr);
4596 printk("(GFRCR stayed 0)\n",
4597 */
4598 return chip_number;
4599 }
4600 if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
4601 0x40) {
4602 /*
4603 printk(" chip #%d at %#6lx is not valid (GFRCR == "
4604 "%#2x)\n",
4605 chip_number, (unsigned long)base_addr,
4606 base_addr[CyGFRCR<<index]);
4607 */
4608 return chip_number;
4609 }
4610 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
4611 if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
4612 /* It is a CD1400 rev. J or later */
4613 /* Impossible to reach 5ms with this chip.
4614 Changed to 2ms instead (f = 500 Hz). */
4615 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
4616 } else {
4617 /* f = 200 Hz */
4618 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
4619 }
4620
4621 /*
4622 printk(" chip #%d at %#6lx is rev 0x%2x\n",
4623 chip_number, (unsigned long)base_addr,
4624 cy_readb(base_addr+(CyGFRCR<<index)));
4625 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004627 return chip_number;
4628} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629
4630/*
4631 * ---------------------------------------------------------------------
4632 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
4633 * sets global variables and return the number of ISA boards found.
4634 * ---------------------------------------------------------------------
4635 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004636static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637{
4638#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08004639 unsigned short cy_isa_irq, nboard;
4640 void __iomem *cy_isa_address;
4641 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08004643 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644#endif
4645
Jiri Slaby02f11752006-12-08 02:39:28 -08004646 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647
4648#ifdef MODULE
4649 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08004650 for (i = 0; i < NR_CARDS; i++) {
4651 if (maddr[i] || i) {
4652 isparam = 1;
4653 cy_isa_addresses[i] = maddr[i];
4654 }
4655 if (!maddr[i])
4656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 }
4658#endif
4659
Jiri Slaby02f11752006-12-08 02:39:28 -08004660 /* scan the address table probing for Cyclom-Y/ISA boards */
4661 for (i = 0; i < NR_ISA_ADDRS; i++) {
4662 unsigned int isa_address = cy_isa_addresses[i];
4663 if (isa_address == 0x0000) {
4664 return (nboard);
4665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666
Jiri Slaby02f11752006-12-08 02:39:28 -08004667 /* probe for CD1400... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 cy_isa_address = ioremap(isa_address, CyISA_Ywin);
Jiri Slaby02f11752006-12-08 02:39:28 -08004669 cy_isa_nchan = CyPORTS_PER_CHIP *
4670 cyy_init_card(cy_isa_address, 0);
4671 if (cy_isa_nchan == 0) {
4672 continue;
4673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674#ifdef MODULE
4675 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08004676 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 else
4678#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004679 /* find out the board's irq by probing */
4680 cy_isa_irq = detect_isa_irq(cy_isa_address);
4681 if (cy_isa_irq == 0) {
4682 printk("Cyclom-Y/ISA found at 0x%lx ",
4683 (unsigned long)cy_isa_address);
4684 printk("but the IRQ could not be detected.\n");
4685 continue;
4686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Jiri Slaby02f11752006-12-08 02:39:28 -08004688 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
4689 printk("Cyclom-Y/ISA found at 0x%lx ",
4690 (unsigned long)cy_isa_address);
4691 printk("but no more channels are available.\n");
4692 printk("Change NR_PORTS in cyclades.c and recompile "
4693 "kernel.\n");
4694 return (nboard);
4695 }
4696 /* fill the next cy_card structure available */
4697 for (j = 0; j < NR_CARDS; j++) {
4698 if (cy_card[j].base_addr == 0)
4699 break;
4700 }
4701 if (j == NR_CARDS) { /* no more cy_cards available */
4702 printk("Cyclom-Y/ISA found at 0x%lx ",
4703 (unsigned long)cy_isa_address);
4704 printk("but no more cards can be used .\n");
4705 printk("Change NR_CARDS in cyclades.c and recompile "
4706 "kernel.\n");
4707 return (nboard);
4708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
Jiri Slaby02f11752006-12-08 02:39:28 -08004710 /* allocate IRQ */
4711 if (request_irq(cy_isa_irq, cyy_interrupt,
4712 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
4713 printk("Cyclom-Y/ISA found at 0x%lx ",
4714 (unsigned long)cy_isa_address);
4715 printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
4716 return (nboard);
4717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718
Jiri Slaby02f11752006-12-08 02:39:28 -08004719 /* set cy_card */
4720 cy_card[j].base_addr = cy_isa_address;
4721 cy_card[j].ctl_addr = NULL;
4722 cy_card[j].irq = (int)cy_isa_irq;
4723 cy_card[j].bus_index = 0;
4724 cy_card[j].first_line = cy_next_channel;
4725 cy_card[j].num_chips = cy_isa_nchan / 4;
4726 nboard++;
4727
4728 /* print message */
4729 printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
4730 j + 1, (unsigned long)cy_isa_address,
4731 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
4732 cy_isa_irq);
4733 printk("%d channels starting from port %d.\n",
4734 cy_isa_nchan, cy_next_channel);
4735 cy_next_channel += cy_isa_nchan;
4736 }
4737 return (nboard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738#else
Jiri Slaby02f11752006-12-08 02:39:28 -08004739 return (0);
4740#endif /* CONFIG_ISA */
4741} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742
Jiri Slaby02f11752006-12-08 02:39:28 -08004743static void plx_init(void __iomem * addr, uclong initctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
Jiri Slaby02f11752006-12-08 02:39:28 -08004745 /* Reset PLX */
4746 cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
4747 udelay(100L);
4748 cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749
Jiri Slaby02f11752006-12-08 02:39:28 -08004750 /* Reload Config. Registers from EEPROM */
4751 cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
4752 udelay(100L);
4753 cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754}
4755
4756/*
4757 * ---------------------------------------------------------------------
4758 * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
4759 * sets global variables and return the number of PCI boards found.
4760 * ---------------------------------------------------------------------
4761 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004762static int __init cy_detect_pci(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
4764#ifdef CONFIG_PCI
4765
Jiri Slaby02f11752006-12-08 02:39:28 -08004766 struct pci_dev *pdev = NULL;
4767 unsigned char cyy_rev_id;
4768 unsigned char cy_pci_irq = 0;
4769 uclong cy_pci_phys0, cy_pci_phys2;
4770 void __iomem *cy_pci_addr0, *cy_pci_addr2;
4771 unsigned short i, j, cy_pci_nchan, plx_ver;
4772 unsigned short device_id, dev_index = 0;
4773 uclong mailbox;
4774 uclong ZeIndex = 0;
4775 void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
4776 uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
4777 unsigned char Ze_irq[NR_CARDS];
4778 struct pci_dev *Ze_pdev[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Jiri Slaby02f11752006-12-08 02:39:28 -08004780 for (i = 0; i < NR_CARDS; i++) {
4781 /* look for a Cyclades card by vendor and device id */
4782 while ((device_id = cy_pci_dev_id[dev_index]) != 0) {
4783 if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
4784 device_id, pdev)) == NULL) {
4785 dev_index++; /* try next device id */
4786 } else {
4787 break; /* found a board */
4788 }
4789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790
4791 if (device_id == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08004792 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793
4794 if (pci_enable_device(pdev))
Jiri Slaby02f11752006-12-08 02:39:28 -08004795 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
Jiri Slaby02f11752006-12-08 02:39:28 -08004797 /* read PCI configuration area */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 cy_pci_irq = pdev->irq;
4799 cy_pci_phys0 = pci_resource_start(pdev, 0);
4800 cy_pci_phys2 = pci_resource_start(pdev, 2);
4801 pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
4802
4803 device_id &= ~PCI_DEVICE_ID_MASK;
4804
Jiri Slaby02f11752006-12-08 02:39:28 -08004805 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
4806 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807#ifdef CY_PCI_DEBUG
Jiri Slaby02f11752006-12-08 02:39:28 -08004808 printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
4809 pdev->bus->number, pdev->devfn);
4810 printk("rev_id=%d) IRQ%d\n",
4811 cyy_rev_id, (int)cy_pci_irq);
4812 printk("Cyclom-Y/PCI:found winaddr=0x%lx "
4813 "ctladdr=0x%lx\n",
4814 (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815#endif
4816
Jiri Slaby02f11752006-12-08 02:39:28 -08004817 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
4818 printk(" Warning: PCI I/O bit incorrectly "
4819 "set. Ignoring it...\n");
4820 pdev->resource[2].flags &= ~IORESOURCE_IO;
4821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822
Jiri Slaby02f11752006-12-08 02:39:28 -08004823 /* Although we don't use this I/O region, we should
4824 request it from the kernel anyway, to avoid problems
4825 with other drivers accessing it. */
4826 if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
4827 printk(KERN_ERR "cyclades: failed to reserve "
4828 "PCI resources\n");
4829 continue;
4830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831#if defined(__alpha__)
Jiri Slaby02f11752006-12-08 02:39:28 -08004832 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
4833 printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
4834 pdev->bus->number, pdev->devfn);
4835 printk("rev_id=%d) IRQ%d\n",
4836 cyy_rev_id, (int)cy_pci_irq);
4837 printk("Cyclom-Y/PCI:found winaddr=0x%lx "
4838 "ctladdr=0x%lx\n",
4839 (ulong)cy_pci_phys2,
4840 (ulong)cy_pci_phys0);
4841 printk("Cyclom-Y/PCI not supported for low "
4842 "addresses in Alpha systems.\n");
4843 i--;
4844 continue;
4845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004847 cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
4848 cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
4850#ifdef CY_PCI_DEBUG
Jiri Slaby02f11752006-12-08 02:39:28 -08004851 printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
4852 "ctladdr=0x%lx\n",
4853 (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004855 cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
4856 cyy_init_card(cy_pci_addr2, 1));
4857 if (cy_pci_nchan == 0) {
4858 printk("Cyclom-Y PCI host card with ");
4859 printk("no Serial-Modules at 0x%lx.\n",
4860 (ulong) cy_pci_phys2);
4861 i--;
4862 continue;
4863 }
4864 if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
4865 printk("Cyclom-Y/PCI found at 0x%lx ",
4866 (ulong) cy_pci_phys2);
4867 printk("but no channels are available.\n");
4868 printk("Change NR_PORTS in cyclades.c and "
4869 "recompile kernel.\n");
4870 return (i);
4871 }
4872 /* fill the next cy_card structure available */
4873 for (j = 0; j < NR_CARDS; j++) {
4874 if (cy_card[j].base_addr == 0)
4875 break;
4876 }
4877 if (j == NR_CARDS) { /* no more cy_cards available */
4878 printk("Cyclom-Y/PCI found at 0x%lx ",
4879 (ulong) cy_pci_phys2);
4880 printk("but no more cards can be used.\n");
4881 printk("Change NR_CARDS in cyclades.c and "
4882 "recompile kernel.\n");
4883 return (i);
4884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
Jiri Slaby02f11752006-12-08 02:39:28 -08004886 /* allocate IRQ */
4887 if (request_irq(cy_pci_irq, cyy_interrupt,
4888 IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
4889 printk("Cyclom-Y/PCI found at 0x%lx ",
4890 (ulong) cy_pci_phys2);
4891 printk("but could not allocate IRQ%d.\n",
4892 cy_pci_irq);
4893 return (i);
4894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895
Jiri Slaby02f11752006-12-08 02:39:28 -08004896 /* set cy_card */
4897 cy_card[j].base_phys = (ulong) cy_pci_phys2;
4898 cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
4899 cy_card[j].base_addr = cy_pci_addr2;
4900 cy_card[j].ctl_addr = cy_pci_addr0;
4901 cy_card[j].irq = (int)cy_pci_irq;
4902 cy_card[j].bus_index = 1;
4903 cy_card[j].first_line = cy_next_channel;
4904 cy_card[j].num_chips = cy_pci_nchan / 4;
4905 cy_card[j].pdev = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
Jiri Slaby02f11752006-12-08 02:39:28 -08004907 /* enable interrupts in the PCI interface */
4908 plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
4909 switch (plx_ver) {
4910 case PLX_9050:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911
Jiri Slaby02f11752006-12-08 02:39:28 -08004912 cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
4913 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914
Jiri Slaby02f11752006-12-08 02:39:28 -08004915 case PLX_9060:
4916 case PLX_9080:
4917 default: /* Old boards, use PLX_9060 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Jiri Slaby02f11752006-12-08 02:39:28 -08004919 plx_init(cy_pci_addr0, 0x6c);
4920 /* For some yet unknown reason, once the PLX9060 reloads
4921 the EEPROM, the IRQ is lost and, thus, we have to
4922 re-write it to the PCI config. registers.
4923 This will remain here until we find a permanent
4924 fix. */
4925 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
4926 cy_pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927
Jiri Slaby02f11752006-12-08 02:39:28 -08004928 cy_writew(cy_pci_addr0 + 0x68,
4929 cy_readw(cy_pci_addr0 +
4930 0x68) | 0x0900);
4931 break;
4932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933
Jiri Slaby02f11752006-12-08 02:39:28 -08004934 /* print message */
4935 printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
4936 j + 1, (ulong)cy_pci_phys2,
4937 (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
4938 (int)cy_pci_irq);
4939 printk("%d channels starting from port %d.\n",
4940 cy_pci_nchan, cy_next_channel);
4941
4942 cy_next_channel += cy_pci_nchan;
4943 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
4944 /* print message */
4945 printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
4946 pdev->bus->number, pdev->devfn);
4947 printk("rev_id=%d) IRQ%d\n",
4948 cyy_rev_id, (int)cy_pci_irq);
4949 printk("Cyclades-Z/PCI: found winaddr=0x%lx "
4950 "ctladdr=0x%lx\n",
4951 (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
4952 printk("Cyclades-Z/PCI not supported for low "
4953 "addresses\n");
4954 break;
4955 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956#ifdef CY_PCI_DEBUG
Jiri Slaby02f11752006-12-08 02:39:28 -08004957 printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
4958 pdev->bus->number, pdev->devfn);
4959 printk("rev_id=%d) IRQ%d\n",
4960 cyy_rev_id, (int)cy_pci_irq);
4961 printk("Cyclades-Z/PCI: found winaddr=0x%lx "
4962 "ctladdr=0x%lx\n",
4963 (ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004965 cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966
Jiri Slaby02f11752006-12-08 02:39:28 -08004967 /* Disable interrupts on the PLX before resetting it */
4968 cy_writew(cy_pci_addr0 + 0x68,
4969 cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970
Jiri Slaby02f11752006-12-08 02:39:28 -08004971 plx_init(cy_pci_addr0, 0x6c);
4972 /* For some yet unknown reason, once the PLX9060 reloads
4973 the EEPROM, the IRQ is lost and, thus, we have to
4974 re-write it to the PCI config. registers.
4975 This will remain here until we find a permanent
4976 fix. */
4977 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
4978 cy_pci_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979
Jiri Slaby02f11752006-12-08 02:39:28 -08004980 mailbox =
4981 (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
4982 cy_pci_addr0)->mail_box_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
Jiri Slaby02f11752006-12-08 02:39:28 -08004984 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
4985 printk(" Warning: PCI I/O bit incorrectly "
4986 "set. Ignoring it...\n");
4987 pdev->resource[2].flags &= ~IORESOURCE_IO;
4988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
Jiri Slaby02f11752006-12-08 02:39:28 -08004990 /* Although we don't use this I/O region, we should
4991 request it from the kernel anyway, to avoid problems
4992 with other drivers accessing it. */
4993 if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
4994 printk(KERN_ERR "cyclades: failed to reserve "
4995 "PCI resources\n");
4996 continue;
4997 }
4998
4999 if (mailbox == ZE_V1) {
5000 cy_pci_addr2 = ioremap(cy_pci_phys2,
5001 CyPCI_Ze_win);
5002 if (ZeIndex == NR_CARDS) {
5003 printk("Cyclades-Ze/PCI found at "
5004 "0x%lx but no more cards can "
5005 "be used.\nChange NR_CARDS in "
5006 "cyclades.c and recompile "
5007 "kernel.\n",
5008 (ulong)cy_pci_phys2);
5009 } else {
5010 Ze_phys0[ZeIndex] = cy_pci_phys0;
5011 Ze_phys2[ZeIndex] = cy_pci_phys2;
5012 Ze_addr0[ZeIndex] = cy_pci_addr0;
5013 Ze_addr2[ZeIndex] = cy_pci_addr2;
5014 Ze_irq[ZeIndex] = cy_pci_irq;
5015 Ze_pdev[ZeIndex] = pdev;
5016 ZeIndex++;
5017 }
5018 i--;
5019 continue;
5020 } else {
5021 cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
5022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
5024#ifdef CY_PCI_DEBUG
Jiri Slaby02f11752006-12-08 02:39:28 -08005025 printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
5026 "ctladdr=0x%lx\n",
5027 (ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
5028 if (mailbox == ZO_V1) {
5029 cy_writel(&((struct RUNTIME_9060 *)
5030 (cy_pci_addr0))->loc_addr_base,
5031 WIN_CREG);
5032 PAUSE
5033 printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
5034 "%lx\n", (ulong) (0xff &
5035 cy_readl(&((struct CUSTOM_REG *)
5036 (cy_pci_addr2))->fpga_id)),
5037 (ulong)(0xff &
5038 cy_readl(&((struct CUSTOM_REG *)
5039 (cy_pci_addr2))->
5040 fpga_version)));
5041 cy_writel(&((struct RUNTIME_9060 *)
5042 (cy_pci_addr0))->loc_addr_base,
5043 WIN_RAM);
5044 } else {
5045 printk("Cyclades-Z/PCI: New Cyclades-Z board. "
5046 "FPGA not loaded\n");
5047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08005049 /* The following clears the firmware id word. This
5050 ensures that the driver will not attempt to talk to
5051 the board until it has been properly initialized.
5052 */
5053 PAUSE
5054 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
5055 cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Jiri Slaby02f11752006-12-08 02:39:28 -08005057 /* This must be a Cyclades-8Zo/PCI. The extendable
5058 version will have a different device_id and will
5059 be allocated its maximum number of ports. */
5060 cy_pci_nchan = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061
Jiri Slaby02f11752006-12-08 02:39:28 -08005062 if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
5063 printk("Cyclades-8Zo/PCI found at 0x%lx but"
5064 "no channels are available.\nChange "
5065 "NR_PORTS in cyclades.c and recompile "
5066 "kernel.\n", (ulong)cy_pci_phys2);
5067 return (i);
5068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
Jiri Slaby02f11752006-12-08 02:39:28 -08005070 /* fill the next cy_card structure available */
5071 for (j = 0; j < NR_CARDS; j++) {
5072 if (cy_card[j].base_addr == 0)
5073 break;
5074 }
5075 if (j == NR_CARDS) { /* no more cy_cards available */
5076 printk("Cyclades-8Zo/PCI found at 0x%lx but"
5077 "no more cards can be used.\nChange "
5078 "NR_CARDS in cyclades.c and recompile "
5079 "kernel.\n", (ulong)cy_pci_phys2);
5080 return (i);
5081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08005083 /* allocate IRQ only if board has an IRQ */
5084 if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
5085 if (request_irq(cy_pci_irq, cyz_interrupt,
5086 IRQF_SHARED, "Cyclades-Z",
5087 &cy_card[j])) {
5088 printk("Cyclom-8Zo/PCI found at 0x%lx "
5089 "but could not allocate "
5090 "IRQ%d.\n", (ulong)cy_pci_phys2,
5091 cy_pci_irq);
5092 return (i);
5093 }
5094 }
5095#endif /* CONFIG_CYZ_INTR */
5096
5097 /* set cy_card */
5098 cy_card[j].base_phys = cy_pci_phys2;
5099 cy_card[j].ctl_phys = cy_pci_phys0;
5100 cy_card[j].base_addr = cy_pci_addr2;
5101 cy_card[j].ctl_addr = cy_pci_addr0;
5102 cy_card[j].irq = (int)cy_pci_irq;
5103 cy_card[j].bus_index = 1;
5104 cy_card[j].first_line = cy_next_channel;
5105 cy_card[j].num_chips = -1;
5106 cy_card[j].pdev = pdev;
5107
5108 /* print message */
5109#ifdef CONFIG_CYZ_INTR
5110 /* don't report IRQ if board is no IRQ */
5111 if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
5112 printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
5113 "IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
5114 (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
5115 (int)cy_pci_irq);
5116 else
5117#endif /* CONFIG_CYZ_INTR */
5118 printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
5119 j + 1, (ulong)cy_pci_phys2,
5120 (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
5121
5122 printk("%d channels starting from port %d.\n",
5123 cy_pci_nchan, cy_next_channel);
5124 cy_next_channel += cy_pci_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127
Jiri Slaby02f11752006-12-08 02:39:28 -08005128 for (; ZeIndex != 0 && i < NR_CARDS; i++) {
5129 cy_pci_phys0 = Ze_phys0[0];
5130 cy_pci_phys2 = Ze_phys2[0];
5131 cy_pci_addr0 = Ze_addr0[0];
5132 cy_pci_addr2 = Ze_addr2[0];
5133 cy_pci_irq = Ze_irq[0];
5134 pdev = Ze_pdev[0];
5135 for (j = 0; j < ZeIndex - 1; j++) {
5136 Ze_phys0[j] = Ze_phys0[j + 1];
5137 Ze_phys2[j] = Ze_phys2[j + 1];
5138 Ze_addr0[j] = Ze_addr0[j + 1];
5139 Ze_addr2[j] = Ze_addr2[j + 1];
5140 Ze_irq[j] = Ze_irq[j + 1];
5141 Ze_pdev[j] = Ze_pdev[j + 1];
5142 }
5143 ZeIndex--;
5144 mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
5145 cy_pci_addr0)->mail_box_0);
5146#ifdef CY_PCI_DEBUG
5147 printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
5148 (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
5149 printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not "
5150 "loaded\n");
5151#endif
5152 PAUSE
5153 /* This must be the new Cyclades-Ze/PCI. */
5154 cy_pci_nchan = ZE_V1_NPORTS;
5155
5156 if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
5157 printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
5158 "are available.\nChange NR_PORTS in cyclades.c "
5159 "and recompile kernel.\n",
5160 (ulong) cy_pci_phys2);
5161 return (i);
5162 }
5163
5164 /* fill the next cy_card structure available */
5165 for (j = 0; j < NR_CARDS; j++) {
5166 if (cy_card[j].base_addr == 0)
5167 break;
5168 }
5169 if (j == NR_CARDS) { /* no more cy_cards available */
5170 printk("Cyclades-Ze/PCI found at 0x%lx but no more "
5171 "cards can be used.\nChange NR_CARDS in "
5172 "cyclades.c and recompile kernel.\n",
5173 (ulong) cy_pci_phys2);
5174 return (i);
5175 }
5176#ifdef CONFIG_CYZ_INTR
5177 /* allocate IRQ only if board has an IRQ */
5178 if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
5179 if (request_irq(cy_pci_irq, cyz_interrupt,
5180 IRQF_SHARED, "Cyclades-Z",
5181 &cy_card[j])) {
5182 printk("Cyclom-Ze/PCI found at 0x%lx ",
5183 (ulong) cy_pci_phys2);
5184 printk("but could not allocate IRQ%d.\n",
5185 cy_pci_irq);
5186 return (i);
5187 }
5188 }
5189#endif /* CONFIG_CYZ_INTR */
5190
5191 /* set cy_card */
5192 cy_card[j].base_phys = cy_pci_phys2;
5193 cy_card[j].ctl_phys = cy_pci_phys0;
5194 cy_card[j].base_addr = cy_pci_addr2;
5195 cy_card[j].ctl_addr = cy_pci_addr0;
5196 cy_card[j].irq = (int)cy_pci_irq;
5197 cy_card[j].bus_index = 1;
5198 cy_card[j].first_line = cy_next_channel;
5199 cy_card[j].num_chips = -1;
5200 cy_card[j].pdev = pdev;
5201
5202 /* print message */
5203#ifdef CONFIG_CYZ_INTR
5204 /* don't report IRQ if board is no IRQ */
5205 if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
5206 printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
5207 j + 1, (ulong) cy_pci_phys2,
5208 (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
5209 (int)cy_pci_irq);
5210 else
5211#endif /* CONFIG_CYZ_INTR */
5212 printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
5213 j + 1, (ulong) cy_pci_phys2,
5214 (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
5215
5216 printk("%d channels starting from port %d.\n",
5217 cy_pci_nchan, cy_next_channel);
5218 cy_next_channel += cy_pci_nchan;
5219 }
5220 if (ZeIndex != 0) {
5221 printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
5222 "used.\nChange NR_CARDS in cyclades.c and recompile "
5223 "kernel.\n", (unsigned int)Ze_phys2[0]);
5224 }
5225 return (i);
5226#else
5227 return (0);
5228#endif /* ifdef CONFIG_PCI */
5229} /* cy_detect_pci */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
5231/*
5232 * This routine prints out the appropriate serial driver version number
5233 * and identifies which options were configured into this driver.
5234 */
Jiri Slaby02f11752006-12-08 02:39:28 -08005235static inline void show_version(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236{
Jiri Slaby02f11752006-12-08 02:39:28 -08005237 char *rcsvers, *rcsdate, *tmp;
5238 rcsvers = strchr(rcsid, ' ');
5239 rcsvers++;
5240 tmp = strchr(rcsvers, ' ');
5241 *tmp++ = '\0';
5242 rcsdate = strchr(tmp, ' ');
5243 rcsdate++;
5244 tmp = strrchr(rcsdate, ' ');
5245 *tmp = '\0';
5246 printk("Cyclades driver %s %s\n", rcsvers, rcsdate);
5247 printk(" built %s %s\n", __DATE__, __TIME__);
5248} /* show_version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249
Jiri Slaby02f11752006-12-08 02:39:28 -08005250static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
Jiri Slaby02f11752006-12-08 02:39:28 -08005252 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253{
Jiri Slaby02f11752006-12-08 02:39:28 -08005254 struct cyclades_port *info;
5255 int i;
5256 int len = 0;
5257 off_t begin = 0;
5258 off_t pos = 0;
5259 int size;
5260 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
Jiri Slaby02f11752006-12-08 02:39:28 -08005262 size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn "
5263 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
Jiri Slaby02f11752006-12-08 02:39:28 -08005265 pos += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 len += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267
Jiri Slaby02f11752006-12-08 02:39:28 -08005268 /* Output one line for each known port */
5269 for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
5270 info = &cy_port[i];
5271
5272 if (info->count)
5273 size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
5274 "%8lu %9lu %6ld\n", info->line,
5275 JIFFIES_DIFF(info->idle_stats.in_use,
5276 cur_jifs) / HZ,
5277 info->idle_stats.xmit_bytes,
5278 JIFFIES_DIFF(info->idle_stats.xmit_idle,
5279 cur_jifs) / HZ,
5280 info->idle_stats.recv_bytes,
5281 JIFFIES_DIFF(info->idle_stats.recv_idle,
5282 cur_jifs) / HZ,
5283 info->idle_stats.overruns,
5284 (long)info->tty->ldisc.num);
5285 else
5286 size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
5287 "%8lu %9lu %6ld\n",
5288 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
5289 len += size;
5290 pos = begin + len;
5291
5292 if (pos < offset) {
5293 len = 0;
5294 begin = pos;
5295 }
5296 if (pos > offset + length)
5297 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 }
Jiri Slaby02f11752006-12-08 02:39:28 -08005299 *eof = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300done:
Jiri Slaby02f11752006-12-08 02:39:28 -08005301 *start = buf + (offset - begin); /* Start of wanted data */
5302 len -= (offset - begin); /* Start slop */
5303 if (len > length)
5304 len = length; /* Ending slop */
5305 if (len < 0)
5306 len = 0;
5307 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308}
5309
5310/* The serial driver boot-time initialization code!
5311 Hardware I/O ports are mapped to character special devices on a
5312 first found, first allocated manner. That is, this code searches
5313 for Cyclom cards in the system. As each is found, it is probed
5314 to discover how many chips (and thus how many ports) are present.
5315 These ports are mapped to the tty ports 32 and upward in monotonic
5316 fashion. If an 8-port card is replaced with a 16-port card, the
5317 port mapping on a following card will shift.
5318
5319 This approach is different from what is used in the other serial
5320 device driver because the Cyclom is more properly a multiplexer,
5321 not just an aggregation of serial ports on one card.
5322
5323 If there are more cards with more ports than have been
5324 statically allocated above, a warning is printed and the
5325 extra ports are ignored.
5326 */
5327
Jeff Dikeb68e31d2006-10-02 02:17:18 -07005328static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08005329 .open = cy_open,
5330 .close = cy_close,
5331 .write = cy_write,
5332 .put_char = cy_put_char,
5333 .flush_chars = cy_flush_chars,
5334 .write_room = cy_write_room,
5335 .chars_in_buffer = cy_chars_in_buffer,
5336 .flush_buffer = cy_flush_buffer,
5337 .ioctl = cy_ioctl,
5338 .throttle = cy_throttle,
5339 .unthrottle = cy_unthrottle,
5340 .set_termios = cy_set_termios,
5341 .stop = cy_stop,
5342 .start = cy_start,
5343 .hangup = cy_hangup,
5344 .break_ctl = cy_break,
5345 .wait_until_sent = cy_wait_until_sent,
5346 .read_proc = cyclades_get_proc_info,
5347 .tiocmget = cy_tiocmget,
5348 .tiocmset = cy_tiocmset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349};
5350
Jiri Slaby02f11752006-12-08 02:39:28 -08005351static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352{
Jiri Slaby02f11752006-12-08 02:39:28 -08005353 struct cyclades_port *info;
5354 struct cyclades_card *cinfo;
5355 int number_z_boards = 0;
5356 int board, port, i, index;
5357 unsigned long mailbox;
5358 unsigned short chip_number;
5359 int nports;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360
Jiri Slaby02f11752006-12-08 02:39:28 -08005361 cy_serial_driver = alloc_tty_driver(NR_PORTS);
5362 if (!cy_serial_driver)
5363 return -ENOMEM;
5364 show_version();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
Jiri Slaby02f11752006-12-08 02:39:28 -08005366 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367
Jiri Slaby02f11752006-12-08 02:39:28 -08005368 cy_serial_driver->owner = THIS_MODULE;
5369 cy_serial_driver->driver_name = "cyclades";
5370 cy_serial_driver->name = "ttyC";
5371 cy_serial_driver->major = CYCLADES_MAJOR;
5372 cy_serial_driver->minor_start = 0;
5373 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
5374 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
5375 cy_serial_driver->init_termios = tty_std_termios;
5376 cy_serial_driver->init_termios.c_cflag =
5377 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
5378 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
5379 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380
Jiri Slaby02f11752006-12-08 02:39:28 -08005381 if (tty_register_driver(cy_serial_driver))
5382 panic("Couldn't register Cyclades serial driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383
Jiri Slaby02f11752006-12-08 02:39:28 -08005384 for (i = 0; i < NR_CARDS; i++) {
5385 /* base_addr=0 indicates board not found */
5386 cy_card[i].base_addr = NULL;
5387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Jiri Slaby02f11752006-12-08 02:39:28 -08005389 /* the code below is responsible to find the boards. Each different
5390 type of board has its own detection routine. If a board is found,
5391 the next cy_card structure available is set by the detection
5392 routine. These functions are responsible for checking the
5393 availability of cy_card and cy_port data structures and updating
5394 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395
Jiri Slaby02f11752006-12-08 02:39:28 -08005396 /* look for isa boards */
5397 cy_isa_nboard = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Jiri Slaby02f11752006-12-08 02:39:28 -08005399 /* look for pci boards */
5400 cy_pci_nboard = cy_detect_pci();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401
Jiri Slaby02f11752006-12-08 02:39:28 -08005402 cy_nboard = cy_isa_nboard + cy_pci_nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403
Jiri Slaby02f11752006-12-08 02:39:28 -08005404 /* invalidate remaining cy_card structures */
5405 for (i = 0; i < NR_CARDS; i++) {
5406 if (cy_card[i].base_addr == 0) {
5407 cy_card[i].first_line = -1;
5408 cy_card[i].ctl_addr = NULL;
5409 cy_card[i].irq = 0;
5410 cy_card[i].bus_index = 0;
5411 cy_card[i].first_line = 0;
5412 cy_card[i].num_chips = 0;
5413 }
5414 }
5415 /* invalidate remaining cy_port structures */
5416 for (i = cy_next_channel; i < NR_PORTS; i++) {
5417 cy_port[i].line = -1;
5418 cy_port[i].magic = -1;
5419 }
5420
5421 /* initialize per-port data structures for each valid board found */
5422 for (board = 0; board < cy_nboard; board++) {
5423 cinfo = &cy_card[board];
5424 if (cinfo->num_chips == -1) { /* Cyclades-Z */
5425 number_z_boards++;
5426 mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
5427 cy_card[board].ctl_addr)->
5428 mail_box_0);
5429 nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
5430 cinfo->intr_enabled = 0;
5431 cinfo->nports = 0; /* Will be correctly set later, after
5432 Z FW is loaded */
5433 spin_lock_init(&cinfo->card_lock);
5434 for (port = cinfo->first_line;
5435 port < cinfo->first_line + nports; port++) {
5436 info = &cy_port[port];
5437 info->magic = CYCLADES_MAGIC;
5438 info->type = PORT_STARTECH;
5439 info->card = board;
5440 info->line = port;
5441 info->chip_rev = 0;
5442 info->flags = STD_COM_FLAGS;
5443 info->tty = NULL;
5444 if (mailbox == ZO_V1)
5445 info->xmit_fifo_size = CYZ_FIFO_SIZE;
5446 else
5447 info->xmit_fifo_size =
5448 4 * CYZ_FIFO_SIZE;
5449 info->cor1 = 0;
5450 info->cor2 = 0;
5451 info->cor3 = 0;
5452 info->cor4 = 0;
5453 info->cor5 = 0;
5454 info->tbpr = 0;
5455 info->tco = 0;
5456 info->rbpr = 0;
5457 info->rco = 0;
5458 info->custom_divisor = 0;
5459 info->close_delay = 5 * HZ / 10;
5460 info->closing_wait = CLOSING_WAIT_DELAY;
5461 info->icount.cts = info->icount.dsr =
5462 info->icount.rng = info->icount.dcd = 0;
5463 info->icount.rx = info->icount.tx = 0;
5464 info->icount.frame = info->icount.parity = 0;
5465 info->icount.overrun = info->icount.brk = 0;
5466 info->x_char = 0;
5467 info->event = 0;
5468 info->count = 0;
5469 info->blocked_open = 0;
5470 info->default_threshold = 0;
5471 info->default_timeout = 0;
5472 INIT_WORK(&info->tqueue, do_softint);
5473 init_waitqueue_head(&info->open_wait);
5474 init_waitqueue_head(&info->close_wait);
5475 init_waitqueue_head(&info->shutdown_wait);
5476 init_waitqueue_head(&info->delta_msr_wait);
5477 /* info->session */
5478 /* info->pgrp */
5479 info->read_status_mask = 0;
5480 /* info->timeout */
5481 /* Bentson's vars */
5482 info->jiffies[0] = 0;
5483 info->jiffies[1] = 0;
5484 info->jiffies[2] = 0;
5485 info->rflush_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08005487 init_timer(&cyz_rx_full_timer[port]);
5488 cyz_rx_full_timer[port].function = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08005490 }
5491 continue;
5492 } else { /* Cyclom-Y of some kind */
5493 index = cinfo->bus_index;
5494 spin_lock_init(&cinfo->card_lock);
5495 cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
5496 for (port = cinfo->first_line;
5497 port < cinfo->first_line + cinfo->nports; port++) {
5498 info = &cy_port[port];
5499 info->magic = CYCLADES_MAGIC;
5500 info->type = PORT_CIRRUS;
5501 info->card = board;
5502 info->line = port;
5503 info->flags = STD_COM_FLAGS;
5504 info->tty = NULL;
5505 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
5506 info->cor1 =
5507 CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
5508 info->cor2 = CyETC;
5509 info->cor3 = 0x08; /* _very_ small rcv threshold */
5510 info->cor4 = 0;
5511 info->cor5 = 0;
5512 info->custom_divisor = 0;
5513 info->close_delay = 5 * HZ / 10;
5514 info->closing_wait = CLOSING_WAIT_DELAY;
5515 info->icount.cts = info->icount.dsr =
5516 info->icount.rng = info->icount.dcd = 0;
5517 info->icount.rx = info->icount.tx = 0;
5518 info->icount.frame = info->icount.parity = 0;
5519 info->icount.overrun = info->icount.brk = 0;
5520 chip_number = (port - cinfo->first_line) / 4;
5521 if ((info->chip_rev =
5522 cy_readb(cinfo->base_addr +
5523 (cy_chip_offset[chip_number] <<
5524 index) + (CyGFRCR << index))) >=
5525 CD1400_REV_J) {
5526 /* It is a CD1400 rev. J or later */
5527 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
5528 info->tco = baud_co_60[13]; /* Tx CO */
5529 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
5530 info->rco = baud_co_60[13]; /* Rx CO */
5531 info->rflow = 0;
5532 info->rtsdtr_inv = 1;
5533 } else {
5534 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
5535 info->tco = baud_co_25[13]; /* Tx CO */
5536 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
5537 info->rco = baud_co_25[13]; /* Rx CO */
5538 info->rflow = 0;
5539 info->rtsdtr_inv = 0;
5540 }
5541 info->x_char = 0;
5542 info->event = 0;
5543 info->count = 0;
5544 info->blocked_open = 0;
5545 info->default_threshold = 0;
5546 info->default_timeout = 0;
5547 INIT_WORK(&info->tqueue, do_softint);
5548 init_waitqueue_head(&info->open_wait);
5549 init_waitqueue_head(&info->close_wait);
5550 init_waitqueue_head(&info->shutdown_wait);
5551 init_waitqueue_head(&info->delta_msr_wait);
5552 /* info->session */
5553 /* info->pgrp */
5554 info->read_status_mask =
5555 CyTIMEOUT | CySPECHAR | CyBREAK
5556 | CyPARITY | CyFRAME | CyOVERRUN;
5557 /* info->timeout */
5558 }
5559 }
5560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
5562#ifndef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08005563 if (number_z_boards && !cyz_timeron) {
5564 cyz_timeron++;
5565 cyz_timerlist.expires = jiffies + 1;
5566 add_timer(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567#ifdef CY_PCI_DEBUG
Jiri Slaby02f11752006-12-08 02:39:28 -08005568 printk("Cyclades-Z polling initialized\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08005570 }
5571#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572
Jiri Slaby02f11752006-12-08 02:39:28 -08005573 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574
Jiri Slaby02f11752006-12-08 02:39:28 -08005575} /* cy_init */
5576
5577static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578{
Jiri Slaby02f11752006-12-08 02:39:28 -08005579 int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580
5581#ifndef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08005582 if (cyz_timeron){
5583 cyz_timeron = 0;
5584 del_timer(&cyz_timerlist);
5585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586#endif /* CONFIG_CYZ_INTR */
5587
Jiri Slaby02f11752006-12-08 02:39:28 -08005588 if ((e1 = tty_unregister_driver(cy_serial_driver)))
5589 printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
5590 e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591
Jiri Slaby02f11752006-12-08 02:39:28 -08005592 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593
Jiri Slaby02f11752006-12-08 02:39:28 -08005594 for (i = 0; i < NR_CARDS; i++) {
5595 if (cy_card[i].base_addr) {
5596 iounmap(cy_card[i].base_addr);
5597 if (cy_card[i].ctl_addr)
5598 iounmap(cy_card[i].ctl_addr);
5599 if (cy_card[i].irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600#ifndef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08005601 && cy_card[i].num_chips != -1 /* not a Z card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08005603 )
5604 free_irq(cy_card[i].irq, &cy_card[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08005606 if (cy_card[i].pdev)
5607 pci_release_regions(cy_card[i].pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08005609 }
5610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611} /* cy_cleanup_module */
5612
5613module_init(cy_init);
5614module_exit(cy_cleanup_module);
5615
5616MODULE_LICENSE("GPL");