blob: 817fef3071afbbe1bd9a364fe77833b9b0c9ee3b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5/*
6 * linux/drivers/char/cyclades.c
7 *
8 * This file contains the driver for the Cyclades async multiport
9 * serial boards.
10 *
11 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
12 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Jiri Slabyc8e16932007-05-08 00:37:05 -070014 * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
16 * Much of the design and some of the code came from serial.c
17 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
18 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
19 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070020 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 *
22 * This version supports shared IRQ's (only for PCI boards).
23 *
24 * $Log: cyclades.c,v $
25 * Prevent users from opening non-existing Z ports.
26 *
27 * Revision 2.3.2.8 2000/07/06 18:14:16 ivan
28 * Fixed the PCI detection function to work properly on Alpha systems.
29 * Implemented support for TIOCSERGETLSR ioctl.
30 * Implemented full support for non-standard baud rates.
31 *
32 * Revision 2.3.2.7 2000/06/01 18:26:34 ivan
33 * Request PLX I/O region, although driver doesn't use it, to avoid
34 * problems with other drivers accessing it.
35 * Removed count for on-board buffer characters in cy_chars_in_buffer
36 * (Cyclades-Z only).
37 *
38 * Revision 2.3.2.6 2000/05/05 13:56:05 ivan
39 * Driver now reports physical instead of virtual memory addresses.
40 * Masks were added to some Cyclades-Z read accesses.
41 * Implemented workaround for PLX9050 bug that would cause a system lockup
42 * in certain systems, depending on the MMIO addresses allocated to the
43 * board.
44 * Changed the Tx interrupt programming in the CD1400 chips to boost up
45 * performance (Cyclom-Y only).
46 * Code is now compliant with the new module interface (module_[init|exit]).
47 * Make use of the PCI helper functions to access PCI resources.
48 * Did some code "housekeeping".
49 *
50 * Revision 2.3.2.5 2000/01/19 14:35:33 ivan
51 * Fixed bug in cy_set_termios on CRTSCTS flag turnoff.
52 *
53 * Revision 2.3.2.4 2000/01/17 09:19:40 ivan
54 * Fixed SMP locking in Cyclom-Y interrupt handler.
55 *
56 * Revision 2.3.2.3 1999/12/28 12:11:39 ivan
57 * Added a new cyclades_card field called nports to allow the driver to
58 * know the exact number of ports found by the Z firmware after its load;
59 * RX buffer contention prevention logic on interrupt op mode revisited
60 * (Cyclades-Z only);
61 * Revisited printk's for Z debug;
62 * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
63 *
64 * Revision 2.3.2.2 1999/10/01 11:27:43 ivan
65 * Fixed bug in cyz_poll that would make all ports but port 0
66 * unable to transmit/receive data (Cyclades-Z only);
67 * Implemented logic to prevent the RX buffer from being stuck with data
68 * due to a driver / firmware race condition in interrupt op mode
69 * (Cyclades-Z only);
70 * Fixed bug in block_til_ready logic that would lead to a system crash;
71 * Revisited cy_close spinlock usage;
72 *
73 * Revision 2.3.2.1 1999/09/28 11:01:22 ivan
74 * Revisited CONFIG_PCI conditional compilation for PCI board support;
75 * Implemented TIOCGICOUNT and TIOCMIWAIT ioctl support;
76 * _Major_ cleanup on the Cyclades-Z interrupt support code / logic;
77 * Removed CTS handling from the driver -- this is now completely handled
78 * by the firmware (Cyclades-Z only);
79 * Flush RX on-board buffers on a port open (Cyclades-Z only);
80 * Fixed handling of ASYNC_SPD_* TTY flags;
81 * Module unload now unmaps all memory area allocated by ioremap;
82 *
83 * Revision 2.3.1.1 1999/07/15 16:45:53 ivan
84 * Removed CY_PROC conditional compilation;
85 * Implemented SMP-awareness for the driver;
86 * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
87 * functions;
88 * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
89 * (irq=NN) as parameters (only for ISA boards);
90 * Fixed bug in set_line_char that would prevent the Cyclades-Z
91 * ports from being configured at speeds above 115.2Kbps;
92 * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
93 * switching from working properly;
94 * The driver now only prints IRQ info for the Cyclades-Z if it's
95 * configured to work in interrupt mode;
96 *
97 * Revision 2.2.2.3 1999/06/28 11:13:29 ivan
98 * Added support for interrupt mode operation for the Z cards;
99 * Removed the driver inactivity control for the Z;
100 * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
101 * the Z firmware is not loaded yet;
102 * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
103 * same functionality;
104 * Implemented workaround for IRQ setting loss on the PCI configuration
105 * registers after a PCI bridge EEPROM reload (affects PLX9060 only);
106 *
107 * Revision 2.2.2.2 1999/05/14 17:18:15 ivan
108 * /proc entry location changed to /proc/tty/driver/cyclades;
109 * Added support to shared IRQ's (only for PCI boards);
110 * Added support for Cobalt Qube2 systems;
111 * IRQ [de]allocation scheme revisited;
112 * BREAK implementation changed in order to make use of the 'break_ctl'
113 * TTY facility;
114 * Fixed typo in TTY structure field 'driver_name';
115 * Included a PCI bridge reset and EEPROM reload in the board
116 * initialization code (for both Y and Z series).
117 *
118 * Revision 2.2.2.1 1999/04/08 16:17:43 ivan
119 * Fixed a bug in cy_wait_until_sent that was preventing the port to be
120 * closed properly after a SIGINT;
121 * Module usage counter scheme revisited;
122 * Added support to the upcoming Y PCI boards (i.e., support to additional
123 * PCI Device ID's).
124 *
125 * Revision 2.2.1.10 1999/01/20 16:14:29 ivan
126 * Removed all unnecessary page-alignement operations in ioremap calls
127 * (ioremap is currently safe for these operations).
128 *
129 * Revision 2.2.1.9 1998/12/30 18:18:30 ivan
130 * Changed access to PLX PCI bridge registers from I/O to MMIO, in
131 * order to make PLX9050-based boards work with certain motherboards.
132 *
133 * Revision 2.2.1.8 1998/11/13 12:46:20 ivan
134 * cy_close function now resets (correctly) the tty->closing flag;
135 * JIFFIES_DIFF macro fixed.
136 *
137 * Revision 2.2.1.7 1998/09/03 12:07:28 ivan
138 * Fixed bug in cy_close function, which was not informing HW of
139 * which port should have the reception disabled before doing so;
140 * fixed Cyclom-8YoP hardware detection bug.
141 *
142 * Revision 2.2.1.6 1998/08/20 17:15:39 ivan
143 * Fixed bug in cy_close function, which causes malfunction
144 * of one of the first 4 ports when a higher port is closed
145 * (Cyclom-Y only).
146 *
147 * Revision 2.2.1.5 1998/08/10 18:10:28 ivan
148 * Fixed Cyclom-4Yo hardware detection bug.
149 *
150 * Revision 2.2.1.4 1998/08/04 11:02:50 ivan
151 * /proc/cyclades implementation with great collaboration of
152 * Marc Lewis <marc@blarg.net>;
153 * cyy_interrupt was changed to avoid occurrence of kernel oopses
154 * during PPP operation.
155 *
156 * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
157 * General code review in order to comply with 2.1 kernel standards;
158 * data loss prevention for slow devices revisited (cy_wait_until_sent
159 * was created);
160 * removed conditional compilation for new/old PCI structure support
161 * (now the driver only supports the new PCI structure).
162 *
163 * Revision 2.2.1.1 1998/03/19 16:43:12 ivan
164 * added conditional compilation for new/old PCI structure support;
165 * removed kernel series (2.0.x / 2.1.x) conditional compilation.
166 *
167 * Revision 2.1.1.3 1998/03/16 18:01:12 ivan
168 * cleaned up the data loss fix;
169 * fixed XON/XOFF handling once more (Cyclades-Z);
170 * general review of the driver routines;
171 * introduction of a mechanism to prevent data loss with slow
172 * printers, by forcing a delay before closing the port.
173 *
174 * Revision 2.1.1.2 1998/02/17 16:50:00 ivan
175 * fixed detection/handling of new CD1400 in Ye boards;
176 * fixed XON/XOFF handling (Cyclades-Z);
177 * fixed data loss caused by a premature port close;
178 * introduction of a flag that holds the CD1400 version ID per port
179 * (used by the CYGETCD1400VER new ioctl).
180 *
181 * Revision 2.1.1.1 1997/12/03 17:31:19 ivan
182 * Code review for the module cleanup routine;
183 * fixed RTS and DTR status report for new CD1400's in get_modem_info;
184 * includes anonymous changes regarding signal_pending.
185 *
186 * Revision 2.1 1997/11/01 17:42:41 ivan
187 * Changes in the driver to support Alpha systems (except 8Zo V_1);
188 * BREAK fix for the Cyclades-Z boards;
189 * driver inactivity control by FW implemented;
190 * introduction of flag that allows driver to take advantage of
191 * a special CD1400 feature related to HW flow control;
192 * added support for the CD1400 rev. J (Cyclom-Y boards);
193 * introduction of ioctls to:
194 * - control the rtsdtr_inv flag (Cyclom-Y);
195 * - control the rflow flag (Cyclom-Y);
196 * - adjust the polling interval (Cyclades-Z);
197 *
198 * Revision 1.36.4.33 1997/06/27 19:00:00 ivan
199 * Fixes related to kernel version conditional
200 * compilation.
201 *
202 * Revision 1.36.4.32 1997/06/14 19:30:00 ivan
203 * Compatibility issues between kernels 2.0.x and
204 * 2.1.x (mainly related to clear_bit function).
205 *
206 * Revision 1.36.4.31 1997/06/03 15:30:00 ivan
207 * Changes to define the memory window according to the
208 * board type.
209 *
210 * Revision 1.36.4.30 1997/05/16 15:30:00 daniel
211 * Changes to support new cycladesZ boards.
212 *
213 * Revision 1.36.4.29 1997/05/12 11:30:00 daniel
214 * Merge of Bentson's and Daniel's version 1.36.4.28.
215 * Corrects bug in cy_detect_pci: check if there are more
216 * ports than the number of static structs allocated.
217 * Warning message during initialization if this driver is
218 * used with the new generation of cycladesZ boards. Those
219 * will be supported only in next release of the driver.
220 * Corrects bug in cy_detect_pci and cy_detect_isa that
221 * returned wrong number of VALID boards, when a cyclomY
222 * was found with no serial modules connected.
223 * Changes to use current (2.1.x) kernel subroutine names
224 * and created macros for compilation with 2.0.x kernel,
225 * instead of the other way around.
226 *
227 * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson
228 * Change queue_task_irq_off to queue_task_irq.
229 * The inline function queue_task_irq_off (tqueue.h)
230 * was removed from latest releases of 2.1.x kernel.
231 * Use of macro __init to mark the initialization
232 * routines, so memory can be reused.
233 * Also incorporate implementation of critical region
234 * in function cleanup_module() created by anonymous
235 * linuxer.
236 *
237 * Revision 1.36.4.28 1997/04/25 16:00:00 daniel
238 * Change to support new firmware that solves DCD problem:
239 * application could fail to receive SIGHUP signal when DCD
240 * varying too fast.
241 *
242 * Revision 1.36.4.27 1997/03/26 10:30:00 daniel
243 * Changed for support linux versions 2.1.X.
244 * Backward compatible with linux versions 2.0.X.
245 * Corrected illegal use of filler field in
246 * CH_CTRL struct.
247 * Deleted some debug messages.
248 *
249 * Revision 1.36.4.26 1997/02/27 12:00:00 daniel
250 * Included check for NULL tty pointer in cyz_poll.
251 *
252 * Revision 1.36.4.25 1997/02/26 16:28:30 bentson
253 * Bill Foster at Blarg! Online services noticed that
254 * some of the switch elements of -Z modem control
255 * lacked a closing "break;"
256 *
257 * Revision 1.36.4.24 1997/02/24 11:00:00 daniel
258 * Changed low water threshold for buffer xmit_buf
259 *
260 * Revision 1.36.4.23 1996/12/02 21:50:16 bentson
261 * Marcio provided fix to modem status fetch for -Z
262 *
263 * Revision 1.36.4.22 1996/10/28 22:41:17 bentson
264 * improve mapping of -Z control page (thanks to Steve
265 * Price <stevep@fa.tdktca.com> for help on this)
266 *
267 * Revision 1.36.4.21 1996/09/10 17:00:10 bentson
268 * shift from CPU-bound to memcopy in cyz_polling operation
269 *
270 * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
271 * Added support to set and report higher speeds.
272 *
273 * Revision 1.36.4.19c 1996/08/09 10:00:00 Marcio Saito
274 * Some fixes in the HW flow control for the BETA release.
275 * Don't try to register the IRQ.
276 *
277 * Revision 1.36.4.19 1996/08/08 16:23:18 Bentson
278 * make sure "cyc" appears in all kernel messages; all soft interrupts
279 * handled by same routine; recognize out-of-band reception; comment
280 * out some diagnostic messages; leave RTS/CTS flow control to hardware;
Jean Delvare33430dc2005-10-30 15:02:20 -0800281 * fix race condition in -Z buffer management; only -Y needs to explicitly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 * flush chars; tidy up some startup messages;
283 *
284 * Revision 1.36.4.18 1996/07/25 18:57:31 bentson
285 * shift MOD_INC_USE_COUNT location to match
286 * serial.c; purge some diagnostic messages;
287 *
288 * Revision 1.36.4.17 1996/07/25 18:01:08 bentson
289 * enable modem status messages and fetch & process them; note
290 * time of last activity type for each port; set_line_char now
291 * supports more than line 0 and treats 0 baud correctly;
292 * get_modem_info senses rs_status;
293 *
294 * Revision 1.36.4.16 1996/07/20 08:43:15 bentson
295 * barely works--now's time to turn on
296 * more features 'til it breaks
297 *
298 * Revision 1.36.4.15 1996/07/19 22:30:06 bentson
299 * check more -Z board status; shorten boot message
300 *
301 * Revision 1.36.4.14 1996/07/19 22:20:37 bentson
302 * fix reference to ch_ctrl in startup; verify return
303 * values from cyz_issue_cmd and cyz_update_channel;
304 * more stuff to get modem control correct;
305 *
306 * Revision 1.36.4.13 1996/07/11 19:53:33 bentson
307 * more -Z stuff folded in; re-order changes to put -Z stuff
308 * after -Y stuff (to make changes clearer)
309 *
310 * Revision 1.36.4.12 1996/07/11 15:40:55 bentson
311 * Add code to poll Cyclades-Z. Add code to get & set RS-232 control.
312 * Add code to send break. Clear firmware ID word at startup (so
313 * that other code won't talk to inactive board).
314 *
315 * Revision 1.36.4.11 1996/07/09 05:28:29 bentson
316 * add code for -Z in set_line_char
317 *
318 * Revision 1.36.4.10 1996/07/08 19:28:37 bentson
319 * fold more -Z stuff (or in some cases, error messages)
320 * into driver; add text to "don't know what to do" messages.
321 *
322 * Revision 1.36.4.9 1996/07/08 18:38:38 bentson
323 * moved compile-time flags near top of file; cosmetic changes
324 * to narrow text (to allow 2-up printing); changed many declarations
325 * to "static" to limit external symbols; shuffled code order to
326 * coalesce -Y and -Z specific code, also to put internal functions
327 * in order of tty_driver structure; added code to recognize -Z
328 * ports (and for moment, do nothing or report error); add cy_startup
329 * to parse boot command line for extra base addresses for ISA probes;
330 *
331 * Revision 1.36.4.8 1996/06/25 17:40:19 bentson
332 * reorder some code, fix types of some vars (int vs. long),
333 * add cy_setup to support user declared ISA addresses
334 *
335 * Revision 1.36.4.7 1996/06/21 23:06:18 bentson
336 * dump ioctl based firmware load (it's now a user level
337 * program); ensure uninitialzed ports cannot be used
338 *
339 * Revision 1.36.4.6 1996/06/20 23:17:19 bentson
340 * rename vars and restructure some code
341 *
342 * Revision 1.36.4.5 1996/06/14 15:09:44 bentson
343 * get right status back after boot load
344 *
345 * Revision 1.36.4.4 1996/06/13 19:51:44 bentson
346 * successfully loads firmware
347 *
348 * Revision 1.36.4.3 1996/06/13 06:08:33 bentson
349 * add more of the code for the boot/load ioctls
350 *
351 * Revision 1.36.4.2 1996/06/11 21:00:51 bentson
352 * start to add Z functionality--starting with ioctl
353 * for loading firmware
354 *
355 * Revision 1.36.4.1 1996/06/10 18:03:02 bentson
356 * added code to recognize Z/PCI card at initialization; report
357 * presence, but card is not initialized (because firmware needs
358 * to be loaded)
359 *
360 * Revision 1.36.3.8 1996/06/07 16:29:00 bentson
361 * starting minor number at zero; added missing verify_area
362 * as noted by Heiko Eissfeldt <heiko@colossus.escape.de>
363 *
364 * Revision 1.36.3.7 1996/04/19 21:06:18 bentson
365 * remove unneeded boot message & fix CLOCAL hardware flow
366 * control (Miquel van Smoorenburg <miquels@Q.cistron.nl>);
367 * remove unused diagnostic statements; minor 0 is first;
368 *
369 * Revision 1.36.3.6 1996/03/13 13:21:17 marcio
370 * The kernel function vremap (available only in later 1.3.xx kernels)
371 * allows the access to memory addresses above the RAM. This revision
372 * of the driver supports PCI boards below 1Mb (device id 0x100) and
373 * above 1Mb (device id 0x101).
374 *
375 * Revision 1.36.3.5 1996/03/07 15:20:17 bentson
376 * Some global changes to interrupt handling spilled into
377 * this driver--mostly unused arguments in system function
378 * calls. Also added change by Marcio Saito which should
379 * reduce lost interrupts at startup by fast processors.
380 *
381 * Revision 1.36.3.4 1995/11/13 20:45:10 bentson
382 * Changes by Corey Minyard <minyard@wf-rch.cirr.com> distributed
383 * in 1.3.41 kernel to remove a possible race condition, extend
384 * some error messages, and let the driver run as a loadable module
385 * Change by Alan Wendt <alan@ez0.ezlink.com> to remove a
386 * possible race condition.
387 * Change by Marcio Saito <marcio@cyclades.com> to fix PCI addressing.
388 *
389 * Revision 1.36.3.3 1995/11/13 19:44:48 bentson
390 * Changes by Linus Torvalds in 1.3.33 kernel distribution
391 * required due to reordering of driver initialization.
392 * Drivers are now initialized *after* memory management.
393 *
394 * Revision 1.36.3.2 1995/09/08 22:07:14 bentson
395 * remove printk from ISR; fix typo
396 *
397 * Revision 1.36.3.1 1995/09/01 12:00:42 marcio
398 * Minor fixes in the PCI board support. PCI function calls in
399 * conditional compilation (CONFIG_PCI). Thanks to Jim Duncan
400 * <duncan@okay.com>. "bad serial count" message removed.
401 *
402 * Revision 1.36.3 1995/08/22 09:19:42 marcio
403 * Cyclom-Y/PCI support added. Changes in the cy_init routine and
404 * board initialization. Changes in the boot messages. The driver
405 * supports up to 4 boards and 64 ports by default.
406 *
407 * Revision 1.36.1.4 1995/03/29 06:14:14 bentson
408 * disambiguate between Cyclom-16Y and Cyclom-32Ye;
409 *
410 * Revision 1.36.1.3 1995/03/23 22:15:35 bentson
411 * add missing break in modem control block in ioctl switch statement
412 * (discovered by Michael Edward Chastain <mec@jobe.shell.portal.com>);
413 *
414 * Revision 1.36.1.2 1995/03/22 19:16:22 bentson
415 * make sure CTS flow control is set as soon as possible (thanks
416 * to note from David Lambert <lambert@chesapeake.rps.slb.com>);
417 *
418 * Revision 1.36.1.1 1995/03/13 15:44:43 bentson
419 * initialize defaults for receive threshold and stale data timeout;
420 * cosmetic changes;
421 *
422 * Revision 1.36 1995/03/10 23:33:53 bentson
423 * added support of chips 4-7 in 32 port Cyclom-Ye;
424 * fix cy_interrupt pointer dereference problem
425 * (Joe Portman <baron@aa.net>);
426 * give better error response if open is attempted on non-existent port
427 * (Zachariah Vaum <jchryslr@netcom.com>);
428 * correct command timeout (Kenneth Lerman <lerman@@seltd.newnet.com>);
429 * conditional compilation for -16Y on systems with fast, noisy bus;
430 * comment out diagnostic print function;
431 * cleaned up table of base addresses;
432 * set receiver time-out period register to correct value,
433 * set receive threshold to better default values,
434 * set chip timer to more accurate 200 Hz ticking,
435 * add code to monitor and modify receive parameters
436 * (Rik Faith <faith@cs.unc.edu> Nick Simicich
437 * <njs@scifi.emi.net>);
438 *
439 * Revision 1.35 1994/12/16 13:54:18 steffen
440 * additional patch by Marcio Saito for board detection
441 * Accidently left out in 1.34
442 *
443 * Revision 1.34 1994/12/10 12:37:12 steffen
444 * This is the corrected version as suggested by Marcio Saito
445 *
446 * Revision 1.33 1994/12/01 22:41:18 bentson
447 * add hooks to support more high speeds directly; add tytso
448 * patch regarding CLOCAL wakeups
449 *
450 * Revision 1.32 1994/11/23 19:50:04 bentson
451 * allow direct kernel control of higher signalling rates;
452 * look for cards at additional locations
453 *
454 * Revision 1.31 1994/11/16 04:33:28 bentson
455 * ANOTHER fix from Corey Minyard, minyard@wf-rch.cirr.com--
456 * a problem in chars_in_buffer has been resolved by some
457 * small changes; this should yield smoother output
458 *
459 * Revision 1.30 1994/11/16 04:28:05 bentson
460 * Fix from Corey Minyard, Internet: minyard@metronet.com,
461 * UUCP: minyard@wf-rch.cirr.com, WORK: minyardbnr.ca, to
462 * cy_hangup that appears to clear up much (all?) of the
463 * DTR glitches; also he's added/cleaned-up diagnostic messages
464 *
465 * Revision 1.29 1994/11/16 04:16:07 bentson
466 * add change proposed by Ralph Sims, ralphs@halcyon.com, to
467 * operate higher speeds in same way as other serial ports;
468 * add more serial ports (for up to two 16-port muxes).
469 *
470 * Revision 1.28 1994/11/04 00:13:16 root
471 * turn off diagnostic messages
472 *
473 * Revision 1.27 1994/11/03 23:46:37 root
474 * bunch of changes to bring driver into greater conformance
475 * with the serial.c driver (looking for missed fixes)
476 *
477 * Revision 1.26 1994/11/03 22:40:36 root
478 * automatic interrupt probing fixed.
479 *
480 * Revision 1.25 1994/11/03 20:17:02 root
481 * start to implement auto-irq
482 *
483 * Revision 1.24 1994/11/03 18:01:55 root
484 * still working on modem signals--trying not to drop DTR
485 * during the getty/login processes
486 *
487 * Revision 1.23 1994/11/03 17:51:36 root
488 * extend baud rate support; set receive threshold as function
489 * of baud rate; fix some problems with RTS/CTS;
490 *
491 * Revision 1.22 1994/11/02 18:05:35 root
492 * changed arguments to udelay to type long to get
493 * delays to be of correct duration
494 *
495 * Revision 1.21 1994/11/02 17:37:30 root
496 * employ udelay (after calibrating loops_per_second earlier
497 * in init/main.c) instead of using home-grown delay routines
498 *
499 * Revision 1.20 1994/11/02 03:11:38 root
500 * cy_chars_in_buffer forces a return value of 0 to let
501 * login work (don't know why it does); some functions
502 * that were returning EFAULT, now executes the code;
503 * more work on deciding when to disable xmit interrupts;
504 *
505 * Revision 1.19 1994/11/01 20:10:14 root
506 * define routine to start transmission interrupts (by enabling
507 * transmit interrupts); directly enable/disable modem interrupts;
508 *
509 * Revision 1.18 1994/11/01 18:40:45 bentson
510 * Don't always enable transmit interrupts in startup; interrupt on
511 * TxMpty instead of TxRdy to help characters get out before shutdown;
512 * restructure xmit interrupt to check for chars first and quit if
513 * none are ready to go; modem status (MXVRx) is upright, _not_ inverted
514 * (to my view);
515 *
516 * Revision 1.17 1994/10/30 04:39:45 bentson
517 * rename serial_driver and callout_driver to cy_serial_driver and
518 * cy_callout_driver to avoid linkage interference; initialize
519 * info->type to PORT_CIRRUS; ruggedize paranoia test; elide ->port
520 * from cyclades_port structure; add paranoia check to cy_close;
521 *
522 * Revision 1.16 1994/10/30 01:14:33 bentson
523 * change major numbers; add some _early_ return statements;
524 *
525 * Revision 1.15 1994/10/29 06:43:15 bentson
526 * final tidying up for clean compile; enable some error reporting
527 *
528 * Revision 1.14 1994/10/28 20:30:22 Bentson
529 * lots of changes to drag the driver towards the new tty_io
530 * structures and operation. not expected to work, but may
531 * compile cleanly.
532 *
533 * Revision 1.13 1994/07/21 23:08:57 Bentson
534 * add some diagnostic cruft; support 24 lines (for testing
535 * both -8Y and -16Y cards; be more thorough in servicing all
536 * chips during interrupt; add "volatile" a few places to
537 * circumvent compiler optimizations; fix base & offset
538 * computations in block_til_ready (was causing chip 0 to
539 * stop operation)
540 *
541 * Revision 1.12 1994/07/19 16:42:11 Bentson
542 * add some hackery for kernel version 1.1.8; expand
543 * error messages; refine timing for delay loops and
544 * declare loop params volatile
545 *
546 * Revision 1.11 1994/06/11 21:53:10 bentson
547 * get use of save_car right in transmit interrupt service
548 *
549 * Revision 1.10.1.1 1994/06/11 21:31:18 bentson
550 * add some diagnostic printing; try to fix save_car stuff
551 *
552 * Revision 1.10 1994/06/11 20:36:08 bentson
553 * clean up compiler warnings
554 *
555 * Revision 1.9 1994/06/11 19:42:46 bentson
556 * added a bunch of code to support modem signalling
557 *
558 * Revision 1.8 1994/06/11 17:57:07 bentson
559 * recognize break & parity error
560 *
561 * Revision 1.7 1994/06/05 05:51:34 bentson
562 * Reorder baud table to be monotonic; add cli to CP; discard
563 * incoming characters and status if the line isn't open; start to
564 * fold code into cy_throttle; start to port get_serial_info,
565 * set_serial_info, get_modem_info, set_modem_info, and send_break
566 * from serial.c; expand cy_ioctl; relocate and expand config_setup;
567 * get flow control characters from tty struct; invalidate ports w/o
568 * hardware;
569 *
570 * Revision 1.6 1994/05/31 18:42:21 bentson
571 * add a loop-breaker in the interrupt service routine;
572 * note when port is initialized so that it can be shut
573 * down under the right conditions; receive works without
574 * any obvious errors
575 *
576 * Revision 1.5 1994/05/30 00:55:02 bentson
577 * transmit works without obvious errors
578 *
579 * Revision 1.4 1994/05/27 18:46:27 bentson
580 * incorporated more code from lib_y.c; can now print short
581 * strings under interrupt control to port zero; seems to
582 * select ports/channels/lines correctly
583 *
584 * Revision 1.3 1994/05/25 22:12:44 bentson
585 * shifting from multi-port on a card to proper multiplexor
586 * data structures; added skeletons of most routines
587 *
588 * Revision 1.2 1994/05/19 13:21:43 bentson
589 * start to crib from other sources
590 *
591 */
592
Jiri Slabyc8e16932007-05-08 00:37:05 -0700593#define CY_VERSION "2.5"
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595/* 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626/*
627 * Include section
628 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629#include <linux/module.h>
630#include <linux/errno.h>
631#include <linux/signal.h>
632#include <linux/sched.h>
633#include <linux/timer.h>
634#include <linux/interrupt.h>
635#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -0800636#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637#include <linux/serial.h>
638#include <linux/major.h>
639#include <linux/string.h>
640#include <linux/fcntl.h>
641#include <linux/ptrace.h>
642#include <linux/cyclades.h>
643#include <linux/mm.h>
644#include <linux/ioport.h>
645#include <linux/init.h>
646#include <linux/delay.h>
647#include <linux/spinlock.h>
648#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -0700649#include <linux/firmware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651#include <asm/system.h>
652#include <asm/io.h>
653#include <asm/irq.h>
654#include <asm/uaccess.h>
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#include <linux/kernel.h>
657#include <linux/pci.h>
658
659#include <linux/stat.h>
660#include <linux/proc_fs.h>
661
Jiri Slaby02f11752006-12-08 02:39:28 -0800662static void cy_throttle(struct tty_struct *tty);
663static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665#define IS_CYC_Z(card) ((card).num_chips == -1)
666
667#define Z_FPGA_CHECK(card) \
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700668 ((readl(&((struct RUNTIME_9060 __iomem *) \
Jiri Slaby02f11752006-12-08 02:39:28 -0800669 ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700671#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 ((card).ctl_addr))->mail_box_0)) || \
673 Z_FPGA_CHECK(card)) && \
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700674 (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 ((card).base_addr+ID_ADDRESS))->signature)))
676
677#ifndef SERIAL_XMIT_SIZE
678#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
679#endif
680#define WAKEUP_CHARS 256
681
682#define STD_COM_FLAGS (0)
683
Jiri Slaby054f5b02007-07-17 04:05:16 -0700684/* firmware stuff */
685#define ZL_MAX_BLOCKS 16
686#define DRIVER_VERSION 0x02010203
687#define RAM_SIZE 0x80000
688
689#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
690
691enum zblock_type {
692 ZBLOCK_PRG = 0,
693 ZBLOCK_FPGA = 1
694};
695
696struct zfile_header {
697 char name[64];
698 char date[32];
699 char aux[32];
700 u32 n_config;
701 u32 config_offset;
702 u32 n_blocks;
703 u32 block_offset;
704 u32 reserved[9];
705} __attribute__ ((packed));
706
707struct zfile_config {
708 char name[64];
709 u32 mailbox;
710 u32 function;
711 u32 n_blocks;
712 u32 block_list[ZL_MAX_BLOCKS];
713} __attribute__ ((packed));
714
715struct zfile_block {
716 u32 type;
717 u32 file_offset;
718 u32 ram_offset;
719 u32 size;
720} __attribute__ ((packed));
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722static struct tty_driver *cy_serial_driver;
723
724#ifdef CONFIG_ISA
725/* This is the address lookup table. The driver will probe for
726 Cyclom-Y/ISA boards at all addresses in here. If you want the
727 driver to probe addresses at a different address, add it to
728 this table. If the driver is probing some other board and
729 causing problems, remove the offending address from this table.
730 The cy_setup function extracts additional addresses from the
731 boot options line. The form is "cyclades=address,address..."
732*/
733
734static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800735 0xD0000,
736 0xD2000,
737 0xD4000,
738 0xD6000,
739 0xD8000,
740 0xDA000,
741 0xDC000,
742 0xDE000,
743 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744};
Jiri Slaby02f11752006-12-08 02:39:28 -0800745
Tobias Klauserfe971072006-01-09 20:54:02 -0800746#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748#ifdef MODULE
Jiri Slaby3046d502007-05-08 00:36:46 -0700749static long maddr[NR_CARDS];
750static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752module_param_array(maddr, long, NULL, 0);
753module_param_array(irq, int, NULL, 0);
754#endif
755
Jiri Slaby02f11752006-12-08 02:39:28 -0800756#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758/* This is the per-card data structure containing address, irq, number of
759 channels, etc. This driver supports a maximum of NR_CARDS cards.
760*/
761static struct cyclades_card cy_card[NR_CARDS];
762
Jiri Slaby02f11752006-12-08 02:39:28 -0800763static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 * This is used to look up the divisor speeds and the timeouts
767 * We're normally limited to 15 distinct baud rates. The extra
768 * are accessed via settings in info->flags.
769 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
770 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
771 * HI VHI
772 * 20
773 */
774static int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800775 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
776 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
777 230400, 0
778};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Jiri Slaby02f11752006-12-08 02:39:28 -0800780static char baud_co_25[] = { /* 25 MHz clock option table */
781 /* value => 00 01 02 03 04 */
782 /* divide by 8 32 128 512 2048 */
783 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
784 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
785};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Jiri Slaby02f11752006-12-08 02:39:28 -0800787static char baud_bpr_25[] = { /* 25 MHz baud rate period table */
788 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
789 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
790};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Jiri Slaby02f11752006-12-08 02:39:28 -0800792static char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
793 /* value => 00 01 02 03 04 */
794 /* divide by 8 32 128 512 2048 */
795 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
796 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x00
798};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Jiri Slaby02f11752006-12-08 02:39:28 -0800800static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
801 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
802 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
803 0x21
804};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Jiri Slaby02f11752006-12-08 02:39:28 -0800806static char baud_cor3[] = { /* receive threshold */
807 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
808 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
809 0x07
810};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812/*
813 * The Cyclades driver implements HW flow control as any serial driver.
814 * The cyclades_port structure member rflow and the vector rflow_thr
815 * allows us to take advantage of a special feature in the CD1400 to avoid
816 * data loss even when the system interrupt latency is too high. These flags
817 * are to be used only with very special applications. Setting these flags
818 * requires the use of a special cable (DTR and RTS reversed). In the new
819 * CD1400-based boards (rev. 6.00 or later), there is no need for special
820 * cables.
821 */
822
Jiri Slaby02f11752006-12-08 02:39:28 -0800823static char rflow_thr[] = { /* rflow threshold */
824 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
826 0x0a
827};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829/* The Cyclom-Ye has placed the sequential chips in non-sequential
830 * address order. This look-up table overcomes that problem.
831 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800832static int cy_chip_offset[] = { 0x0000,
833 0x0400,
834 0x0800,
835 0x0C00,
836 0x0200,
837 0x0600,
838 0x0A00,
839 0x0E00
840};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
842/* PCI related definitions */
843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844#ifdef CONFIG_PCI
Jiri Slaby893de2d2007-02-12 00:51:49 -0800845static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
846 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
847 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */
848 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */
849 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */
850 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */
851 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */
852 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */
853 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */
854 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800855};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800856MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#endif
858
859static void cy_start(struct tty_struct *);
860static void set_line_char(struct cyclades_port *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700861static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862#ifdef CONFIG_ISA
863static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800864#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
Jiri Slaby02f11752006-12-08 02:39:28 -0800866static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868#ifndef CONFIG_CYZ_INTR
869static void cyz_poll(unsigned long);
870
871/* The Cyclades-Z polling cycle is defined by this variable */
872static long cyz_polling_cycle = CZ_DEF_POLL;
873
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700874static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Jiri Slaby02f11752006-12-08 02:39:28 -0800876#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877static void cyz_rx_restart(unsigned long);
878static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800879#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Jiri Slaby02f11752006-12-08 02:39:28 -0800881static inline int serial_paranoia_check(struct cyclades_port *info,
882 char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800885 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700886 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
887 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800888 return 1;
889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Jiri Slaby02f11752006-12-08 02:39:28 -0800891 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700892 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
893 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800894 return 1;
895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800897 return 0;
898} /* serial_paranoia_check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900/***********************************************************/
901/********* Start of block of Cyclom-Y specific code ********/
902
903/* This routine waits up to 1000 micro-seconds for the previous
904 command to the Cirrus chip to complete and then issues the
905 new command. An error is returned if the previous command
906 didn't finish within the time limit.
907
908 This function is only called from inside spinlock-protected code.
909 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800910static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
Jiri Slabyad39c302007-05-08 00:35:49 -0700912 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Jiri Slaby02f11752006-12-08 02:39:28 -0800914 /* Check to see that the previous command has completed */
915 for (i = 0; i < 100; i++) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700916 if (readb(base_addr + (CyCCR << index)) == 0) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800917 break;
918 }
919 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800921 /* if the CCR never cleared, the previous command
922 didn't finish within the "reasonable time" */
923 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800924 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Jiri Slaby02f11752006-12-08 02:39:28 -0800926 /* Issue the new command */
927 cy_writeb(base_addr + (CyCCR << index), cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800929 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800930} /* cyy_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932#ifdef CONFIG_ISA
933/* ISA interrupt detection code */
Jiri Slaby02f11752006-12-08 02:39:28 -0800934static unsigned detect_isa_irq(void __iomem * address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 int irq;
937 unsigned long irqs, flags;
938 int save_xir, save_car;
939 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Jiri Slaby02f11752006-12-08 02:39:28 -0800941 /* forget possible initially masked and pending IRQ */
942 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Jiri Slaby02f11752006-12-08 02:39:28 -0800944 /* Clear interrupts on the board first */
945 cy_writeb(address + (Cy_ClrIntr << index), 0);
946 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Jiri Slaby02f11752006-12-08 02:39:28 -0800948 irqs = probe_irq_on();
949 /* Wait ... */
950 udelay(5000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Jiri Slaby02f11752006-12-08 02:39:28 -0800952 /* Enable the Tx interrupts on the CD1400 */
953 local_irq_save(flags);
954 cy_writeb(address + (CyCAR << index), 0);
955 cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Jiri Slaby02f11752006-12-08 02:39:28 -0800957 cy_writeb(address + (CyCAR << index), 0);
958 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700959 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800960 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Jiri Slaby02f11752006-12-08 02:39:28 -0800962 /* Wait ... */
963 udelay(5000L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Jiri Slaby02f11752006-12-08 02:39:28 -0800965 /* Check which interrupt is in use */
966 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Jiri Slaby02f11752006-12-08 02:39:28 -0800968 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700969 save_xir = (u_char) readb(address + (CyTIR << index));
970 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800971 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
972 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700973 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800974 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
975 cy_writeb(address + (CyCAR << index), (save_car));
976 cy_writeb(address + (Cy_ClrIntr << index), 0);
977 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Jiri Slaby02f11752006-12-08 02:39:28 -0800979 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
Jiri Slaby02f11752006-12-08 02:39:28 -0800981#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Jiri Slabye9410272006-12-08 02:39:28 -0800983static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
Jiri Slaby02f11752006-12-08 02:39:28 -0800984 void __iomem * base_addr, int status, int index)
Jiri Slabye9410272006-12-08 02:39:28 -0800985{
986 struct cyclades_port *info;
987 struct tty_struct *tty;
Jiri Slabyad39c302007-05-08 00:35:49 -0700988 int char_count;
Jiri Slabydd025c02007-05-08 00:37:02 -0700989 int j, len, mdm_change, mdm_status, outch;
Jiri Slabye9410272006-12-08 02:39:28 -0800990 int save_xir, channel, save_car;
991 char data;
992
Jiri Slaby02f11752006-12-08 02:39:28 -0800993 if (status & CySRReceive) { /* reception interrupt */
Jiri Slabye9410272006-12-08 02:39:28 -0800994#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -0700995 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800996#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800997 /* determine the channel & change to that context */
998 spin_lock(&cinfo->card_lock);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700999 save_xir = (u_char) readb(base_addr + (CyRIR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001000 channel = (u_short) (save_xir & CyIRChannel);
Jiri Slabydd025c02007-05-08 00:37:02 -07001001 info = &cinfo->ports[channel + chip * 4];
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001002 save_car = readb(base_addr + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001003 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001004
Jiri Slaby02f11752006-12-08 02:39:28 -08001005 /* if there is nowhere to put the data, discard it */
Jiri Slabyf7429032007-05-08 00:36:59 -07001006 if (info->tty == NULL) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001007 j = (readb(base_addr + (CyRIVR << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001008 CyIVRMask);
1009 if (j == CyIVRRxEx) { /* exception */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001010 data = readb(base_addr + (CyRDSR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001011 } else { /* normal character reception */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001012 char_count = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001013 (CyRDCR << index));
1014 while (char_count--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001015 data = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001016 (CyRDSR << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001017 }
Jiri Slabye9410272006-12-08 02:39:28 -08001018 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001019 } else { /* there is an open port for this data */
1020 tty = info->tty;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001021 j = (readb(base_addr + (CyRIVR << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001022 CyIVRMask);
1023 if (j == CyIVRRxEx) { /* exception */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001024 data = readb(base_addr + (CyRDSR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001025
1026 /* For statistics only */
1027 if (data & CyBREAK)
1028 info->icount.brk++;
1029 else if (data & CyFRAME)
1030 info->icount.frame++;
1031 else if (data & CyPARITY)
1032 info->icount.parity++;
1033 else if (data & CyOVERRUN)
1034 info->icount.overrun++;
1035
1036 if (data & info->ignore_status_mask) {
1037 info->icount.rx++;
Jiri Slaby3fcbc722007-05-23 13:57:56 -07001038 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -08001039 return;
1040 }
1041 if (tty_buffer_request_room(tty, 1)) {
1042 if (data & info->read_status_mask) {
1043 if (data & CyBREAK) {
1044 tty_insert_flip_char(
1045 tty,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001046 readb(
Jiri Slaby02f11752006-12-08 02:39:28 -08001047 base_addr +
1048 (CyRDSR <<
1049 index)),
1050 TTY_BREAK);
1051 info->icount.rx++;
1052 if (info->flags &
1053 ASYNC_SAK) {
1054 do_SAK(tty);
1055 }
1056 } else if (data & CyFRAME) {
1057 tty_insert_flip_char(
1058 tty,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001059 readb(
Jiri Slaby02f11752006-12-08 02:39:28 -08001060 base_addr +
1061 (CyRDSR <<
1062 index)),
1063 TTY_FRAME);
1064 info->icount.rx++;
1065 info->idle_stats.
1066 frame_errs++;
1067 } else if (data & CyPARITY) {
1068 /* Pieces of seven... */
1069 tty_insert_flip_char(
1070 tty,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001071 readb(
Jiri Slaby02f11752006-12-08 02:39:28 -08001072 base_addr +
1073 (CyRDSR <<
1074 index)),
1075 TTY_PARITY);
1076 info->icount.rx++;
1077 info->idle_stats.
1078 parity_errs++;
1079 } else if (data & CyOVERRUN) {
1080 tty_insert_flip_char(
1081 tty, 0,
1082 TTY_OVERRUN);
1083 info->icount.rx++;
1084 /* If the flip buffer itself is
1085 overflowing, we still lose
1086 the next incoming character.
1087 */
1088 tty_insert_flip_char(
1089 tty,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001090 readb(
Jiri Slaby02f11752006-12-08 02:39:28 -08001091 base_addr +
1092 (CyRDSR <<
1093 index)),
1094 TTY_FRAME);
1095 info->icount.rx++;
1096 info->idle_stats.
1097 overruns++;
1098 /* These two conditions may imply */
1099 /* a normal read should be done. */
1100 /* }else if(data & CyTIMEOUT){ */
1101 /* }else if(data & CySPECHAR){ */
1102 } else {
1103 tty_insert_flip_char(
1104 tty, 0,
1105 TTY_NORMAL);
1106 info->icount.rx++;
1107 }
1108 } else {
1109 tty_insert_flip_char(tty, 0,
1110 TTY_NORMAL);
1111 info->icount.rx++;
1112 }
1113 } else {
1114 /* there was a software buffer
1115 overrun and nothing could be
1116 done about it!!! */
1117 info->icount.buf_overrun++;
1118 info->idle_stats.overruns++;
1119 }
1120 } else { /* normal character reception */
1121 /* load # chars available from the chip */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001122 char_count = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001123 (CyRDCR << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001124
1125#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -08001126 ++info->mon.int_count;
1127 info->mon.char_count += char_count;
1128 if (char_count > info->mon.char_max)
1129 info->mon.char_max = char_count;
1130 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -08001131#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001132 len = tty_buffer_request_room(tty, char_count);
1133 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001134 data = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001135 (CyRDSR << index));
1136 tty_insert_flip_char(tty, data,
1137 TTY_NORMAL);
1138 info->idle_stats.recv_bytes++;
1139 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -08001140#ifdef CY_16Y_HACK
Jiri Slaby02f11752006-12-08 02:39:28 -08001141 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -08001142#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001143 }
1144 info->idle_stats.recv_idle = jiffies;
1145 }
1146 tty_schedule_flip(tty);
Jiri Slabye9410272006-12-08 02:39:28 -08001147 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001148 /* end of service */
1149 cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
1150 cy_writeb(base_addr + (CyCAR << index), (save_car));
1151 spin_unlock(&cinfo->card_lock);
Jiri Slabye9410272006-12-08 02:39:28 -08001152 }
1153
Jiri Slaby02f11752006-12-08 02:39:28 -08001154 if (status & CySRTransmit) { /* transmission interrupt */
1155 /* Since we only get here when the transmit buffer
1156 is empty, we know we can always stuff a dozen
1157 characters. */
Jiri Slabye9410272006-12-08 02:39:28 -08001158#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001159 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -08001160#endif
1161
Jiri Slaby02f11752006-12-08 02:39:28 -08001162 /* determine the channel & change to that context */
1163 spin_lock(&cinfo->card_lock);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001164 save_xir = (u_char) readb(base_addr + (CyTIR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001165 channel = (u_short) (save_xir & CyIRChannel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001166 save_car = readb(base_addr + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001167 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001168
Jiri Slaby02f11752006-12-08 02:39:28 -08001169 /* validate the port# (as configured and open) */
Jiri Slabydd025c02007-05-08 00:37:02 -07001170 if (channel + chip * 4 >= cinfo->nports) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001171 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001172 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001173 ~CyTxRdy);
1174 goto txend;
1175 }
Jiri Slabydd025c02007-05-08 00:37:02 -07001176 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyf7429032007-05-08 00:36:59 -07001177 if (info->tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001178 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001179 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001180 ~CyTxRdy);
Jiri Slabyebafeef2007-10-18 03:06:20 -07001181 goto txend;
Jiri Slaby02f11752006-12-08 02:39:28 -08001182 }
Jiri Slabye9410272006-12-08 02:39:28 -08001183
Jiri Slaby02f11752006-12-08 02:39:28 -08001184 /* load the on-chip space for outbound data */
1185 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -08001186
Jiri Slaby02f11752006-12-08 02:39:28 -08001187 if (info->x_char) { /* send special char */
1188 outch = info->x_char;
1189 cy_writeb(base_addr + (CyTDR << index), outch);
Jiri Slabye9410272006-12-08 02:39:28 -08001190 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -08001191 info->icount.tx++;
1192 info->x_char = 0;
Jiri Slabye9410272006-12-08 02:39:28 -08001193 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001194
1195 if (info->breakon || info->breakoff) {
1196 if (info->breakon) {
1197 cy_writeb(base_addr + (CyTDR << index), 0);
1198 cy_writeb(base_addr + (CyTDR << index), 0x81);
1199 info->breakon = 0;
1200 char_count -= 2;
1201 }
1202 if (info->breakoff) {
1203 cy_writeb(base_addr + (CyTDR << index), 0);
1204 cy_writeb(base_addr + (CyTDR << index), 0x83);
1205 info->breakoff = 0;
1206 char_count -= 2;
1207 }
1208 }
1209
1210 while (char_count-- > 0) {
1211 if (!info->xmit_cnt) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001212 if (readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001213 CyTxMpty) {
1214 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001215 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001216 (CySRER << index)) &
1217 ~CyTxMpty);
1218 } else {
1219 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001220 (readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 (CySRER << index)) &
1222 ~CyTxRdy) | CyTxMpty);
1223 }
1224 goto txdone;
1225 }
Jiri Slabyf7429032007-05-08 00:36:59 -07001226 if (info->xmit_buf == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001227 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001228 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001229 ~CyTxRdy);
1230 goto txdone;
1231 }
1232 if (info->tty->stopped || info->tty->hw_stopped) {
1233 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001234 readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001235 ~CyTxRdy);
1236 goto txdone;
1237 }
1238 /* Because the Embedded Transmit Commands have
1239 been enabled, we must check to see if the
1240 escape character, NULL, is being sent. If it
1241 is, we must ensure that there is room for it
1242 to be doubled in the output stream. Therefore
1243 we no longer advance the pointer when the
1244 character is fetched, but rather wait until
1245 after the check for a NULL output character.
1246 This is necessary because there may not be
1247 room for the two chars needed to send a NULL.)
1248 */
1249 outch = info->xmit_buf[info->xmit_tail];
1250 if (outch) {
1251 info->xmit_cnt--;
1252 info->xmit_tail = (info->xmit_tail + 1) &
1253 (SERIAL_XMIT_SIZE - 1);
1254 cy_writeb(base_addr + (CyTDR << index), outch);
1255 info->icount.tx++;
1256 } else {
1257 if (char_count > 1) {
1258 info->xmit_cnt--;
1259 info->xmit_tail = (info->xmit_tail + 1)&
1260 (SERIAL_XMIT_SIZE - 1);
1261 cy_writeb(base_addr + (CyTDR << index),
1262 outch);
1263 cy_writeb(base_addr + (CyTDR << index),
1264 0);
1265 info->icount.tx++;
1266 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -08001267 }
1268 }
1269 }
Jiri Slabye9410272006-12-08 02:39:28 -08001270
1271txdone:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001272 tty_wakeup(info->tty);
Jiri Slabye9410272006-12-08 02:39:28 -08001273txend:
Jiri Slaby02f11752006-12-08 02:39:28 -08001274 /* end of service */
1275 cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
1276 cy_writeb(base_addr + (CyCAR << index), (save_car));
1277 spin_unlock(&cinfo->card_lock);
Jiri Slabye9410272006-12-08 02:39:28 -08001278 }
1279
Jiri Slaby02f11752006-12-08 02:39:28 -08001280 if (status & CySRModem) { /* modem interrupt */
Jiri Slabye9410272006-12-08 02:39:28 -08001281
Jiri Slaby02f11752006-12-08 02:39:28 -08001282 /* determine the channel & change to that context */
1283 spin_lock(&cinfo->card_lock);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001284 save_xir = (u_char) readb(base_addr + (CyMIR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001285 channel = (u_short) (save_xir & CyIRChannel);
Jiri Slabydd025c02007-05-08 00:37:02 -07001286 info = &cinfo->ports[channel + chip * 4];
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001287 save_car = readb(base_addr + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08001288 cy_writeb(base_addr + (CyCAR << index), save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -08001289
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001290 mdm_change = readb(base_addr + (CyMISR << index));
1291 mdm_status = readb(base_addr + (CyMSVR1 << index));
Jiri Slabye9410272006-12-08 02:39:28 -08001292
Jiri Slabyf7429032007-05-08 00:36:59 -07001293 if (info->tty) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001294 if (mdm_change & CyANY_DELTA) {
1295 /* For statistics only */
1296 if (mdm_change & CyDCD)
1297 info->icount.dcd++;
1298 if (mdm_change & CyCTS)
1299 info->icount.cts++;
1300 if (mdm_change & CyDSR)
1301 info->icount.dsr++;
1302 if (mdm_change & CyRI)
1303 info->icount.rng++;
Jiri Slabye9410272006-12-08 02:39:28 -08001304
Jiri Slabyebafeef2007-10-18 03:06:20 -07001305 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slabye9410272006-12-08 02:39:28 -08001306 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001307
1308 if ((mdm_change & CyDCD) &&
1309 (info->flags & ASYNC_CHECK_CD)) {
Jiri Slabyebafeef2007-10-18 03:06:20 -07001310 if (!(mdm_status & CyDCD)) {
1311 tty_hangup(info->tty);
1312 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby02f11752006-12-08 02:39:28 -08001313 }
Jiri Slabyebafeef2007-10-18 03:06:20 -07001314 wake_up_interruptible(&info->open_wait);
Jiri Slabye9410272006-12-08 02:39:28 -08001315 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001316 if ((mdm_change & CyCTS) &&
1317 (info->flags & ASYNC_CTS_FLOW)) {
1318 if (info->tty->hw_stopped) {
1319 if (mdm_status & CyCTS) {
1320 /* cy_start isn't used
1321 because... !!! */
1322 info->tty->hw_stopped = 0;
1323 cy_writeb(base_addr +
1324 (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001325 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001326 (CySRER <<
1327 index))|
1328 CyTxRdy);
Jiri Slabyebafeef2007-10-18 03:06:20 -07001329 tty_wakeup(info->tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001330 }
1331 } else {
1332 if (!(mdm_status & CyCTS)) {
1333 /* cy_stop isn't used
1334 because ... !!! */
1335 info->tty->hw_stopped = 1;
1336 cy_writeb(base_addr +
1337 (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001338 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001339 (CySRER <<
1340 index)) &
1341 ~CyTxRdy);
1342 }
1343 }
1344 }
Jiri Slabyf7429032007-05-08 00:36:59 -07001345/* if (mdm_change & CyDSR) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001346 }
1347 if (mdm_change & CyRI) {
Jiri Slabyf7429032007-05-08 00:36:59 -07001348 }*/
Jiri Slabye9410272006-12-08 02:39:28 -08001349 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001350 /* end of service */
1351 cy_writeb(base_addr + (CyMIR << 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}
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357/* The real interrupt service routine is called
1358 whenever the card wants its hand held--chars
1359 received, out buffer empty, modem change, etc.
1360 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001361static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362{
Jiri Slaby02f11752006-12-08 02:39:28 -08001363 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -07001364 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001365 void __iomem *base_addr, *card_base_addr;
1366 int chip;
1367 int index;
1368 int too_many;
1369 int had_work;
Jiri Slabye9410272006-12-08 02:39:28 -08001370
Jiri Slabyf7429032007-05-08 00:36:59 -07001371 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001373 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001375 return IRQ_NONE; /* spurious interrupt */
1376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
Jiri Slaby02f11752006-12-08 02:39:28 -08001378 card_base_addr = cinfo->base_addr;
1379 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Jiri Slabyf1e83c62007-05-08 00:36:24 -07001381 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
1382 if (unlikely(card_base_addr == NULL))
1383 return IRQ_HANDLED;
1384
Jiri Slaby02f11752006-12-08 02:39:28 -08001385 /* This loop checks all chips in the card. Make a note whenever
1386 _any_ chip had some work to do, as this is considered an
1387 indication that there will be more to do. Only when no chip
1388 has any work does this outermost loop exit.
1389 */
1390 do {
1391 had_work = 0;
1392 for (chip = 0; chip < cinfo->num_chips; chip++) {
1393 base_addr = cinfo->base_addr +
1394 (cy_chip_offset[chip] << index);
1395 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001396 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001397 (CySVRR << index))) != 0x00) {
1398 had_work++;
1399 /* The purpose of the following test is to ensure that
1400 no chip can monopolize the driver. This forces the
1401 chips to be checked in a round-robin fashion (after
1402 draining each of a bunch (1000) of characters).
1403 */
1404 if (1000 < too_many++) {
1405 break;
1406 }
1407 cyy_intr_chip(cinfo, chip, base_addr, status,
1408 index);
1409 }
1410 }
1411 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Jiri Slaby02f11752006-12-08 02:39:28 -08001413 /* clear interrupts */
1414 spin_lock(&cinfo->card_lock);
1415 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
1416 /* Cy_ClrIntr is 0x1800 */
1417 spin_unlock(&cinfo->card_lock);
1418 return IRQ_HANDLED;
1419} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421/***********************************************************/
1422/********* End of block of Cyclom-Y specific code **********/
1423/******** Start of block of Cyclades-Z specific code *********/
1424/***********************************************************/
1425
1426static int
Jiri Slaby02f11752006-12-08 02:39:28 -08001427cyz_fetch_msg(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001428 __u32 * channel, __u8 * cmd, __u32 * param)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
Jiri Slaby02f11752006-12-08 02:39:28 -08001430 struct FIRM_ID __iomem *firm_id;
1431 struct ZFW_CTRL __iomem *zfw_ctrl;
1432 struct BOARD_CTRL __iomem *board_ctrl;
1433 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Jiri Slaby02f11752006-12-08 02:39:28 -08001435 firm_id = cinfo->base_addr + ID_ADDRESS;
1436 if (!ISZLOADED(*cinfo)) {
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001437 return -1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001438 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001439 zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001440 board_ctrl = &zfw_ctrl->board_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001442 loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
Jiri Slaby02f11752006-12-08 02:39:28 -08001443 (cinfo->ctl_addr))->loc_doorbell);
1444 if (loc_doorbell) {
1445 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001446 *channel = readl(&board_ctrl->fwcmd_channel);
1447 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby02f11752006-12-08 02:39:28 -08001448 cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
1449 loc_doorbell, 0xffffffff);
1450 return 1;
1451 }
1452 return 0;
1453} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455static int
Jiri Slaby02f11752006-12-08 02:39:28 -08001456cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001457 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
Jiri Slaby02f11752006-12-08 02:39:28 -08001459 struct FIRM_ID __iomem *firm_id;
1460 struct ZFW_CTRL __iomem *zfw_ctrl;
1461 struct BOARD_CTRL __iomem *board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001462 __u32 __iomem *pci_doorbell;
Jiri Slaby02f11752006-12-08 02:39:28 -08001463 int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Jiri Slaby02f11752006-12-08 02:39:28 -08001465 firm_id = cinfo->base_addr + ID_ADDRESS;
1466 if (!ISZLOADED(*cinfo)) {
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001467 return -1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001468 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001469 zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001470 board_ctrl = &zfw_ctrl->board_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Jiri Slaby02f11752006-12-08 02:39:28 -08001472 index = 0;
1473 pci_doorbell =
1474 &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001475 while ((readl(pci_doorbell) & 0xff) != 0) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001476 if (index++ == 1000) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001477 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001478 }
1479 udelay(50L);
1480 }
1481 cy_writel(&board_ctrl->hcmd_channel, channel);
1482 cy_writel(&board_ctrl->hcmd_param, param);
1483 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001485 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001486} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488static void
Jiri Slabyad39c302007-05-08 00:35:49 -07001489cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
1490 struct BUF_CTRL __iomem *buf_ctrl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491{
Jiri Slaby875b2062007-05-08 00:36:49 -07001492 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001493 struct tty_struct *tty = info->tty;
Jiri Slabyad39c302007-05-08 00:35:49 -07001494 int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001495 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -07001497 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498#else
Jiri Slaby02f11752006-12-08 02:39:28 -08001499 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001501 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001503 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
1504 rx_put = readl(&buf_ctrl->rx_put);
1505 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
1506 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001507 if (rx_put >= rx_get)
1508 char_count = rx_put - rx_get;
1509 else
1510 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Jiri Slaby02f11752006-12-08 02:39:28 -08001512 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -08001514 info->mon.int_count++;
1515 info->mon.char_count += char_count;
1516 if (char_count > info->mon.char_max)
1517 info->mon.char_max = char_count;
1518 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519#endif
Jiri Slabyf7429032007-05-08 00:36:59 -07001520 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001521 /* flush received characters */
1522 new_rx_get = (new_rx_get + char_count) &
1523 (rx_bufsize - 1);
1524 info->rflush_count++;
1525 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001527 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
1528 for performance, but because of buffer boundaries, there
1529 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -07001530 while (1) {
1531 len = tty_prepare_flip_string(tty, &buf,
1532 char_count);
1533 if (!len)
1534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Jiri Slabyce71b0f2007-05-08 00:36:53 -07001536 len = min_t(unsigned int, min(len, char_count),
1537 rx_bufsize - new_rx_get);
1538
1539 memcpy_fromio(buf, cinfo->base_addr +
1540 rx_bufaddr + new_rx_get, len);
1541
1542 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001543 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -07001544 char_count -= len;
1545 info->icount.rx += len;
1546 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -08001547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548#else
Jiri Slaby02f11752006-12-08 02:39:28 -08001549 len = tty_buffer_request_room(tty, char_count);
1550 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001551 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -08001552 new_rx_get);
1553 new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
1554 tty_insert_flip_char(tty, data, TTY_NORMAL);
1555 info->idle_stats.recv_bytes++;
1556 info->icount.rx++;
1557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558#endif
1559#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001560 /* Recalculate the number of chars in the RX buffer and issue
1561 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001562 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001563 if (rx_put >= rx_get)
1564 char_count = rx_put - rx_get;
1565 else
1566 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slabyebafeef2007-10-18 03:06:20 -07001567 if (char_count >= (int)readl(&buf_ctrl->rx_threshold) &&
1568 !timer_pending(&cyz_rx_full_timer[
1569 info->line]))
1570 mod_timer(&cyz_rx_full_timer[info->line],
1571 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001573 info->idle_stats.recv_idle = jiffies;
1574 tty_schedule_flip(tty);
1575 }
1576 /* Update rx_get */
1577 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579}
1580
1581static void
Jiri Slabyad39c302007-05-08 00:35:49 -07001582cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
1583 struct BUF_CTRL __iomem *buf_ctrl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584{
Jiri Slaby875b2062007-05-08 00:36:49 -07001585 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001586 struct tty_struct *tty = info->tty;
1587 char data;
Jiri Slabyad39c302007-05-08 00:35:49 -07001588 int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001590 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001592 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Jiri Slaby02f11752006-12-08 02:39:28 -08001594 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1595 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001597 tx_get = readl(&buf_ctrl->tx_get);
1598 tx_put = readl(&buf_ctrl->tx_put);
1599 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1600 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001601 if (tx_put >= tx_get)
1602 char_count = tx_get - tx_put - 1 + tx_bufsize;
1603 else
1604 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
Jiri Slaby02f11752006-12-08 02:39:28 -08001606 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
Jiri Slabyf7429032007-05-08 00:36:59 -07001608 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001609 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001610
1611 if (info->x_char) { /* send special char */
1612 data = info->x_char;
1613
1614 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1615 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1616 info->x_char = 0;
1617 char_count--;
1618 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001619 }
1620#ifdef BLOCKMOVE
1621 while (0 < (small_count = min_t(unsigned int,
1622 tx_bufsize - tx_put, min_t(unsigned int,
1623 (SERIAL_XMIT_SIZE - info->xmit_tail),
1624 min_t(unsigned int, info->xmit_cnt,
1625 char_count))))) {
1626
1627 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1628 tx_put),
1629 &info->xmit_buf[info->xmit_tail],
1630 small_count);
1631
1632 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1633 char_count -= small_count;
1634 info->icount.tx += small_count;
1635 info->xmit_cnt -= small_count;
1636 info->xmit_tail = (info->xmit_tail + small_count) &
1637 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001638 }
1639#else
1640 while (info->xmit_cnt && char_count) {
1641 data = info->xmit_buf[info->xmit_tail];
1642 info->xmit_cnt--;
1643 info->xmit_tail = (info->xmit_tail + 1) &
1644 (SERIAL_XMIT_SIZE - 1);
1645
1646 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1647 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1648 char_count--;
1649 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001652ztxdone:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001653 tty_wakeup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001654 /* Update tx_put */
1655 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657}
1658
Jiri Slaby02f11752006-12-08 02:39:28 -08001659static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660{
Jiri Slaby02f11752006-12-08 02:39:28 -08001661 struct tty_struct *tty;
1662 struct cyclades_port *info;
Jiri Slabyad39c302007-05-08 00:35:49 -07001663 static struct FIRM_ID __iomem *firm_id;
1664 static struct ZFW_CTRL __iomem *zfw_ctrl;
1665 static struct BOARD_CTRL __iomem *board_ctrl;
1666 static struct CH_CTRL __iomem *ch_ctrl;
1667 static struct BUF_CTRL __iomem *buf_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001668 __u32 channel;
1669 __u8 cmd;
1670 __u32 param;
1671 __u32 hw_ver, fw_ver;
Jiri Slaby02f11752006-12-08 02:39:28 -08001672 int special_count;
1673 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 firm_id = cinfo->base_addr + ID_ADDRESS;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001676 zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001677 board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001678 fw_ver = readl(&board_ctrl->fw_version);
1679 hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
Jiri Slaby02f11752006-12-08 02:39:28 -08001680 mail_box_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
Jiri Slaby02f11752006-12-08 02:39:28 -08001682 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1683 special_count = 0;
1684 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001685 info = &cinfo->ports[channel];
Jiri Slabyf7429032007-05-08 00:36:59 -07001686 if ((tty = info->tty) == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001688
Jiri Slaby02f11752006-12-08 02:39:28 -08001689 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
1690 buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
1691
1692 switch (cmd) {
1693 case C_CM_PR_ERROR:
1694 tty_insert_flip_char(tty, 0, TTY_PARITY);
1695 info->icount.rx++;
1696 special_count++;
1697 break;
1698 case C_CM_FR_ERROR:
1699 tty_insert_flip_char(tty, 0, TTY_FRAME);
1700 info->icount.rx++;
1701 special_count++;
1702 break;
1703 case C_CM_RXBRK:
1704 tty_insert_flip_char(tty, 0, TTY_BREAK);
1705 info->icount.rx++;
1706 special_count++;
1707 break;
1708 case C_CM_MDCD:
1709 info->icount.dcd++;
1710 delta_count++;
1711 if (info->flags & ASYNC_CHECK_CD) {
1712 if ((fw_ver > 241 ? ((u_long) param) :
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001713 readl(&ch_ctrl->rs_status)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08001714 C_RS_DCD) {
Jiri Slabyebafeef2007-10-18 03:06:20 -07001715 wake_up_interruptible(&info->open_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001716 } else {
Jiri Slabyebafeef2007-10-18 03:06:20 -07001717 tty_hangup(info->tty);
1718 wake_up_interruptible(&info->open_wait);
1719 info->flags &= ~ASYNC_NORMAL_ACTIVE;
Jiri Slaby02f11752006-12-08 02:39:28 -08001720 }
1721 }
1722 break;
1723 case C_CM_MCTS:
1724 info->icount.cts++;
1725 delta_count++;
1726 break;
1727 case C_CM_MRI:
1728 info->icount.rng++;
1729 delta_count++;
1730 break;
1731 case C_CM_MDSR:
1732 info->icount.dsr++;
1733 delta_count++;
1734 break;
1735#ifdef Z_WAKE
1736 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001737 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001738 break;
1739#endif
1740#ifdef CONFIG_CYZ_INTR
1741 case C_CM_RXHIWM:
1742 case C_CM_RXNNDT:
1743 case C_CM_INTBACK2:
1744 /* Reception Interrupt */
1745#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001746 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1747 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001748#endif
1749 cyz_handle_rx(info, ch_ctrl, buf_ctrl);
1750 break;
1751 case C_CM_TXBEMPTY:
1752 case C_CM_TXLOWWM:
1753 case C_CM_INTBACK:
1754 /* Transmission Interrupt */
1755#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001756 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1757 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001758#endif
1759 cyz_handle_tx(info, ch_ctrl, buf_ctrl);
1760 break;
1761#endif /* CONFIG_CYZ_INTR */
1762 case C_CM_FATAL:
1763 /* should do something with this !!! */
1764 break;
1765 default:
1766 break;
1767 }
1768 if (delta_count)
Jiri Slabyebafeef2007-10-18 03:06:20 -07001769 wake_up_interruptible(&info->delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001770 if (special_count)
1771 tty_schedule_flip(tty);
1772 }
1773}
1774
1775#ifdef CONFIG_CYZ_INTR
1776static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1777{
Jiri Slabyf7429032007-05-08 00:36:59 -07001778 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001779
Jiri Slabyf7429032007-05-08 00:36:59 -07001780 if (unlikely(cinfo == NULL)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001781#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001782 printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001783#endif
1784 return IRQ_NONE; /* spurious interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 }
1786
Jiri Slabyf7429032007-05-08 00:36:59 -07001787 if (unlikely(!ISZLOADED(*cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001788#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001789 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1790 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001791#endif
1792 return IRQ_NONE;
1793 }
1794
1795 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 cyz_handle_cmd(cinfo);
1797
Jiri Slaby02f11752006-12-08 02:39:28 -08001798 return IRQ_HANDLED;
1799} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
Jiri Slaby02f11752006-12-08 02:39:28 -08001801static void cyz_rx_restart(unsigned long arg)
1802{
1803 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001804 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001805 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001806 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001807 unsigned long flags;
1808
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001809 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001810 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001811 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001812 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001815 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001816}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
Jiri Slaby02f11752006-12-08 02:39:28 -08001818#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Jiri Slaby02f11752006-12-08 02:39:28 -08001820static void cyz_poll(unsigned long arg)
1821{
1822 struct cyclades_card *cinfo;
1823 struct cyclades_port *info;
1824 struct tty_struct *tty;
Jiri Slabyc4923b42007-07-17 04:05:17 -07001825 struct FIRM_ID __iomem *firm_id;
1826 struct ZFW_CTRL __iomem *zfw_ctrl;
1827 struct BOARD_CTRL __iomem *board_ctrl;
1828 struct CH_CTRL __iomem *ch_ctrl;
1829 struct BUF_CTRL __iomem *buf_ctrl;
Jiri Slabyb7050902007-05-08 00:35:48 -07001830 unsigned long expires = jiffies + HZ;
Jiri Slaby02f11752006-12-08 02:39:28 -08001831 int card, port;
1832
Jiri Slaby02f11752006-12-08 02:39:28 -08001833 for (card = 0; card < NR_CARDS; card++) {
1834 cinfo = &cy_card[card];
1835
1836 if (!IS_CYC_Z(*cinfo))
1837 continue;
1838 if (!ISZLOADED(*cinfo))
1839 continue;
1840
1841 firm_id = cinfo->base_addr + ID_ADDRESS;
1842 zfw_ctrl = cinfo->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001843 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001844 board_ctrl = &(zfw_ctrl->board_ctrl);
1845
1846 /* Skip first polling cycle to avoid racing conditions with the FW */
1847 if (!cinfo->intr_enabled) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001848 cinfo->nports = (int)readl(&board_ctrl->n_channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001849 cinfo->intr_enabled = 1;
1850 continue;
1851 }
1852
1853 cyz_handle_cmd(cinfo);
1854
1855 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07001856 info = &cinfo->ports[port];
Jiri Slaby02f11752006-12-08 02:39:28 -08001857 tty = info->tty;
1858 ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
1859 buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
1860
1861 if (!info->throttle)
1862 cyz_handle_rx(info, ch_ctrl, buf_ctrl);
1863 cyz_handle_tx(info, ch_ctrl, buf_ctrl);
1864 }
1865 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001866 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001867 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001868 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001869} /* cyz_poll */
1870
1871#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873/********** End of block of Cyclades-Z specific code *********/
1874/***********************************************************/
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876/* This is called whenever a port becomes active;
1877 interrupts are enabled and DTR & RTS are turned on.
1878 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001879static int startup(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880{
Jiri Slaby875b2062007-05-08 00:36:49 -07001881 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001882 unsigned long flags;
1883 int retval = 0;
1884 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07001885 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08001886 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Jiri Slaby02f11752006-12-08 02:39:28 -08001888 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001889 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Jiri Slaby02f11752006-12-08 02:39:28 -08001891 page = get_zeroed_page(GFP_KERNEL);
1892 if (!page)
1893 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001895 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
Jiri Slaby02f11752006-12-08 02:39:28 -08001897 if (info->flags & ASYNC_INITIALIZED) {
1898 free_page(page);
1899 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001901
1902 if (!info->type) {
1903 if (info->tty) {
1904 set_bit(TTY_IO_ERROR, &info->tty->flags);
1905 }
1906 free_page(page);
1907 goto errout;
1908 }
1909
1910 if (info->xmit_buf)
1911 free_page(page);
1912 else
1913 info->xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001915 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
Jiri Slaby02f11752006-12-08 02:39:28 -08001917 set_line_char(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
Jiri Slaby875b2062007-05-08 00:36:49 -07001919 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001920 chip = channel >> 2;
1921 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07001922 index = card->bus_index;
1923 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001926 printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
1927 "base_addr %p\n",
1928 card, chip, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001929#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001930 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001931
1932 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1933
1934 cy_writeb(base_addr + (CyRTPR << index),
1935 (info->default_timeout ? info->default_timeout : 0x02));
1936 /* 10ms rx timeout */
1937
1938 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,
1939 index);
1940
1941 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
1942 cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);
1943 cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
1944
1945#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07001946 printk(KERN_DEBUG "cyc:startup raising DTR\n");
1947 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001948 readb(base_addr + (CyMSVR1 << index)),
1949 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950#endif
1951
Jiri Slaby02f11752006-12-08 02:39:28 -08001952 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001953 readb(base_addr + (CySRER << index)) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001954 info->flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Jiri Slaby02f11752006-12-08 02:39:28 -08001956 if (info->tty) {
1957 clear_bit(TTY_IO_ERROR, &info->tty->flags);
1958 }
1959 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1960 info->breakon = info->breakoff = 0;
1961 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1962 info->idle_stats.in_use =
1963 info->idle_stats.recv_idle =
1964 info->idle_stats.xmit_idle = jiffies;
1965
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001966 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001967
1968 } else {
1969 struct FIRM_ID __iomem *firm_id;
1970 struct ZFW_CTRL __iomem *zfw_ctrl;
1971 struct BOARD_CTRL __iomem *board_ctrl;
1972 struct CH_CTRL __iomem *ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001973
Jiri Slaby875b2062007-05-08 00:36:49 -07001974 base_addr = card->base_addr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001975
1976 firm_id = base_addr + ID_ADDRESS;
Jiri Slaby875b2062007-05-08 00:36:49 -07001977 if (!ISZLOADED(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001978 return -ENODEV;
1979 }
1980
Jiri Slaby875b2062007-05-08 00:36:49 -07001981 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001982 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08001983 board_ctrl = &zfw_ctrl->board_ctrl;
1984 ch_ctrl = zfw_ctrl->ch_ctrl;
1985
1986#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001987 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1988 "base_addr %p\n", card, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001989#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001990 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001991
1992 cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993#ifdef Z_WAKE
1994#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001995 cy_writel(&ch_ctrl[channel].intr_enable,
1996 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1997 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998#else
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 cy_writel(&ch_ctrl[channel].intr_enable,
2000 C_IN_IOCTLW | C_IN_MDCD);
2001#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002#else
2003#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002004 cy_writel(&ch_ctrl[channel].intr_enable,
2005 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
2006 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007#else
Jiri Slaby02f11752006-12-08 02:39:28 -08002008 cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);
2009#endif /* CONFIG_CYZ_INTR */
2010#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
Jiri Slaby875b2062007-05-08 00:36:49 -07002012 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002013 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002014 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
2015 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Jiri Slaby02f11752006-12-08 02:39:28 -08002018 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07002019 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002020 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002021 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
2022 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Jiri Slaby02f11752006-12-08 02:39:28 -08002025 /* set timeout !!! */
2026 /* set RTS and DTR !!! */
2027 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002028 readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
Jiri Slaby02f11752006-12-08 02:39:28 -08002029 C_RS_DTR);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002030 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002031 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002032 printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
2033 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002036 printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037#endif
2038
Jiri Slaby02f11752006-12-08 02:39:28 -08002039 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Jiri Slaby02f11752006-12-08 02:39:28 -08002041 info->flags |= ASYNC_INITIALIZED;
2042 if (info->tty) {
2043 clear_bit(TTY_IO_ERROR, &info->tty->flags);
2044 }
2045 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
2046 info->breakon = info->breakoff = 0;
2047 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
2048 info->idle_stats.in_use =
2049 info->idle_stats.recv_idle =
2050 info->idle_stats.xmit_idle = jiffies;
2051
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002052 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054
2055#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002056 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057#endif
2058 return 0;
2059
2060errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002061 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002063} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Jiri Slaby02f11752006-12-08 02:39:28 -08002065static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
Jiri Slaby875b2062007-05-08 00:36:49 -07002067 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002068 unsigned long flags;
2069 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002070 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Jiri Slaby02f11752006-12-08 02:39:28 -08002072 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002073 channel = info->line - card->first_line;
2074 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002075 chip = channel >> 2;
2076 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002077 index = card->bus_index;
2078 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002080 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002081 cy_writeb(base_addr + (CyCAR << index), channel);
2082 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002083 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002084 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002085 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08002087 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002089 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07002090 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002091 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002092 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
2093 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002094 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002095 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002096#else /* CONFIG_CYZ_INTR */
2097 /* Don't have to do anything at this time */
2098#endif /* CONFIG_CYZ_INTR */
2099 }
2100} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102/*
2103 * This routine shuts down a serial port; interrupts are disabled,
2104 * and DTR is dropped if the hangup on close termio flag is on.
2105 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002106static void shutdown(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
Jiri Slaby875b2062007-05-08 00:36:49 -07002108 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002109 unsigned long flags;
2110 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002111 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
Jiri Slaby02f11752006-12-08 02:39:28 -08002113 if (!(info->flags & ASYNC_INITIALIZED)) {
2114 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
2116
Jiri Slaby02f11752006-12-08 02:39:28 -08002117 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002118 channel = info->line - card->first_line;
2119 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002120 chip = channel >> 2;
2121 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002122 index = card->bus_index;
2123 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002126 printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
2127 "channel %d, base_addr %p\n",
2128 card, chip, channel, base_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002131 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002132
2133 /* Clear delta_msr_wait queue to avoid mem leaks. */
2134 wake_up_interruptible(&info->delta_msr_wait);
2135
2136 if (info->xmit_buf) {
2137 unsigned char *temp;
2138 temp = info->xmit_buf;
2139 info->xmit_buf = NULL;
2140 free_page((unsigned long)temp);
2141 }
2142 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2143 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
2144 cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
2145 cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
2146#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002147 printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
2148 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002149 readb(base_addr + (CyMSVR1 << index)),
2150 readb(base_addr + (CyMSVR2 << index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08002151#endif
2152 }
2153 cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
2154 /* it may be appropriate to clear _XMIT at
2155 some later date (after testing)!!! */
2156
2157 if (info->tty) {
2158 set_bit(TTY_IO_ERROR, &info->tty->flags);
2159 }
2160 info->flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002161 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002162 } else {
2163 struct FIRM_ID __iomem *firm_id;
2164 struct ZFW_CTRL __iomem *zfw_ctrl;
2165 struct BOARD_CTRL __iomem *board_ctrl;
2166 struct CH_CTRL __iomem *ch_ctrl;
2167 int retval;
2168
Jiri Slaby875b2062007-05-08 00:36:49 -07002169 base_addr = card->base_addr;
Jiri Slaby02f11752006-12-08 02:39:28 -08002170#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002171 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
2172 "base_addr %p\n", card, channel, base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08002173#endif
2174
2175 firm_id = base_addr + ID_ADDRESS;
Jiri Slaby875b2062007-05-08 00:36:49 -07002176 if (!ISZLOADED(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002177 return;
2178 }
2179
Jiri Slaby875b2062007-05-08 00:36:49 -07002180 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002181 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08002182 board_ctrl = &zfw_ctrl->board_ctrl;
2183 ch_ctrl = zfw_ctrl->ch_ctrl;
2184
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002185 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002186
2187 if (info->xmit_buf) {
2188 unsigned char *temp;
2189 temp = info->xmit_buf;
2190 info->xmit_buf = NULL;
2191 free_page((unsigned long)temp);
2192 }
2193
2194 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
2195 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002196 (__u32)(readl(&ch_ctrl[channel].rs_control) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002197 ~(C_RS_RTS | C_RS_DTR)));
Jiri Slaby875b2062007-05-08 00:36:49 -07002198 retval = cyz_issue_cmd(info->card, channel,
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 C_CM_IOCTLM, 0L);
2200 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002201 printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
2202 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002203 }
2204#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002205 printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002206#endif
2207 }
2208
2209 if (info->tty) {
2210 set_bit(TTY_IO_ERROR, &info->tty->flags);
2211 }
2212 info->flags &= ~ASYNC_INITIALIZED;
2213
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002214 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002215 }
2216
2217#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002218 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002219#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002220} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222/*
2223 * ------------------------------------------------------------
2224 * cy_open() and friends
2225 * ------------------------------------------------------------
2226 */
2227
2228static int
Jiri Slaby02f11752006-12-08 02:39:28 -08002229block_til_ready(struct tty_struct *tty, struct file *filp,
2230 struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
Jiri Slaby02f11752006-12-08 02:39:28 -08002232 DECLARE_WAITQUEUE(wait, current);
2233 struct cyclades_card *cinfo;
2234 unsigned long flags;
2235 int chip, channel, index;
2236 int retval;
2237 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Jiri Slaby875b2062007-05-08 00:36:49 -07002239 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002240 channel = info->line - cinfo->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Jiri Slaby02f11752006-12-08 02:39:28 -08002242 /*
2243 * If the device is in the middle of being closed, then block
2244 * until it's done, and then try again.
2245 */
2246 if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002247 wait_event_interruptible(info->close_wait,
2248 !(info->flags & ASYNC_CLOSING));
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002249 return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08002250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
Jiri Slaby02f11752006-12-08 02:39:28 -08002252 /*
2253 * If non-blocking mode is set, then make the check up front
2254 * and then exit.
2255 */
2256 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
2257 info->flags |= ASYNC_NORMAL_ACTIVE;
2258 return 0;
2259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
Jiri Slaby02f11752006-12-08 02:39:28 -08002261 /*
2262 * Block waiting for the carrier detect and the line to become
2263 * free (i.e., not in use by the callout). While we are in
2264 * this loop, info->count is dropped by one, so that
2265 * cy_close() knows when to free things. We restore it upon
2266 * exit, either normal or abnormal.
2267 */
2268 retval = 0;
2269 add_wait_queue(&info->open_wait, &wait);
2270#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002271 printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
2272 "count = %d\n", info->line, info->count);
Jiri Slaby02f11752006-12-08 02:39:28 -08002273#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002274 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002275 if (!tty_hung_up_p(filp))
2276 info->count--;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002277 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002278#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07002279 printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
2280 "%d\n", current->pid, info->count);
Jiri Slaby02f11752006-12-08 02:39:28 -08002281#endif
2282 info->blocked_open++;
2283
2284 if (!IS_CYC_Z(*cinfo)) {
2285 chip = channel >> 2;
2286 channel &= 0x03;
2287 index = cinfo->bus_index;
2288 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
2289
2290 while (1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002291 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002292 if ((tty->termios->c_cflag & CBAUD)) {
2293 cy_writeb(base_addr + (CyCAR << index),
2294 (u_char) channel);
2295 cy_writeb(base_addr + (CyMSVR1 << index),
2296 CyRTS);
2297 cy_writeb(base_addr + (CyMSVR2 << index),
2298 CyDTR);
2299#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002300 printk(KERN_DEBUG "cyc:block_til_ready raising "
2301 "DTR\n");
2302 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002303 readb(base_addr + (CyMSVR1 << index)),
2304 readb(base_addr + (CyMSVR2 << index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08002305#endif
2306 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002307 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Jiri Slaby02f11752006-12-08 02:39:28 -08002309 set_current_state(TASK_INTERRUPTIBLE);
2310 if (tty_hung_up_p(filp) ||
2311 !(info->flags & ASYNC_INITIALIZED)) {
2312 retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
2313 -EAGAIN : -ERESTARTSYS);
2314 break;
2315 }
2316
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002317 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002318 cy_writeb(base_addr + (CyCAR << index),
2319 (u_char) channel);
2320 if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002321 (readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002322 (CyMSVR1 << index)) & CyDCD))) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002323 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002324 break;
2325 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002326 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002327
2328 if (signal_pending(current)) {
2329 retval = -ERESTARTSYS;
2330 break;
2331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002333 printk(KERN_DEBUG "cyc block_til_ready blocking: "
2334 "ttyC%d, count = %d\n",
2335 info->line, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002337 schedule();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002339 } else {
2340 struct FIRM_ID __iomem *firm_id;
2341 struct ZFW_CTRL __iomem *zfw_ctrl;
2342 struct BOARD_CTRL __iomem *board_ctrl;
2343 struct CH_CTRL __iomem *ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002344
2345 base_addr = cinfo->base_addr;
2346 firm_id = base_addr + ID_ADDRESS;
2347 if (!ISZLOADED(*cinfo)) {
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07002348 __set_current_state(TASK_RUNNING);
Jiri Slaby02f11752006-12-08 02:39:28 -08002349 remove_wait_queue(&info->open_wait, &wait);
2350 return -EINVAL;
2351 }
2352
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002353 zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08002354 board_ctrl = &zfw_ctrl->board_ctrl;
2355 ch_ctrl = zfw_ctrl->ch_ctrl;
2356
2357 while (1) {
2358 if ((tty->termios->c_cflag & CBAUD)) {
2359 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002360 readl(&ch_ctrl[channel].rs_control) |
2361 C_RS_RTS | C_RS_DTR);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002362 retval = cyz_issue_cmd(cinfo,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002363 channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002364 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002365 printk(KERN_ERR "cyc:block_til_ready "
2366 "retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08002367 info->line, retval);
2368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002370 printk(KERN_DEBUG "cyc:block_til_ready raising "
2371 "Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Jiri Slaby02f11752006-12-08 02:39:28 -08002375 set_current_state(TASK_INTERRUPTIBLE);
2376 if (tty_hung_up_p(filp) ||
2377 !(info->flags & ASYNC_INITIALIZED)) {
2378 retval = ((info->flags & ASYNC_HUP_NOTIFY) ?
2379 -EAGAIN : -ERESTARTSYS);
2380 break;
2381 }
2382 if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002383 (readl(&ch_ctrl[channel].rs_status) &
Jiri Slaby02f11752006-12-08 02:39:28 -08002384 C_RS_DCD))) {
2385 break;
2386 }
2387 if (signal_pending(current)) {
2388 retval = -ERESTARTSYS;
2389 break;
2390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002392 printk(KERN_DEBUG "cyc block_til_ready blocking: "
2393 "ttyC%d, count = %d\n",
2394 info->line, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002396 schedule();
2397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07002399 __set_current_state(TASK_RUNNING);
Jiri Slaby02f11752006-12-08 02:39:28 -08002400 remove_wait_queue(&info->open_wait, &wait);
2401 if (!tty_hung_up_p(filp)) {
2402 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07002404 printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
2405 "count to %d\n", current->pid, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002407 }
2408 info->blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002410 printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
2411 "count = %d\n", info->line, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002413 if (retval)
2414 return retval;
2415 info->flags |= ASYNC_NORMAL_ACTIVE;
2416 return 0;
2417} /* block_til_ready */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
2419/*
2420 * This routine is called whenever a serial port is opened. It
2421 * performs the serial-specific initialization for the tty structure.
2422 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002423static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424{
Jiri Slaby02f11752006-12-08 02:39:28 -08002425 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07002426 unsigned int i;
Jiri Slaby02f11752006-12-08 02:39:28 -08002427 int retval, line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
Jiri Slaby02f11752006-12-08 02:39:28 -08002429 line = tty->index;
2430 if ((line < 0) || (NR_PORTS <= line)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08002432 }
Jiri Slabydd025c02007-05-08 00:37:02 -07002433 for (i = 0; i < NR_CARDS; i++)
2434 if (line < cy_card[i].first_line + cy_card[i].nports &&
2435 line >= cy_card[i].first_line)
2436 break;
2437 if (i >= NR_CARDS)
2438 return -ENODEV;
2439 info = &cy_card[i].ports[line - cy_card[i].first_line];
Jiri Slaby02f11752006-12-08 02:39:28 -08002440 if (info->line < 0) {
2441 return -ENODEV;
2442 }
2443
2444 /* If the card's firmware hasn't been loaded,
2445 treat it as absent from the system. This
2446 will make the user pay attention.
2447 */
Jiri Slaby875b2062007-05-08 00:36:49 -07002448 if (IS_CYC_Z(*info->card)) {
2449 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002450 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
2451
2452 if (!ISZLOADED(*cinfo)) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002453 if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
Jiri Slaby02f11752006-12-08 02:39:28 -08002454 (cinfo->ctl_addr))->mail_box_0)) &&
2455 Z_FPGA_CHECK(*cinfo)) &&
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002456 (ZFIRM_HLT == readl(
Jiri Slaby02f11752006-12-08 02:39:28 -08002457 &firm_id->signature))) {
Jiri Slaby21719192007-05-08 00:36:42 -07002458 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
2459 "need an external power supply for "
2460 "this number of ports.\nFirmware "
2461 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002462 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07002463 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
2464 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002465 }
2466 return -ENODEV;
2467 }
2468#ifdef CONFIG_CYZ_INTR
2469 else {
2470 /* In case this Z board is operating in interrupt mode, its
2471 interrupts should be enabled as soon as the first open
2472 happens to one of its ports. */
2473 if (!cinfo->intr_enabled) {
2474 struct ZFW_CTRL __iomem *zfw_ctrl;
2475 struct BOARD_CTRL __iomem *board_ctrl;
2476
2477 zfw_ctrl = cinfo->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002478 (readl(&firm_id->zfwctrl_addr) &
2479 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08002480
2481 board_ctrl = &zfw_ctrl->board_ctrl;
2482
2483 /* Enable interrupts on the PLX chip */
2484 cy_writew(cinfo->ctl_addr + 0x68,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002485 readw(cinfo->ctl_addr + 0x68) | 0x0900);
Jiri Slaby02f11752006-12-08 02:39:28 -08002486 /* Enable interrupts on the FW */
2487 retval = cyz_issue_cmd(cinfo, 0,
2488 C_CM_IRQ_ENBL, 0L);
2489 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002490 printk(KERN_ERR "cyc:IRQ enable retval "
2491 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002492 }
2493 cinfo->nports =
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002494 (int)readl(&board_ctrl->n_channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08002495 cinfo->intr_enabled = 1;
2496 }
2497 }
2498#endif /* CONFIG_CYZ_INTR */
2499 /* Make sure this Z port really exists in hardware */
2500 if (info->line > (cinfo->first_line + cinfo->nports - 1))
2501 return -ENODEV;
2502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002504 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002506 tty->driver_data = info;
2507 info->tty = tty;
2508 if (serial_paranoia_check(info, tty->name, "cy_open")) {
2509 return -ENODEV;
2510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002512 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
2513 info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002515 info->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07002517 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08002518 current->pid, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
Jiri Slaby02f11752006-12-08 02:39:28 -08002521 /*
2522 * If the port is the middle of closing, bail out now
2523 */
2524 if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002525 wait_event_interruptible(info->close_wait,
2526 !(info->flags & ASYNC_CLOSING));
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002527 return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08002528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
Jiri Slaby02f11752006-12-08 02:39:28 -08002530 /*
2531 * Start up serial port
2532 */
2533 retval = startup(info);
2534 if (retval) {
2535 return retval;
2536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Jiri Slaby02f11752006-12-08 02:39:28 -08002538 retval = block_til_ready(tty, filp, info);
2539 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002541 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
2542 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002544 return retval;
2545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
Jiri Slaby02f11752006-12-08 02:39:28 -08002547 info->throttle = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002550 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002552 return 0;
2553} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
2555/*
2556 * cy_wait_until_sent() --- wait until the transmitter is empty
2557 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002558static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
Jiri Slaby875b2062007-05-08 00:36:49 -07002560 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002561 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002562 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002563 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002564 unsigned long orig_jiffies;
2565 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Jiri Slaby02f11752006-12-08 02:39:28 -08002567 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
2568 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 if (info->xmit_fifo_size == 0)
2571 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572
Jiri Slaby02f11752006-12-08 02:39:28 -08002573 orig_jiffies = jiffies;
2574 /*
2575 * Set the check interval to be 1/5 of the estimated time to
2576 * send a single character, and make it at least 1. The check
2577 * interval should also be less than the timeout.
2578 *
2579 * Note: we have to use pretty tight timings here to satisfy
2580 * the NIST-PCTS.
2581 */
2582 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
2583 char_time = char_time / 5;
2584 if (char_time <= 0)
2585 char_time = 1;
2586 if (timeout < 0)
2587 timeout = 0;
2588 if (timeout)
2589 char_time = min(char_time, timeout);
2590 /*
2591 * If the transmitter hasn't cleared in twice the approximate
2592 * amount of time to send the entire FIFO, it probably won't
2593 * ever clear. This assumes the UART isn't doing flow
2594 * control, which is currently the case. Hence, if it ever
2595 * takes longer than info->timeout, this is probably due to a
2596 * UART bug of some kind. So, we clamp the timeout parameter at
2597 * 2*info->timeout.
2598 */
2599 if (!timeout || timeout > 2 * info->timeout)
2600 timeout = 2 * info->timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07002602 printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
2603 timeout, char_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002605 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002606 channel = (info->line) - (card->first_line);
2607 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002608 chip = channel >> 2;
2609 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07002610 index = card->bus_index;
2611 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002612 while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07002614 printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002616 if (msleep_interruptible(jiffies_to_msecs(char_time)))
2617 break;
2618 if (timeout && time_after(jiffies, orig_jiffies +
2619 timeout))
2620 break;
2621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002623 /* Run one more char cycle */
2624 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625#ifdef CY_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby21719192007-05-08 00:36:42 -07002626 printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627#endif
2628}
2629
2630/*
2631 * This routine is called when a particular tty device is closed.
2632 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002633static void cy_close(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002635 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002636 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002637 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
2639#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002640 printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641#endif
2642
Jiri Slaby02f11752006-12-08 02:39:28 -08002643 if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
2644 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002647 card = info->card;
2648
2649 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002650 /* If the TTY is being hung up, nothing to do */
2651 if (tty_hung_up_p(filp)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002652 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002653 return;
2654 }
2655#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07002656 printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
2657 info->count);
Jiri Slaby02f11752006-12-08 02:39:28 -08002658#endif
2659 if ((tty->count == 1) && (info->count != 1)) {
2660 /*
2661 * Uh, oh. tty->count is 1, which means that the tty
2662 * structure will be freed. Info->count should always
2663 * be one in these conditions. If it's greater than
2664 * one, we've got real problems, since it means the
2665 * serial port won't be shutdown.
2666 */
Jiri Slaby21719192007-05-08 00:36:42 -07002667 printk(KERN_ERR "cyc:cy_close: bad serial port count; "
2668 "tty->count is 1, info->count is %d\n", info->count);
Jiri Slaby02f11752006-12-08 02:39:28 -08002669 info->count = 1;
2670 }
2671#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07002672 printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08002673 current->pid, info->count - 1);
2674#endif
2675 if (--info->count < 0) {
2676#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07002677 printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08002678#endif
2679 info->count = 0;
2680 }
2681 if (info->count) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002682 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002683 return;
2684 }
2685 info->flags |= ASYNC_CLOSING;
2686
2687 /*
2688 * Now we wait for the transmit buffer to clear; and we notify
2689 * the line discipline to only process XON/XOFF characters.
2690 */
2691 tty->closing = 1;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002692 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002693 if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
2694 tty_wait_until_sent(tty, info->closing_wait);
2695 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002696 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002697
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002698 if (!IS_CYC_Z(*card)) {
2699 int channel = info->line - card->first_line;
2700 int index = card->bus_index;
2701 void __iomem *base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08002702 (cy_chip_offset[channel >> 2] << index);
2703 /* Stop accepting input */
2704 channel &= 0x03;
2705 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
2706 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002707 readb(base_addr + (CySRER << index)) & ~CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 if (info->flags & ASYNC_INITIALIZED) {
2709 /* Waiting for on-board buffers to be empty before closing
2710 the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002711 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002712 cy_wait_until_sent(tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002713 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002714 }
2715 } else {
2716#ifdef Z_WAKE
2717 /* Waiting for on-board buffers to be empty before closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002718 void __iomem *base_addr = card->base_addr;
Jiri Slaby02f11752006-12-08 02:39:28 -08002719 struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
2720 struct ZFW_CTRL __iomem *zfw_ctrl =
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002721 base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08002722 struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002723 int channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002724 int retval;
2725
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002726 if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002727 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002728 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002729 printk(KERN_DEBUG "cyc:cy_close retval on "
2730 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002731 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002732 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002733 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002734 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002735 }
2736#endif
2737 }
2738
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002739 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002740 shutdown(info);
2741 if (tty->driver->flush_buffer)
2742 tty->driver->flush_buffer(tty);
2743 tty_ldisc_flush(tty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002744 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002745
2746 tty->closing = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002747 info->tty = NULL;
2748 if (info->blocked_open) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002749 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002750 if (info->close_delay) {
2751 msleep_interruptible(jiffies_to_msecs
2752 (info->close_delay));
2753 }
2754 wake_up_interruptible(&info->open_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002755 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002756 }
2757 info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
2758 wake_up_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
2760#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002761 printk(KERN_DEBUG "cyc:cy_close done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762#endif
2763
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002764 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002765} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
2767/* This routine gets called when tty_write has put something into
2768 * the write_queue. The characters may come from user space or
2769 * kernel space.
2770 *
2771 * This routine will return the number of characters actually
2772 * accepted for writing.
2773 *
2774 * If the port is not already transmitting stuff, start it off by
2775 * enabling interrupts. The interrupt service routine will then
2776 * ensure that the characters are sent.
2777 * If the port is already active, there is no need to kick it.
2778 *
2779 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002780static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002782 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002783 unsigned long flags;
2784 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
2786#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002787 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788#endif
2789
Jiri Slaby02f11752006-12-08 02:39:28 -08002790 if (serial_paranoia_check(info, tty->name, "cy_write")) {
2791 return 0;
2792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793
Jiri Slaby02f11752006-12-08 02:39:28 -08002794 if (!info->xmit_buf)
2795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002797 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002798 while (1) {
2799 c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
2800 (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
Jiri Slaby02f11752006-12-08 02:39:28 -08002802 if (c <= 0)
2803 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Jiri Slaby02f11752006-12-08 02:39:28 -08002805 memcpy(info->xmit_buf + info->xmit_head, buf, c);
2806 info->xmit_head = (info->xmit_head + c) &
2807 (SERIAL_XMIT_SIZE - 1);
2808 info->xmit_cnt += c;
2809 buf += c;
2810 count -= c;
2811 ret += c;
2812 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002813 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Jiri Slaby02f11752006-12-08 02:39:28 -08002815 info->idle_stats.xmit_bytes += ret;
2816 info->idle_stats.xmit_idle = jiffies;
2817
2818 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
2819 start_xmit(info);
2820 }
2821 return ret;
2822} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824/*
2825 * This routine is called by the kernel to write a single
2826 * character to the tty device. If the kernel uses this routine,
2827 * it must call the flush_chars() routine (if defined) when it is
2828 * done stuffing characters into the driver. If there is no room
2829 * in the queue, the character is ignored.
2830 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002831static void cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002833 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002834 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002837 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838#endif
2839
Jiri Slaby02f11752006-12-08 02:39:28 -08002840 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
2841 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
Jiri Slaby02f11752006-12-08 02:39:28 -08002843 if (!info->xmit_buf)
2844 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002846 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08002847 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002848 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002849 return;
2850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Jiri Slaby02f11752006-12-08 02:39:28 -08002852 info->xmit_buf[info->xmit_head++] = ch;
2853 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
2854 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 info->idle_stats.xmit_bytes++;
2856 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002857 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002858} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860/*
2861 * This routine is called by the kernel after it has written a
2862 * series of characters to the tty device using put_char().
2863 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002864static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002866 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002867
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002869 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870#endif
2871
Jiri Slaby02f11752006-12-08 02:39:28 -08002872 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
2873 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
Jiri Slaby02f11752006-12-08 02:39:28 -08002875 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
2876 !info->xmit_buf)
2877 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878
Jiri Slaby02f11752006-12-08 02:39:28 -08002879 start_xmit(info);
2880} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881
2882/*
2883 * This routine returns the numbers of characters the tty driver
2884 * will accept for queuing to be written. This number is subject
2885 * to change as output buffers get emptied, or if the output flow
2886 * control is activated.
2887 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002888static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002890 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002891 int ret;
2892
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002894 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895#endif
2896
Jiri Slaby02f11752006-12-08 02:39:28 -08002897 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
2898 return 0;
2899 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
2900 if (ret < 0)
2901 ret = 0;
2902 return ret;
2903} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Jiri Slaby02f11752006-12-08 02:39:28 -08002905static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906{
Jiri Slaby875b2062007-05-08 00:36:49 -07002907 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002908 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002909 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
Jiri Slaby02f11752006-12-08 02:39:28 -08002911 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
2912 return 0;
2913
2914 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002915 channel = (info->line) - (card->first_line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002918 if (!IS_CYC_Z(cy_card[card])) {
2919#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002921 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2922 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002924 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08002926 } else {
Jiri Slabyad39c302007-05-08 00:35:49 -07002927 static struct FIRM_ID *firm_id;
2928 static struct ZFW_CTRL *zfw_ctrl;
2929 static struct CH_CTRL *ch_ctrl;
2930 static struct BUF_CTRL *buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08002931 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07002932 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
Jiri Slaby875b2062007-05-08 00:36:49 -07002934 firm_id = card->base_addr + ID_ADDRESS;
2935 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002936 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08002937 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
2938 buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002940 tx_get = readl(&buf_ctrl->tx_get);
2941 tx_put = readl(&buf_ctrl->tx_put);
2942 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08002943 if (tx_put >= tx_get)
2944 char_count = tx_put - tx_get;
2945 else
2946 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07002948 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
2949 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08002951 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08002952 }
2953#endif /* Z_EXT_CHARS_IN_BUFFER */
2954} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
2956/*
2957 * ------------------------------------------------------------
2958 * cy_ioctl() and friends
2959 * ------------------------------------------------------------
2960 */
2961
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002962static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
Jiri Slaby02f11752006-12-08 02:39:28 -08002964 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002965 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08002966 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967
Jiri Slaby02f11752006-12-08 02:39:28 -08002968 if (baud == 0) {
2969 info->tbpr = info->tco = info->rbpr = info->rco = 0;
2970 return;
2971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972
Jiri Slaby02f11752006-12-08 02:39:28 -08002973 /* determine which prescaler to use */
2974 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
2975 if (cy_clock / co_val / baud > 63)
2976 break;
2977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
Jiri Slaby02f11752006-12-08 02:39:28 -08002979 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
2980 if (bpr > 255)
2981 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
Jiri Slaby02f11752006-12-08 02:39:28 -08002983 info->tbpr = info->rbpr = bpr;
2984 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985}
2986
2987/*
2988 * This routine finds or computes the various line characteristics.
2989 * It used to be called config_setup
2990 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002991static void set_line_char(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992{
Jiri Slaby875b2062007-05-08 00:36:49 -07002993 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002994 unsigned long flags;
2995 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07002996 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08002997 unsigned cflag, iflag;
2998 unsigned short chip_number;
2999 int baud, baud_rate = 0;
3000 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
Jiri Slaby02f11752006-12-08 02:39:28 -08003002 if (!info->tty || !info->tty->termios) {
3003 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003005 if (info->line == -1) {
3006 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003008 cflag = info->tty->termios->c_cflag;
3009 iflag = info->tty->termios->c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
Jiri Slaby02f11752006-12-08 02:39:28 -08003011 /*
3012 * Set up the tty->alt_speed kludge
3013 */
3014 if (info->tty) {
3015 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
3016 info->tty->alt_speed = 57600;
3017 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
3018 info->tty->alt_speed = 115200;
3019 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
3020 info->tty->alt_speed = 230400;
3021 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
3022 info->tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
Jiri Slaby02f11752006-12-08 02:39:28 -08003025 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003026 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08003027 chip_number = channel / 4;
3028
Jiri Slaby875b2062007-05-08 00:36:49 -07003029 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003030
Jiri Slaby875b2062007-05-08 00:36:49 -07003031 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003032
3033 /* baud rate */
3034 baud = tty_get_baud_rate(info->tty);
3035 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3036 ASYNC_SPD_CUST) {
3037 if (info->custom_divisor)
3038 baud_rate = info->baud / info->custom_divisor;
3039 else
3040 baud_rate = info->baud;
3041 } else if (baud > CD1400_MAX_SPEED) {
3042 baud = CD1400_MAX_SPEED;
3043 }
3044 /* find the baud index */
3045 for (i = 0; i < 20; i++) {
3046 if (baud == baud_table[i]) {
3047 break;
3048 }
3049 }
3050 if (i == 20) {
3051 i = 19; /* CD1400_MAX_SPEED */
3052 }
3053
3054 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3055 ASYNC_SPD_CUST) {
3056 cyy_baud_calc(info, baud_rate);
3057 } else {
3058 if (info->chip_rev >= CD1400_REV_J) {
3059 /* It is a CD1400 rev. J or later */
3060 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
3061 info->tco = baud_co_60[i]; /* Tx CO */
3062 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
3063 info->rco = baud_co_60[i]; /* Rx CO */
3064 } else {
3065 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
3066 info->tco = baud_co_25[i]; /* Tx CO */
3067 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
3068 info->rco = baud_co_25[i]; /* Rx CO */
3069 }
3070 }
3071 if (baud_table[i] == 134) {
3072 /* get it right for 134.5 baud */
3073 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
3074 2;
3075 } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3076 ASYNC_SPD_CUST) {
3077 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3078 baud_rate) + 2;
3079 } else if (baud_table[i]) {
3080 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3081 baud_table[i]) + 2;
3082 /* this needs to be propagated into the card info */
3083 } else {
3084 info->timeout = 0;
3085 }
3086 /* By tradition (is it a standard?) a baud rate of zero
3087 implies the line should be/has been closed. A bit
3088 later in this routine such a test is performed. */
3089
3090 /* byte size and parity */
3091 info->cor5 = 0;
3092 info->cor4 = 0;
3093 /* receive threshold */
3094 info->cor3 = (info->default_threshold ?
3095 info->default_threshold : baud_cor3[i]);
3096 info->cor2 = CyETC;
3097 switch (cflag & CSIZE) {
3098 case CS5:
3099 info->cor1 = Cy_5_BITS;
3100 break;
3101 case CS6:
3102 info->cor1 = Cy_6_BITS;
3103 break;
3104 case CS7:
3105 info->cor1 = Cy_7_BITS;
3106 break;
3107 case CS8:
3108 info->cor1 = Cy_8_BITS;
3109 break;
3110 }
3111 if (cflag & CSTOPB) {
3112 info->cor1 |= Cy_2_STOP;
3113 }
3114 if (cflag & PARENB) {
3115 if (cflag & PARODD) {
3116 info->cor1 |= CyPARITY_O;
3117 } else {
3118 info->cor1 |= CyPARITY_E;
3119 }
3120 } else {
3121 info->cor1 |= CyPARITY_NONE;
3122 }
3123
3124 /* CTS flow control flag */
3125 if (cflag & CRTSCTS) {
3126 info->flags |= ASYNC_CTS_FLOW;
3127 info->cor2 |= CyCtsAE;
3128 } else {
3129 info->flags &= ~ASYNC_CTS_FLOW;
3130 info->cor2 &= ~CyCtsAE;
3131 }
3132 if (cflag & CLOCAL)
3133 info->flags &= ~ASYNC_CHECK_CD;
3134 else
3135 info->flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136
3137 /***********************************************
3138 The hardware option, CyRtsAO, presents RTS when
3139 the chip has characters to send. Since most modems
3140 use RTS as reverse (inbound) flow control, this
3141 option is not used. If inbound flow control is
3142 necessary, DTR can be programmed to provide the
3143 appropriate signals for use with a non-standard
3144 cable. Contact Marcio Saito for details.
3145 ***********************************************/
3146
Jiri Slaby02f11752006-12-08 02:39:28 -08003147 chip = channel >> 2;
3148 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003149 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003151 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003152 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
Jiri Slaby02f11752006-12-08 02:39:28 -08003154 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
Jiri Slaby02f11752006-12-08 02:39:28 -08003156 cy_writeb(base_addr + (CyTCOR << index), info->tco);
3157 cy_writeb(base_addr + (CyTBPR << index), info->tbpr);
3158 cy_writeb(base_addr + (CyRCOR << index), info->rco);
3159 cy_writeb(base_addr + (CyRBPR << index), info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
Jiri Slaby02f11752006-12-08 02:39:28 -08003161 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Jiri Slaby02f11752006-12-08 02:39:28 -08003163 cy_writeb(base_addr + (CySCHR1 << index),
3164 START_CHAR(info->tty));
3165 cy_writeb(base_addr + (CySCHR2 << index), STOP_CHAR(info->tty));
3166 cy_writeb(base_addr + (CyCOR1 << index), info->cor1);
3167 cy_writeb(base_addr + (CyCOR2 << index), info->cor2);
3168 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
3169 cy_writeb(base_addr + (CyCOR4 << index), info->cor4);
3170 cy_writeb(base_addr + (CyCOR5 << index), info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Jiri Slaby02f11752006-12-08 02:39:28 -08003172 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
3173 CyCOR3ch, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
Jiri Slaby02f11752006-12-08 02:39:28 -08003175 cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
3176 cy_writeb(base_addr + (CyRTPR << index),
3177 (info->default_timeout ? info->default_timeout : 0x02));
3178 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Jiri Slaby02f11752006-12-08 02:39:28 -08003180 if (C_CLOCAL(info->tty)) {
3181 /* without modem intr */
3182 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003183 readb(base_addr + (CySRER << index)) | CyMdmCh);
Jiri Slaby02f11752006-12-08 02:39:28 -08003184 /* act on 1->0 modem transitions */
3185 if ((cflag & CRTSCTS) && info->rflow) {
3186 cy_writeb(base_addr + (CyMCOR1 << index),
3187 (CyCTS | rflow_thr[i]));
3188 } else {
3189 cy_writeb(base_addr + (CyMCOR1 << index),
3190 CyCTS);
3191 }
3192 /* act on 0->1 modem transitions */
3193 cy_writeb(base_addr + (CyMCOR2 << index), CyCTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08003195 /* without modem intr */
3196 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003197 readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003198 (CySRER << index)) | CyMdmCh);
3199 /* act on 1->0 modem transitions */
3200 if ((cflag & CRTSCTS) && info->rflow) {
3201 cy_writeb(base_addr + (CyMCOR1 << index),
3202 (CyDSR | CyCTS | CyRI | CyDCD |
3203 rflow_thr[i]));
3204 } else {
3205 cy_writeb(base_addr + (CyMCOR1 << index),
3206 CyDSR | CyCTS | CyRI | CyDCD);
3207 }
3208 /* act on 0->1 modem transitions */
3209 cy_writeb(base_addr + (CyMCOR2 << index),
3210 CyDSR | CyCTS | CyRI | CyDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003212
3213 if (i == 0) { /* baud rate is zero, turn off line */
3214 if (info->rtsdtr_inv) {
3215 cy_writeb(base_addr + (CyMSVR1 << index),
3216 ~CyRTS);
3217 } else {
3218 cy_writeb(base_addr + (CyMSVR2 << index),
3219 ~CyDTR);
3220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003222 printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
3223 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003224 readb(base_addr + (CyMSVR1 << index)),
3225 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003227 } else {
3228 if (info->rtsdtr_inv) {
3229 cy_writeb(base_addr + (CyMSVR1 << index),
3230 CyRTS);
3231 } else {
3232 cy_writeb(base_addr + (CyMSVR2 << index),
3233 CyDTR);
3234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003236 printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
3237 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003238 readb(base_addr + (CyMSVR1 << index)),
3239 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
Jiri Slaby02f11752006-12-08 02:39:28 -08003243 if (info->tty) {
3244 clear_bit(TTY_IO_ERROR, &info->tty->flags);
3245 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003246 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08003249 struct FIRM_ID __iomem *firm_id;
3250 struct ZFW_CTRL __iomem *zfw_ctrl;
3251 struct BOARD_CTRL __iomem *board_ctrl;
3252 struct CH_CTRL __iomem *ch_ctrl;
3253 struct BUF_CTRL __iomem *buf_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07003254 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08003255 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
Jiri Slaby875b2062007-05-08 00:36:49 -07003257 firm_id = card->base_addr + ID_ADDRESS;
3258 if (!ISZLOADED(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003259 return;
3260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
Jiri Slaby875b2062007-05-08 00:36:49 -07003262 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003263 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08003264 board_ctrl = &zfw_ctrl->board_ctrl;
3265 ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
3266 buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
Jiri Slaby02f11752006-12-08 02:39:28 -08003268 /* baud rate */
3269 baud = tty_get_baud_rate(info->tty);
3270 if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3271 ASYNC_SPD_CUST) {
3272 if (info->custom_divisor)
3273 baud_rate = info->baud / info->custom_divisor;
3274 else
3275 baud_rate = info->baud;
3276 } else if (baud > CYZ_MAX_SPEED) {
3277 baud = CYZ_MAX_SPEED;
3278 }
3279 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Jiri Slaby02f11752006-12-08 02:39:28 -08003281 if (baud == 134) {
3282 /* get it right for 134.5 baud */
3283 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
3284 2;
3285 } else if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
3286 ASYNC_SPD_CUST) {
3287 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3288 baud_rate) + 2;
3289 } else if (baud) {
3290 info->timeout = (info->xmit_fifo_size * HZ * 15 /
3291 baud) + 2;
3292 /* this needs to be propagated into the card info */
3293 } else {
3294 info->timeout = 0;
3295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
Jiri Slaby02f11752006-12-08 02:39:28 -08003297 /* byte size and parity */
3298 switch (cflag & CSIZE) {
3299 case CS5:
3300 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
3301 break;
3302 case CS6:
3303 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
3304 break;
3305 case CS7:
3306 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
3307 break;
3308 case CS8:
3309 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
3310 break;
3311 }
3312 if (cflag & CSTOPB) {
3313 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003314 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08003315 } else {
3316 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003317 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08003318 }
3319 if (cflag & PARENB) {
3320 if (cflag & PARODD) {
3321 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
3322 } else {
3323 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
3324 }
3325 } else {
3326 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
3327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328
Jiri Slaby02f11752006-12-08 02:39:28 -08003329 /* CTS flow control flag */
3330 if (cflag & CRTSCTS) {
3331 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003332 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08003333 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003334 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
3335 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08003336 }
3337 /* As the HW flow control is done in firmware, the driver
3338 doesn't need to care about it */
3339 info->flags &= ~ASYNC_CTS_FLOW;
3340
3341 /* XON/XOFF/XANY flow control flags */
3342 sw_flow = 0;
3343 if (iflag & IXON) {
3344 sw_flow |= C_FL_OXX;
3345 if (iflag & IXANY)
3346 sw_flow |= C_FL_OIXANY;
3347 }
3348 cy_writel(&ch_ctrl->sw_flow, sw_flow);
3349
Jiri Slaby875b2062007-05-08 00:36:49 -07003350 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003351 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003352 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
3353 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08003354 }
3355
3356 /* CD sensitivity */
3357 if (cflag & CLOCAL) {
3358 info->flags &= ~ASYNC_CHECK_CD;
3359 } else {
3360 info->flags |= ASYNC_CHECK_CD;
3361 }
3362
3363 if (baud == 0) { /* baud rate is zero, turn off line */
3364 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003365 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003367 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003369 } else {
3370 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003371 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003373 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08003375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
Jiri Slaby875b2062007-05-08 00:36:49 -07003377 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003378 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003379 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
3380 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08003381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382
Jiri Slaby02f11752006-12-08 02:39:28 -08003383 if (info->tty) {
3384 clear_bit(TTY_IO_ERROR, &info->tty->flags);
3385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003387} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388
3389static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003390get_serial_info(struct cyclades_port *info,
3391 struct serial_struct __user * retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392{
Jiri Slaby02f11752006-12-08 02:39:28 -08003393 struct serial_struct tmp;
Jiri Slaby875b2062007-05-08 00:36:49 -07003394 struct cyclades_card *cinfo = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Jiri Slaby02f11752006-12-08 02:39:28 -08003396 if (!retinfo)
3397 return -EFAULT;
3398 memset(&tmp, 0, sizeof(tmp));
3399 tmp.type = info->type;
3400 tmp.line = info->line;
Jiri Slaby875b2062007-05-08 00:36:49 -07003401 tmp.port = (info->card - cy_card) * 0x100 + info->line -
3402 cinfo->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08003403 tmp.irq = cinfo->irq;
3404 tmp.flags = info->flags;
3405 tmp.close_delay = info->close_delay;
Andrew Mortond5dedf92007-03-05 00:30:04 -08003406 tmp.closing_wait = info->closing_wait;
Jiri Slaby02f11752006-12-08 02:39:28 -08003407 tmp.baud_base = info->baud;
3408 tmp.custom_divisor = info->custom_divisor;
3409 tmp.hub6 = 0; /*!!! */
3410 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
3411} /* get_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412
3413static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003414set_serial_info(struct cyclades_port *info,
3415 struct serial_struct __user * new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416{
Jiri Slaby02f11752006-12-08 02:39:28 -08003417 struct serial_struct new_serial;
3418 struct cyclades_port old_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
Jiri Slaby02f11752006-12-08 02:39:28 -08003420 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
3421 return -EFAULT;
3422 old_info = *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
Jiri Slaby02f11752006-12-08 02:39:28 -08003424 if (!capable(CAP_SYS_ADMIN)) {
3425 if (new_serial.close_delay != info->close_delay ||
3426 new_serial.baud_base != info->baud ||
3427 (new_serial.flags & ASYNC_FLAGS &
3428 ~ASYNC_USR_MASK) !=
3429 (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
3430 return -EPERM;
3431 info->flags = (info->flags & ~ASYNC_USR_MASK) |
3432 (new_serial.flags & ASYNC_USR_MASK);
3433 info->baud = new_serial.baud_base;
3434 info->custom_divisor = new_serial.custom_divisor;
3435 goto check_and_exit;
3436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
Jiri Slaby02f11752006-12-08 02:39:28 -08003438 /*
3439 * OK, past this point, all the error checking has been done.
3440 * At this point, we start making changes.....
3441 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
Jiri Slaby02f11752006-12-08 02:39:28 -08003443 info->baud = new_serial.baud_base;
3444 info->custom_divisor = new_serial.custom_divisor;
3445 info->flags = (info->flags & ~ASYNC_FLAGS) |
3446 (new_serial.flags & ASYNC_FLAGS);
3447 info->close_delay = new_serial.close_delay * HZ / 100;
3448 info->closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
3450check_and_exit:
Jiri Slaby02f11752006-12-08 02:39:28 -08003451 if (info->flags & ASYNC_INITIALIZED) {
3452 set_line_char(info);
3453 return 0;
3454 } else {
3455 return startup(info);
3456 }
3457} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
3459/*
3460 * get_lsr_info - get line status register info
3461 *
3462 * Purpose: Let user call ioctl() to get info when the UART physically
3463 * is emptied. On bus types like RS485, the transmitter must
3464 * release the bus after transmitting. This must be done when
3465 * the transmit shift register is empty, not be done when the
3466 * transmit holding register is empty. This functionality
3467 * allows an RS485 driver to be written in user space.
3468 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003469static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470{
Jiri Slaby875b2062007-05-08 00:36:49 -07003471 struct cyclades_card *card;
3472 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003473 unsigned char status;
3474 unsigned int result;
3475 unsigned long flags;
3476 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Jiri Slaby02f11752006-12-08 02:39:28 -08003478 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003479 channel = (info->line) - (card->first_line);
3480 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003481 chip = channel >> 2;
3482 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003483 index = card->bus_index;
3484 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003486 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003487 status = readb(base_addr + (CySRER << index)) &
Jiri Slaby02f11752006-12-08 02:39:28 -08003488 (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003489 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003490 result = (status ? 0 : TIOCSER_TEMT);
3491 } else {
3492 /* Not supported yet */
3493 return -EINVAL;
3494 }
3495 return put_user(result, (unsigned long __user *)value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496}
3497
Jiri Slaby02f11752006-12-08 02:39:28 -08003498static int cy_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003500 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003501 struct cyclades_card *card;
3502 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003503 void __iomem *base_addr;
3504 unsigned long flags;
3505 unsigned char status;
3506 unsigned long lstatus;
3507 unsigned int result;
3508 struct FIRM_ID __iomem *firm_id;
3509 struct ZFW_CTRL __iomem *zfw_ctrl;
3510 struct BOARD_CTRL __iomem *board_ctrl;
3511 struct CH_CTRL __iomem *ch_ctrl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Jiri Slaby02f11752006-12-08 02:39:28 -08003513 if (serial_paranoia_check(info, tty->name, __FUNCTION__))
3514 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
Jiri Slaby02f11752006-12-08 02:39:28 -08003516 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003517 channel = info->line - card->first_line;
3518 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003519 chip = channel >> 2;
3520 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003521 index = card->bus_index;
3522 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003524 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003525 cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003526 status = readb(base_addr + (CyMSVR1 << index));
3527 status |= readb(base_addr + (CyMSVR2 << index));
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003528 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529
Jiri Slaby02f11752006-12-08 02:39:28 -08003530 if (info->rtsdtr_inv) {
3531 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
3532 ((status & CyDTR) ? TIOCM_RTS : 0);
3533 } else {
3534 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
3535 ((status & CyDTR) ? TIOCM_DTR : 0);
3536 }
3537 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
3538 ((status & CyRI) ? TIOCM_RNG : 0) |
3539 ((status & CyDSR) ? TIOCM_DSR : 0) |
3540 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 } else {
Jiri Slaby875b2062007-05-08 00:36:49 -07003542 base_addr = card->base_addr;
3543 firm_id = card->base_addr + ID_ADDRESS;
3544 if (ISZLOADED(*card)) {
3545 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003546 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08003547 board_ctrl = &zfw_ctrl->board_ctrl;
3548 ch_ctrl = zfw_ctrl->ch_ctrl;
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003549 lstatus = readl(&ch_ctrl[channel].rs_status);
Jiri Slaby02f11752006-12-08 02:39:28 -08003550 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
3551 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
3552 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
3553 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
3554 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
3555 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
3556 } else {
3557 result = 0;
3558 return -ENODEV;
3559 }
3560
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003562 return result;
3563} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
3565static int
3566cy_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby02f11752006-12-08 02:39:28 -08003567 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003569 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07003570 struct cyclades_card *card;
3571 int chip, channel, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003572 void __iomem *base_addr;
3573 unsigned long flags;
3574 struct FIRM_ID __iomem *firm_id;
3575 struct ZFW_CTRL __iomem *zfw_ctrl;
3576 struct BOARD_CTRL __iomem *board_ctrl;
3577 struct CH_CTRL __iomem *ch_ctrl;
3578 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
Jiri Slaby02f11752006-12-08 02:39:28 -08003580 if (serial_paranoia_check(info, tty->name, __FUNCTION__))
3581 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Jiri Slaby02f11752006-12-08 02:39:28 -08003583 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003584 channel = (info->line) - (card->first_line);
3585 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003586 chip = channel >> 2;
3587 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003588 index = card->bus_index;
3589 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Jiri Slaby02f11752006-12-08 02:39:28 -08003591 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003592 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003593 cy_writeb(base_addr + (CyCAR << index),
3594 (u_char) channel);
3595 if (info->rtsdtr_inv) {
3596 cy_writeb(base_addr + (CyMSVR2 << index),
3597 CyDTR);
3598 } else {
3599 cy_writeb(base_addr + (CyMSVR1 << index),
3600 CyRTS);
3601 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003602 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003603 }
3604 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003605 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003606 cy_writeb(base_addr + (CyCAR << index),
3607 (u_char) channel);
3608 if (info->rtsdtr_inv) {
3609 cy_writeb(base_addr + (CyMSVR2 << index),
3610 ~CyDTR);
3611 } else {
3612 cy_writeb(base_addr + (CyMSVR1 << index),
3613 ~CyRTS);
3614 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003615 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003616 }
3617 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003618 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003619 cy_writeb(base_addr + (CyCAR << index),
3620 (u_char) channel);
3621 if (info->rtsdtr_inv) {
3622 cy_writeb(base_addr + (CyMSVR1 << index),
3623 CyRTS);
3624 } else {
3625 cy_writeb(base_addr + (CyMSVR2 << index),
3626 CyDTR);
3627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003629 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
3630 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003631 readb(base_addr + (CyMSVR1 << index)),
3632 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003634 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003635 }
3636 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003637 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003638 cy_writeb(base_addr + (CyCAR << index),
3639 (u_char) channel);
3640 if (info->rtsdtr_inv) {
3641 cy_writeb(base_addr + (CyMSVR1 << index),
3642 ~CyRTS);
3643 } else {
3644 cy_writeb(base_addr + (CyMSVR2 << index),
3645 ~CyDTR);
3646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647
3648#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003649 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
3650 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003651 readb(base_addr + (CyMSVR1 << index)),
3652 readb(base_addr + (CyMSVR2 << index)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003654 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003655 }
3656 } else {
Jiri Slaby875b2062007-05-08 00:36:49 -07003657 base_addr = card->base_addr;
Jiri Slaby02f11752006-12-08 02:39:28 -08003658
Jiri Slaby875b2062007-05-08 00:36:49 -07003659 firm_id = card->base_addr + ID_ADDRESS;
3660 if (ISZLOADED(*card)) {
3661 zfw_ctrl = card->base_addr +
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003662 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
Jiri Slaby02f11752006-12-08 02:39:28 -08003663 board_ctrl = &zfw_ctrl->board_ctrl;
3664 ch_ctrl = zfw_ctrl->ch_ctrl;
3665
3666 if (set & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003667 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003668 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003669 readl(&ch_ctrl[channel].rs_control) |
3670 C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003671 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003672 }
3673 if (clear & TIOCM_RTS) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003674 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003675 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003676 readl(&ch_ctrl[channel].rs_control) &
3677 ~C_RS_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003678 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003679 }
3680 if (set & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003681 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003682 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003683 readl(&ch_ctrl[channel].rs_control) |
3684 C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08003685#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003686 printk(KERN_DEBUG "cyc:set_modem_info raising "
3687 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08003688#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003689 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003690 }
3691 if (clear & TIOCM_DTR) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003692 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003693 cy_writel(&ch_ctrl[channel].rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003694 readl(&ch_ctrl[channel].rs_control) &
3695 ~C_RS_DTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08003696#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07003697 printk(KERN_DEBUG "cyc:set_modem_info clearing "
3698 "Z DTR\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08003699#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003700 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003701 }
3702 } else {
3703 return -ENODEV;
3704 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003705 spin_lock_irqsave(&card->card_lock, flags);
3706 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003707 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003708 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
3709 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08003710 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003711 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003713 return 0;
3714} /* cy_tiocmset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
3716/*
3717 * cy_break() --- routine which turns the break handling on or off
3718 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003719static void cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003721 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003722 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003723 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
Jiri Slaby02f11752006-12-08 02:39:28 -08003725 if (serial_paranoia_check(info, tty->name, "cy_break"))
3726 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003728 card = info->card;
3729
3730 spin_lock_irqsave(&card->card_lock, flags);
3731 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003732 /* Let the transmit ISR take care of this (since it
3733 requires stuffing characters into the output stream).
3734 */
3735 if (break_state == -1) {
3736 if (!info->breakon) {
3737 info->breakon = 1;
3738 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003739 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003740 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003741 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003742 }
3743 }
3744 } else {
3745 if (!info->breakoff) {
3746 info->breakoff = 1;
3747 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003748 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003749 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003750 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003751 }
3752 }
3753 }
3754 } else {
3755 int retval;
3756
3757 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003758 retval = cyz_issue_cmd(card,
3759 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08003760 C_CM_SET_BREAK, 0L);
3761 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003762 printk(KERN_ERR "cyc:cy_break (set) retval on "
3763 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08003764 }
3765 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003766 retval = cyz_issue_cmd(card,
3767 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08003768 C_CM_CLR_BREAK, 0L);
3769 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003770 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
3771 "on ttyC%d was %x\n", info->line,
3772 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08003773 }
3774 }
3775 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003776 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003777} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
3779static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003780get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Jiri Slaby02f11752006-12-08 02:39:28 -08003783 if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
3784 return -EFAULT;
3785 info->mon.int_count = 0;
3786 info->mon.char_count = 0;
3787 info->mon.char_max = 0;
3788 info->mon.char_last = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003790} /* get_mon_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
Jiri Slaby02f11752006-12-08 02:39:28 -08003792static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793{
Jiri Slaby875b2062007-05-08 00:36:49 -07003794 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003795 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003796 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003797 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Jiri Slaby02f11752006-12-08 02:39:28 -08003799 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003800 channel = info->line - card->first_line;
3801 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003802 chip = channel >> 2;
3803 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003804 index = card->bus_index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003805 base_addr =
Jiri Slaby875b2062007-05-08 00:36:49 -07003806 card->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807
Jiri Slaby02f11752006-12-08 02:39:28 -08003808 info->cor3 &= ~CyREC_FIFO;
3809 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003811 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003812 cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
3813 cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003814 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003817} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818
3819static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003820get_threshold(struct cyclades_port *info, unsigned long __user * value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821{
Jiri Slaby875b2062007-05-08 00:36:49 -07003822 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003823 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003824 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003825 unsigned long tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826
Jiri Slaby02f11752006-12-08 02:39:28 -08003827 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003828 channel = info->line - card->first_line;
3829 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003830 chip = channel >> 2;
3831 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003832 index = card->bus_index;
3833 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003834
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003835 tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08003836 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08003837 }
Jiri Slabyf7429032007-05-08 00:36:59 -07003838 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003839} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840
3841static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003842set_default_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843{
Jiri Slaby02f11752006-12-08 02:39:28 -08003844 info->default_threshold = value & 0x0f;
3845 return 0;
3846} /* set_default_threshold */
3847
3848static int
3849get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
3850{
3851 return put_user(info->default_threshold, value);
3852} /* get_default_threshold */
3853
3854static int set_timeout(struct cyclades_port *info, unsigned long value)
3855{
Jiri Slaby875b2062007-05-08 00:36:49 -07003856 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003857 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003858 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003859 unsigned long flags;
3860
3861 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003862 channel = info->line - card->first_line;
3863 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003864 chip = channel >> 2;
3865 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003866 index = card->bus_index;
3867 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003868
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003869 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003870 cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07003871 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08003872 }
3873 return 0;
3874} /* set_timeout */
3875
3876static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
3877{
Jiri Slaby875b2062007-05-08 00:36:49 -07003878 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003879 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07003880 int channel, chip, index;
Jiri Slaby02f11752006-12-08 02:39:28 -08003881 unsigned long tmp;
3882
3883 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07003884 channel = info->line - card->first_line;
3885 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003886 chip = channel >> 2;
3887 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07003888 index = card->bus_index;
3889 base_addr = card->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08003890
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003891 tmp = readb(base_addr + (CyRTPR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -08003892 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08003893 }
Jiri Slabyf7429032007-05-08 00:36:59 -07003894 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003895} /* get_timeout */
3896
3897static int set_default_timeout(struct cyclades_port *info, unsigned long value)
3898{
3899 info->default_timeout = value & 0xff;
3900 return 0;
3901} /* set_default_timeout */
3902
3903static int
3904get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
3905{
3906 return put_user(info->default_timeout, value);
3907} /* get_default_timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
3909/*
3910 * This routine allows the tty driver to implement device-
3911 * specific ioctl's. If the ioctl number passed in cmd is
3912 * not recognized by the driver, it should return ENOIOCTLCMD.
3913 */
3914static int
Jiri Slaby02f11752006-12-08 02:39:28 -08003915cy_ioctl(struct tty_struct *tty, struct file *file,
3916 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003918 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003919 struct cyclades_icount cprev, cnow; /* kernel counter temps */
3920 struct serial_icounter_struct __user *p_cuser; /* user space */
3921 int ret_val = 0;
3922 unsigned long flags;
3923 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924
Jiri Slaby02f11752006-12-08 02:39:28 -08003925 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
3926 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003929 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
3930 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931#endif
3932
Jiri Slaby02f11752006-12-08 02:39:28 -08003933 switch (cmd) {
3934 case CYGETMON:
3935 ret_val = get_mon_info(info, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08003937 case CYGETTHRESH:
3938 ret_val = get_threshold(info, argp);
3939 break;
3940 case CYSETTHRESH:
3941 ret_val = set_threshold(info, arg);
3942 break;
3943 case CYGETDEFTHRESH:
3944 ret_val = get_default_threshold(info, argp);
3945 break;
3946 case CYSETDEFTHRESH:
3947 ret_val = set_default_threshold(info, arg);
3948 break;
3949 case CYGETTIMEOUT:
3950 ret_val = get_timeout(info, argp);
3951 break;
3952 case CYSETTIMEOUT:
3953 ret_val = set_timeout(info, arg);
3954 break;
3955 case CYGETDEFTIMEOUT:
3956 ret_val = get_default_timeout(info, argp);
3957 break;
3958 case CYSETDEFTIMEOUT:
3959 ret_val = set_default_timeout(info, arg);
3960 break;
3961 case CYSETRFLOW:
3962 info->rflow = (int)arg;
3963 ret_val = 0;
3964 break;
3965 case CYGETRFLOW:
3966 ret_val = info->rflow;
3967 break;
3968 case CYSETRTSDTR_INV:
3969 info->rtsdtr_inv = (int)arg;
3970 ret_val = 0;
3971 break;
3972 case CYGETRTSDTR_INV:
3973 ret_val = info->rtsdtr_inv;
3974 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08003976 ret_val = info->chip_rev;
3977 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978#ifndef CONFIG_CYZ_INTR
3979 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08003980 cyz_polling_cycle = (arg * HZ) / 1000;
3981 ret_val = 0;
3982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08003984 ret_val = (cyz_polling_cycle * 1000) / HZ;
3985 break;
3986#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 case CYSETWAIT:
Jiri Slaby02f11752006-12-08 02:39:28 -08003988 info->closing_wait = (unsigned short)arg *HZ / 100;
3989 ret_val = 0;
3990 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 case CYGETWAIT:
Jiri Slaby02f11752006-12-08 02:39:28 -08003992 ret_val = info->closing_wait / (HZ / 100);
3993 break;
3994 case TIOCGSERIAL:
3995 ret_val = get_serial_info(info, argp);
3996 break;
3997 case TIOCSSERIAL:
3998 ret_val = set_serial_info(info, argp);
3999 break;
4000 case TIOCSERGETLSR: /* Get line status register */
4001 ret_val = get_lsr_info(info, argp);
4002 break;
4003 /*
4004 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
4005 * - mask passed in arg for lines of interest
4006 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
4007 * Caller should use TIOCGICOUNT to see which one it was
4008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004010 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004011 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07004012 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004013 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07004014 ret_val = wait_event_interruptible(info->delta_msr_wait, ({
4015 cprev = cnow;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004016 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004017 cnow = info->icount; /* atomic copy */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004018 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
Jiri Slaby2c7fea92007-05-08 00:36:51 -07004020 ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
4021 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
4022 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
4023 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
4024 }));
4025 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08004026
4027 /*
4028 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
4029 * Return: write counters to the user passed counter struct
4030 * NB: both 1->0 and 0->1 transitions are counted except for
4031 * RI where only 0->1 is counted.
4032 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 case TIOCGICOUNT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004034 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004035 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004036 spin_unlock_irqrestore(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004037 p_cuser = argp;
4038 ret_val = put_user(cnow.cts, &p_cuser->cts);
4039 if (ret_val)
4040 return ret_val;
4041 ret_val = put_user(cnow.dsr, &p_cuser->dsr);
4042 if (ret_val)
4043 return ret_val;
4044 ret_val = put_user(cnow.rng, &p_cuser->rng);
4045 if (ret_val)
4046 return ret_val;
4047 ret_val = put_user(cnow.dcd, &p_cuser->dcd);
4048 if (ret_val)
4049 return ret_val;
4050 ret_val = put_user(cnow.rx, &p_cuser->rx);
4051 if (ret_val)
4052 return ret_val;
4053 ret_val = put_user(cnow.tx, &p_cuser->tx);
4054 if (ret_val)
4055 return ret_val;
4056 ret_val = put_user(cnow.frame, &p_cuser->frame);
4057 if (ret_val)
4058 return ret_val;
4059 ret_val = put_user(cnow.overrun, &p_cuser->overrun);
4060 if (ret_val)
4061 return ret_val;
4062 ret_val = put_user(cnow.parity, &p_cuser->parity);
4063 if (ret_val)
4064 return ret_val;
4065 ret_val = put_user(cnow.brk, &p_cuser->brk);
4066 if (ret_val)
4067 return ret_val;
4068 ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
4069 if (ret_val)
4070 return ret_val;
4071 ret_val = 0;
4072 break;
4073 default:
4074 ret_val = -ENOIOCTLCMD;
4075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076
4077#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07004078 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079#endif
4080
Jiri Slaby02f11752006-12-08 02:39:28 -08004081 return ret_val;
4082} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
4084/*
4085 * This routine allows the tty driver to be notified when
4086 * device's termios settings have changed. Note that a
4087 * well-designed tty driver should be prepared to accept the case
4088 * where old == NULL, and try to do something rational.
4089 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004090static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004092 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093
4094#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07004095 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096#endif
4097
Jiri Slaby02f11752006-12-08 02:39:28 -08004098 set_line_char(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
Jiri Slaby02f11752006-12-08 02:39:28 -08004100 if ((old_termios->c_cflag & CRTSCTS) &&
4101 !(tty->termios->c_cflag & CRTSCTS)) {
4102 tty->hw_stopped = 0;
4103 cy_start(tty);
4104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08004106 /*
4107 * No need to wake up processes in open wait, since they
4108 * sample the CLOCAL flag once, and don't recheck it.
4109 * XXX It's not clear whether the current behavior is correct
4110 * or not. Hence, this may change.....
4111 */
4112 if (!(old_termios->c_cflag & CLOCAL) &&
4113 (tty->termios->c_cflag & CLOCAL))
4114 wake_up_interruptible(&info->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004116} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117
4118/* This function is used to send a high-priority XON/XOFF character to
4119 the device.
4120*/
Jiri Slaby02f11752006-12-08 02:39:28 -08004121static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004123 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07004124 struct cyclades_card *card;
4125 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
Jiri Slaby02f11752006-12-08 02:39:28 -08004127 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 return;
4129
Jiri Slaby02f11752006-12-08 02:39:28 -08004130 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131
4132 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08004133 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
4135 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07004136 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
Jiri Slaby875b2062007-05-08 00:36:49 -07004138 if (IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004139 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07004140 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004141 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07004142 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 }
4144}
4145
4146/* This routine is called by the upper-layer tty layer to signal
4147 that incoming characters should be throttled because the input
4148 buffers are close to full.
4149 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004150static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004152 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07004153 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08004154 unsigned long flags;
4155 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07004156 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157
4158#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08004159 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
Jiri Slaby21719192007-05-08 00:36:42 -07004161 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08004162 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163#endif
4164
Jiri Slaby02f11752006-12-08 02:39:28 -08004165 if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
4166 return;
4167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168
Jiri Slaby02f11752006-12-08 02:39:28 -08004169 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170
Jiri Slaby02f11752006-12-08 02:39:28 -08004171 if (I_IXOFF(tty)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07004172 if (!IS_CYC_Z(*card))
Jiri Slaby02f11752006-12-08 02:39:28 -08004173 cy_send_xchar(tty, STOP_CHAR(tty));
4174 else
4175 info->throttle = 1;
4176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
Jiri Slaby02f11752006-12-08 02:39:28 -08004178 if (tty->termios->c_cflag & CRTSCTS) {
Jiri Slaby875b2062007-05-08 00:36:49 -07004179 channel = info->line - card->first_line;
4180 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004181 chip = channel >> 2;
4182 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07004183 index = card->bus_index;
4184 base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08004185 (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004187 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004188 cy_writeb(base_addr + (CyCAR << index),
4189 (u_char) channel);
4190 if (info->rtsdtr_inv) {
4191 cy_writeb(base_addr + (CyMSVR2 << index),
4192 ~CyDTR);
4193 } else {
4194 cy_writeb(base_addr + (CyMSVR1 << index),
4195 ~CyRTS);
4196 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004197 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004198 } else {
4199 info->throttle = 1;
4200 }
4201 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004202} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
4204/*
4205 * This routine notifies the tty driver that it should signal
4206 * that characters can now be sent to the tty without fear of
4207 * overrunning the input buffers of the line disciplines.
4208 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004209static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004211 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07004212 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08004213 unsigned long flags;
4214 void __iomem *base_addr;
Jiri Slaby875b2062007-05-08 00:36:49 -07004215 int chip, channel, index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
4217#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08004218 char buf[64];
4219
Jiri Slaby21719192007-05-08 00:36:42 -07004220 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
4221 tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222#endif
4223
Jiri Slaby02f11752006-12-08 02:39:28 -08004224 if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
4225 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
Jiri Slaby02f11752006-12-08 02:39:28 -08004228 if (I_IXOFF(tty)) {
4229 if (info->x_char)
4230 info->x_char = 0;
4231 else
4232 cy_send_xchar(tty, START_CHAR(tty));
4233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
Jiri Slaby02f11752006-12-08 02:39:28 -08004235 if (tty->termios->c_cflag & CRTSCTS) {
4236 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07004237 channel = info->line - card->first_line;
4238 if (!IS_CYC_Z(*card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004239 chip = channel >> 2;
4240 channel &= 0x03;
Jiri Slaby875b2062007-05-08 00:36:49 -07004241 index = card->bus_index;
4242 base_addr = card->base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08004243 (cy_chip_offset[chip] << index);
4244
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004245 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004246 cy_writeb(base_addr + (CyCAR << index),
4247 (u_char) channel);
4248 if (info->rtsdtr_inv) {
4249 cy_writeb(base_addr + (CyMSVR2 << index),
4250 CyDTR);
4251 } else {
4252 cy_writeb(base_addr + (CyMSVR1 << index),
4253 CyRTS);
4254 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004255 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004256 } else {
4257 info->throttle = 0;
4258 }
4259 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004260} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262/* cy_start and cy_stop provide software output flow control as a
4263 function of XON/XOFF, software CTS, and other such stuff.
4264*/
Jiri Slaby02f11752006-12-08 02:39:28 -08004265static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
Jiri Slaby02f11752006-12-08 02:39:28 -08004267 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004268 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08004269 void __iomem *base_addr;
4270 int chip, channel, index;
4271 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
4273#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07004274 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275#endif
4276
Jiri Slaby02f11752006-12-08 02:39:28 -08004277 if (serial_paranoia_check(info, tty->name, "cy_stop"))
4278 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279
Jiri Slaby875b2062007-05-08 00:36:49 -07004280 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08004281 channel = info->line - cinfo->first_line;
4282 if (!IS_CYC_Z(*cinfo)) {
4283 index = cinfo->bus_index;
4284 chip = channel >> 2;
4285 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004286 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004288 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004289 cy_writeb(base_addr + (CyCAR << index),
4290 (u_char)(channel & 0x0003)); /* index channel */
4291 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004292 readb(base_addr + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004293 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004295} /* cy_stop */
4296
4297static void cy_start(struct tty_struct *tty)
4298{
4299 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004300 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08004301 void __iomem *base_addr;
4302 int chip, channel, index;
4303 unsigned long flags;
4304
4305#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07004306 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08004307#endif
4308
4309 if (serial_paranoia_check(info, tty->name, "cy_start"))
4310 return;
4311
Jiri Slaby875b2062007-05-08 00:36:49 -07004312 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08004313 channel = info->line - cinfo->first_line;
4314 index = cinfo->bus_index;
4315 if (!IS_CYC_Z(*cinfo)) {
4316 chip = channel >> 2;
4317 channel &= 0x03;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004318 base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
Jiri Slaby02f11752006-12-08 02:39:28 -08004319
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004320 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004321 cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
4322 cy_writeb(base_addr + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004323 readb(base_addr + (CySRER << index)) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004324 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004325 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004326} /* cy_start */
4327
4328static void cy_flush_buffer(struct tty_struct *tty)
4329{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004330 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07004331 struct cyclades_card *card;
4332 int channel, retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004333 unsigned long flags;
4334
4335#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07004336 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08004337#endif
4338
4339 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
4340 return;
4341
4342 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07004343 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08004344
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004345 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004346 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004347 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004348
Jiri Slaby875b2062007-05-08 00:36:49 -07004349 if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
Jiri Slaby02f11752006-12-08 02:39:28 -08004350 buffers as well */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004351 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07004352 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004353 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07004354 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
4355 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08004356 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07004357 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08004358 }
4359 tty_wakeup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08004360} /* cy_flush_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361
4362/*
4363 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
4364 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004365static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07004367 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08004368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07004370 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371#endif
4372
Jiri Slaby02f11752006-12-08 02:39:28 -08004373 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
4374 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Jiri Slaby02f11752006-12-08 02:39:28 -08004376 cy_flush_buffer(tty);
4377 shutdown(info);
Jiri Slaby02f11752006-12-08 02:39:28 -08004378 info->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07004380 printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
4381 current->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004383 info->tty = NULL;
4384 info->flags &= ~ASYNC_NORMAL_ACTIVE;
4385 wake_up_interruptible(&info->open_wait);
4386} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
4388/*
4389 * ---------------------------------------------------------------------
4390 * cy_init() and friends
4391 *
4392 * cy_init() is called at boot-time to initialize the serial driver.
4393 * ---------------------------------------------------------------------
4394 */
4395
Jiri Slabydd025c02007-05-08 00:37:02 -07004396static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07004397{
4398 struct cyclades_port *info;
Jeff Garzika6343af2007-07-17 05:39:58 -04004399 u32 uninitialized_var(mailbox);
Jiri Slaby0809e262007-05-08 00:36:14 -07004400 unsigned int nports;
4401 unsigned short chip_number;
Jeff Garzika6343af2007-07-17 05:39:58 -04004402 int uninitialized_var(index), port;
Jiri Slaby0809e262007-05-08 00:36:14 -07004403
Jiri Slaby3046d502007-05-08 00:36:46 -07004404 spin_lock_init(&cinfo->card_lock);
4405
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07004406 if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
Jiri Slaby0809e262007-05-08 00:36:14 -07004407 mailbox = readl(&((struct RUNTIME_9060 __iomem *)
4408 cinfo->ctl_addr)->mail_box_0);
4409 nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
4410 cinfo->intr_enabled = 0;
4411 cinfo->nports = 0; /* Will be correctly set later, after
4412 Z FW is loaded */
Jiri Slaby3046d502007-05-08 00:36:46 -07004413 } else {
4414 index = cinfo->bus_index;
4415 nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
4416 }
4417
Jiri Slabydd025c02007-05-08 00:37:02 -07004418 cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
4419 if (cinfo->ports == NULL) {
4420 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
Jiri Slaby31375532007-05-08 00:37:04 -07004421 cinfo->nports = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07004422 return -ENOMEM;
4423 }
4424
Jiri Slaby3046d502007-05-08 00:36:46 -07004425 for (port = cinfo->first_line; port < cinfo->first_line + nports;
4426 port++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004427 info = &cinfo->ports[port - cinfo->first_line];
Jiri Slaby3046d502007-05-08 00:36:46 -07004428 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07004429 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07004430 info->line = port;
4431 info->flags = STD_COM_FLAGS;
4432 info->closing_wait = CLOSING_WAIT_DELAY;
4433 info->close_delay = 5 * HZ / 10;
4434
Jiri Slaby3046d502007-05-08 00:36:46 -07004435 init_waitqueue_head(&info->open_wait);
4436 init_waitqueue_head(&info->close_wait);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07004437 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07004438 init_waitqueue_head(&info->delta_msr_wait);
4439
4440 if (IS_CYC_Z(*cinfo)) {
Jiri Slaby0809e262007-05-08 00:36:14 -07004441 info->type = PORT_STARTECH;
Jiri Slaby0809e262007-05-08 00:36:14 -07004442 if (mailbox == ZO_V1)
4443 info->xmit_fifo_size = CYZ_FIFO_SIZE;
4444 else
Jiri Slaby3046d502007-05-08 00:36:46 -07004445 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07004446#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07004447 setup_timer(&cyz_rx_full_timer[port],
4448 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07004449#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07004450 } else {
Jiri Slaby0809e262007-05-08 00:36:14 -07004451 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07004452 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07004453 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07004454 info->cor2 = CyETC;
4455 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07004456
Jiri Slaby0809e262007-05-08 00:36:14 -07004457 chip_number = (port - cinfo->first_line) / 4;
Jiri Slaby3046d502007-05-08 00:36:46 -07004458 if ((info->chip_rev = readb(cinfo->base_addr +
Jiri Slaby0809e262007-05-08 00:36:14 -07004459 (cy_chip_offset[chip_number] <<
4460 index) + (CyGFRCR << index))) >=
4461 CD1400_REV_J) {
4462 /* It is a CD1400 rev. J or later */
4463 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
4464 info->tco = baud_co_60[13]; /* Tx CO */
4465 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
4466 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07004467 info->rtsdtr_inv = 1;
4468 } else {
4469 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
4470 info->tco = baud_co_25[13]; /* Tx CO */
4471 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
4472 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07004473 info->rtsdtr_inv = 0;
4474 }
Jiri Slaby3046d502007-05-08 00:36:46 -07004475 info->read_status_mask = CyTIMEOUT | CySPECHAR |
4476 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07004477 }
Jiri Slaby3046d502007-05-08 00:36:46 -07004478
Jiri Slaby0809e262007-05-08 00:36:14 -07004479 }
Jiri Slaby3046d502007-05-08 00:36:46 -07004480
4481#ifndef CONFIG_CYZ_INTR
4482 if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
4483 mod_timer(&cyz_timerlist, jiffies + 1);
4484#ifdef CY_PCI_DEBUG
4485 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
4486#endif
4487 }
4488#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07004489 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07004490}
4491
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492/* initialize chips on Cyclom-Y card -- return number of valid
4493 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07004494static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
4495 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496{
Jiri Slaby02f11752006-12-08 02:39:28 -08004497 unsigned int chip_number;
4498 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
Jiri Slaby02f11752006-12-08 02:39:28 -08004500 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
4501 /* Cy_HwReset is 0x1400 */
4502 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
4503 /* Cy_ClrIntr is 0x1800 */
4504 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505
Jiri Slaby02f11752006-12-08 02:39:28 -08004506 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
4507 base_addr =
4508 true_base_addr + (cy_chip_offset[chip_number] << index);
4509 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004510 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004511 /*************
4512 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
4513 chip_number, (unsigned long)base_addr);
4514 *************/
4515 return chip_number;
4516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
Jiri Slaby02f11752006-12-08 02:39:28 -08004518 cy_writeb(base_addr + (CyGFRCR << index), 0);
4519 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
Jiri Slaby02f11752006-12-08 02:39:28 -08004521 /* The Cyclom-16Y does not decode address bit 9 and therefore
4522 cannot distinguish between references to chip 0 and a non-
4523 existent chip 4. If the preceding clearing of the supposed
4524 chip 4 GFRCR register appears at chip 0, there is no chip 4
4525 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
4526 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004527 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08004528 (cy_chip_offset[0] << index) +
4529 (CyGFRCR << index)) == 0) {
4530 return chip_number;
4531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Jiri Slaby02f11752006-12-08 02:39:28 -08004533 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
4534 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004536 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004537 /*
4538 printk(" chip #%d at %#6lx is not responding ",
4539 chip_number, (unsigned long)base_addr);
4540 printk("(GFRCR stayed 0)\n",
4541 */
4542 return chip_number;
4543 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004544 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08004545 0x40) {
4546 /*
4547 printk(" chip #%d at %#6lx is not valid (GFRCR == "
4548 "%#2x)\n",
4549 chip_number, (unsigned long)base_addr,
4550 base_addr[CyGFRCR<<index]);
4551 */
4552 return chip_number;
4553 }
4554 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004555 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08004556 /* It is a CD1400 rev. J or later */
4557 /* Impossible to reach 5ms with this chip.
4558 Changed to 2ms instead (f = 500 Hz). */
4559 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
4560 } else {
4561 /* f = 200 Hz */
4562 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
4563 }
4564
4565 /*
4566 printk(" chip #%d at %#6lx is rev 0x%2x\n",
4567 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07004568 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08004569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004571 return chip_number;
4572} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573
4574/*
4575 * ---------------------------------------------------------------------
4576 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
4577 * sets global variables and return the number of ISA boards found.
4578 * ---------------------------------------------------------------------
4579 */
Jiri Slaby02f11752006-12-08 02:39:28 -08004580static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581{
4582#ifdef CONFIG_ISA
Jiri Slaby02f11752006-12-08 02:39:28 -08004583 unsigned short cy_isa_irq, nboard;
4584 void __iomem *cy_isa_address;
4585 unsigned short i, j, cy_isa_nchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586#ifdef MODULE
Jiri Slaby02f11752006-12-08 02:39:28 -08004587 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588#endif
4589
Jiri Slaby02f11752006-12-08 02:39:28 -08004590 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
4592#ifdef MODULE
4593 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08004594 for (i = 0; i < NR_CARDS; i++) {
4595 if (maddr[i] || i) {
4596 isparam = 1;
4597 cy_isa_addresses[i] = maddr[i];
4598 }
4599 if (!maddr[i])
4600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 }
4602#endif
4603
Jiri Slaby02f11752006-12-08 02:39:28 -08004604 /* scan the address table probing for Cyclom-Y/ISA boards */
4605 for (i = 0; i < NR_ISA_ADDRS; i++) {
4606 unsigned int isa_address = cy_isa_addresses[i];
4607 if (isa_address == 0x0000) {
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004608 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08004609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Jiri Slaby02f11752006-12-08 02:39:28 -08004611 /* probe for CD1400... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 cy_isa_address = ioremap(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07004613 if (cy_isa_address == NULL) {
4614 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
4615 "address\n");
4616 continue;
4617 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004618 cy_isa_nchan = CyPORTS_PER_CHIP *
4619 cyy_init_card(cy_isa_address, 0);
4620 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07004621 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08004622 continue;
4623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624#ifdef MODULE
4625 if (isparam && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08004626 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 else
4628#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08004629 /* find out the board's irq by probing */
4630 cy_isa_irq = detect_isa_irq(cy_isa_address);
4631 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07004632 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
4633 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08004634 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07004635 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08004636 continue;
4637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638
Jiri Slaby02f11752006-12-08 02:39:28 -08004639 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07004640 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
4641 "more channels are available. Change NR_PORTS "
4642 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08004643 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07004644 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004645 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08004646 }
4647 /* fill the next cy_card structure available */
4648 for (j = 0; j < NR_CARDS; j++) {
Jiri Slabyf7429032007-05-08 00:36:59 -07004649 if (cy_card[j].base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08004650 break;
4651 }
4652 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07004653 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
4654 "more cards can be used. Change NR_CARDS in "
4655 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08004656 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07004657 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004658 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08004659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Jiri Slaby02f11752006-12-08 02:39:28 -08004661 /* allocate IRQ */
4662 if (request_irq(cy_isa_irq, cyy_interrupt,
4663 IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
Jiri Slaby21719192007-05-08 00:36:42 -07004664 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
4665 "could not allocate IRQ#%d.\n",
4666 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07004667 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004668 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08004669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Jiri Slaby02f11752006-12-08 02:39:28 -08004671 /* set cy_card */
4672 cy_card[j].base_addr = cy_isa_address;
4673 cy_card[j].ctl_addr = NULL;
4674 cy_card[j].irq = (int)cy_isa_irq;
4675 cy_card[j].bus_index = 0;
4676 cy_card[j].first_line = cy_next_channel;
4677 cy_card[j].num_chips = cy_isa_nchan / 4;
Jiri Slaby31375532007-05-08 00:37:04 -07004678 if (cy_init_card(&cy_card[j])) {
4679 cy_card[j].base_addr = NULL;
4680 free_irq(cy_isa_irq, &cy_card[j]);
4681 iounmap(cy_isa_address);
4682 continue;
4683 }
Jiri Slaby02f11752006-12-08 02:39:28 -08004684 nboard++;
4685
Jiri Slaby21719192007-05-08 00:36:42 -07004686 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
4687 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08004688 j + 1, (unsigned long)cy_isa_address,
4689 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07004690 cy_isa_irq, cy_isa_nchan, cy_next_channel);
4691
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004692 for (j = cy_next_channel;
4693 j < cy_next_channel + cy_isa_nchan; j++)
4694 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08004695 cy_next_channel += cy_isa_nchan;
4696 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004697 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08004699 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08004700#endif /* CONFIG_ISA */
4701} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702
Jiri Slaby58936d82007-05-08 00:36:13 -07004703#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07004704static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
4705{
4706 unsigned int a;
4707
4708 for (a = 0; a < size && *str; a++, str++)
4709 if (*str & 0x80)
4710 return -EINVAL;
4711
4712 for (; a < size; a++, str++)
4713 if (*str)
4714 return -EINVAL;
4715
4716 return 0;
4717}
4718
4719static inline void __devinit cyz_fpga_copy(void __iomem *fpga, u8 *data,
4720 unsigned int size)
4721{
4722 for (; size > 0; size--) {
4723 cy_writel(fpga, *data++);
4724 udelay(10);
4725 }
4726}
4727
4728static void __devinit plx_init(struct pci_dev *pdev, int irq,
4729 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730{
Jiri Slaby02f11752006-12-08 02:39:28 -08004731 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07004732 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08004733 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07004734 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
Jiri Slaby02f11752006-12-08 02:39:28 -08004736 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07004737 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08004738 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07004739 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
4740
4741 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
4742 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
4743 * registers. This will remain here until we find a permanent fix.
4744 */
4745 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
4746}
4747
4748static int __devinit __cyz_load_fw(const struct firmware *fw,
4749 const char *name, const u32 mailbox, void __iomem *base,
4750 void __iomem *fpga)
4751{
4752 void *ptr = fw->data;
4753 struct zfile_header *h = ptr;
4754 struct zfile_config *c, *cs;
4755 struct zfile_block *b, *bs;
4756 unsigned int a, tmp, len = fw->size;
4757#define BAD_FW KERN_ERR "Bad firmware: "
4758 if (len < sizeof(*h)) {
4759 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
4760 return -EINVAL;
4761 }
4762
4763 cs = ptr + h->config_offset;
4764 bs = ptr + h->block_offset;
4765
4766 if ((void *)(cs + h->n_config) > ptr + len ||
4767 (void *)(bs + h->n_blocks) > ptr + len) {
4768 printk(BAD_FW "too short");
4769 return -EINVAL;
4770 }
4771
4772 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
4773 cyc_isfwstr(h->date, sizeof(h->date))) {
4774 printk(BAD_FW "bad formatted header string\n");
4775 return -EINVAL;
4776 }
4777
4778 if (strncmp(name, h->name, sizeof(h->name))) {
4779 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
4780 return -EINVAL;
4781 }
4782
4783 tmp = 0;
4784 for (c = cs; c < cs + h->n_config; c++) {
4785 for (a = 0; a < c->n_blocks; a++)
4786 if (c->block_list[a] > h->n_blocks) {
4787 printk(BAD_FW "bad block ref number in cfgs\n");
4788 return -EINVAL;
4789 }
4790 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
4791 tmp++;
4792 }
4793 if (!tmp) {
4794 printk(BAD_FW "nothing appropriate\n");
4795 return -EINVAL;
4796 }
4797
4798 for (b = bs; b < bs + h->n_blocks; b++)
4799 if (b->file_offset + b->size > len) {
4800 printk(BAD_FW "bad block data offset\n");
4801 return -EINVAL;
4802 }
4803
4804 /* everything is OK, let's seek'n'load it */
4805 for (c = cs; c < cs + h->n_config; c++)
4806 if (c->mailbox == mailbox && c->function == 0)
4807 break;
4808
4809 for (a = 0; a < c->n_blocks; a++) {
4810 b = &bs[c->block_list[a]];
4811 if (b->type == ZBLOCK_FPGA) {
4812 if (fpga != NULL)
4813 cyz_fpga_copy(fpga, ptr + b->file_offset,
4814 b->size);
4815 } else {
4816 if (base != NULL)
4817 memcpy_toio(base + b->ram_offset,
4818 ptr + b->file_offset, b->size);
4819 }
4820 }
4821#undef BAD_FW
4822 return 0;
4823}
4824
4825static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
4826 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
4827{
4828 const struct firmware *fw;
4829 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
4830 struct CUSTOM_REG __iomem *cust = base_addr;
4831 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07004832 void __iomem *tmp;
Jiri Slaby054f5b02007-07-17 04:05:16 -07004833 u32 mailbox, status;
4834 unsigned int i;
4835 int retval;
4836
4837 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
4838 if (retval) {
4839 dev_err(&pdev->dev, "can't get firmware\n");
4840 goto err;
4841 }
4842
4843 /* Check whether the firmware is already loaded and running. If
4844 positive, skip this board */
4845 if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
4846 u32 cntval = readl(base_addr + 0x190);
4847
4848 udelay(100);
4849 if (cntval != readl(base_addr + 0x190)) {
4850 /* FW counter is working, FW is running */
4851 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
4852 "Skipping board.\n");
4853 retval = 0;
4854 goto err_rel;
4855 }
4856 }
4857
4858 /* start boot */
4859 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
4860 ~0x00030800UL);
4861
4862 mailbox = readl(&ctl_addr->mail_box_0);
4863
4864 if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
4865 /* stops CPU and set window to beginning of RAM */
4866 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4867 cy_writel(&cust->cpu_stop, 0);
4868 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4869 udelay(100);
4870 }
4871
4872 plx_init(pdev, irq, ctl_addr);
4873
4874 if (mailbox != 0) {
4875 /* load FPGA */
4876 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
4877 base_addr);
4878 if (retval)
4879 goto err_rel;
4880 if (!Z_FPGA_LOADED(ctl_addr)) {
4881 dev_err(&pdev->dev, "fw upload successful, but fw is "
4882 "not loaded\n");
4883 goto err_rel;
4884 }
4885 }
4886
4887 /* stops CPU and set window to beginning of RAM */
4888 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4889 cy_writel(&cust->cpu_stop, 0);
4890 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4891 udelay(100);
4892
4893 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07004894 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07004895 cy_writeb(tmp, 255);
4896 if (mailbox != 0) {
4897 /* set window to last 512K of RAM */
4898 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
4899 //sleep(1);
Jiri Slabyc4923b42007-07-17 04:05:17 -07004900 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07004901 cy_writeb(tmp, 255);
4902 /* set window to beginning of RAM */
4903 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4904 //sleep(1);
4905 }
4906
4907 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
4908 release_firmware(fw);
4909 if (retval)
4910 goto err;
4911
4912 /* finish boot and start boards */
4913 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
4914 cy_writel(&cust->cpu_start, 0);
4915 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
4916 i = 0;
4917 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
4918 msleep(100);
4919 if (status != ZFIRM_ID) {
4920 if (status == ZFIRM_HLT) {
4921 dev_err(&pdev->dev, "you need an external power supply "
4922 "for this number of ports. Firmware halted and "
4923 "board reset.\n");
4924 retval = -EIO;
4925 goto err;
4926 }
4927 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
4928 "some more time\n", status);
4929 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
4930 i++ < 200)
4931 msleep(100);
4932 if (status != ZFIRM_ID) {
4933 dev_err(&pdev->dev, "Board not started in 20 seconds! "
4934 "Giving up. (fid->signature = 0x%x)\n",
4935 status);
4936 dev_info(&pdev->dev, "*** Warning ***: if you are "
4937 "upgrading the FW, please power cycle the "
4938 "system before loading the new FW to the "
4939 "Cyclades-Z.\n");
4940
4941 if (Z_FPGA_LOADED(ctl_addr))
4942 plx_init(pdev, irq, ctl_addr);
4943
4944 retval = -EIO;
4945 goto err;
4946 }
4947 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
4948 i / 10);
4949 }
4950 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
4951
4952 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
4953 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
4954 base_addr + readl(&fid->zfwctrl_addr));
4955
4956 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
4957 readl(&pt_zfwctrl->board_ctrl.fw_version),
4958 readl(&pt_zfwctrl->board_ctrl.n_channel));
4959
4960 if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
4961 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
4962 "check the connection between the Z host card and the "
4963 "serial expanders.\n");
4964
4965 if (Z_FPGA_LOADED(ctl_addr))
4966 plx_init(pdev, irq, ctl_addr);
4967
4968 dev_info(&pdev->dev, "Null number of ports detected. Board "
4969 "reset.\n");
4970 retval = 0;
4971 goto err;
4972 }
4973
4974 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
4975 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
4976
4977 /*
4978 Early firmware failed to start looking for commands.
4979 This enables firmware interrupts for those commands.
4980 */
4981 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
4982 (1 << 17));
4983 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
4984 0x00030800UL);
4985
4986 plx_init(pdev, irq, ctl_addr);
4987
4988 return 0;
4989err_rel:
4990 release_firmware(fw);
4991err:
4992 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993}
4994
Jiri Slaby58936d82007-05-08 00:36:13 -07004995static int __devinit cy_pci_probe(struct pci_dev *pdev,
4996 const struct pci_device_id *ent)
4997{
Jiri Slaby31375532007-05-08 00:37:04 -07004998 void __iomem *addr0 = NULL, *addr2 = NULL;
4999 char *card_name = NULL;
5000 u32 mailbox;
5001 unsigned int device_id, nchan = 0, card_no, i;
5002 unsigned char plx_ver;
5003 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07005004
5005 retval = pci_enable_device(pdev);
5006 if (retval) {
5007 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07005008 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07005009 }
5010
5011 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07005012 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07005013 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
5014
Jiri Slaby31375532007-05-08 00:37:04 -07005015#if defined(__alpha__)
5016 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
5017 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
5018 "addresses on Alpha systems.\n");
5019 retval = -EIO;
5020 goto err_dis;
5021 }
5022#endif
5023 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
5024 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
5025 "addresses\n");
5026 retval = -EIO;
5027 goto err_dis;
5028 }
5029
5030 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
5031 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
5032 "it...\n");
5033 pdev->resource[2].flags &= ~IORESOURCE_IO;
5034 }
5035
5036 retval = pci_request_regions(pdev, "cyclades");
5037 if (retval) {
5038 dev_err(&pdev->dev, "failed to reserve resources\n");
5039 goto err_dis;
5040 }
5041
5042 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07005043 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
5044 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07005045 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07005046
Jiri Slaby31375532007-05-08 00:37:04 -07005047 addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
5048 if (addr0 == NULL) {
5049 dev_err(&pdev->dev, "can't remap ctl region\n");
5050 goto err_reg;
5051 }
5052 addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
5053 if (addr2 == NULL) {
5054 dev_err(&pdev->dev, "can't remap base region\n");
5055 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07005056 }
5057
Jiri Slaby31375532007-05-08 00:37:04 -07005058 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
5059 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07005060 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
5061 "Serial-Modules\n");
Jiri Slaby58936d82007-05-08 00:36:13 -07005062 return -EIO;
5063 }
Jiri Slaby31375532007-05-08 00:37:04 -07005064 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
5065 struct RUNTIME_9060 __iomem *ctl_addr;
5066
5067 ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
5068 if (addr0 == NULL) {
5069 dev_err(&pdev->dev, "can't remap ctl region\n");
5070 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07005071 }
5072
Jiri Slaby31375532007-05-08 00:37:04 -07005073 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby054f5b02007-07-17 04:05:16 -07005074 cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07005075
Jiri Slaby054f5b02007-07-17 04:05:16 -07005076 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07005077
5078 mailbox = (u32)readl(&ctl_addr->mail_box_0);
5079
5080 addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
5081 CyPCI_Ze_win : CyPCI_Zwin);
5082 if (addr2 == NULL) {
5083 dev_err(&pdev->dev, "can't remap base region\n");
5084 goto err_unmap;
5085 }
5086
5087 if (mailbox == ZE_V1) {
5088 card_name = "Cyclades-Ze";
5089
5090 readl(&ctl_addr->mail_box_0);
5091 nchan = ZE_V1_NPORTS;
5092 } else {
5093 card_name = "Cyclades-8Zo";
5094
5095#ifdef CY_PCI_DEBUG
5096 if (mailbox == ZO_V1) {
5097 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
5098 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
5099 "id %lx, ver %lx\n", (ulong)(0xff &
5100 readl(&((struct CUSTOM_REG *)addr2)->
5101 fpga_id)), (ulong)(0xff &
5102 readl(&((struct CUSTOM_REG *)addr2)->
5103 fpga_version)));
5104 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
5105 } else {
5106 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
5107 "Cyclades-Z board. FPGA not loaded\n");
5108 }
5109#endif
5110 /* The following clears the firmware id word. This
5111 ensures that the driver will not attempt to talk to
5112 the board until it has been properly initialized.
5113 */
5114 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
5115 cy_writel(addr2 + ID_ADDRESS, 0L);
5116
Jiri Slaby054f5b02007-07-17 04:05:16 -07005117 retval = cyz_load_fw(pdev, addr2, addr0, irq);
5118 if (retval)
5119 goto err_unmap;
Jiri Slaby31375532007-05-08 00:37:04 -07005120 /* This must be a Cyclades-8Zo/PCI. The extendable
5121 version will have a different device_id and will
5122 be allocated its maximum number of ports. */
5123 nchan = 8;
5124 }
5125 }
5126
5127 if ((cy_next_channel + nchan) > NR_PORTS) {
5128 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
5129 "channels are available. Change NR_PORTS in "
5130 "cyclades.c and recompile kernel.\n");
5131 goto err_unmap;
5132 }
5133 /* fill the next cy_card structure available */
5134 for (card_no = 0; card_no < NR_CARDS; card_no++) {
5135 if (cy_card[card_no].base_addr == NULL)
5136 break;
5137 }
5138 if (card_no == NR_CARDS) { /* no more cy_cards available */
5139 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
5140 "more cards can be used. Change NR_CARDS in "
5141 "cyclades.c and recompile kernel.\n");
5142 goto err_unmap;
5143 }
5144
5145 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
5146 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07005147 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07005148 retval = request_irq(irq, cyy_interrupt,
5149 IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
Jiri Slaby58936d82007-05-08 00:36:13 -07005150 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07005151 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07005152 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07005153 }
Jiri Slaby31375532007-05-08 00:37:04 -07005154 cy_card[card_no].num_chips = nchan / 4;
5155 } else {
5156#ifdef CONFIG_CYZ_INTR
5157 /* allocate IRQ only if board has an IRQ */
5158 if (irq != 0 && irq != 255) {
5159 retval = request_irq(irq, cyz_interrupt,
5160 IRQF_SHARED, "Cyclades-Z",
5161 &cy_card[card_no]);
5162 if (retval) {
5163 dev_err(&pdev->dev, "could not allocate IRQ\n");
5164 goto err_unmap;
5165 }
5166 }
5167#endif /* CONFIG_CYZ_INTR */
5168 cy_card[card_no].num_chips = -1;
5169 }
Jiri Slaby58936d82007-05-08 00:36:13 -07005170
Jiri Slaby31375532007-05-08 00:37:04 -07005171 /* set cy_card */
5172 cy_card[card_no].base_addr = addr2;
5173 cy_card[card_no].ctl_addr = addr0;
5174 cy_card[card_no].irq = irq;
5175 cy_card[card_no].bus_index = 1;
5176 cy_card[card_no].first_line = cy_next_channel;
5177 retval = cy_init_card(&cy_card[card_no]);
5178 if (retval)
5179 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07005180
Jiri Slaby31375532007-05-08 00:37:04 -07005181 pci_set_drvdata(pdev, &cy_card[card_no]);
5182
5183 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
5184 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07005185 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07005186 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07005187 switch (plx_ver) {
5188 case PLX_9050:
5189
Jiri Slaby31375532007-05-08 00:37:04 -07005190 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07005191 break;
5192
5193 case PLX_9060:
5194 case PLX_9080:
5195 default: /* Old boards, use PLX_9060 */
Jiri Slaby054f5b02007-07-17 04:05:16 -07005196 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07005197 cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07005198 break;
5199 }
Jiri Slaby58936d82007-05-08 00:36:13 -07005200 }
5201
Jiri Slaby31375532007-05-08 00:37:04 -07005202 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
5203 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
5204 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
5205 tty_register_device(cy_serial_driver, i, &pdev->dev);
5206 cy_next_channel += nchan;
5207
Jiri Slaby58936d82007-05-08 00:36:13 -07005208 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07005209err_null:
5210 cy_card[card_no].base_addr = NULL;
5211 free_irq(irq, &cy_card[card_no]);
5212err_unmap:
5213 pci_iounmap(pdev, addr0);
5214 if (addr2)
5215 pci_iounmap(pdev, addr2);
5216err_reg:
5217 pci_release_regions(pdev);
5218err_dis:
5219 pci_disable_device(pdev);
5220err:
5221 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07005222}
Jiri Slaby58936d82007-05-08 00:36:13 -07005223
Jiri Slaby6747cd92007-05-08 00:36:34 -07005224static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225{
Jiri Slaby38d09092007-05-08 00:36:10 -07005226 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07005227 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07005228
Jiri Slaby85c93fa2007-05-08 00:36:23 -07005229 /* non-Z with old PLX */
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07005230 if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
5231 PLX_9050)
Jiri Slaby85c93fa2007-05-08 00:36:23 -07005232 cy_writeb(cinfo->ctl_addr + 0x4c, 0);
5233 else
5234#ifndef CONFIG_CYZ_INTR
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07005235 if (!IS_CYC_Z(*cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07005236#endif
5237 cy_writew(cinfo->ctl_addr + 0x68,
5238 readw(cinfo->ctl_addr + 0x68) & ~0x0900);
5239
Jiri Slaby38d09092007-05-08 00:36:10 -07005240 pci_iounmap(pdev, cinfo->base_addr);
5241 if (cinfo->ctl_addr)
5242 pci_iounmap(pdev, cinfo->ctl_addr);
5243 if (cinfo->irq
5244#ifndef CONFIG_CYZ_INTR
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07005245 && !IS_CYC_Z(*cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07005246#endif /* CONFIG_CYZ_INTR */
5247 )
5248 free_irq(cinfo->irq, cinfo);
5249 pci_release_regions(pdev);
5250
5251 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07005252 for (i = cinfo->first_line; i < cinfo->first_line +
5253 cinfo->nports; i++)
5254 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07005255 cinfo->nports = 0;
5256 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07005257}
5258
Jiri Slaby6747cd92007-05-08 00:36:34 -07005259static struct pci_driver cy_pci_driver = {
5260 .name = "cyclades",
5261 .id_table = cy_pci_dev_id,
5262 .probe = cy_pci_probe,
5263 .remove = __devexit_p(cy_pci_remove)
5264};
5265#endif
5266
Jiri Slaby02f11752006-12-08 02:39:28 -08005267static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
Jiri Slaby02f11752006-12-08 02:39:28 -08005269 int *eof, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270{
Jiri Slaby02f11752006-12-08 02:39:28 -08005271 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07005272 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08005273 int len = 0;
5274 off_t begin = 0;
5275 off_t pos = 0;
5276 int size;
5277 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
Jiri Slaby02f11752006-12-08 02:39:28 -08005279 size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn "
5280 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281
Jiri Slaby02f11752006-12-08 02:39:28 -08005282 pos += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 len += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
Jiri Slaby02f11752006-12-08 02:39:28 -08005285 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07005286 for (i = 0; i < NR_CARDS; i++)
5287 for (j = 0; j < cy_card[i].nports; j++) {
5288 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08005289
Jiri Slabydd025c02007-05-08 00:37:02 -07005290 if (info->count)
5291 size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
5292 "%10lu %8lu %9lu %6ld\n", info->line,
5293 (cur_jifs - info->idle_stats.in_use) /
5294 HZ, info->idle_stats.xmit_bytes,
5295 (cur_jifs - info->idle_stats.xmit_idle)/
5296 HZ, info->idle_stats.recv_bytes,
5297 (cur_jifs - info->idle_stats.recv_idle)/
5298 HZ, info->idle_stats.overruns,
5299 (long)info->tty->ldisc.num);
5300 else
5301 size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
5302 "%10lu %8lu %9lu %6ld\n",
5303 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
5304 len += size;
5305 pos = begin + len;
Jiri Slaby02f11752006-12-08 02:39:28 -08005306
Jiri Slabydd025c02007-05-08 00:37:02 -07005307 if (pos < offset) {
5308 len = 0;
5309 begin = pos;
5310 }
5311 if (pos > offset + length)
5312 goto done;
Jiri Slaby02f11752006-12-08 02:39:28 -08005313 }
Jiri Slaby02f11752006-12-08 02:39:28 -08005314 *eof = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315done:
Jiri Slaby02f11752006-12-08 02:39:28 -08005316 *start = buf + (offset - begin); /* Start of wanted data */
5317 len -= (offset - begin); /* Start slop */
5318 if (len > length)
5319 len = length; /* Ending slop */
5320 if (len < 0)
5321 len = 0;
5322 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323}
5324
5325/* The serial driver boot-time initialization code!
5326 Hardware I/O ports are mapped to character special devices on a
5327 first found, first allocated manner. That is, this code searches
5328 for Cyclom cards in the system. As each is found, it is probed
5329 to discover how many chips (and thus how many ports) are present.
5330 These ports are mapped to the tty ports 32 and upward in monotonic
5331 fashion. If an 8-port card is replaced with a 16-port card, the
5332 port mapping on a following card will shift.
5333
5334 This approach is different from what is used in the other serial
5335 device driver because the Cyclom is more properly a multiplexer,
5336 not just an aggregation of serial ports on one card.
5337
5338 If there are more cards with more ports than have been
5339 statically allocated above, a warning is printed and the
5340 extra ports are ignored.
5341 */
5342
Jeff Dikeb68e31d2006-10-02 02:17:18 -07005343static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08005344 .open = cy_open,
5345 .close = cy_close,
5346 .write = cy_write,
5347 .put_char = cy_put_char,
5348 .flush_chars = cy_flush_chars,
5349 .write_room = cy_write_room,
5350 .chars_in_buffer = cy_chars_in_buffer,
5351 .flush_buffer = cy_flush_buffer,
5352 .ioctl = cy_ioctl,
5353 .throttle = cy_throttle,
5354 .unthrottle = cy_unthrottle,
5355 .set_termios = cy_set_termios,
5356 .stop = cy_stop,
5357 .start = cy_start,
5358 .hangup = cy_hangup,
5359 .break_ctl = cy_break,
5360 .wait_until_sent = cy_wait_until_sent,
5361 .read_proc = cyclades_get_proc_info,
5362 .tiocmget = cy_tiocmget,
5363 .tiocmset = cy_tiocmset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364};
5365
Jiri Slaby02f11752006-12-08 02:39:28 -08005366static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367{
Jiri Slabydd025c02007-05-08 00:37:02 -07005368 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07005369 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370
Jiri Slaby02f11752006-12-08 02:39:28 -08005371 cy_serial_driver = alloc_tty_driver(NR_PORTS);
5372 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07005373 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07005374
5375 printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
5376 __DATE__, __TIME__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
Jiri Slaby02f11752006-12-08 02:39:28 -08005378 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379
Jiri Slaby02f11752006-12-08 02:39:28 -08005380 cy_serial_driver->owner = THIS_MODULE;
5381 cy_serial_driver->driver_name = "cyclades";
5382 cy_serial_driver->name = "ttyC";
5383 cy_serial_driver->major = CYCLADES_MAJOR;
5384 cy_serial_driver->minor_start = 0;
5385 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
5386 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
5387 cy_serial_driver->init_termios = tty_std_termios;
5388 cy_serial_driver->init_termios.c_cflag =
5389 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07005390 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08005391 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07005393 retval = tty_register_driver(cy_serial_driver);
5394 if (retval) {
5395 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
5396 goto err_frtty;
5397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Jiri Slaby02f11752006-12-08 02:39:28 -08005399 /* the code below is responsible to find the boards. Each different
5400 type of board has its own detection routine. If a board is found,
5401 the next cy_card structure available is set by the detection
5402 routine. These functions are responsible for checking the
5403 availability of cy_card and cy_port data structures and updating
5404 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405
Jiri Slaby02f11752006-12-08 02:39:28 -08005406 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07005407 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408
Jiri Slaby6747cd92007-05-08 00:36:34 -07005409#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08005410 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07005411 retval = pci_register_driver(&cy_pci_driver);
5412 if (retval && !nboards)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07005413 goto err_unr;
Jiri Slaby6747cd92007-05-08 00:36:34 -07005414#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07005415
5416 return 0;
5417err_unr:
5418 tty_unregister_driver(cy_serial_driver);
5419err_frtty:
5420 put_tty_driver(cy_serial_driver);
5421err:
5422 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08005423} /* cy_init */
5424
5425static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426{
Jiri Slabydd025c02007-05-08 00:37:02 -07005427 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08005428 int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429
5430#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07005431 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432#endif /* CONFIG_CYZ_INTR */
5433
Jiri Slaby02f11752006-12-08 02:39:28 -08005434 if ((e1 = tty_unregister_driver(cy_serial_driver)))
Jiri Slaby21719192007-05-08 00:36:42 -07005435 printk(KERN_ERR "failed to unregister Cyclades serial "
5436 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
Jiri Slaby6747cd92007-05-08 00:36:34 -07005438#ifdef CONFIG_PCI
5439 pci_unregister_driver(&cy_pci_driver);
5440#endif
5441
Jiri Slaby02f11752006-12-08 02:39:28 -08005442 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07005443 card = &cy_card[i];
5444 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07005445 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07005446 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
5447 iounmap(card->base_addr);
5448 if (card->ctl_addr)
5449 iounmap(card->ctl_addr);
5450 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451#ifndef CONFIG_CYZ_INTR
Jiri Slabydd025c02007-05-08 00:37:02 -07005452 && !IS_CYC_Z(*card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08005454 )
Jiri Slabydd025c02007-05-08 00:37:02 -07005455 free_irq(card->irq, card);
5456 for (e1 = card->first_line;
5457 e1 < card->first_line +
5458 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07005459 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07005460 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08005461 }
5462 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07005463
5464 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465} /* cy_cleanup_module */
5466
5467module_init(cy_init);
5468module_exit(cy_cleanup_module);
5469
5470MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07005471MODULE_VERSION(CY_VERSION);