blob: ba4e86281fbf29dde6dc9b121da6228628f22d33 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* sx.c -- driver for the Specialix SX series cards.
2 *
3 * This driver will also support the older SI, and XIO cards.
4 *
5 *
6 * (C) 1998 - 2004 R.E.Wolff@BitWizard.nl
7 *
8 * Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
9 * version of this driver. Some fragments may have been copied. (none
10 * yet :-)
11 *
12 * Specialix pays for the development and support of this driver.
13 * Please DO contact support@specialix.co.uk if you require
14 * support. But please read the documentation (sx.txt) first.
15 *
16 *
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License as
20 * published by the Free Software Foundation; either version 2 of
21 * the License, or (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be
24 * useful, but WITHOUT ANY WARRANTY; without even the implied
25 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
26 * PURPOSE. See the GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public
29 * License along with this program; if not, write to the Free
30 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
31 * USA.
32 *
33 * Revision history:
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 * Revision 1.33 2000/03/09 10:00:00 pvdl,wolff
35 * - Fixed module and port counting
36 * - Fixed signal handling
37 * - Fixed an Ooops
38 *
39 * Revision 1.32 2000/03/07 09:00:00 wolff,pvdl
40 * - Fixed some sx_dprintk typos
41 * - added detection for an invalid board/module configuration
42 *
43 * Revision 1.31 2000/03/06 12:00:00 wolff,pvdl
44 * - Added support for EISA
45 *
46 * Revision 1.30 2000/01/21 17:43:06 wolff
47 * - Added support for SX+
48 *
49 * Revision 1.26 1999/08/05 15:22:14 wolff
50 * - Port to 2.3.x
51 * - Reformatted to Linus' liking.
52 *
53 * Revision 1.25 1999/07/30 14:24:08 wolff
54 * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0).
55 *
56 * Revision 1.24 1999/07/28 09:41:52 wolff
57 * - I noticed the remark about use-count straying in sx.txt. I checked
58 * sx_open, and found a few places where that could happen. I hope it's
59 * fixed now.
60 *
61 * Revision 1.23 1999/07/28 08:56:06 wolff
62 * - Fixed crash when sx_firmware run twice.
63 * - Added sx_slowpoll as a module parameter (I guess nobody really wanted
64 * to change it from the default... )
65 * - Fixed a stupid editing problem I introduced in 1.22.
66 * - Fixed dropping characters on a termios change.
67 *
68 * Revision 1.22 1999/07/26 21:01:43 wolff
69 * Russell Brown noticed that I had overlooked 4 out of six modem control
70 * signals in sx_getsignals. Ooops.
71 *
72 * Revision 1.21 1999/07/23 09:11:33 wolff
73 * I forgot to free dynamically allocated memory when the driver is unloaded.
74 *
75 * Revision 1.20 1999/07/20 06:25:26 wolff
76 * The "closing wait" wasn't honoured. Thanks to James Griffiths for
77 * reporting this.
78 *
79 * Revision 1.19 1999/07/11 08:59:59 wolff
80 * Fixed an oops in close, when an open was pending. Changed the memtest
81 * a bit. Should also test the board in word-mode, however my card fails the
82 * memtest then. I still have to figure out what is wrong...
83 *
84 * Revision 1.18 1999/06/10 09:38:42 wolff
85 * Changed the format of the firmware revision from %04x to %x.%02x .
86 *
87 * Revision 1.17 1999/06/04 09:44:35 wolff
88 * fixed problem: reference to pci stuff when config_pci was off...
89 * Thanks to Jorge Novo for noticing this.
90 *
91 * Revision 1.16 1999/06/02 08:30:15 wolff
92 * added/removed the workaround for the DCD bug in the Firmware.
93 * A bit more debugging code to locate that...
94 *
95 * Revision 1.15 1999/06/01 11:35:30 wolff
96 * when DCD is left low (floating?), on TA's the firmware first tells us
97 * that DCD is high, but after a short while suddenly comes to the
98 * conclusion that it is low. All this would be fine, if it weren't that
99 * Unix requires us to send a "hangup" signal in that case. This usually
100 * all happens BEFORE the program has had a chance to ioctl the device
101 * into clocal mode..
102 *
103 * Revision 1.14 1999/05/25 11:18:59 wolff
104 * Added PCI-fix.
105 * Added checks for return code of sx_sendcommand.
106 * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...)
107 *
108 * Revision 1.13 1999/04/29 15:18:01 wolff
109 * Fixed an "oops" that showed on SuSE 6.0 systems.
110 * Activate DTR again after stty 0.
111 *
112 * Revision 1.12 1999/04/29 07:49:52 wolff
113 * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming
114 * the connection would be dropped anyway. That is not always the case,
115 * and confuses people).
116 * Told the card to always monitor the modem signals.
117 * Added support for dynamic gs_debug adjustments.
118 * Now tells the rest of the system the number of ports.
119 *
120 * Revision 1.11 1999/04/24 11:11:30 wolff
121 * Fixed two stupid typos in the memory test.
122 *
123 * Revision 1.10 1999/04/24 10:53:39 wolff
124 * Added some of Christian's suggestions.
125 * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the
126 * card to send the signal to the process.....)
127 *
128 * Revision 1.9 1999/04/23 07:26:38 wolff
129 * Included Christian Lademann's 2.0 compile-warning fixes and interrupt
130 * assignment redesign.
131 * Cleanup of some other stuff.
132 *
133 * Revision 1.8 1999/04/16 13:05:30 wolff
134 * fixed a DCD change unnoticed bug.
135 *
136 * Revision 1.7 1999/04/14 22:19:51 wolff
137 * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!)
138 *
139 * Revision 1.6 1999/04/13 18:40:20 wolff
140 * changed misc-minor to 161, as assigned by HPA.
141 *
142 * Revision 1.5 1999/04/13 15:12:25 wolff
143 * Fixed use-count leak when "hangup" occurred.
144 * Added workaround for a stupid-PCIBIOS bug.
145 *
146 *
147 * Revision 1.4 1999/04/01 22:47:40 wolff
148 * Fixed < 1M linux-2.0 problem.
149 * (vremap isn't compatible with ioremap in that case)
150 *
151 * Revision 1.3 1999/03/31 13:45:45 wolff
152 * Firmware loading is now done through a separate IOCTL.
153 *
154 * Revision 1.2 1999/03/28 12:22:29 wolff
155 * rcs cleanup
156 *
157 * Revision 1.1 1999/03/28 12:10:34 wolff
158 * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS).
159 *
160 * Revision 0.12 1999/03/28 09:20:10 wolff
161 * Fixed problem in 0.11, continueing cleanup.
162 *
163 * Revision 0.11 1999/03/28 08:46:44 wolff
164 * cleanup. Not good.
165 *
166 * Revision 0.10 1999/03/28 08:09:43 wolff
167 * Fixed loosing characters on close.
168 *
169 * Revision 0.9 1999/03/21 22:52:01 wolff
170 * Ported back to 2.2.... (minor things)
171 *
172 * Revision 0.8 1999/03/21 22:40:33 wolff
173 * Port to 2.0
174 *
175 * Revision 0.7 1999/03/21 19:06:34 wolff
176 * Fixed hangup processing.
177 *
178 * Revision 0.6 1999/02/05 08:45:14 wolff
179 * fixed real_raw problems. Inclusion into kernel imminent.
180 *
181 * Revision 0.5 1998/12/21 23:51:06 wolff
182 * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it
183 * shouldn't have. THATs why I want to have transmit interrupts even when
184 * the buffer is empty.
185 *
186 * Revision 0.4 1998/12/17 09:34:46 wolff
187 * PPP works. ioctl works. Basically works!
188 *
189 * Revision 0.3 1998/12/15 13:05:18 wolff
190 * It works! Wow! Gotta start implementing IOCTL and stuff....
191 *
192 * Revision 0.2 1998/12/01 08:33:53 wolff
193 * moved over to 2.1.130
194 *
195 * Revision 0.1 1998/11/03 21:23:51 wolff
196 * Initial revision. Detects SX card.
197 *
198 * */
199
Jiri Slaby11c83872006-12-08 02:38:56 -0800200#define SX_VERSION 1.33
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203#include <linux/kdev_t.h>
204#include <linux/kernel.h>
205#include <linux/sched.h>
206#include <linux/ioport.h>
207#include <linux/interrupt.h>
208#include <linux/errno.h>
209#include <linux/tty.h>
210#include <linux/tty_flip.h>
211#include <linux/mm.h>
212#include <linux/serial.h>
213#include <linux/fcntl.h>
214#include <linux/major.h>
215#include <linux/delay.h>
Jiri Slaby18f813e2006-12-08 02:39:01 -0800216#include <linux/eisa.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217#include <linux/pci.h>
218#include <linux/slab.h>
219#include <linux/init.h>
220#include <linux/miscdevice.h>
221#include <linux/bitops.h>
222
223#include <asm/io.h>
224#include <asm/uaccess.h>
225
226/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */
227#define BYTE u8
228#define WORD u16
229
230/* .... but the 3.0.4 version uses _u8 and _u16. */
231#define _u8 u8
232#define _u16 u16
233
234#include "sxboards.h"
235#include "sxwindow.h"
236
237#include <linux/generic_serial.h>
238#include "sx.h"
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240/* I don't think that this driver can handle more than 256 ports on
241 one machine. You'll have to increase the number of boards in sx.h
242 if you want more than 4 boards. */
243
244#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
245#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
246#endif
247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248/* Configurable options:
249 (Don't be too sure that it'll work if you toggle them) */
250
251/* Am I paranoid or not ? ;-) */
252#undef SX_PARANOIA_CHECK
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
255 Hz, but it is user configurable. I don't recommend going above 1000
256 Hz. The interrupt ratelimit might trigger if the interrupt is
257 shared with a very active other device. */
258#define IRQ_RATE_LIMIT 20
259
260/* Sharing interrupts is possible now. If the other device wants more
261 than 2000 interrupts per second, we'd gracefully decline further
262 interrupts. That's not what we want. On the other hand, if the
263 other device interrupts 2000 times a second, don't use the SX
264 interrupt. Use polling. */
265#undef IRQ_RATE_LIMIT
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#if 0
268/* Not implemented */
269/*
270 * The following defines are mostly for testing purposes. But if you need
271 * some nice reporting in your syslog, you can define them also.
272 */
273#define SX_REPORT_FIFO
274#define SX_REPORT_OVERRUN
Jiri Slaby15b611f2006-12-08 02:39:04 -0800275#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277/* Function prototypes */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800278static void sx_disable_tx_interrupts(void *ptr);
279static void sx_enable_tx_interrupts(void *ptr);
280static void sx_disable_rx_interrupts(void *ptr);
281static void sx_enable_rx_interrupts(void *ptr);
282static int sx_get_CD(void *ptr);
283static void sx_shutdown_port(void *ptr);
284static int sx_set_real_termios(void *ptr);
285static void sx_close(void *ptr);
286static int sx_chars_in_buffer(void *ptr);
287static int sx_init_board(struct sx_board *board);
288static int sx_init_portstructs(int nboards, int nports);
Alan Cox11af7472008-07-25 01:48:15 -0700289static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
290 unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291static int sx_init_drivers(void);
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static struct tty_driver *sx_driver;
294
Jiri Slaby42f63842006-12-08 02:39:03 -0800295static DEFINE_MUTEX(sx_boards_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296static struct sx_board boards[SX_NBOARDS];
297static struct sx_port *sx_ports;
298static int sx_initialized;
299static int sx_nports;
300static int sx_debug;
301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302/* You can have the driver poll your card.
303 - Set sx_poll to 1 to poll every timer tick (10ms on Intel).
304 This is used when the card cannot use an interrupt for some reason.
305
306 - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If
307 the driver misses an interrupt (report this if it DOES happen to you!)
308 everything will continue to work....
309 */
310static int sx_poll = 1;
311static int sx_slowpoll;
312
313/* The card limits the number of interrupts per second.
314 At 115k2 "100" should be sufficient.
315 If you're using higher baudrates, you can increase this...
316 */
317
318static int sx_maxints = 100;
319
Jiri Slaby927a6f92006-12-08 02:39:02 -0800320#ifdef CONFIG_ISA
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322/* These are the only open spaces in my computer. Yours may have more
323 or less.... -- REW
324 duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
325*/
Jiri Slaby15b611f2006-12-08 02:39:04 -0800326static int sx_probe_addrs[] = {
327 0xc0000, 0xd0000, 0xe0000,
328 0xc8000, 0xd8000, 0xe8000
329};
330static int si_probe_addrs[] = {
331 0xc0000, 0xd0000, 0xe0000,
332 0xc8000, 0xd8000, 0xe8000, 0xa0000
333};
334static int si1_probe_addrs[] = {
335 0xd0000
336};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Tobias Klauserfe971072006-01-09 20:54:02 -0800338#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
339#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
340#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jiri Slaby927a6f92006-12-08 02:39:02 -0800342module_param_array(sx_probe_addrs, int, NULL, 0);
343module_param_array(si_probe_addrs, int, NULL, 0);
344#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346/* Set the mask to all-ones. This alas, only supports 32 interrupts.
347 Some architectures may need more. */
348static int sx_irqmask = -1;
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350module_param(sx_poll, int, 0);
351module_param(sx_slowpoll, int, 0);
352module_param(sx_maxints, int, 0);
353module_param(sx_debug, int, 0);
354module_param(sx_irqmask, int, 0);
355
356MODULE_LICENSE("GPL");
357
358static struct real_driver sx_real_driver = {
359 sx_disable_tx_interrupts,
360 sx_enable_tx_interrupts,
361 sx_disable_rx_interrupts,
362 sx_enable_rx_interrupts,
363 sx_get_CD,
Jiri Slaby15b611f2006-12-08 02:39:04 -0800364 sx_shutdown_port,
365 sx_set_real_termios,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 sx_chars_in_buffer,
367 sx_close,
368};
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370/*
371 This driver can spew a whole lot of debugging output at you. If you
372 need maximum performance, you should disable the DEBUG define. To
373 aid in debugging in the field, I'm leaving the compile-time debug
374 features enabled, and disable them "runtime". That allows me to
375 instruct people with problems to enable debugging without requiring
376 them to recompile...
377*/
378#define DEBUG
379
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380#ifdef DEBUG
Jiri Slaby15b611f2006-12-08 02:39:04 -0800381#define sx_dprintk(f, str...) if (sx_debug & f) printk (str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382#else
Jiri Slaby15b611f2006-12-08 02:39:04 -0800383#define sx_dprintk(f, str...) /* nothing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384#endif
385
Harvey Harrisonbf9d8922008-04-30 00:55:10 -0700386#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__)
387#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__func__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Jiri Slaby15b611f2006-12-08 02:39:04 -0800389#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
Harvey Harrisonbf9d8922008-04-30 00:55:10 -0700390 __func__, port->line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392/*
393 * Firmware loader driver specific routines
394 *
395 */
396
Arjan van de Ven62322d22006-07-03 00:24:21 -0700397static const struct file_operations sx_fw_fops = {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800398 .owner = THIS_MODULE,
Alan Cox11af7472008-07-25 01:48:15 -0700399 .unlocked_ioctl = sx_fw_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400};
401
402static struct miscdevice sx_fw_device = {
403 SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
404};
405
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406#ifdef SX_PARANOIA_CHECK
407
408/* This doesn't work. Who's paranoid around here? Not me! */
409
Jiri Slaby15b611f2006-12-08 02:39:04 -0800410static inline int sx_paranoia_check(struct sx_port const *port,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 char *name, const char *routine)
412{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800413 static const char *badmagic = KERN_ERR "sx: Warning: bad sx port magic "
414 "number for device %s in %s\n";
415 static const char *badinfo = KERN_ERR "sx: Warning: null sx port for "
416 "device %s in %s\n";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (!port) {
419 printk(badinfo, name, routine);
420 return 1;
421 }
422 if (port->magic != SX_MAGIC) {
423 printk(badmagic, name, routine);
424 return 1;
425 }
426
427 return 0;
428}
429#else
430#define sx_paranoia_check(a,b,c) 0
431#endif
432
433/* The timeouts. First try 30 times as fast as possible. Then give
434 the card some time to breathe between accesses. (Otherwise the
435 processor on the card might not be able to access its OWN bus... */
436
437#define TIMEOUT_1 30
438#define TIMEOUT_2 1000000
439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440#ifdef DEBUG
441static void my_hd_io(void __iomem *p, int len)
442{
443 int i, j, ch;
444 unsigned char __iomem *addr = p;
445
Jiri Slaby15b611f2006-12-08 02:39:04 -0800446 for (i = 0; i < len; i += 16) {
447 printk("%p ", addr + i);
448 for (j = 0; j < 16; j++) {
449 printk("%02x %s", readb(addr + j + i),
450 (j == 7) ? " " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800452 for (j = 0; j < 16; j++) {
453 ch = readb(addr + j + i);
454 printk("%c", (ch < 0x20) ? '.' :
455 ((ch > 0x7f) ? '.' : ch));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800457 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 }
459}
460static void my_hd(void *p, int len)
461{
462 int i, j, ch;
463 unsigned char *addr = p;
464
Jiri Slaby15b611f2006-12-08 02:39:04 -0800465 for (i = 0; i < len; i += 16) {
466 printk("%p ", addr + i);
467 for (j = 0; j < 16; j++) {
468 printk("%02x %s", addr[j + i], (j == 7) ? " " : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800470 for (j = 0; j < 16; j++) {
471 ch = addr[j + i];
472 printk("%c", (ch < 0x20) ? '.' :
473 ((ch > 0x7f) ? '.' : ch));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800475 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
477}
478#endif
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480/* This needs redoing for Alpha -- REW -- Done. */
481
Jiri Slaby15b611f2006-12-08 02:39:04 -0800482static inline void write_sx_byte(struct sx_board *board, int offset, u8 byte)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800484 writeb(byte, board->base + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Jiri Slaby15b611f2006-12-08 02:39:04 -0800487static inline u8 read_sx_byte(struct sx_board *board, int offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800489 return readb(board->base + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490}
491
Jiri Slaby15b611f2006-12-08 02:39:04 -0800492static inline void write_sx_word(struct sx_board *board, int offset, u16 word)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800494 writew(word, board->base + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495}
496
Jiri Slaby15b611f2006-12-08 02:39:04 -0800497static inline u16 read_sx_word(struct sx_board *board, int offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800499 return readw(board->base + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500}
501
Jiri Slaby15b611f2006-12-08 02:39:04 -0800502static int sx_busy_wait_eq(struct sx_board *board,
503 int offset, int mask, int correctval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504{
505 int i;
506
Jiri Slaby15b611f2006-12-08 02:39:04 -0800507 func_enter();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Jiri Slaby15b611f2006-12-08 02:39:04 -0800509 for (i = 0; i < TIMEOUT_1; i++)
510 if ((read_sx_byte(board, offset) & mask) == correctval) {
511 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return 1;
513 }
514
Jiri Slaby15b611f2006-12-08 02:39:04 -0800515 for (i = 0; i < TIMEOUT_2; i++) {
516 if ((read_sx_byte(board, offset) & mask) == correctval) {
517 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return 1;
519 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800520 udelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
522
Jiri Slaby15b611f2006-12-08 02:39:04 -0800523 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return 0;
525}
526
Jiri Slaby15b611f2006-12-08 02:39:04 -0800527static int sx_busy_wait_neq(struct sx_board *board,
528 int offset, int mask, int badval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
530 int i;
531
Jiri Slaby15b611f2006-12-08 02:39:04 -0800532 func_enter();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Jiri Slaby15b611f2006-12-08 02:39:04 -0800534 for (i = 0; i < TIMEOUT_1; i++)
535 if ((read_sx_byte(board, offset) & mask) != badval) {
536 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return 1;
538 }
539
Jiri Slaby15b611f2006-12-08 02:39:04 -0800540 for (i = 0; i < TIMEOUT_2; i++) {
541 if ((read_sx_byte(board, offset) & mask) != badval) {
542 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return 1;
544 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800545 udelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
547
Jiri Slaby15b611f2006-12-08 02:39:04 -0800548 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 return 0;
550}
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552/* 5.6.4 of 6210028 r2.3 */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800553static int sx_reset(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800555 func_enter();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
Jiri Slaby15b611f2006-12-08 02:39:04 -0800557 if (IS_SX_BOARD(board)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Jiri Slaby15b611f2006-12-08 02:39:04 -0800559 write_sx_byte(board, SX_CONFIG, 0);
560 write_sx_byte(board, SX_RESET, 1); /* Value doesn't matter */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Jiri Slaby15b611f2006-12-08 02:39:04 -0800562 if (!sx_busy_wait_eq(board, SX_RESET_STATUS, 1, 0)) {
563 printk(KERN_INFO "sx: Card doesn't respond to "
564 "reset...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return 0;
566 }
567 } else if (IS_EISA_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800568 outb(board->irq << 4, board->eisa_base + 0xc02);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 } else if (IS_SI1_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800570 write_sx_byte(board, SI1_ISA_RESET, 0); /*value doesn't matter*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 } else {
572 /* Gory details of the SI/ISA board */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800573 write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
574 write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
575 write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
576 write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
577 write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
578 write_sx_byte(board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
580
Jiri Slaby15b611f2006-12-08 02:39:04 -0800581 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 1;
583}
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585/* This doesn't work on machines where "NULL" isn't 0 */
586/* If you have one of those, someone will need to write
587 the equivalent of this, which will amount to about 3 lines. I don't
588 want to complicate this right now. -- REW
589 (See, I do write comments every now and then :-) */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800590#define OFFSETOF(strct, elem) ((long)&(((struct strct *)NULL)->elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Jiri Slaby15b611f2006-12-08 02:39:04 -0800592#define CHAN_OFFSET(port,elem) (port->ch_base + OFFSETOF (_SXCHANNEL, elem))
593#define MODU_OFFSET(board,addr,elem) (addr + OFFSETOF (_SXMODULE, elem))
594#define BRD_OFFSET(board,elem) (OFFSETOF (_SXCARD, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596#define sx_write_channel_byte(port, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800597 write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
599#define sx_read_channel_byte(port, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800600 read_sx_byte (port->board, CHAN_OFFSET (port, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602#define sx_write_channel_word(port, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800603 write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605#define sx_read_channel_word(port, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800606 read_sx_word (port->board, CHAN_OFFSET (port, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608#define sx_write_module_byte(board, addr, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800609 write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611#define sx_read_module_byte(board, addr, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800612 read_sx_byte (board, MODU_OFFSET (board, addr, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614#define sx_write_module_word(board, addr, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800615 write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617#define sx_read_module_word(board, addr, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800618 read_sx_word (board, MODU_OFFSET (board, addr, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620#define sx_write_board_byte(board, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800621 write_sx_byte (board, BRD_OFFSET (board, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623#define sx_read_board_byte(board, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800624 read_sx_byte (board, BRD_OFFSET (board, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
626#define sx_write_board_word(board, elem, val) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800627 write_sx_word (board, BRD_OFFSET (board, elem), val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629#define sx_read_board_word(board, elem) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800630 read_sx_word (board, BRD_OFFSET (board, elem))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Jiri Slaby15b611f2006-12-08 02:39:04 -0800632static int sx_start_board(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800634 if (IS_SX_BOARD(board)) {
635 write_sx_byte(board, SX_CONFIG, SX_CONF_BUSEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 } else if (IS_EISA_BOARD(board)) {
637 write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL);
Jiri Slaby15b611f2006-12-08 02:39:04 -0800638 outb((board->irq << 4) | 4, board->eisa_base + 0xc02);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 } else if (IS_SI1_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800640 write_sx_byte(board, SI1_ISA_RESET_CLEAR, 0);
641 write_sx_byte(board, SI1_ISA_INTCL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 } else {
643 /* Don't bug me about the clear_set.
644 I haven't the foggiest idea what it's about -- REW */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800645 write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
646 write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 }
648 return 1;
649}
650
651#define SX_IRQ_REG_VAL(board) \
Jiri Slaby15b611f2006-12-08 02:39:04 -0800652 ((board->flags & SX_ISA_BOARD) ? (board->irq << 4) : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654/* Note. The SX register is write-only. Therefore, we have to enable the
655 bus too. This is a no-op, if you don't mess with this driver... */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800656static int sx_start_interrupts(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658
659 /* Don't call this with board->irq == 0 */
660
661 if (IS_SX_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800662 write_sx_byte(board, SX_CONFIG, SX_IRQ_REG_VAL(board) |
663 SX_CONF_BUSEN | SX_CONF_HOSTIRQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 } else if (IS_EISA_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800665 inb(board->eisa_base + 0xc03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 } else if (IS_SI1_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800667 write_sx_byte(board, SI1_ISA_INTCL, 0);
668 write_sx_byte(board, SI1_ISA_INTCL_CLEAR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 } else {
670 switch (board->irq) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800671 case 11:
672 write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);
673 break;
674 case 12:
675 write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);
676 break;
677 case 15:
678 write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);
679 break;
680 default:
681 printk(KERN_INFO "sx: SI/XIO card doesn't support "
682 "interrupt %d.\n", board->irq);
683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800685 write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 }
687
688 return 1;
689}
690
Jiri Slaby15b611f2006-12-08 02:39:04 -0800691static int sx_send_command(struct sx_port *port,
692 int command, int mask, int newstat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800694 func_enter2();
695 write_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat), command);
696 func_exit();
697 return sx_busy_wait_eq(port->board, CHAN_OFFSET(port, hi_hstat), mask,
698 newstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699}
700
Jiri Slaby15b611f2006-12-08 02:39:04 -0800701static char *mod_type_s(int module_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 switch (module_type) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800704 case TA4:
705 return "TA4";
706 case TA8:
707 return "TA8";
708 case TA4_ASIC:
709 return "TA4_ASIC";
710 case TA8_ASIC:
711 return "TA8_ASIC";
712 case MTA_CD1400:
713 return "MTA_CD1400";
714 case SXDC:
715 return "SXDC";
716 default:
717 return "Unknown/invalid";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 }
719}
720
Jiri Slaby15b611f2006-12-08 02:39:04 -0800721static char *pan_type_s(int pan_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
723 switch (pan_type) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800724 case MOD_RS232DB25:
725 return "MOD_RS232DB25";
726 case MOD_RS232RJ45:
727 return "MOD_RS232RJ45";
728 case MOD_RS422DB25:
729 return "MOD_RS422DB25";
730 case MOD_PARALLEL:
731 return "MOD_PARALLEL";
732 case MOD_2_RS232DB25:
733 return "MOD_2_RS232DB25";
734 case MOD_2_RS232RJ45:
735 return "MOD_2_RS232RJ45";
736 case MOD_2_RS422DB25:
737 return "MOD_2_RS422DB25";
738 case MOD_RS232DB25MALE:
739 return "MOD_RS232DB25MALE";
740 case MOD_2_PARALLEL:
741 return "MOD_2_PARALLEL";
742 case MOD_BLANK:
743 return "empty";
744 default:
745 return "invalid";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 }
747}
748
Jiri Slaby15b611f2006-12-08 02:39:04 -0800749static int mod_compat_type(int module_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
751 return module_type >> 4;
752}
753
754static void sx_reconfigure_port(struct sx_port *port)
755{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800756 if (sx_read_channel_byte(port, hi_hstat) == HS_IDLE_OPEN) {
757 if (sx_send_command(port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
758 printk(KERN_WARNING "sx: Sent reconfigure command, but "
759 "card didn't react.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 }
761 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800762 sx_dprintk(SX_DEBUG_TERMIOS, "sx: Not sending reconfigure: "
763 "port isn't open (%02x).\n",
764 sx_read_channel_byte(port, hi_hstat));
765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Jiri Slaby15b611f2006-12-08 02:39:04 -0800768static void sx_setsignals(struct sx_port *port, int dtr, int rts)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
770 int t;
Jiri Slaby15b611f2006-12-08 02:39:04 -0800771 func_enter2();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Jiri Slaby15b611f2006-12-08 02:39:04 -0800773 t = sx_read_channel_byte(port, hi_op);
774 if (dtr >= 0)
775 t = dtr ? (t | OP_DTR) : (t & ~OP_DTR);
776 if (rts >= 0)
777 t = rts ? (t | OP_RTS) : (t & ~OP_RTS);
778 sx_write_channel_byte(port, hi_op, t);
779 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Jiri Slaby15b611f2006-12-08 02:39:04 -0800781 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
Jiri Slaby15b611f2006-12-08 02:39:04 -0800784static int sx_getsignals(struct sx_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785{
Jiri Slaby15b611f2006-12-08 02:39:04 -0800786 int i_stat, o_stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Jiri Slaby15b611f2006-12-08 02:39:04 -0800788 o_stat = sx_read_channel_byte(port, hi_op);
789 i_stat = sx_read_channel_byte(port, hi_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Jiri Slaby15b611f2006-12-08 02:39:04 -0800791 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d (%d/%d) "
792 "%02x/%02x\n",
793 (o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
794 port->c_dcd, sx_get_CD(port),
795 sx_read_channel_byte(port, hi_ip),
796 sx_read_channel_byte(port, hi_state));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Jiri Slaby15b611f2006-12-08 02:39:04 -0800798 return (((o_stat & OP_DTR) ? TIOCM_DTR : 0) |
799 ((o_stat & OP_RTS) ? TIOCM_RTS : 0) |
800 ((i_stat & IP_CTS) ? TIOCM_CTS : 0) |
801 ((i_stat & IP_DCD) ? TIOCM_CAR : 0) |
802 ((i_stat & IP_DSR) ? TIOCM_DSR : 0) |
803 ((i_stat & IP_RI) ? TIOCM_RNG : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804}
805
Jiri Slaby15b611f2006-12-08 02:39:04 -0800806static void sx_set_baud(struct sx_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 int t;
809
810 if (port->board->ta_type == MOD_SXDC) {
811 switch (port->gs.baud) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800812 /* Save some typing work... */
813#define e(x) case x: t = BAUD_ ## x; break
814 e(50);
815 e(75);
816 e(110);
817 e(150);
818 e(200);
819 e(300);
820 e(600);
821 e(1200);
822 e(1800);
823 e(2000);
824 e(2400);
825 e(4800);
826 e(7200);
827 e(9600);
828 e(14400);
829 e(19200);
830 e(28800);
831 e(38400);
832 e(56000);
833 e(57600);
834 e(64000);
835 e(76800);
836 e(115200);
837 e(128000);
838 e(150000);
839 e(230400);
840 e(256000);
841 e(460800);
842 e(921600);
843 case 134:
844 t = BAUD_134_5;
845 break;
846 case 0:
847 t = -1;
848 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 default:
850 /* Can I return "invalid"? */
851 t = BAUD_9600;
Jiri Slaby15b611f2006-12-08 02:39:04 -0800852 printk(KERN_INFO "sx: unsupported baud rate: %d.\n",
853 port->gs.baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 break;
855 }
856#undef e
857 if (t > 0) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800858/* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
859 sx_setsignals(port, 1, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 /* XXX This is not TA & MTA compatible */
Jiri Slaby15b611f2006-12-08 02:39:04 -0800861 sx_write_channel_byte(port, hi_csr, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Jiri Slaby15b611f2006-12-08 02:39:04 -0800863 sx_write_channel_byte(port, hi_txbaud, t);
864 sx_write_channel_byte(port, hi_rxbaud, t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800866 sx_setsignals(port, 0, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868 } else {
869 switch (port->gs.baud) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800870#define e(x) case x: t = CSR_ ## x; break
871 e(75);
872 e(150);
873 e(300);
874 e(600);
875 e(1200);
876 e(2400);
877 e(4800);
878 e(1800);
879 e(9600);
880 e(19200);
881 e(57600);
882 e(38400);
883/* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
884 case 110:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if (port->board->ta_type == MOD_TA) {
886 t = CSR_110;
887 break;
888 } else {
889 t = CSR_9600;
Jiri Slaby15b611f2006-12-08 02:39:04 -0800890 printk(KERN_INFO "sx: Unsupported baud rate: "
891 "%d.\n", port->gs.baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 break;
893 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800894 case 115200:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if (port->board->ta_type == MOD_TA) {
896 t = CSR_9600;
Jiri Slaby15b611f2006-12-08 02:39:04 -0800897 printk(KERN_INFO "sx: Unsupported baud rate: "
898 "%d.\n", port->gs.baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 break;
900 } else {
901 t = CSR_110;
902 break;
903 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800904 case 0:
905 t = -1;
906 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 default:
908 t = CSR_9600;
Jiri Slaby15b611f2006-12-08 02:39:04 -0800909 printk(KERN_INFO "sx: Unsupported baud rate: %d.\n",
910 port->gs.baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 break;
912 }
913#undef e
914 if (t >= 0) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800915 sx_setsignals(port, 1, -1);
916 sx_write_channel_byte(port, hi_csr, t * 0x11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800918 sx_setsignals(port, 0, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 }
920 }
921}
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
924 better. -- REW */
925
Jiri Slaby15b611f2006-12-08 02:39:04 -0800926static int sx_set_real_termios(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 struct sx_port *port = ptr;
929
930 func_enter2();
931
Alan Coxb5391e22008-07-16 21:55:20 +0100932 if (!port->gs.port.tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return 0;
934
935 /* What is this doing here? -- REW
936 Ha! figured it out. It is to allow you to get DTR active again
937 if you've dropped it with stty 0. Moved to set_baud, where it
938 belongs (next to the drop dtr if baud == 0) -- REW */
939 /* sx_setsignals (port, 1, -1); */
940
Jiri Slaby15b611f2006-12-08 02:39:04 -0800941 sx_set_baud(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Alan Coxb5391e22008-07-16 21:55:20 +0100943#define CFLAG port->gs.port.tty->termios->c_cflag
Jiri Slaby15b611f2006-12-08 02:39:04 -0800944 sx_write_channel_byte(port, hi_mr1,
Alan Coxb5391e22008-07-16 21:55:20 +0100945 (C_PARENB(port->gs.port.tty) ? MR1_WITH : MR1_NONE) |
946 (C_PARODD(port->gs.port.tty) ? MR1_ODD : MR1_EVEN) |
947 (C_CRTSCTS(port->gs.port.tty) ? MR1_RTS_RXFLOW : 0) |
Jiri Slaby15b611f2006-12-08 02:39:04 -0800948 (((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) |
949 (((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) |
950 (((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) |
951 (((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Jiri Slaby15b611f2006-12-08 02:39:04 -0800953 sx_write_channel_byte(port, hi_mr2,
Alan Coxb5391e22008-07-16 21:55:20 +0100954 (C_CRTSCTS(port->gs.port.tty) ? MR2_CTS_TXFLOW : 0) |
955 (C_CSTOPB(port->gs.port.tty) ? MR2_2_STOP :
Jiri Slaby15b611f2006-12-08 02:39:04 -0800956 MR2_1_STOP));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 switch (CFLAG & CSIZE) {
Jiri Slaby15b611f2006-12-08 02:39:04 -0800959 case CS8:
960 sx_write_channel_byte(port, hi_mask, 0xff);
961 break;
962 case CS7:
963 sx_write_channel_byte(port, hi_mask, 0x7f);
964 break;
965 case CS6:
966 sx_write_channel_byte(port, hi_mask, 0x3f);
967 break;
968 case CS5:
969 sx_write_channel_byte(port, hi_mask, 0x1f);
970 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 default:
Andrew Morton32fb3ca2008-05-06 20:42:35 -0700972 printk(KERN_INFO "sx: Invalid wordsize: %u\n",
973 (unsigned int)CFLAG & CSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 break;
975 }
976
Jiri Slaby15b611f2006-12-08 02:39:04 -0800977 sx_write_channel_byte(port, hi_prtcl,
Alan Coxb5391e22008-07-16 21:55:20 +0100978 (I_IXON(port->gs.port.tty) ? SP_TXEN : 0) |
979 (I_IXOFF(port->gs.port.tty) ? SP_RXEN : 0) |
980 (I_IXANY(port->gs.port.tty) ? SP_TANY : 0) | SP_DCEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Jiri Slaby15b611f2006-12-08 02:39:04 -0800982 sx_write_channel_byte(port, hi_break,
Alan Coxb5391e22008-07-16 21:55:20 +0100983 (I_IGNBRK(port->gs.port.tty) ? BR_IGN : 0 |
984 I_BRKINT(port->gs.port.tty) ? BR_INT : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Alan Coxb5391e22008-07-16 21:55:20 +0100986 sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.port.tty));
987 sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.port.tty));
988 sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.port.tty));
989 sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.port.tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 sx_reconfigure_port(port);
992
993 /* Tell line discipline whether we will do input cooking */
Alan Coxb5391e22008-07-16 21:55:20 +0100994 if (I_OTHER(port->gs.port.tty)) {
995 clear_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 } else {
Alan Coxb5391e22008-07-16 21:55:20 +0100997 set_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
Jiri Slaby15b611f2006-12-08 02:39:04 -0800999 sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
Alan Coxb5391e22008-07-16 21:55:20 +01001000 (unsigned int)port->gs.port.tty->termios->c_iflag,
1001 I_OTHER(port->gs.port.tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003/* Tell line discipline whether we will do output cooking.
1004 * If OPOST is set and no other output flags are set then we can do output
1005 * processing. Even if only *one* other flag in the O_OTHER group is set
1006 * we do cooking in software.
1007 */
Alan Coxb5391e22008-07-16 21:55:20 +01001008 if (O_OPOST(port->gs.port.tty) && !O_OTHER(port->gs.port.tty)) {
1009 set_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 } else {
Alan Coxb5391e22008-07-16 21:55:20 +01001011 clear_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08001013 sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
Alan Coxb5391e22008-07-16 21:55:20 +01001014 (unsigned int)port->gs.port.tty->termios->c_oflag,
1015 O_OTHER(port->gs.port.tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /* port->c_dcd = sx_get_CD (port); */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001017 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return 0;
1019}
1020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021/* ********************************************************************** *
1022 * the interrupt related routines *
1023 * ********************************************************************** */
1024
1025/* Note:
1026 Other drivers use the macro "MIN" to calculate how much to copy.
1027 This has the disadvantage that it will evaluate parts twice. That's
1028 expensive when it's IO (and the compiler cannot optimize those away!).
1029 Moreover, I'm not sure that you're race-free.
1030
1031 I assign a value, and then only allow the value to decrease. This
1032 is always safe. This makes the code a few lines longer, and you
1033 know I'm dead against that, but I think it is required in this
1034 case. */
1035
Jiri Slaby15b611f2006-12-08 02:39:04 -08001036static void sx_transmit_chars(struct sx_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
1038 int c;
1039 int tx_ip;
1040 int txroom;
1041
Jiri Slaby15b611f2006-12-08 02:39:04 -08001042 func_enter2();
1043 sx_dprintk(SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
1044 port, port->gs.xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Jiri Slaby15b611f2006-12-08 02:39:04 -08001046 if (test_and_set_bit(SX_PORT_TRANSMIT_LOCK, &port->locks)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 return;
1048 }
1049
1050 while (1) {
1051 c = port->gs.xmit_cnt;
1052
Jiri Slaby15b611f2006-12-08 02:39:04 -08001053 sx_dprintk(SX_DEBUG_TRANSMIT, "Copying %d ", c);
1054 tx_ip = sx_read_channel_byte(port, hi_txipos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056 /* Took me 5 minutes to deduce this formula.
1057 Luckily it is literally in the manual in section 6.5.4.3.5 */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001058 txroom = (sx_read_channel_byte(port, hi_txopos) - tx_ip - 1) &
1059 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 /* Don't copy more bytes than there is room for in the buffer */
1062 if (c > txroom)
1063 c = txroom;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001064 sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 /* Don't copy past the end of the hardware transmit buffer */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001067 if (c > 0x100 - tx_ip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 c = 0x100 - tx_ip;
1069
Jiri Slaby15b611f2006-12-08 02:39:04 -08001070 sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100 - tx_ip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 /* Don't copy pas the end of the source buffer */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001073 if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
1075
Jiri Slaby15b611f2006-12-08 02:39:04 -08001076 sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%ld) \n",
1077 c, SERIAL_XMIT_SIZE - port->gs.xmit_tail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Jiri Slaby15b611f2006-12-08 02:39:04 -08001079 /* If for one reason or another, we can't copy more data, we're
1080 done! */
1081 if (c == 0)
1082 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Jiri Slaby15b611f2006-12-08 02:39:04 -08001084 memcpy_toio(port->board->base + CHAN_OFFSET(port, hi_txbuf) +
1085 tx_ip, port->gs.xmit_buf + port->gs.xmit_tail, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
1087 /* Update the pointer in the card */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001088 sx_write_channel_byte(port, hi_txipos, (tx_ip + c) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090 /* Update the kernel buffer end */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001091 port->gs.xmit_tail = (port->gs.xmit_tail + c) &
1092 (SERIAL_XMIT_SIZE - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 /* This one last. (this is essential)
Jiri Slaby15b611f2006-12-08 02:39:04 -08001095 It would allow others to start putting more data into the
1096 buffer! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 port->gs.xmit_cnt -= c;
1098 }
1099
1100 if (port->gs.xmit_cnt == 0) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001101 sx_disable_tx_interrupts(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 }
1103
Alan Coxb5391e22008-07-16 21:55:20 +01001104 if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) {
1105 tty_wakeup(port->gs.port.tty);
Jiri Slaby15b611f2006-12-08 02:39:04 -08001106 sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
1107 port->gs.wakeup_chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 }
1109
Jiri Slaby15b611f2006-12-08 02:39:04 -08001110 clear_bit(SX_PORT_TRANSMIT_LOCK, &port->locks);
1111 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112}
1113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114/* Note the symmetry between receiving chars and transmitting them!
1115 Note: The kernel should have implemented both a receive buffer and
1116 a transmit buffer. */
1117
1118/* Inlined: Called only once. Remove the inline when you add another call */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001119static inline void sx_receive_chars(struct sx_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120{
1121 int c;
1122 int rx_op;
1123 struct tty_struct *tty;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001124 int copied = 0;
Alan Cox33f0f882006-01-09 20:54:13 -08001125 unsigned char *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Jiri Slaby15b611f2006-12-08 02:39:04 -08001127 func_enter2();
Alan Coxb5391e22008-07-16 21:55:20 +01001128 tty = port->gs.port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 while (1) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001130 rx_op = sx_read_channel_byte(port, hi_rxopos);
1131 c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Jiri Slaby15b611f2006-12-08 02:39:04 -08001133 sx_dprintk(SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Marc Zyngierd904ffd2006-02-27 12:08:00 +01001135 /* Don't copy past the end of the hardware receive buffer */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001136 if (rx_op + c > 0x100)
1137 c = 0x100 - rx_op;
Marc Zyngierd904ffd2006-02-27 12:08:00 +01001138
Jiri Slaby15b611f2006-12-08 02:39:04 -08001139 sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
Marc Zyngierd904ffd2006-02-27 12:08:00 +01001140
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 /* Don't copy more bytes than there is room for in the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001142
1143 c = tty_prepare_flip_string(tty, &rp, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Jiri Slaby15b611f2006-12-08 02:39:04 -08001145 sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 /* If for one reason or another, we can't copy more data, we're done! */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001148 if (c == 0)
1149 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Jiri Slaby15b611f2006-12-08 02:39:04 -08001151 sx_dprintk(SX_DEBUG_RECEIVE, "Copying over %d chars. First is "
1152 "%d at %lx\n", c, read_sx_byte(port->board,
1153 CHAN_OFFSET(port, hi_rxbuf) + rx_op),
1154 CHAN_OFFSET(port, hi_rxbuf));
1155 memcpy_fromio(rp, port->board->base +
1156 CHAN_OFFSET(port, hi_rxbuf) + rx_op, c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
1158 /* This one last. ( Not essential.)
Jiri Slaby15b611f2006-12-08 02:39:04 -08001159 It allows the card to start putting more data into the
1160 buffer!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 Update the pointer in the card */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001162 sx_write_channel_byte(port, hi_rxopos, (rx_op + c) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 copied += c;
1165 }
1166 if (copied) {
1167 struct timeval tv;
1168
Jiri Slaby15b611f2006-12-08 02:39:04 -08001169 do_gettimeofday(&tv);
1170 sx_dprintk(SX_DEBUG_RECEIVE, "pushing flipq port %d (%3d "
1171 "chars): %d.%06d (%d/%d)\n", port->line,
1172 copied, (int)(tv.tv_sec % 60), (int)tv.tv_usec,
1173 tty->raw, tty->real_raw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Jiri Slaby15b611f2006-12-08 02:39:04 -08001175 /* Tell the rest of the system the news. Great news. New
1176 characters! */
1177 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 /* tty_schedule_flip (tty); */
1179 }
1180
Jiri Slaby15b611f2006-12-08 02:39:04 -08001181 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182}
1183
1184/* Inlined: it is called only once. Remove the inline if you add another
1185 call */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001186static inline void sx_check_modem_signals(struct sx_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187{
1188 int hi_state;
1189 int c_dcd;
1190
Jiri Slaby15b611f2006-12-08 02:39:04 -08001191 hi_state = sx_read_channel_byte(port, hi_state);
1192 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
1193 port->c_dcd, sx_get_CD(port));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195 if (hi_state & ST_BREAK) {
1196 hi_state &= ~ST_BREAK;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001197 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a break.\n");
1198 sx_write_channel_byte(port, hi_state, hi_state);
1199 gs_got_break(&port->gs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 }
1201 if (hi_state & ST_DCD) {
1202 hi_state &= ~ST_DCD;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001203 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
1204 sx_write_channel_byte(port, hi_state, hi_state);
1205 c_dcd = sx_get_CD(port);
1206 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (c_dcd != port->c_dcd) {
1208 port->c_dcd = c_dcd;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001209 if (sx_get_CD(port)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 /* DCD went UP */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001211 if ((sx_read_channel_byte(port, hi_hstat) !=
1212 HS_IDLE_CLOSED) &&
Alan Coxb5391e22008-07-16 21:55:20 +01001213 !(port->gs.port.tty->termios->
Jiri Slaby15b611f2006-12-08 02:39:04 -08001214 c_cflag & CLOCAL)) {
1215 /* Are we blocking in open? */
1216 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
1217 "active, unblocking open\n");
Alan Coxb5391e22008-07-16 21:55:20 +01001218 wake_up_interruptible(&port->gs.port.
Jiri Slaby15b611f2006-12-08 02:39:04 -08001219 open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001221 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
1222 "raised. Ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 }
1224 } else {
1225 /* DCD went down! */
Alan Coxb5391e22008-07-16 21:55:20 +01001226 if (!(port->gs.port.tty->termios->c_cflag & CLOCAL)){
Jiri Slaby15b611f2006-12-08 02:39:04 -08001227 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
1228 "dropped. hanging up....\n");
Alan Coxb5391e22008-07-16 21:55:20 +01001229 tty_hangup(port->gs.port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001231 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
1232 "dropped. ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 }
1234 }
1235 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001236 sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us "
1237 "DCD changed, but it didn't.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 }
1239 }
1240}
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242/* This is what an interrupt routine should look like.
1243 * Small, elegant, clear.
1244 */
1245
Jiri Slaby15b611f2006-12-08 02:39:04 -08001246static irqreturn_t sx_interrupt(int irq, void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
1248 struct sx_board *board = ptr;
1249 struct sx_port *port;
1250 int i;
1251
Jiri Slaby15b611f2006-12-08 02:39:04 -08001252 func_enter();
1253 sx_dprintk(SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq,
1254 board->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 /* AAargh! The order in which to do these things is essential and
1257 not trivial.
1258
1259 - Rate limit goes before "recursive". Otherwise a series of
Jiri Slaby15b611f2006-12-08 02:39:04 -08001260 recursive calls will hang the machine in the interrupt routine.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
1262 - hardware twiddling goes before "recursive". Otherwise when we
Jiri Slaby15b611f2006-12-08 02:39:04 -08001263 poll the card, and a recursive interrupt happens, we won't
1264 ack the card, so it might keep on interrupting us. (especially
1265 level sensitive interrupt systems like PCI).
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
1267 - Rate limit goes before hardware twiddling. Otherwise we won't
Jiri Slaby15b611f2006-12-08 02:39:04 -08001268 catch a card that has gone bonkers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 - The "initialized" test goes after the hardware twiddling. Otherwise
Jiri Slaby15b611f2006-12-08 02:39:04 -08001271 the card will stick us in the interrupt routine again.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273 - The initialized test goes before recursive.
Jiri Slaby15b611f2006-12-08 02:39:04 -08001274 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
1276#ifdef IRQ_RATE_LIMIT
1277 /* Aaargh! I'm ashamed. This costs more lines-of-code than the
Jiri Slaby15b611f2006-12-08 02:39:04 -08001278 actual interrupt routine!. (Well, used to when I wrote that
1279 comment) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 {
1281 static int lastjif;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001282 static int nintr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
1284 if (lastjif == jiffies) {
1285 if (++nintr > IRQ_RATE_LIMIT) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001286 free_irq(board->irq, board);
1287 printk(KERN_ERR "sx: Too many interrupts. "
1288 "Turning off interrupt %d.\n",
1289 board->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
1291 } else {
1292 lastjif = jiffies;
1293 nintr = 0;
1294 }
1295 }
1296#endif
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (board->irq == irq) {
1299 /* Tell the card we've noticed the interrupt. */
1300
Jiri Slaby15b611f2006-12-08 02:39:04 -08001301 sx_write_board_word(board, cc_int_pending, 0);
1302 if (IS_SX_BOARD(board)) {
1303 write_sx_byte(board, SX_RESET_IRQ, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 } else if (IS_EISA_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001305 inb(board->eisa_base + 0xc03);
1306 write_sx_word(board, 8, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001308 write_sx_byte(board, SI2_ISA_INTCLEAR,
1309 SI2_ISA_INTCLEAR_CLEAR);
1310 write_sx_byte(board, SI2_ISA_INTCLEAR,
1311 SI2_ISA_INTCLEAR_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 }
1313 }
1314
1315 if (!sx_initialized)
1316 return IRQ_HANDLED;
1317 if (!(board->flags & SX_BOARD_INITIALIZED))
1318 return IRQ_HANDLED;
1319
Jiri Slaby15b611f2006-12-08 02:39:04 -08001320 if (test_and_set_bit(SX_BOARD_INTR_LOCK, &board->locks)) {
1321 printk(KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 return IRQ_HANDLED;
1323 }
1324
Jiri Slaby15b611f2006-12-08 02:39:04 -08001325 for (i = 0; i < board->nports; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 port = &board->ports[i];
Alan Coxb5391e22008-07-16 21:55:20 +01001327 if (port->gs.port.flags & GS_ACTIVE) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001328 if (sx_read_channel_byte(port, hi_state)) {
1329 sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: "
1330 "modem signal change?... \n",i);
1331 sx_check_modem_signals(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
1333 if (port->gs.xmit_cnt) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001334 sx_transmit_chars(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
Alan Coxb5391e22008-07-16 21:55:20 +01001336 if (!(port->gs.port.flags & SX_RX_THROTTLE)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001337 sx_receive_chars(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339 }
1340 }
1341
Jiri Slaby15b611f2006-12-08 02:39:04 -08001342 clear_bit(SX_BOARD_INTR_LOCK, &board->locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Jiri Slaby15b611f2006-12-08 02:39:04 -08001344 sx_dprintk(SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq,
1345 board->irq);
1346 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 return IRQ_HANDLED;
1348}
1349
Jiri Slaby15b611f2006-12-08 02:39:04 -08001350static void sx_pollfunc(unsigned long data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Jiri Slaby15b611f2006-12-08 02:39:04 -08001352 struct sx_board *board = (struct sx_board *)data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Jiri Slaby15b611f2006-12-08 02:39:04 -08001354 func_enter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Jiri Slaby15b611f2006-12-08 02:39:04 -08001356 sx_interrupt(0, board);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Jiri Slabyc9594642006-12-08 02:39:05 -08001358 mod_timer(&board->timer, jiffies + sx_poll);
Jiri Slaby15b611f2006-12-08 02:39:04 -08001359 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360}
1361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362/* ********************************************************************** *
1363 * Here are the routines that actually *
1364 * interface with the generic_serial driver *
1365 * ********************************************************************** */
1366
1367/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
1368/* Hmm. Ok I figured it out. You don't. */
1369
Jiri Slaby15b611f2006-12-08 02:39:04 -08001370static void sx_disable_tx_interrupts(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
Jiri Slaby15b611f2006-12-08 02:39:04 -08001372 struct sx_port *port = ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 func_enter2();
1374
Alan Coxb5391e22008-07-16 21:55:20 +01001375 port->gs.port.flags &= ~GS_TX_INTEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
1377 func_exit();
1378}
1379
Jiri Slaby15b611f2006-12-08 02:39:04 -08001380static void sx_enable_tx_interrupts(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
Jiri Slaby15b611f2006-12-08 02:39:04 -08001382 struct sx_port *port = ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 int data_in_buffer;
1384 func_enter2();
1385
1386 /* First transmit the characters that we're supposed to */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001387 sx_transmit_chars(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 /* The sx card will never interrupt us if we don't fill the buffer
1390 past 25%. So we keep considering interrupts off if that's the case. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001391 data_in_buffer = (sx_read_channel_byte(port, hi_txipos) -
1392 sx_read_channel_byte(port, hi_txopos)) & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 /* XXX Must be "HIGH_WATER" for SI card according to doc. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001395 if (data_in_buffer < LOW_WATER)
Alan Coxb5391e22008-07-16 21:55:20 +01001396 port->gs.port.flags &= ~GS_TX_INTEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398 func_exit();
1399}
1400
Jiri Slaby15b611f2006-12-08 02:39:04 -08001401static void sx_disable_rx_interrupts(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402{
1403 /* struct sx_port *port = ptr; */
1404 func_enter();
1405
1406 func_exit();
1407}
1408
Jiri Slaby15b611f2006-12-08 02:39:04 -08001409static void sx_enable_rx_interrupts(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
1411 /* struct sx_port *port = ptr; */
1412 func_enter();
1413
1414 func_exit();
1415}
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417/* Jeez. Isn't this simple? */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001418static int sx_get_CD(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419{
1420 struct sx_port *port = ptr;
1421 func_enter2();
1422
1423 func_exit();
Jiri Slaby15b611f2006-12-08 02:39:04 -08001424 return ((sx_read_channel_byte(port, hi_ip) & IP_DCD) != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425}
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427/* Jeez. Isn't this simple? */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001428static int sx_chars_in_buffer(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429{
1430 struct sx_port *port = ptr;
1431 func_enter2();
1432
1433 func_exit();
Jiri Slaby15b611f2006-12-08 02:39:04 -08001434 return ((sx_read_channel_byte(port, hi_txipos) -
1435 sx_read_channel_byte(port, hi_txopos)) & 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436}
1437
Jiri Slaby15b611f2006-12-08 02:39:04 -08001438static void sx_shutdown_port(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439{
Jiri Slaby15b611f2006-12-08 02:39:04 -08001440 struct sx_port *port = ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 func_enter();
1443
Alan Coxb5391e22008-07-16 21:55:20 +01001444 port->gs.port.flags &= ~GS_ACTIVE;
1445 if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001446 sx_setsignals(port, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 sx_reconfigure_port(port);
1448 }
1449
1450 func_exit();
1451}
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453/* ********************************************************************** *
1454 * Here are the routines that actually *
1455 * interface with the rest of the system *
1456 * ********************************************************************** */
1457
Jiri Slaby15b611f2006-12-08 02:39:04 -08001458static int sx_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
1460 struct sx_port *port;
1461 int retval, line;
1462 unsigned long flags;
1463
1464 func_enter();
1465
1466 if (!sx_initialized) {
1467 return -EIO;
1468 }
1469
1470 line = tty->index;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001471 sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -07001472 "np=%d)\n", task_pid_nr(current), line, tty,
Jiri Slaby15b611f2006-12-08 02:39:04 -08001473 current->signal->tty, sx_nports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
1475 if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
1476 return -ENODEV;
1477
Jiri Slaby15b611f2006-12-08 02:39:04 -08001478 port = &sx_ports[line];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
Jiri Slaby15b611f2006-12-08 02:39:04 -08001480 1 -> 0 transition. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
Jiri Slaby15b611f2006-12-08 02:39:04 -08001482 sx_dprintk(SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 spin_lock_irqsave(&port->gs.driver_lock, flags);
1485
1486 tty->driver_data = port;
Alan Coxb5391e22008-07-16 21:55:20 +01001487 port->gs.port.tty = tty;
1488 port->gs.port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 spin_unlock_irqrestore(&port->gs.driver_lock, flags);
1490
Jiri Slaby15b611f2006-12-08 02:39:04 -08001491 sx_dprintk(SX_DEBUG_OPEN, "starting port\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492
1493 /*
1494 * Start up serial port
1495 */
1496 retval = gs_init_port(&port->gs);
Jiri Slaby15b611f2006-12-08 02:39:04 -08001497 sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (retval) {
Alan Coxb5391e22008-07-16 21:55:20 +01001499 port->gs.port.count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 return retval;
1501 }
1502
Alan Coxb5391e22008-07-16 21:55:20 +01001503 port->gs.port.flags |= GS_ACTIVE;
1504 if (port->gs.port.count <= 1)
Jiri Slaby15b611f2006-12-08 02:39:04 -08001505 sx_setsignals(port, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
1507#if 0
1508 if (sx_debug & SX_DEBUG_OPEN)
Jiri Slaby15b611f2006-12-08 02:39:04 -08001509 my_hd(port, sizeof(*port));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510#else
1511 if (sx_debug & SX_DEBUG_OPEN)
Jiri Slaby15b611f2006-12-08 02:39:04 -08001512 my_hd_io(port->board->base + port->ch_base, sizeof(*port));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513#endif
1514
Alan Coxb5391e22008-07-16 21:55:20 +01001515 if (port->gs.port.count <= 1) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001516 if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
1517 printk(KERN_ERR "sx: Card didn't respond to LOPEN "
1518 "command.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 spin_lock_irqsave(&port->gs.driver_lock, flags);
Alan Coxb5391e22008-07-16 21:55:20 +01001520 port->gs.port.count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 spin_unlock_irqrestore(&port->gs.driver_lock, flags);
1522 return -EIO;
1523 }
1524 }
1525
1526 retval = gs_block_til_ready(port, filp);
Jiri Slaby15b611f2006-12-08 02:39:04 -08001527 sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
Alan Coxb5391e22008-07-16 21:55:20 +01001528 retval, port->gs.port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 if (retval) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001531/*
Alan Coxb5391e22008-07-16 21:55:20 +01001532 * Don't lower gs.port.count here because sx_close() will be called later
Jiri Slaby15b611f2006-12-08 02:39:04 -08001533 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535 return retval;
1536 }
1537 /* tty->low_latency = 1; */
1538
Jiri Slaby15b611f2006-12-08 02:39:04 -08001539 port->c_dcd = sx_get_CD(port);
1540 sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542 func_exit();
1543 return 0;
1544
1545}
1546
Jiri Slaby15b611f2006-12-08 02:39:04 -08001547static void sx_close(void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548{
Jiri Slaby15b611f2006-12-08 02:39:04 -08001549 struct sx_port *port = ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 /* Give the port 5 seconds to close down. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001551 int to = 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
Jiri Slaby15b611f2006-12-08 02:39:04 -08001553 func_enter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Jiri Slaby15b611f2006-12-08 02:39:04 -08001555 sx_setsignals(port, 0, 0);
1556 sx_reconfigure_port(port);
1557 sx_send_command(port, HS_CLOSE, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Jiri Slaby15b611f2006-12-08 02:39:04 -08001559 while (to-- && (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 if (msleep_interruptible(10))
1561 break;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001562 if (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) {
1563 if (sx_send_command(port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED)
1564 != 1) {
1565 printk(KERN_ERR "sx: sent the force_close command, but "
1566 "card didn't react\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 } else
Jiri Slaby15b611f2006-12-08 02:39:04 -08001568 sx_dprintk(SX_DEBUG_CLOSE, "sent the force_close "
1569 "command.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
1571
Jiri Slaby15b611f2006-12-08 02:39:04 -08001572 sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
Alan Coxb5391e22008-07-16 21:55:20 +01001573 5 * HZ - to - 1, port->gs.port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Alan Coxb5391e22008-07-16 21:55:20 +01001575 if (port->gs.port.count) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001576 sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
Alan Coxb5391e22008-07-16 21:55:20 +01001577 port->gs.port.count);
Jiri Slaby15b611f2006-12-08 02:39:04 -08001578 /*printk("%s SETTING port count to zero: %p count: %d\n",
Alan Coxb5391e22008-07-16 21:55:20 +01001579 __func__, port, port->gs.port.count);
1580 port->gs.port.count = 0;*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
1582
Jiri Slaby15b611f2006-12-08 02:39:04 -08001583 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584}
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586/* This is relatively thorough. But then again it is only 20 lines. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001587#define MARCHUP for (i = min; i < max; i++)
1588#define MARCHDOWN for (i = max - 1; i >= min; i--)
1589#define W0 write_sx_byte(board, i, 0x55)
1590#define W1 write_sx_byte(board, i, 0xaa)
1591#define R0 if (read_sx_byte(board, i) != 0x55) return 1
1592#define R1 if (read_sx_byte(board, i) != 0xaa) return 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
1594/* This memtest takes a human-noticable time. You normally only do it
1595 once a boot, so I guess that it is worth it. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001596static int do_memtest(struct sx_board *board, int min, int max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
1598 int i;
1599
1600 /* This is a marchb. Theoretically, marchb catches much more than
1601 simpler tests. In practise, the longer test just catches more
1602 intermittent errors. -- REW
1603 (For the theory behind memory testing see:
1604 Testing Semiconductor Memories by A.J. van de Goor.) */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001605 MARCHUP {
1606 W0;
1607 }
1608 MARCHUP {
1609 R0;
1610 W1;
1611 R1;
1612 W0;
1613 R0;
1614 W1;
1615 }
1616 MARCHUP {
1617 R1;
1618 W0;
1619 W1;
1620 }
1621 MARCHDOWN {
1622 R1;
1623 W0;
1624 W1;
1625 W0;
1626 }
1627 MARCHDOWN {
1628 R0;
1629 W1;
1630 W0;
1631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 return 0;
1634}
1635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#undef MARCHUP
1637#undef MARCHDOWN
1638#undef W0
1639#undef W1
1640#undef R0
1641#undef R1
1642
Jiri Slaby15b611f2006-12-08 02:39:04 -08001643#define MARCHUP for (i = min; i < max; i += 2)
1644#define MARCHDOWN for (i = max - 1; i >= min; i -= 2)
1645#define W0 write_sx_word(board, i, 0x55aa)
1646#define W1 write_sx_word(board, i, 0xaa55)
1647#define R0 if (read_sx_word(board, i) != 0x55aa) return 1
1648#define R1 if (read_sx_word(board, i) != 0xaa55) return 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650#if 0
1651/* This memtest takes a human-noticable time. You normally only do it
1652 once a boot, so I guess that it is worth it. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001653static int do_memtest_w(struct sx_board *board, int min, int max)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654{
1655 int i;
1656
Jiri Slaby15b611f2006-12-08 02:39:04 -08001657 MARCHUP {
1658 W0;
1659 }
1660 MARCHUP {
1661 R0;
1662 W1;
1663 R1;
1664 W0;
1665 R0;
1666 W1;
1667 }
1668 MARCHUP {
1669 R1;
1670 W0;
1671 W1;
1672 }
1673 MARCHDOWN {
1674 R1;
1675 W0;
1676 W1;
1677 W0;
1678 }
1679 MARCHDOWN {
1680 R0;
1681 W1;
1682 W0;
1683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
1685 return 0;
1686}
1687#endif
1688
Alan Cox11af7472008-07-25 01:48:15 -07001689static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
1690 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691{
Alan Cox11af7472008-07-25 01:48:15 -07001692 long rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 int __user *descr = (int __user *)arg;
1694 int i;
1695 static struct sx_board *board = NULL;
1696 int nbytes, offset;
1697 unsigned long data;
1698 char *tmp;
1699
1700 func_enter();
1701
Alan Cox11af7472008-07-25 01:48:15 -07001702 if (!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 return -EPERM;
Alan Cox11af7472008-07-25 01:48:15 -07001704
1705 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706
Jiri Slaby15b611f2006-12-08 02:39:04 -08001707 sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Jiri Slaby15b611f2006-12-08 02:39:04 -08001709 if (!board)
1710 board = &boards[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 if (board->flags & SX_BOARD_PRESENT) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001712 sx_dprintk(SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
1713 board->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001715 sx_dprintk(SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
1716 board->flags);
1717 for (i = 0; i < SX_NBOARDS; i++)
1718 sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
1719 sx_dprintk(SX_DEBUG_FIRMWARE, "\n");
Alan Cox11af7472008-07-25 01:48:15 -07001720 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 return -EIO;
1722 }
1723
1724 switch (cmd) {
1725 case SXIO_SET_BOARD:
Jiri Slaby15b611f2006-12-08 02:39:04 -08001726 sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
Alan Cox11af7472008-07-25 01:48:15 -07001727 rc = -EIO;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001728 if (arg >= SX_NBOARDS)
Alan Cox11af7472008-07-25 01:48:15 -07001729 break;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001730 sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");
1731 if (!(boards[arg].flags & SX_BOARD_PRESENT))
Alan Cox11af7472008-07-25 01:48:15 -07001732 break;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001733 sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 board = &boards[arg];
Alan Cox11af7472008-07-25 01:48:15 -07001735 rc = 0;
1736 /* FIXME: And this does ... nothing?? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 break;
1738 case SXIO_GET_TYPE:
Jiri Slaby15b611f2006-12-08 02:39:04 -08001739 rc = -ENOENT; /* If we manage to miss one, return error. */
1740 if (IS_SX_BOARD(board))
1741 rc = SX_TYPE_SX;
1742 if (IS_CF_BOARD(board))
1743 rc = SX_TYPE_CF;
1744 if (IS_SI_BOARD(board))
1745 rc = SX_TYPE_SI;
1746 if (IS_SI1_BOARD(board))
1747 rc = SX_TYPE_SI;
1748 if (IS_EISA_BOARD(board))
1749 rc = SX_TYPE_SI;
Alan Cox11af7472008-07-25 01:48:15 -07001750 sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 break;
1752 case SXIO_DO_RAMTEST:
Jiri Slaby15b611f2006-12-08 02:39:04 -08001753 if (sx_initialized) /* Already initialized: better not ramtest the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 return -EPERM;
Jiri Slaby15b611f2006-12-08 02:39:04 -08001755 if (IS_SX_BOARD(board)) {
1756 rc = do_memtest(board, 0, 0x7000);
1757 if (!rc)
1758 rc = do_memtest(board, 0, 0x7000);
1759 /*if (!rc) rc = do_memtest_w (board, 0, 0x7000); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001761 rc = do_memtest(board, 0, 0x7ff8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 /* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
1763 }
Alan Cox11af7472008-07-25 01:48:15 -07001764 sx_dprintk(SX_DEBUG_FIRMWARE,
1765 "returning memtest result= %ld\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 break;
1767 case SXIO_DOWNLOAD:
Alan Cox11af7472008-07-25 01:48:15 -07001768 if (sx_initialized) {/* Already initialized */
1769 rc = -EEXIST;
1770 break;
1771 }
1772 if (!sx_reset(board)) {
1773 rc = -EIO;
1774 break;
1775 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08001776 sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Jiri Slaby15b611f2006-12-08 02:39:04 -08001778 tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);
Alan Cox11af7472008-07-25 01:48:15 -07001779 if (!tmp) {
1780 rc = -ENOMEM;
1781 break;
1782 }
1783 /* FIXME: check returns */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001784 get_user(nbytes, descr++);
1785 get_user(offset, descr++);
1786 get_user(data, descr++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 while (nbytes && data) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08001788 for (i = 0; i < nbytes; i += SX_CHUNK_SIZE) {
1789 if (copy_from_user(tmp, (char __user *)data + i,
1790 (i + SX_CHUNK_SIZE > nbytes) ?
1791 nbytes - i : SX_CHUNK_SIZE)) {
1792 kfree(tmp);
Alan Cox11af7472008-07-25 01:48:15 -07001793 rc = -EFAULT;
1794 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08001796 memcpy_toio(board->base2 + offset + i, tmp,
1797 (i + SX_CHUNK_SIZE > nbytes) ?
1798 nbytes - i : SX_CHUNK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
1800
Jiri Slaby15b611f2006-12-08 02:39:04 -08001801 get_user(nbytes, descr++);
1802 get_user(offset, descr++);
1803 get_user(data, descr++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08001805 kfree(tmp);
1806 sx_nports += sx_init_board(board);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 rc = sx_nports;
1808 break;
1809 case SXIO_INIT:
Alan Cox11af7472008-07-25 01:48:15 -07001810 if (sx_initialized) { /* Already initialized */
1811 rc = -EEXIST;
1812 break;
1813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 /* This is not allowed until all boards are initialized... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001815 for (i = 0; i < SX_NBOARDS; i++) {
1816 if ((boards[i].flags & SX_BOARD_PRESENT) &&
Alan Cox11af7472008-07-25 01:48:15 -07001817 !(boards[i].flags & SX_BOARD_INITIALIZED)) {
1818 rc = -EIO;
1819 break;
1820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08001822 for (i = 0; i < SX_NBOARDS; i++)
1823 if (!(boards[i].flags & SX_BOARD_PRESENT))
1824 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Jiri Slaby15b611f2006-12-08 02:39:04 -08001826 sx_dprintk(SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
1827 "%d channels, first board: %d ports\n",
1828 i, sx_nports, boards[0].nports);
1829 rc = sx_init_portstructs(i, sx_nports);
1830 sx_init_drivers();
1831 if (rc >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 sx_initialized++;
1833 break;
1834 case SXIO_SETDEBUG:
1835 sx_debug = arg;
1836 break;
1837 case SXIO_GETDEBUG:
1838 rc = sx_debug;
1839 break;
1840 case SXIO_GETGSDEBUG:
1841 case SXIO_SETGSDEBUG:
1842 rc = -EINVAL;
1843 break;
1844 case SXIO_GETNPORTS:
1845 rc = sx_nports;
1846 break;
1847 default:
Alan Cox11af7472008-07-25 01:48:15 -07001848 rc = -ENOTTY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 break;
1850 }
Alan Cox11af7472008-07-25 01:48:15 -07001851 unlock_kernel();
Jiri Slaby15b611f2006-12-08 02:39:04 -08001852 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 return rc;
1854}
1855
Alan Cox9e989662008-07-22 11:18:03 +01001856static int sx_break(struct tty_struct *tty, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857{
1858 struct sx_port *port = tty->driver_data;
1859 int rv;
1860
Jiri Slaby15b611f2006-12-08 02:39:04 -08001861 func_enter();
Alan Cox341339e2008-04-30 00:53:24 -07001862 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
Jiri Slaby15b611f2006-12-08 02:39:04 -08001864 if (flag)
1865 rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
1866 else
1867 rv = sx_send_command(port, HS_STOP, -1, HS_IDLE_OPEN);
1868 if (rv != 1)
1869 printk(KERN_ERR "sx: couldn't send break (%x).\n",
1870 read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
Alan Cox341339e2008-04-30 00:53:24 -07001871 unlock_kernel();
Jiri Slaby15b611f2006-12-08 02:39:04 -08001872 func_exit();
Alan Cox9e989662008-07-22 11:18:03 +01001873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874}
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876static int sx_tiocmget(struct tty_struct *tty, struct file *file)
1877{
1878 struct sx_port *port = tty->driver_data;
1879 return sx_getsignals(port);
1880}
1881
1882static int sx_tiocmset(struct tty_struct *tty, struct file *file,
Jiri Slaby15b611f2006-12-08 02:39:04 -08001883 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
1885 struct sx_port *port = tty->driver_data;
1886 int rts = -1, dtr = -1;
1887
1888 if (set & TIOCM_RTS)
1889 rts = 1;
1890 if (set & TIOCM_DTR)
1891 dtr = 1;
1892 if (clear & TIOCM_RTS)
1893 rts = 0;
1894 if (clear & TIOCM_DTR)
1895 dtr = 0;
1896
1897 sx_setsignals(port, dtr, rts);
1898 sx_reconfigure_port(port);
1899 return 0;
1900}
1901
Jiri Slaby15b611f2006-12-08 02:39:04 -08001902static int sx_ioctl(struct tty_struct *tty, struct file *filp,
1903 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904{
1905 int rc;
1906 struct sx_port *port = tty->driver_data;
1907 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
1909 /* func_enter2(); */
1910
1911 rc = 0;
Alan Cox341339e2008-04-30 00:53:24 -07001912 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 case TIOCGSERIAL:
1915 rc = gs_getserial(&port->gs, argp);
1916 break;
1917 case TIOCSSERIAL:
1918 rc = gs_setserial(&port->gs, argp);
1919 break;
1920 default:
1921 rc = -ENOIOCTLCMD;
1922 break;
1923 }
Alan Cox341339e2008-04-30 00:53:24 -07001924 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
1926 /* func_exit(); */
1927 return rc;
1928}
1929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930/* The throttle/unthrottle scheme for the Specialix card is different
1931 * from other drivers and deserves some explanation.
1932 * The Specialix hardware takes care of XON/XOFF
1933 * and CTS/RTS flow control itself. This means that all we have to
1934 * do when signalled by the upper tty layer to throttle/unthrottle is
1935 * to make a note of it here. When we come to read characters from the
1936 * rx buffers on the card (sx_receive_chars()) we look to see if the
1937 * upper layer can accept more (as noted here in sx_rx_throt[]).
1938 * If it can't we simply don't remove chars from the cards buffer.
1939 * When the tty layer can accept chars, we again note that here and when
1940 * sx_receive_chars() is called it will remove them from the cards buffer.
1941 * The card will notice that a ports buffer has drained below some low
1942 * water mark and will unflow control the line itself, using whatever
1943 * flow control scheme is in use for that port. -- Simon Allen
1944 */
1945
Jiri Slaby15b611f2006-12-08 02:39:04 -08001946static void sx_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947{
1948 struct sx_port *port = (struct sx_port *)tty->driver_data;
1949
1950 func_enter2();
1951 /* If the port is using any type of input flow
1952 * control then throttle the port.
1953 */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001954 if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
Alan Coxb5391e22008-07-16 21:55:20 +01001955 port->gs.port.flags |= SX_RX_THROTTLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 }
1957 func_exit();
1958}
1959
Jiri Slaby15b611f2006-12-08 02:39:04 -08001960static void sx_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961{
1962 struct sx_port *port = (struct sx_port *)tty->driver_data;
1963
1964 func_enter2();
1965 /* Always unthrottle even if flow control is not enabled on
1966 * this port in case we disabled flow control while the port
1967 * was throttled
1968 */
Alan Coxb5391e22008-07-16 21:55:20 +01001969 port->gs.port.flags &= ~SX_RX_THROTTLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 func_exit();
1971 return;
1972}
1973
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974/* ********************************************************************** *
1975 * Here are the initialization routines. *
1976 * ********************************************************************** */
1977
Jiri Slaby15b611f2006-12-08 02:39:04 -08001978static int sx_init_board(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 int addr;
1981 int chans;
1982 int type;
1983
1984 func_enter();
1985
1986 /* This is preceded by downloading the download code. */
1987
1988 board->flags |= SX_BOARD_INITIALIZED;
1989
Jiri Slaby15b611f2006-12-08 02:39:04 -08001990 if (read_sx_byte(board, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 /* CF boards may need this. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001992 write_sx_byte(board, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 /* This resets the processor again, to make sure it didn't do any
1995 foolish things while we were downloading the image */
Jiri Slaby15b611f2006-12-08 02:39:04 -08001996 if (!sx_reset(board))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 return 0;
1998
Jiri Slaby15b611f2006-12-08 02:39:04 -08001999 sx_start_board(board);
2000 udelay(10);
2001 if (!sx_busy_wait_neq(board, 0, 0xff, 0)) {
2002 printk(KERN_ERR "sx: Ooops. Board won't initialize.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 return 0;
2004 }
2005
2006 /* Ok. So now the processor on the card is running. It gathered
2007 some info for us... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002008 sx_dprintk(SX_DEBUG_INIT, "The sxcard structure:\n");
2009 if (sx_debug & SX_DEBUG_INIT)
2010 my_hd_io(board->base, 0x10);
2011 sx_dprintk(SX_DEBUG_INIT, "the first sx_module structure:\n");
2012 if (sx_debug & SX_DEBUG_INIT)
2013 my_hd_io(board->base + 0x80, 0x30);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Jiri Slaby15b611f2006-12-08 02:39:04 -08002015 sx_dprintk(SX_DEBUG_INIT, "init_status: %x, %dk memory, firmware "
2016 "V%x.%02x,\n",
2017 read_sx_byte(board, 0), read_sx_byte(board, 1),
2018 read_sx_byte(board, 5), read_sx_byte(board, 4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Jiri Slaby15b611f2006-12-08 02:39:04 -08002020 if (read_sx_byte(board, 0) == 0xff) {
2021 printk(KERN_INFO "sx: No modules found. Sorry.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 board->nports = 0;
2023 return 0;
2024 }
2025
2026 chans = 0;
2027
2028 if (IS_SX_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002029 sx_write_board_word(board, cc_int_count, sx_maxints);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 } else {
2031 if (sx_maxints)
Jiri Slaby15b611f2006-12-08 02:39:04 -08002032 sx_write_board_word(board, cc_int_count,
2033 SI_PROCESSOR_CLOCK / 8 / sx_maxints);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 }
2035
2036 /* grab the first module type... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002037 /* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
2038 board->ta_type = mod_compat_type(sx_read_module_byte(board, 0x80,
2039 mc_chip));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
2041 /* XXX byteorder */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002042 for (addr = 0x80; addr != 0; addr = read_sx_word(board, addr) & 0x7fff){
2043 type = sx_read_module_byte(board, addr, mc_chip);
2044 sx_dprintk(SX_DEBUG_INIT, "Module at %x: %d channels\n",
2045 addr, read_sx_byte(board, addr + 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
Jiri Slaby15b611f2006-12-08 02:39:04 -08002047 chans += sx_read_module_byte(board, addr, mc_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
Jiri Slaby15b611f2006-12-08 02:39:04 -08002049 sx_dprintk(SX_DEBUG_INIT, "module is an %s, which has %s/%s "
2050 "panels\n",
2051 mod_type_s(type),
2052 pan_type_s(sx_read_module_byte(board, addr,
2053 mc_mods) & 0xf),
2054 pan_type_s(sx_read_module_byte(board, addr,
2055 mc_mods) >> 4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Jiri Slaby15b611f2006-12-08 02:39:04 -08002057 sx_dprintk(SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC "
2058 "version: %x\n",
2059 sx_read_module_byte(board, addr, mc_rev1),
2060 sx_read_module_byte(board, addr, mc_rev2),
2061 sx_read_module_byte(board, addr, mc_mtaasic_rev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
2063 /* The following combinations are illegal: It should theoretically
2064 work, but timing problems make the bus HANG. */
2065
Jiri Slaby15b611f2006-12-08 02:39:04 -08002066 if (mod_compat_type(type) != board->ta_type) {
2067 printk(KERN_ERR "sx: This is an invalid "
2068 "configuration.\nDon't mix TA/MTA/SXDC on the "
2069 "same hostadapter.\n");
2070 chans = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 break;
2072 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002073 if ((IS_EISA_BOARD(board) ||
2074 IS_SI_BOARD(board)) &&
2075 (mod_compat_type(type) == 4)) {
2076 printk(KERN_ERR "sx: This is an invalid "
2077 "configuration.\nDon't use SXDCs on an SI/XIO "
2078 "adapter.\n");
2079 chans = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 break;
2081 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002082#if 0 /* Problem fixed: firmware 3.05 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 if (IS_SX_BOARD(board) && (type == TA8)) {
2084 /* There are some issues with the firmware and the DCD/RTS
2085 lines. It might work if you tie them together or something.
Jiri Slaby15b611f2006-12-08 02:39:04 -08002086 It might also work if you get a newer sx_firmware. Therefore
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 this is just a warning. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002088 printk(KERN_WARNING
2089 "sx: The SX host doesn't work too well "
2090 "with the TA8 adapters.\nSpecialix is working on it.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 }
2092#endif
2093 }
2094
2095 if (chans) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002096 if (board->irq > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 /* fixed irq, probably PCI */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002098 if (sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
2099 if (request_irq(board->irq, sx_interrupt,
2100 IRQF_SHARED | IRQF_DISABLED,
2101 "sx", board)) {
2102 printk(KERN_ERR "sx: Cannot allocate "
2103 "irq %d.\n", board->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 board->irq = 0;
2105 }
2106 } else
2107 board->irq = 0;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002108 } else if (board->irq < 0 && sx_irqmask) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 /* auto-allocate irq */
2110 int irqnr;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002111 int irqmask = sx_irqmask & (IS_SX_BOARD(board) ?
2112 SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
2113 for (irqnr = 15; irqnr > 0; irqnr--)
2114 if (irqmask & (1 << irqnr))
2115 if (!request_irq(irqnr, sx_interrupt,
2116 IRQF_SHARED | IRQF_DISABLED,
2117 "sx", board))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 break;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002119 if (!irqnr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
2121 board->irq = irqnr;
2122 } else
2123 board->irq = 0;
2124
2125 if (board->irq) {
2126 /* Found a valid interrupt, start up interrupts! */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002127 sx_dprintk(SX_DEBUG_INIT, "Using irq %d.\n",
2128 board->irq);
2129 sx_start_interrupts(board);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 board->poll = sx_slowpoll;
2131 board->flags |= SX_IRQ_ALLOCATED;
2132 } else {
2133 /* no irq: setup board for polled operation */
2134 board->poll = sx_poll;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002135 sx_dprintk(SX_DEBUG_INIT, "Using poll-interval %d.\n",
2136 board->poll);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 }
2138
Jiri Slaby15b611f2006-12-08 02:39:04 -08002139 /* The timer should be initialized anyway: That way we can
2140 safely del_timer it when the module is unloaded. */
Jiri Slabyc9594642006-12-08 02:39:05 -08002141 setup_timer(&board->timer, sx_pollfunc, (unsigned long)board);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Jiri Slabyc9594642006-12-08 02:39:05 -08002143 if (board->poll)
2144 mod_timer(&board->timer, jiffies + board->poll);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 } else {
2146 board->irq = 0;
2147 }
2148
2149 board->nports = chans;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002150 sx_dprintk(SX_DEBUG_INIT, "returning %d ports.", board->nports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
2152 func_exit();
2153 return chans;
2154}
2155
Jiri Slabycda52652006-12-08 02:39:00 -08002156static void __devinit printheader(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157{
2158 static int header_printed;
2159
2160 if (!header_printed) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002161 printk(KERN_INFO "Specialix SX driver "
2162 "(C) 1998/1999 R.E.Wolff@BitWizard.nl\n");
2163 printk(KERN_INFO "sx: version " __stringify(SX_VERSION) "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 header_printed = 1;
2165 }
2166}
2167
Jiri Slaby15b611f2006-12-08 02:39:04 -08002168static int __devinit probe_sx(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169{
2170 struct vpd_prom vpdp;
2171 char *p;
2172 int i;
2173
2174 func_enter();
2175
Jiri Slaby15b611f2006-12-08 02:39:04 -08002176 if (!IS_CF_BOARD(board)) {
2177 sx_dprintk(SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
2178 board->base + SX_VPD_ROM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180 if (sx_debug & SX_DEBUG_PROBE)
2181 my_hd_io(board->base + SX_VPD_ROM, 0x40);
2182
Jiri Slaby15b611f2006-12-08 02:39:04 -08002183 p = (char *)&vpdp;
2184 for (i = 0; i < sizeof(struct vpd_prom); i++)
2185 *p++ = read_sx_byte(board, SX_VPD_ROM + i * 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
2187 if (sx_debug & SX_DEBUG_PROBE)
Jiri Slaby15b611f2006-12-08 02:39:04 -08002188 my_hd(&vpdp, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Jiri Slaby15b611f2006-12-08 02:39:04 -08002190 sx_dprintk(SX_DEBUG_PROBE, "checking identifier...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Jiri Slaby15b611f2006-12-08 02:39:04 -08002192 if (strncmp(vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
2193 sx_dprintk(SX_DEBUG_PROBE, "Got non-SX identifier: "
2194 "'%s'\n", vpdp.identifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 return 0;
2196 }
2197 }
2198
Jiri Slaby15b611f2006-12-08 02:39:04 -08002199 printheader();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Jiri Slaby15b611f2006-12-08 02:39:04 -08002201 if (!IS_CF_BOARD(board)) {
2202 printk(KERN_DEBUG "sx: Found an SX board at %lx\n",
2203 board->hw_base);
2204 printk(KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, "
2205 "uniq ID:%08x, ",
2206 vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
2207 printk("Manufactured: %d/%d\n", 1970 + vpdp.myear, vpdp.mweek);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Jiri Slaby15b611f2006-12-08 02:39:04 -08002209 if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) !=
2210 SX_PCI_UNIQUEID1) && (((vpdp.uniqid >> 24) &
2211 SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
2212 /* This might be a bit harsh. This was the primary
2213 reason the SX/ISA card didn't work at first... */
2214 printk(KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA "
2215 "card. Sorry: giving up.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 return (0);
2217 }
2218
Jiri Slaby15b611f2006-12-08 02:39:04 -08002219 if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) ==
2220 SX_ISA_UNIQUEID1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (((unsigned long)board->hw_base) & 0x8000) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002222 printk(KERN_WARNING "sx: Warning: There may be "
2223 "hardware problems with the card at "
2224 "%lx.\n", board->hw_base);
2225 printk(KERN_WARNING "sx: Read sx.txt for more "
2226 "info.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 }
2228 }
2229 }
2230
2231 board->nports = -1;
2232
2233 /* This resets the processor, and keeps it off the bus. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002234 if (!sx_reset(board))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 return 0;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002236 sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 func_exit();
2239 return 1;
2240}
2241
Jiri Slaby927a6f92006-12-08 02:39:02 -08002242#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
2244/* Specialix probes for this card at 32k increments from 640k to 16M.
2245 I consider machines with less than 16M unlikely nowadays, so I'm
2246 not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA
2247 card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
2248 0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
2249
Jiri Slaby15b611f2006-12-08 02:39:04 -08002250static int __devinit probe_si(struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
2252 int i;
2253
2254 func_enter();
Jiri Slaby15b611f2006-12-08 02:39:04 -08002255 sx_dprintk(SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at "
2256 "%p.\n", board->hw_base, board->base + SI2_ISA_ID_BASE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
2258 if (sx_debug & SX_DEBUG_PROBE)
2259 my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
2260
2261 if (!IS_EISA_BOARD(board)) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002262 if (IS_SI1_BOARD(board)) {
2263 for (i = 0; i < 8; i++) {
2264 write_sx_byte(board, SI2_ISA_ID_BASE + 7 - i,i);
2265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002267 for (i = 0; i < 8; i++) {
2268 if ((read_sx_byte(board, SI2_ISA_ID_BASE + 7 - i) & 7)
2269 != i) {
2270 func_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 return 0;
2272 }
2273 }
2274 }
2275
2276 /* Now we're pretty much convinced that there is an SI board here,
2277 but to prevent trouble, we'd better double check that we don't
2278 have an SI1 board when we're probing for an SI2 board.... */
2279
Jiri Slaby15b611f2006-12-08 02:39:04 -08002280 write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
2281 if (IS_SI1_BOARD(board)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 /* This should be an SI1 board, which has this
2283 location writable... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002284 if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
2285 func_exit();
2286 return 0;
Marc Zyngier04a3d312006-02-26 12:02:56 +01002287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 } else {
2289 /* This should be an SI2 board, which has the bottom
2290 3 bits non-writable... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002291 if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
2292 func_exit();
2293 return 0;
Marc Zyngier04a3d312006-02-26 12:02:56 +01002294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 }
2296
2297 /* Now we're pretty much convinced that there is an SI board here,
2298 but to prevent trouble, we'd better double check that we don't
2299 have an SI1 board when we're probing for an SI2 board.... */
2300
Jiri Slaby15b611f2006-12-08 02:39:04 -08002301 write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
2302 if (IS_SI1_BOARD(board)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 /* This should be an SI1 board, which has this
2304 location writable... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002305 if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 func_exit();
Jiri Slaby15b611f2006-12-08 02:39:04 -08002307 return 0;
Marc Zyngier04a3d312006-02-26 12:02:56 +01002308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 } else {
2310 /* This should be an SI2 board, which has the bottom
2311 3 bits non-writable... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002312 if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
2313 func_exit();
2314 return 0;
Marc Zyngier04a3d312006-02-26 12:02:56 +01002315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 }
2317
Jiri Slaby15b611f2006-12-08 02:39:04 -08002318 printheader();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Jiri Slaby15b611f2006-12-08 02:39:04 -08002320 printk(KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 /* Compared to the SX boards, it is a complete guess as to what
Jiri Slaby15b611f2006-12-08 02:39:04 -08002322 this card is up to... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
2324 board->nports = -1;
2325
2326 /* This resets the processor, and keeps it off the bus. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002327 if (!sx_reset(board))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 return 0;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002329 sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 func_exit();
2332 return 1;
2333}
Jiri Slaby927a6f92006-12-08 02:39:02 -08002334#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002336static const struct tty_operations sx_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 .break_ctl = sx_break,
Jiri Slaby15b611f2006-12-08 02:39:04 -08002338 .open = sx_open,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 .close = gs_close,
2340 .write = gs_write,
2341 .put_char = gs_put_char,
2342 .flush_chars = gs_flush_chars,
2343 .write_room = gs_write_room,
2344 .chars_in_buffer = gs_chars_in_buffer,
2345 .flush_buffer = gs_flush_buffer,
2346 .ioctl = sx_ioctl,
2347 .throttle = sx_throttle,
2348 .unthrottle = sx_unthrottle,
2349 .set_termios = gs_set_termios,
2350 .stop = gs_stop,
2351 .start = gs_start,
2352 .hangup = gs_hangup,
2353 .tiocmget = sx_tiocmget,
2354 .tiocmset = sx_tiocmset,
2355};
2356
2357static int sx_init_drivers(void)
2358{
2359 int error;
2360
2361 func_enter();
2362
2363 sx_driver = alloc_tty_driver(sx_nports);
2364 if (!sx_driver)
2365 return 1;
2366 sx_driver->owner = THIS_MODULE;
2367 sx_driver->driver_name = "specialix_sx";
2368 sx_driver->name = "ttyX";
2369 sx_driver->major = SX_NORMAL_MAJOR;
2370 sx_driver->type = TTY_DRIVER_TYPE_SERIAL;
2371 sx_driver->subtype = SERIAL_TYPE_NORMAL;
2372 sx_driver->init_termios = tty_std_termios;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002373 sx_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002374 sx_driver->init_termios.c_ispeed = 9600;
2375 sx_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 sx_driver->flags = TTY_DRIVER_REAL_RAW;
2377 tty_set_operations(sx_driver, &sx_ops);
2378
2379 if ((error = tty_register_driver(sx_driver))) {
2380 put_tty_driver(sx_driver);
2381 printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
Jiri Slaby15b611f2006-12-08 02:39:04 -08002382 error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 return 1;
2384 }
2385 func_exit();
2386 return 0;
2387}
2388
Jiri Slaby15b611f2006-12-08 02:39:04 -08002389static int sx_init_portstructs(int nboards, int nports)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390{
2391 struct sx_board *board;
2392 struct sx_port *port;
2393 int i, j;
2394 int addr, chans;
2395 int portno;
2396
2397 func_enter();
2398
2399 /* Many drivers statically allocate the maximum number of ports
Jiri Slaby15b611f2006-12-08 02:39:04 -08002400 There is no reason not to allocate them dynamically.
2401 Is there? -- REW */
Jiri Slaby4a7cb692006-12-08 02:38:59 -08002402 sx_ports = kcalloc(nports, sizeof(struct sx_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 if (!sx_ports)
2404 return -ENOMEM;
2405
2406 port = sx_ports;
2407 for (i = 0; i < nboards; i++) {
2408 board = &boards[i];
2409 board->ports = port;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002410 for (j = 0; j < boards[i].nports; j++) {
2411 sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002412 tty_port_init(&port->gs.port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 port->gs.magic = SX_MAGIC;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002414 port->gs.close_delay = HZ / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 port->gs.closing_wait = 30 * HZ;
2416 port->board = board;
2417 port->gs.rd = &sx_real_driver;
2418#ifdef NEW_WRITE_LOCKING
Ingo Molnar81861d72006-03-23 03:00:44 -08002419 port->gs.port_write_mutex = MUTEX;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420#endif
Ingo Molnar34af9462006-06-27 02:53:55 -07002421 spin_lock_init(&port->gs.driver_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 /*
2423 * Initializing wait queue
2424 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 port++;
2426 }
2427 }
2428
2429 port = sx_ports;
2430 portno = 0;
2431 for (i = 0; i < nboards; i++) {
2432 board = &boards[i];
2433 board->port_base = portno;
2434 /* Possibly the configuration was rejected. */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002435 sx_dprintk(SX_DEBUG_PROBE, "Board has %d channels\n",
2436 board->nports);
2437 if (board->nports <= 0)
2438 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 /* XXX byteorder ?? */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002440 for (addr = 0x80; addr != 0;
2441 addr = read_sx_word(board, addr) & 0x7fff) {
2442 chans = sx_read_module_byte(board, addr, mc_type);
2443 sx_dprintk(SX_DEBUG_PROBE, "Module at %x: %d "
2444 "channels\n", addr, chans);
2445 sx_dprintk(SX_DEBUG_PROBE, "Port at");
2446 for (j = 0; j < chans; j++) {
2447 /* The "sx-way" is the way it SHOULD be done.
2448 That way in the future, the firmware may for
2449 example pack the structures a bit more
2450 efficient. Neil tells me it isn't going to
2451 happen anytime soon though. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 if (IS_SX_BOARD(board))
Jiri Slaby15b611f2006-12-08 02:39:04 -08002453 port->ch_base = sx_read_module_word(
2454 board, addr + j * 2,
2455 mc_chan_pointer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 else
Jiri Slaby15b611f2006-12-08 02:39:04 -08002457 port->ch_base = addr + 0x100 + 0x300 *j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458
Jiri Slaby15b611f2006-12-08 02:39:04 -08002459 sx_dprintk(SX_DEBUG_PROBE, " %x",
2460 port->ch_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 port->line = portno++;
2462 port++;
2463 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002464 sx_dprintk(SX_DEBUG_PROBE, "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 }
2466 /* This has to be done earlier. */
2467 /* board->flags |= SX_BOARD_INITIALIZED; */
2468 }
2469
2470 func_exit();
2471 return 0;
2472}
2473
Jiri Slaby18f813e2006-12-08 02:39:01 -08002474static unsigned int sx_find_free_board(void)
2475{
2476 unsigned int i;
2477
Jiri Slaby15b611f2006-12-08 02:39:04 -08002478 for (i = 0; i < SX_NBOARDS; i++)
Jiri Slaby18f813e2006-12-08 02:39:01 -08002479 if (!(boards[i].flags & SX_BOARD_PRESENT))
2480 break;
2481
2482 return i;
2483}
2484
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485static void __exit sx_release_drivers(void)
2486{
2487 func_enter();
2488 tty_unregister_driver(sx_driver);
2489 put_tty_driver(sx_driver);
2490 func_exit();
2491}
2492
Jiri Slaby39103492006-12-08 02:39:07 -08002493static void __devexit sx_remove_card(struct sx_board *board,
2494 struct pci_dev *pdev)
Jiri Slaby18f813e2006-12-08 02:39:01 -08002495{
2496 if (board->flags & SX_BOARD_INITIALIZED) {
2497 /* The board should stop messing with us. (actually I mean the
2498 interrupt) */
2499 sx_reset(board);
2500 if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
2501 free_irq(board->irq, board);
2502
2503 /* It is safe/allowed to del_timer a non-active timer */
2504 del_timer(&board->timer);
Jiri Slaby30f42182006-12-08 02:39:08 -08002505 if (pdev) {
Jiri Slaby3468a332006-12-13 00:34:20 -08002506#ifdef CONFIG_PCI
Jiri Slabyda1cfe12008-10-18 20:27:44 -07002507 iounmap(board->base2);
Jiri Slaby30f42182006-12-08 02:39:08 -08002508 pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
Jiri Slaby3468a332006-12-13 00:34:20 -08002509#endif
Jiri Slaby30f42182006-12-08 02:39:08 -08002510 } else {
Jiri Slaby39103492006-12-08 02:39:07 -08002511 iounmap(board->base);
Jiri Slaby30f42182006-12-08 02:39:08 -08002512 release_region(board->hw_base, board->hw_len);
2513 }
Jiri Slaby18f813e2006-12-08 02:39:01 -08002514
Jiri Slaby15b611f2006-12-08 02:39:04 -08002515 board->flags &= ~(SX_BOARD_INITIALIZED | SX_BOARD_PRESENT);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002516 }
2517}
2518
2519#ifdef CONFIG_EISA
2520
2521static int __devinit sx_eisa_probe(struct device *dev)
2522{
2523 struct eisa_device *edev = to_eisa_device(dev);
2524 struct sx_board *board;
2525 unsigned long eisa_slot = edev->base_addr;
2526 unsigned int i;
2527 int retval = -EIO;
2528
Jiri Slaby42f63842006-12-08 02:39:03 -08002529 mutex_lock(&sx_boards_lock);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002530 i = sx_find_free_board();
Jiri Slaby42f63842006-12-08 02:39:03 -08002531 if (i == SX_NBOARDS) {
2532 mutex_unlock(&sx_boards_lock);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002533 goto err;
Jiri Slaby42f63842006-12-08 02:39:03 -08002534 }
2535 board = &boards[i];
2536 board->flags |= SX_BOARD_PRESENT;
2537 mutex_unlock(&sx_boards_lock);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002538
2539 dev_info(dev, "XIO : Signature found in EISA slot %lu, "
Jiri Slaby15b611f2006-12-08 02:39:04 -08002540 "Product %d Rev %d (REPORT THIS TO LKLM)\n",
2541 eisa_slot >> 12,
2542 inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 2),
2543 inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 3));
Jiri Slaby18f813e2006-12-08 02:39:01 -08002544
Jiri Slaby18f813e2006-12-08 02:39:01 -08002545 board->eisa_base = eisa_slot;
2546 board->flags &= ~SX_BOARD_TYPE;
2547 board->flags |= SI_EISA_BOARD;
2548
2549 board->hw_base = ((inb(eisa_slot + 0xc01) << 8) +
Jiri Slaby15b611f2006-12-08 02:39:04 -08002550 inb(eisa_slot + 0xc00)) << 16;
Jiri Slaby30f42182006-12-08 02:39:08 -08002551 board->hw_len = SI2_EISA_WINDOW_LEN;
2552 if (!request_region(board->hw_base, board->hw_len, "sx")) {
2553 dev_err(dev, "can't request region\n");
2554 goto err_flag;
2555 }
Jiri Slaby18f813e2006-12-08 02:39:01 -08002556 board->base2 =
Alan Cox24cb2332008-04-30 00:54:19 -07002557 board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN);
Jiri Slaby30f42182006-12-08 02:39:08 -08002558 if (!board->base) {
2559 dev_err(dev, "can't remap memory\n");
2560 goto err_reg;
2561 }
Jiri Slaby18f813e2006-12-08 02:39:01 -08002562
2563 sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
2564 sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
2565 board->irq = inb(eisa_slot + 0xc02) >> 4;
2566 sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
2567
2568 if (!probe_si(board))
2569 goto err_unmap;
2570
2571 dev_set_drvdata(dev, board);
2572
2573 return 0;
2574err_unmap:
2575 iounmap(board->base);
Jiri Slaby30f42182006-12-08 02:39:08 -08002576err_reg:
2577 release_region(board->hw_base, board->hw_len);
2578err_flag:
Jiri Slaby42f63842006-12-08 02:39:03 -08002579 board->flags &= ~SX_BOARD_PRESENT;
Jiri Slaby18f813e2006-12-08 02:39:01 -08002580err:
2581 return retval;
2582}
2583
2584static int __devexit sx_eisa_remove(struct device *dev)
2585{
2586 struct sx_board *board = dev_get_drvdata(dev);
2587
Jiri Slaby39103492006-12-08 02:39:07 -08002588 sx_remove_card(board, NULL);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002589
2590 return 0;
2591}
2592
2593static struct eisa_device_id sx_eisa_tbl[] = {
2594 { "SLX" },
2595 { "" }
2596};
Jiri Slaby15b611f2006-12-08 02:39:04 -08002597
Jiri Slaby18f813e2006-12-08 02:39:01 -08002598MODULE_DEVICE_TABLE(eisa, sx_eisa_tbl);
2599
2600static struct eisa_driver sx_eisadriver = {
2601 .id_table = sx_eisa_tbl,
2602 .driver = {
2603 .name = "sx",
2604 .probe = sx_eisa_probe,
2605 .remove = __devexit_p(sx_eisa_remove),
2606 }
2607};
2608
2609#endif
2610
Jiri Slaby3468a332006-12-13 00:34:20 -08002611#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 /********************************************************
2613 * Setting bit 17 in the CNTRL register of the PLX 9050 *
2614 * chip forces a retry on writes while a read is pending.*
2615 * This is to prevent the card locking up on Intel Xeon *
2616 * multiprocessor systems with the NX chipset. -- NV *
2617 ********************************************************/
2618
2619/* Newer cards are produced with this bit set from the configuration
2620 EEprom. As the bit is read/write for the CPU, we can fix it here,
2621 if we detect that it isn't set correctly. -- REW */
2622
Jiri Slabycda52652006-12-08 02:39:00 -08002623static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624{
2625 unsigned int hwbase;
2626 void __iomem *rebase;
2627 unsigned int t;
2628
Jiri Slaby15b611f2006-12-08 02:39:04 -08002629#define CNTRL_REG_OFFSET 0x50
2630#define CNTRL_REG_GOODVALUE 0x18260000
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
2632 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
2633 hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
Alan Cox24cb2332008-04-30 00:54:19 -07002634 rebase = ioremap_nocache(hwbase, 0x80);
Jiri Slaby15b611f2006-12-08 02:39:04 -08002635 t = readl(rebase + CNTRL_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 if (t != CNTRL_REG_GOODVALUE) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002637 printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
2638 "%08x\n", t, CNTRL_REG_GOODVALUE);
2639 writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
2641 iounmap(rebase);
2642}
Jiri Slaby3468a332006-12-13 00:34:20 -08002643#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
Jiri Slaby5572e102006-12-08 02:38:58 -08002645static int __devinit sx_pci_probe(struct pci_dev *pdev,
Jiri Slaby15b611f2006-12-08 02:39:04 -08002646 const struct pci_device_id *ent)
Jiri Slaby5572e102006-12-08 02:38:58 -08002647{
Jiri Slaby3468a332006-12-13 00:34:20 -08002648#ifdef CONFIG_PCI
Jiri Slaby5572e102006-12-08 02:38:58 -08002649 struct sx_board *board;
Jiri Slaby39103492006-12-08 02:39:07 -08002650 unsigned int i, reg;
Jiri Slaby5572e102006-12-08 02:38:58 -08002651 int retval = -EIO;
2652
Jiri Slaby42f63842006-12-08 02:39:03 -08002653 mutex_lock(&sx_boards_lock);
Jiri Slaby18f813e2006-12-08 02:39:01 -08002654 i = sx_find_free_board();
Jiri Slaby42f63842006-12-08 02:39:03 -08002655 if (i == SX_NBOARDS) {
2656 mutex_unlock(&sx_boards_lock);
Jiri Slaby5572e102006-12-08 02:38:58 -08002657 goto err;
Jiri Slaby42f63842006-12-08 02:39:03 -08002658 }
2659 board = &boards[i];
2660 board->flags |= SX_BOARD_PRESENT;
2661 mutex_unlock(&sx_boards_lock);
Jiri Slaby5572e102006-12-08 02:38:58 -08002662
2663 retval = pci_enable_device(pdev);
2664 if (retval)
Jiri Slaby42f63842006-12-08 02:39:03 -08002665 goto err_flag;
Jiri Slaby5572e102006-12-08 02:38:58 -08002666
2667 board->flags &= ~SX_BOARD_TYPE;
2668 board->flags |= (pdev->subsystem_vendor == 0x200) ? SX_PCI_BOARD :
Jiri Slaby15b611f2006-12-08 02:39:04 -08002669 SX_CFPCI_BOARD;
Jiri Slaby5572e102006-12-08 02:38:58 -08002670
2671 /* CF boards use base address 3.... */
Jiri Slaby39103492006-12-08 02:39:07 -08002672 reg = IS_CF_BOARD(board) ? 3 : 2;
Jiri Slaby30f42182006-12-08 02:39:08 -08002673 retval = pci_request_region(pdev, reg, "sx");
2674 if (retval) {
2675 dev_err(&pdev->dev, "can't request region\n");
2676 goto err_flag;
2677 }
Jiri Slaby39103492006-12-08 02:39:07 -08002678 board->hw_base = pci_resource_start(pdev, reg);
Jiri Slaby5572e102006-12-08 02:38:58 -08002679 board->base2 =
Jiri Slabyda1cfe12008-10-18 20:27:44 -07002680 board->base = ioremap_nocache(board->hw_base, WINDOW_LEN(board));
Jiri Slaby5572e102006-12-08 02:38:58 -08002681 if (!board->base) {
2682 dev_err(&pdev->dev, "ioremap failed\n");
Jiri Slaby30f42182006-12-08 02:39:08 -08002683 goto err_reg;
Jiri Slaby5572e102006-12-08 02:38:58 -08002684 }
2685
2686 /* Most of the stuff on the CF board is offset by 0x18000 .... */
Jiri Slaby15b611f2006-12-08 02:39:04 -08002687 if (IS_CF_BOARD(board))
Jiri Slaby5572e102006-12-08 02:38:58 -08002688 board->base += 0x18000;
2689
2690 board->irq = pdev->irq;
2691
2692 dev_info(&pdev->dev, "Got a specialix card: %p(%d) %x.\n", board->base,
Jiri Slaby15b611f2006-12-08 02:39:04 -08002693 board->irq, board->flags);
Jiri Slaby5572e102006-12-08 02:38:58 -08002694
2695 if (!probe_sx(board)) {
2696 retval = -EIO;
2697 goto err_unmap;
2698 }
2699
2700 fix_sx_pci(pdev, board);
2701
2702 pci_set_drvdata(pdev, board);
2703
2704 return 0;
2705err_unmap:
Jiri Slabyda1cfe12008-10-18 20:27:44 -07002706 iounmap(board->base2);
Jiri Slaby30f42182006-12-08 02:39:08 -08002707err_reg:
2708 pci_release_region(pdev, reg);
Jiri Slaby42f63842006-12-08 02:39:03 -08002709err_flag:
2710 board->flags &= ~SX_BOARD_PRESENT;
Jiri Slaby5572e102006-12-08 02:38:58 -08002711err:
2712 return retval;
Jiri Slaby3468a332006-12-13 00:34:20 -08002713#else
2714 return -ENODEV;
2715#endif
Jiri Slaby5572e102006-12-08 02:38:58 -08002716}
2717
2718static void __devexit sx_pci_remove(struct pci_dev *pdev)
2719{
2720 struct sx_board *board = pci_get_drvdata(pdev);
2721
Jiri Slaby39103492006-12-08 02:39:07 -08002722 sx_remove_card(board, pdev);
Jiri Slaby5572e102006-12-08 02:38:58 -08002723}
2724
2725/* Specialix has a whole bunch of cards with 0x2000 as the device ID. They say
2726 its because the standard requires it. So check for SUBVENDOR_ID. */
2727static struct pci_device_id sx_pci_tbl[] = {
2728 { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
Jiri Slabyc14d4442007-07-10 17:22:25 -07002729 .subvendor = PCI_ANY_ID, .subdevice = 0x0200 },
Jiri Slaby5572e102006-12-08 02:38:58 -08002730 { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
Jiri Slabyc14d4442007-07-10 17:22:25 -07002731 .subvendor = PCI_ANY_ID, .subdevice = 0x0300 },
Jiri Slaby5572e102006-12-08 02:38:58 -08002732 { 0 }
2733};
Jiri Slaby15b611f2006-12-08 02:39:04 -08002734
Jiri Slaby5572e102006-12-08 02:38:58 -08002735MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
2736
2737static struct pci_driver sx_pcidriver = {
2738 .name = "sx",
2739 .id_table = sx_pci_tbl,
2740 .probe = sx_pci_probe,
2741 .remove = __devexit_p(sx_pci_remove)
2742};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Jiri Slaby15b611f2006-12-08 02:39:04 -08002744static int __init sx_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
Jiri Slaby18f813e2006-12-08 02:39:01 -08002746#ifdef CONFIG_EISA
2747 int retval1;
2748#endif
Jiri Slaby927a6f92006-12-08 02:39:02 -08002749#ifdef CONFIG_ISA
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 struct sx_board *board;
Jiri Slaby927a6f92006-12-08 02:39:02 -08002751 unsigned int i;
2752#endif
2753 unsigned int found = 0;
2754 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 func_enter();
Jiri Slaby15b611f2006-12-08 02:39:04 -08002757 sx_dprintk(SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n",
2758 sx_debug);
2759 if (abs((long)(&sx_debug) - sx_debug) < 0x10000) {
2760 printk(KERN_WARNING "sx: sx_debug is an address, instead of a "
2761 "value. Assuming -1.\n(%p)\n", &sx_debug);
2762 sx_debug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 }
2764
2765 if (misc_register(&sx_fw_device) < 0) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002766 printk(KERN_ERR "SX: Unable to register firmware loader "
2767 "driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 return -EIO;
2769 }
Jiri Slaby927a6f92006-12-08 02:39:02 -08002770#ifdef CONFIG_ISA
Jiri Slaby15b611f2006-12-08 02:39:04 -08002771 for (i = 0; i < NR_SX_ADDRS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 board = &boards[found];
2773 board->hw_base = sx_probe_addrs[i];
Jiri Slaby30f42182006-12-08 02:39:08 -08002774 board->hw_len = SX_WINDOW_LEN;
2775 if (!request_region(board->hw_base, board->hw_len, "sx"))
2776 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 board->base2 =
Alan Cox24cb2332008-04-30 00:54:19 -07002778 board->base = ioremap_nocache(board->hw_base, board->hw_len);
Jiri Slaby30f42182006-12-08 02:39:08 -08002779 if (!board->base)
2780 goto err_sx_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 board->flags &= ~SX_BOARD_TYPE;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002782 board->flags |= SX_ISA_BOARD;
2783 board->irq = sx_irqmask ? -1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Jiri Slaby15b611f2006-12-08 02:39:04 -08002785 if (probe_sx(board)) {
Jiri Slaby42f63842006-12-08 02:39:03 -08002786 board->flags |= SX_BOARD_PRESENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 found++;
2788 } else {
2789 iounmap(board->base);
Jiri Slaby30f42182006-12-08 02:39:08 -08002790err_sx_reg:
2791 release_region(board->hw_base, board->hw_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 }
2793 }
2794
Jiri Slaby15b611f2006-12-08 02:39:04 -08002795 for (i = 0; i < NR_SI_ADDRS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 board = &boards[found];
2797 board->hw_base = si_probe_addrs[i];
Jiri Slaby30f42182006-12-08 02:39:08 -08002798 board->hw_len = SI2_ISA_WINDOW_LEN;
2799 if (!request_region(board->hw_base, board->hw_len, "sx"))
2800 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 board->base2 =
Alan Cox24cb2332008-04-30 00:54:19 -07002802 board->base = ioremap_nocache(board->hw_base, board->hw_len);
Jiri Slaby30f42182006-12-08 02:39:08 -08002803 if (!board->base)
2804 goto err_si_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 board->flags &= ~SX_BOARD_TYPE;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002806 board->flags |= SI_ISA_BOARD;
2807 board->irq = sx_irqmask ? -1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Jiri Slaby15b611f2006-12-08 02:39:04 -08002809 if (probe_si(board)) {
Jiri Slaby42f63842006-12-08 02:39:03 -08002810 board->flags |= SX_BOARD_PRESENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 found++;
2812 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002813 iounmap(board->base);
Jiri Slaby30f42182006-12-08 02:39:08 -08002814err_si_reg:
2815 release_region(board->hw_base, board->hw_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 }
2817 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002818 for (i = 0; i < NR_SI1_ADDRS; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 board = &boards[found];
2820 board->hw_base = si1_probe_addrs[i];
Jiri Slaby30f42182006-12-08 02:39:08 -08002821 board->hw_len = SI1_ISA_WINDOW_LEN;
2822 if (!request_region(board->hw_base, board->hw_len, "sx"))
2823 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 board->base2 =
Alan Cox24cb2332008-04-30 00:54:19 -07002825 board->base = ioremap_nocache(board->hw_base, board->hw_len);
Jiri Slaby30f42182006-12-08 02:39:08 -08002826 if (!board->base)
2827 goto err_si1_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 board->flags &= ~SX_BOARD_TYPE;
Jiri Slaby15b611f2006-12-08 02:39:04 -08002829 board->flags |= SI1_ISA_BOARD;
2830 board->irq = sx_irqmask ? -1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
Jiri Slaby15b611f2006-12-08 02:39:04 -08002832 if (probe_si(board)) {
Jiri Slaby42f63842006-12-08 02:39:03 -08002833 board->flags |= SX_BOARD_PRESENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 found++;
2835 } else {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002836 iounmap(board->base);
Jiri Slaby30f42182006-12-08 02:39:08 -08002837err_si1_reg:
2838 release_region(board->hw_base, board->hw_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 }
2840 }
Jiri Slaby927a6f92006-12-08 02:39:02 -08002841#endif
Jiri Slaby18f813e2006-12-08 02:39:01 -08002842#ifdef CONFIG_EISA
2843 retval1 = eisa_driver_register(&sx_eisadriver);
2844#endif
Jiri Slaby5572e102006-12-08 02:38:58 -08002845 retval = pci_register_driver(&sx_pcidriver);
2846
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 if (found) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002848 printk(KERN_INFO "sx: total of %d boards detected.\n", found);
Jiri Slaby5572e102006-12-08 02:38:58 -08002849 retval = 0;
2850 } else if (retval) {
Jiri Slaby18f813e2006-12-08 02:39:01 -08002851#ifdef CONFIG_EISA
Jiri Slaby7eb99762006-12-08 02:39:06 -08002852 retval = retval1;
Jiri Slaby18f813e2006-12-08 02:39:01 -08002853 if (retval1)
2854#endif
Jiri Slaby15b611f2006-12-08 02:39:04 -08002855 misc_deregister(&sx_fw_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 }
2857
2858 func_exit();
Jiri Slaby5572e102006-12-08 02:38:58 -08002859 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860}
2861
Jiri Slaby15b611f2006-12-08 02:39:04 -08002862static void __exit sx_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
Jiri Slaby15b611f2006-12-08 02:39:04 -08002864 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
2866 func_enter();
Jiri Slaby18f813e2006-12-08 02:39:01 -08002867#ifdef CONFIG_EISA
2868 eisa_driver_unregister(&sx_eisadriver);
2869#endif
Jiri Slaby5572e102006-12-08 02:38:58 -08002870 pci_unregister_driver(&sx_pcidriver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
Jiri Slaby55e70712006-12-08 02:39:03 -08002872 for (i = 0; i < SX_NBOARDS; i++)
Jiri Slaby39103492006-12-08 02:39:07 -08002873 sx_remove_card(&boards[i], NULL);
Jiri Slaby55e70712006-12-08 02:39:03 -08002874
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (misc_deregister(&sx_fw_device) < 0) {
Jiri Slaby15b611f2006-12-08 02:39:04 -08002876 printk(KERN_INFO "sx: couldn't deregister firmware loader "
2877 "device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 }
Jiri Slaby15b611f2006-12-08 02:39:04 -08002879 sx_dprintk(SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n",
2880 sx_initialized);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 if (sx_initialized)
Jiri Slaby15b611f2006-12-08 02:39:04 -08002882 sx_release_drivers();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
Jiri Slaby15b611f2006-12-08 02:39:04 -08002884 kfree(sx_ports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 func_exit();
2886}
2887
2888module_init(sx_init);
2889module_exit(sx_exit);