blob: 0e29a23ec4c50be1f2d74b492c91785a8feae2b3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * RocketPort device driver for Linux
3 *
4 * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000.
5 *
6 * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * Kernel Synchronization:
25 *
26 * This driver has 2 kernel control paths - exception handlers (calls into the driver
27 * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts
28 * are not used.
29 *
30 * Critical data:
31 * - rp_table[], accessed through passed "info" pointers, is a global (static) array of
32 * serial port state information and the xmit_buf circular buffer. Protected by
33 * a per port spinlock.
34 * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there
35 * is data to be transmitted. Protected by atomic bit operations.
36 * - rp_num_ports, int indicating number of open ports, protected by atomic operations.
37 *
38 * rp_write() and rp_write_char() functions use a per port semaphore to protect against
39 * simultaneous access to the same port by more than one process.
40 */
41
42/****** Defines ******/
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define ROCKET_PARANOIA_CHECK
44#define ROCKET_DISABLE_SIMUSAGE
45
46#undef ROCKET_SOFT_FLOW
47#undef ROCKET_DEBUG_OPEN
48#undef ROCKET_DEBUG_INTR
49#undef ROCKET_DEBUG_WRITE
50#undef ROCKET_DEBUG_FLOW
51#undef ROCKET_DEBUG_THROTTLE
52#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
53#undef ROCKET_DEBUG_RECEIVE
54#undef ROCKET_DEBUG_HANGUP
55#undef REV_PCI_ORDER
56#undef ROCKET_DEBUG_IO
57
58#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */
59
60/****** Kernel includes ******/
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <linux/module.h>
63#include <linux/errno.h>
64#include <linux/major.h>
65#include <linux/kernel.h>
66#include <linux/signal.h>
67#include <linux/slab.h>
68#include <linux/mm.h>
69#include <linux/sched.h>
70#include <linux/timer.h>
71#include <linux/interrupt.h>
72#include <linux/tty.h>
73#include <linux/tty_driver.h>
74#include <linux/tty_flip.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010075#include <linux/serial.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040076#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#include <linux/string.h>
78#include <linux/fcntl.h>
79#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070080#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#include <linux/ioport.h>
82#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070083#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070084#include <linux/wait.h>
85#include <linux/pci.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010086#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#include <asm/atomic.h>
Al Viro457fb602008-03-19 16:27:48 +000088#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#include <linux/bitops.h>
90#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070091#include <linux/init.h>
92
93/****** RocketPort includes ******/
94
95#include "rocket_int.h"
96#include "rocket.h"
97
98#define ROCKET_VERSION "2.09"
99#define ROCKET_DATE "12-June-2003"
100
101/****** RocketPort Local Variables ******/
102
Jiri Slaby40565f12007-02-12 00:52:31 -0800103static void rp_do_poll(unsigned long dummy);
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105static struct tty_driver *rocket_driver;
106
107static struct rocket_version driver_version = {
108 ROCKET_VERSION, ROCKET_DATE
109};
110
111static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
112static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
113 /* eg. Bit 0 indicates port 0 has xmit data, ... */
114static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800115static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
118static unsigned long board2;
119static unsigned long board3;
120static unsigned long board4;
121static unsigned long controller;
122static int support_low_speed;
123static unsigned long modem1;
124static unsigned long modem2;
125static unsigned long modem3;
126static unsigned long modem4;
127static unsigned long pc104_1[8];
128static unsigned long pc104_2[8];
129static unsigned long pc104_3[8];
130static unsigned long pc104_4[8];
131static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
132
133static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
134static unsigned long rcktpt_io_addr[NUM_BOARDS];
135static int rcktpt_type[NUM_BOARDS];
136static int is_PCI[NUM_BOARDS];
137static rocketModel_t rocketModel[NUM_BOARDS];
138static int max_board;
Alan Cox31f35932009-01-02 13:45:05 +0000139static const struct tty_port_operations rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141/*
142 * The following arrays define the interrupt bits corresponding to each AIOP.
143 * These bits are different between the ISA and regular PCI boards and the
144 * Universal PCI boards.
145 */
146
147static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
148 AIOP_INTR_BIT_0,
149 AIOP_INTR_BIT_1,
150 AIOP_INTR_BIT_2,
151 AIOP_INTR_BIT_3
152};
153
154static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
155 UPCI_AIOP_INTR_BIT_0,
156 UPCI_AIOP_INTR_BIT_1,
157 UPCI_AIOP_INTR_BIT_2,
158 UPCI_AIOP_INTR_BIT_3
159};
160
Adrian Bunkf15313b2005-06-25 14:59:05 -0700161static Byte_t RData[RDATASIZE] = {
162 0x00, 0x09, 0xf6, 0x82,
163 0x02, 0x09, 0x86, 0xfb,
164 0x04, 0x09, 0x00, 0x0a,
165 0x06, 0x09, 0x01, 0x0a,
166 0x08, 0x09, 0x8a, 0x13,
167 0x0a, 0x09, 0xc5, 0x11,
168 0x0c, 0x09, 0x86, 0x85,
169 0x0e, 0x09, 0x20, 0x0a,
170 0x10, 0x09, 0x21, 0x0a,
171 0x12, 0x09, 0x41, 0xff,
172 0x14, 0x09, 0x82, 0x00,
173 0x16, 0x09, 0x82, 0x7b,
174 0x18, 0x09, 0x8a, 0x7d,
175 0x1a, 0x09, 0x88, 0x81,
176 0x1c, 0x09, 0x86, 0x7a,
177 0x1e, 0x09, 0x84, 0x81,
178 0x20, 0x09, 0x82, 0x7c,
179 0x22, 0x09, 0x0a, 0x0a
180};
181
182static Byte_t RRegData[RREGDATASIZE] = {
183 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
184 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
185 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
186 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
187 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
188 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
189 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
190 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
191 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
192 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
193 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
194 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
195 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
196};
197
198static CONTROLLER_T sController[CTL_SIZE] = {
199 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
200 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
201 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
202 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
203 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
204 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
205 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
206 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
207};
208
209static Byte_t sBitMapClrTbl[8] = {
210 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
211};
212
213static Byte_t sBitMapSetTbl[8] = {
214 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
215};
216
217static int sClockPrescale = 0x14;
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219/*
220 * Line number is the ttySIx number (x), the Minor number. We
221 * assign them sequentially, starting at zero. The following
222 * array keeps track of the line number assigned to a given board/aiop/channel.
223 */
224static unsigned char lineNumbers[MAX_RP_PORTS];
225static unsigned long nextLineNumber;
226
227/***** RocketPort Static Prototypes *********/
228static int __init init_ISA(int i);
229static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
230static void rp_flush_buffer(struct tty_struct *tty);
231static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
232static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
233static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
234static void rp_start(struct tty_struct *tty);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700235static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
236 int ChanNum);
237static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
238static void sFlushRxFIFO(CHANNEL_T * ChP);
239static void sFlushTxFIFO(CHANNEL_T * ChP);
240static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
241static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
242static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
243static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
244static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
245static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
246 ByteIO_t * AiopIOList, int AiopIOListSize,
247 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
248 int PeriodicOnly, int altChanRingIndicator,
249 int UPCIRingInd);
250static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
251 ByteIO_t * AiopIOList, int AiopIOListSize,
252 int IRQNum, Byte_t Frequency, int PeriodicOnly);
253static int sReadAiopID(ByteIO_t io);
254static int sReadAiopNumChan(WordIO_t io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256MODULE_AUTHOR("Theodore Ts'o");
257MODULE_DESCRIPTION("Comtrol RocketPort driver");
258module_param(board1, ulong, 0);
259MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
260module_param(board2, ulong, 0);
261MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
262module_param(board3, ulong, 0);
263MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
264module_param(board4, ulong, 0);
265MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
266module_param(controller, ulong, 0);
267MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
268module_param(support_low_speed, bool, 0);
269MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
270module_param(modem1, ulong, 0);
271MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem");
272module_param(modem2, ulong, 0);
273MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem");
274module_param(modem3, ulong, 0);
275MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem");
276module_param(modem4, ulong, 0);
277MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem");
278module_param_array(pc104_1, ulong, NULL, 0);
279MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,...");
280module_param_array(pc104_2, ulong, NULL, 0);
281MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,...");
282module_param_array(pc104_3, ulong, NULL, 0);
283MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,...");
284module_param_array(pc104_4, ulong, NULL, 0);
285MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
286
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -0800287static int rp_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288static void rp_cleanup_module(void);
289
290module_init(rp_init);
291module_exit(rp_cleanup_module);
292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294MODULE_LICENSE("Dual BSD/GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296/*************************************************************************/
297/* Module code starts here */
298
299static inline int rocket_paranoia_check(struct r_port *info,
300 const char *routine)
301{
302#ifdef ROCKET_PARANOIA_CHECK
303 if (!info)
304 return 1;
305 if (info->magic != RPORT_MAGIC) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800306 printk(KERN_WARNING "Warning: bad magic number for rocketport "
307 "struct in %s\n", routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 return 1;
309 }
310#endif
311 return 0;
312}
313
314
315/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals
316 * that receive data is present on a serial port. Pulls data from FIFO, moves it into the
317 * tty layer.
318 */
319static void rp_do_receive(struct r_port *info,
320 struct tty_struct *tty,
321 CHANNEL_t * cp, unsigned int ChanStatus)
322{
323 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700324 int ToRecv, wRecv, space;
325 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800329 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700331 if (ToRecv == 0)
332 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 /*
335 * if status indicates there are errored characters in the
336 * FIFO, then enter status mode (a word in FIFO holds
337 * character and status).
338 */
339 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
340 if (!(ChanStatus & STATMODE)) {
341#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800342 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343#endif
344 ChanStatus |= STATMODE;
345 sEnRxStatusMode(cp);
346 }
347 }
348
349 /*
350 * if we previously entered status mode, then read down the
351 * FIFO one word at a time, pulling apart the character and
352 * the status. Update error counters depending on status
353 */
354 if (ChanStatus & STATMODE) {
355#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800356 printk(KERN_INFO "Ignore %x, read %x...\n",
357 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358#endif
359 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700360 char flag;
361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 CharNStat = sInW(sGetTxRxDataIO(cp));
363#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800364 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365#endif
366 if (CharNStat & STMBREAKH)
367 CharNStat &= ~(STMFRAMEH | STMPARITYH);
368 if (CharNStat & info->ignore_status_mask) {
369 ToRecv--;
370 continue;
371 }
372 CharNStat &= info->read_status_mask;
373 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700374 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700376 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700378 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700380 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700382 flag = TTY_NORMAL;
383 tty_insert_flip_char(tty, CharNStat & 0xff, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 ToRecv--;
385 }
386
387 /*
388 * after we've emptied the FIFO in status mode, turn
389 * status mode back off
390 */
391 if (sGetRxCnt(cp) == 0) {
392#ifdef ROCKET_DEBUG_RECEIVE
393 printk(KERN_INFO "Status mode off.\n");
394#endif
395 sDisRxStatusMode(cp);
396 }
397 } else {
398 /*
399 * we aren't in status mode, so read down the FIFO two
400 * characters at time by doing repeated word IO
401 * transfer.
402 */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700403 space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
404 if (space < ToRecv) {
405#ifdef ROCKET_DEBUG_RECEIVE
406 printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
407#endif
408 if (space <= 0)
409 return;
410 ToRecv = space;
411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 wRecv = ToRecv >> 1;
413 if (wRecv)
414 sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
415 if (ToRecv & 1)
416 cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
418 /* Push the data up to the tty layer */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700419 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
421
422/*
423 * Serial port transmit data function. Called from the timer polling loop as a
424 * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready
425 * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is
426 * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks.
427 */
428static void rp_do_transmit(struct r_port *info)
429{
430 int c;
431 CHANNEL_t *cp = &info->channel;
432 struct tty_struct *tty;
433 unsigned long flags;
434
435#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800436 printk(KERN_DEBUG "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437#endif
438 if (!info)
439 return;
Alan Cox47b01b32009-01-02 13:48:30 +0000440 tty = tty_port_tty_get(&info->port);
441
442 if (tty == NULL) {
443 printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
445 return;
446 }
447
448 spin_lock_irqsave(&info->slock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
450
451 /* Loop sending data to FIFO until done or FIFO full */
452 while (1) {
453 if (tty->stopped || tty->hw_stopped)
454 break;
Harvey Harrison709107f2008-04-30 00:53:51 -0700455 c = min(info->xmit_fifo_room, info->xmit_cnt);
456 c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (c <= 0 || info->xmit_fifo_room <= 0)
458 break;
459 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
460 if (c & 1)
461 sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]);
462 info->xmit_tail += c;
463 info->xmit_tail &= XMIT_BUF_SIZE - 1;
464 info->xmit_cnt -= c;
465 info->xmit_fifo_room -= c;
466#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800467 printk(KERN_INFO "tx %d chars...\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468#endif
469 }
470
471 if (info->xmit_cnt == 0)
472 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
473
474 if (info->xmit_cnt < WAKEUP_CHARS) {
475 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476#ifdef ROCKETPORT_HAVE_POLL_WAIT
477 wake_up_interruptible(&tty->poll_wait);
478#endif
479 }
480
481 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox47b01b32009-01-02 13:48:30 +0000482 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800485 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 info->xmit_tail, info->xmit_fifo_room);
487#endif
488}
489
490/*
491 * Called when a serial port signals it has read data in it's RX FIFO.
492 * It checks what interrupts are pending and services them, including
493 * receiving serial data.
494 */
495static void rp_handle_port(struct r_port *info)
496{
497 CHANNEL_t *cp;
498 struct tty_struct *tty;
499 unsigned int IntMask, ChanStatus;
500
501 if (!info)
502 return;
503
Alan Cox21bed702009-01-02 13:48:23 +0000504 if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800505 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
506 "info->flags & NOT_INIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 return;
508 }
Alan Cox47b01b32009-01-02 13:48:30 +0000509 tty = tty_port_tty_get(&info->port);
510 if (!tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800511 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
Alan Cox47b01b32009-01-02 13:48:30 +0000512 "tty==NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return;
514 }
515 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517 IntMask = sGetChanIntID(cp) & info->intmask;
518#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800519 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520#endif
521 ChanStatus = sGetChanStatus(cp);
522 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
523 rp_do_receive(info, tty, cp, ChanStatus);
524 }
525 if (IntMask & DELTA_CD) { /* CD change */
526#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800527 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 (ChanStatus & CD_ACT) ? "on" : "off");
529#endif
530 if (!(ChanStatus & CD_ACT) && info->cd_status) {
531#ifdef ROCKET_DEBUG_HANGUP
532 printk(KERN_INFO "CD drop, calling hangup.\n");
533#endif
534 tty_hangup(tty);
535 }
536 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100537 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 }
539#ifdef ROCKET_DEBUG_INTR
540 if (IntMask & DELTA_CTS) { /* CTS change */
541 printk(KERN_INFO "CTS change...\n");
542 }
543 if (IntMask & DELTA_DSR) { /* DSR change */
544 printk(KERN_INFO "DSR change...\n");
545 }
546#endif
Alan Cox47b01b32009-01-02 13:48:30 +0000547 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
550/*
551 * The top level polling routine. Repeats every 1/100 HZ (10ms).
552 */
553static void rp_do_poll(unsigned long dummy)
554{
555 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700556 int ctrl, aiop, ch, line;
557 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 unsigned int CtlMask;
559 unsigned char AiopMask;
560 Word_t bit;
561
562 /* Walk through all the boards (ctrl's) */
563 for (ctrl = 0; ctrl < max_board; ctrl++) {
564 if (rcktpt_io_addr[ctrl] <= 0)
565 continue;
566
567 /* Get a ptr to the board's control struct */
568 ctlp = sCtlNumToCtlPtr(ctrl);
569
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200570 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571#ifdef CONFIG_PCI
572 if (ctlp->BusType == isPCI)
573 CtlMask = sPCIGetControllerIntStatus(ctlp);
574 else
575#endif
576 CtlMask = sGetControllerIntStatus(ctlp);
577
578 /* Check if any AIOP read bits are set */
579 for (aiop = 0; CtlMask; aiop++) {
580 bit = ctlp->AiopIntrBits[aiop];
581 if (CtlMask & bit) {
582 CtlMask &= ~bit;
583 AiopMask = sGetAiopIntStatus(ctlp, aiop);
584
585 /* Check if any port read bits are set */
586 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
587 if (AiopMask & 1) {
588
589 /* Get the line number (/dev/ttyRx number). */
590 /* Read the data from the port. */
591 line = GetLineNumber(ctrl, aiop, ch);
592 rp_handle_port(rp_table[line]);
593 }
594 }
595 }
596 }
597
598 xmitmask = xmit_flags[ctrl];
599
600 /*
601 * xmit_flags contains bit-significant flags, indicating there is data
602 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
603 * 1, ... (32 total possible). The variable i has the aiop and ch
604 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
605 */
606 if (xmitmask) {
607 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
608 if (xmitmask & (1 << i)) {
609 aiop = (i & 0x18) >> 3;
610 ch = i & 0x07;
611 line = GetLineNumber(ctrl, aiop, ch);
612 rp_do_transmit(rp_table[line]);
613 }
614 }
615 }
616 }
617
618 /*
619 * Reset the timer so we get called at the next clock tick (10ms).
620 */
621 if (atomic_read(&rp_num_ports_open))
622 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
623}
624
625/*
626 * Initializes the r_port structure for a port, as well as enabling the port on
627 * the board.
628 * Inputs: board, aiop, chan numbers
629 */
630static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
631{
632 unsigned rocketMode;
633 struct r_port *info;
634 int line;
635 CONTROLLER_T *ctlp;
636
637 /* Get the next available line number */
638 line = SetLineNumber(board, aiop, chan);
639
640 ctlp = sCtlNumToCtlPtr(board);
641
642 /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700643 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800645 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
646 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return;
648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
650 info->magic = RPORT_MAGIC;
651 info->line = line;
652 info->ctlp = ctlp;
653 info->board = board;
654 info->aiop = aiop;
655 info->chan = chan;
Alan Cox31f35932009-01-02 13:45:05 +0000656 tty_port_init(&info->port);
657 info->port.ops = &rocket_port_ops;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700658 init_completion(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 info->flags &= ~ROCKET_MODE_MASK;
660 switch (pc104[board][line]) {
661 case 422:
662 info->flags |= ROCKET_MODE_RS422;
663 break;
664 case 485:
665 info->flags |= ROCKET_MODE_RS485;
666 break;
667 case 232:
668 default:
669 info->flags |= ROCKET_MODE_RS232;
670 break;
671 }
672
673 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
674 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800675 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
676 board, aiop, chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 kfree(info);
678 return;
679 }
680
681 rocketMode = info->flags & ROCKET_MODE_MASK;
682
683 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
684 sEnRTSToggle(&info->channel);
685 else
686 sDisRTSToggle(&info->channel);
687
688 if (ctlp->boardType == ROCKET_TYPE_PC104) {
689 switch (rocketMode) {
690 case ROCKET_MODE_RS485:
691 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
692 break;
693 case ROCKET_MODE_RS422:
694 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
695 break;
696 case ROCKET_MODE_RS232:
697 default:
698 if (info->flags & ROCKET_RTS_TOGGLE)
699 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
700 else
701 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
702 break;
703 }
704 }
705 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700706 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 rp_table[line] = info;
Jiri Slabyac6aec22007-10-18 03:06:26 -0700708 tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
709 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
712/*
713 * Configures a rocketport port according to its termio settings. Called from
714 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
715 */
Alan Cox47b01b32009-01-02 13:48:30 +0000716static void configure_r_port(struct tty_struct *tty, struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800717 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 unsigned cflag;
720 unsigned long flags;
721 unsigned rocketMode;
722 int bits, baud, divisor;
723 CHANNEL_t *cp;
Alan Cox47b01b32009-01-02 13:48:30 +0000724 struct ktermios *t = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800727 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 /* Byte size and parity */
730 if ((cflag & CSIZE) == CS8) {
731 sSetData8(cp);
732 bits = 10;
733 } else {
734 sSetData7(cp);
735 bits = 9;
736 }
737 if (cflag & CSTOPB) {
738 sSetStop2(cp);
739 bits++;
740 } else {
741 sSetStop1(cp);
742 }
743
744 if (cflag & PARENB) {
745 sEnParity(cp);
746 bits++;
747 if (cflag & PARODD) {
748 sSetOddParity(cp);
749 } else {
750 sSetEvenParity(cp);
751 }
752 } else {
753 sDisParity(cp);
754 }
755
756 /* baud rate */
Alan Cox47b01b32009-01-02 13:48:30 +0000757 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (!baud)
759 baud = 9600;
760 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
761 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800762 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if (!baud)
764 baud = 9600;
765 divisor = (rp_baud_base[info->board] / baud) - 1;
766 }
767 if (divisor >= 8192 || divisor < 0) {
768 baud = 9600;
769 divisor = (rp_baud_base[info->board] / baud) - 1;
770 }
771 info->cps = baud / bits;
772 sSetBaud(cp, divisor);
773
Alan Cox6df35262008-02-08 04:18:45 -0800774 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Cox47b01b32009-01-02 13:48:30 +0000775 tty_encode_baud_rate(tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if (cflag & CRTSCTS) {
778 info->intmask |= DELTA_CTS;
779 sEnCTSFlowCtl(cp);
780 } else {
781 info->intmask &= ~DELTA_CTS;
782 sDisCTSFlowCtl(cp);
783 }
784 if (cflag & CLOCAL) {
785 info->intmask &= ~DELTA_CD;
786 } else {
787 spin_lock_irqsave(&info->slock, flags);
788 if (sGetChanStatus(cp) & CD_ACT)
789 info->cd_status = 1;
790 else
791 info->cd_status = 0;
792 info->intmask |= DELTA_CD;
793 spin_unlock_irqrestore(&info->slock, flags);
794 }
795
796 /*
797 * Handle software flow control in the board
798 */
799#ifdef ROCKET_SOFT_FLOW
Alan Cox47b01b32009-01-02 13:48:30 +0000800 if (I_IXON(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 sEnTxSoftFlowCtl(cp);
Alan Cox47b01b32009-01-02 13:48:30 +0000802 if (I_IXANY(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 sEnIXANY(cp);
804 } else {
805 sDisIXANY(cp);
806 }
Alan Cox47b01b32009-01-02 13:48:30 +0000807 sSetTxXONChar(cp, START_CHAR(tty));
808 sSetTxXOFFChar(cp, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 } else {
810 sDisTxSoftFlowCtl(cp);
811 sDisIXANY(cp);
812 sClrTxXOFF(cp);
813 }
814#endif
815
816 /*
817 * Set up ignore/read mask words
818 */
819 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Cox47b01b32009-01-02 13:48:30 +0000820 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000822 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 info->read_status_mask |= STMBREAKH;
824
825 /*
826 * Characters to ignore
827 */
828 info->ignore_status_mask = 0;
Alan Cox47b01b32009-01-02 13:48:30 +0000829 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000831 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 info->ignore_status_mask |= STMBREAKH;
833 /*
834 * If we're ignoring parity and break indicators,
835 * ignore overruns too. (For real raw support).
836 */
Alan Cox47b01b32009-01-02 13:48:30 +0000837 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 info->ignore_status_mask |= STMRCVROVRH;
839 }
840
841 rocketMode = info->flags & ROCKET_MODE_MASK;
842
843 if ((info->flags & ROCKET_RTS_TOGGLE)
844 || (rocketMode == ROCKET_MODE_RS485))
845 sEnRTSToggle(cp);
846 else
847 sDisRTSToggle(cp);
848
849 sSetRTS(&info->channel);
850
851 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
852 switch (rocketMode) {
853 case ROCKET_MODE_RS485:
854 sSetInterfaceMode(cp, InterfaceModeRS485);
855 break;
856 case ROCKET_MODE_RS422:
857 sSetInterfaceMode(cp, InterfaceModeRS422);
858 break;
859 case ROCKET_MODE_RS232:
860 default:
861 if (info->flags & ROCKET_RTS_TOGGLE)
862 sSetInterfaceMode(cp, InterfaceModeRS232T);
863 else
864 sSetInterfaceMode(cp, InterfaceModeRS232);
865 break;
866 }
867 }
868}
869
Alan Cox31f35932009-01-02 13:45:05 +0000870static int carrier_raised(struct tty_port *port)
871{
872 struct r_port *info = container_of(port, struct r_port, port);
873 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
874}
875
Alan Coxfcc8ac12009-06-11 12:24:17 +0100876static void dtr_rts(struct tty_port *port, int on)
Alan Cox5d951fb2009-01-02 13:45:19 +0000877{
878 struct r_port *info = container_of(port, struct r_port, port);
Alan Coxfcc8ac12009-06-11 12:24:17 +0100879 if (on) {
880 sSetDTR(&info->channel);
881 sSetRTS(&info->channel);
882 } else {
883 sClrDTR(&info->channel);
884 sClrRTS(&info->channel);
885 }
Alan Cox5d951fb2009-01-02 13:45:19 +0000886}
887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888/*
889 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
890 * port's r_port struct. Initializes the port hardware.
891 */
892static int rp_open(struct tty_struct *tty, struct file *filp)
893{
894 struct r_port *info;
Alan Coxfba85e02009-01-02 13:48:39 +0000895 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 int line = 0, retval;
897 CHANNEL_t *cp;
898 unsigned long page;
899
Jiri Slabyf6de0c92008-02-07 00:16:33 -0800900 line = tty->index;
Alan Coxfba85e02009-01-02 13:48:39 +0000901 if (line < 0 || line >= MAX_RP_PORTS || ((info = rp_table[line]) == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return -ENXIO;
Alan Coxfba85e02009-01-02 13:48:39 +0000903 port = &info->port;
904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 page = __get_free_page(GFP_KERNEL);
906 if (!page)
907 return -ENOMEM;
908
Alan Coxfba85e02009-01-02 13:48:39 +0000909 if (port->flags & ASYNC_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700910 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700912 if (retval)
913 return retval;
Alan Coxfba85e02009-01-02 13:48:39 +0000914 return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916
917 /*
918 * We must not sleep from here until the port is marked fully in use.
919 */
920 if (info->xmit_buf)
921 free_page(page);
922 else
923 info->xmit_buf = (unsigned char *) page;
924
925 tty->driver_data = info;
Alan Coxfba85e02009-01-02 13:48:39 +0000926 tty_port_tty_set(port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Alan Coxfba85e02009-01-02 13:48:39 +0000928 if (port->count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 atomic_inc(&rp_num_ports_open);
930
931#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -0800932 printk(KERN_INFO "rocket mod++ = %d...\n",
933 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934#endif
935 }
936#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +0100937 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938#endif
939
940 /*
941 * Info->count is now 1; so it's safe to sleep now.
942 */
Jiri Slabya391ad02009-06-11 12:40:17 +0100943 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 cp = &info->channel;
945 sSetRxTrigger(cp, TRIG_1);
946 if (sGetChanStatus(cp) & CD_ACT)
947 info->cd_status = 1;
948 else
949 info->cd_status = 0;
950 sDisRxStatusMode(cp);
951 sFlushRxFIFO(cp);
952 sFlushTxFIFO(cp);
953
954 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
955 sSetRxTrigger(cp, TRIG_1);
956
957 sGetChanStatus(cp);
958 sDisRxStatusMode(cp);
959 sClrTxXOFF(cp);
960
961 sDisCTSFlowCtl(cp);
962 sDisTxSoftFlowCtl(cp);
963
964 sEnRxFIFO(cp);
965 sEnTransmit(cp);
966
Jiri Slabya391ad02009-06-11 12:40:17 +0100967 set_bit(ASYNCB_INITIALIZED, &info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
969 /*
970 * Set up the tty->alt_speed kludge
971 */
972 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +0000973 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000975 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000977 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +0000979 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Alan Cox47b01b32009-01-02 13:48:30 +0000981 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (tty->termios->c_cflag & CBAUD) {
983 sSetDTR(cp);
984 sSetRTS(cp);
985 }
986 }
987 /* Starts (or resets) the maint polling loop */
988 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
989
Alan Coxfba85e02009-01-02 13:48:39 +0000990 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (retval) {
992#ifdef ROCKET_DEBUG_OPEN
993 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
994#endif
995 return retval;
996 }
997 return 0;
998}
999
1000/*
Alan Coxe60a1082008-07-16 21:56:18 +01001001 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 */
1003static void rp_close(struct tty_struct *tty, struct file *filp)
1004{
Alan Coxc9f19e92009-01-02 13:47:26 +00001005 struct r_port *info = tty->driver_data;
Alan Coxc1314a42009-01-02 13:48:17 +00001006 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 int timeout;
1008 CHANNEL_t *cp;
1009
1010 if (rocket_paranoia_check(info, "rp_close"))
1011 return;
1012
1013#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001014 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015#endif
1016
Alan Coxfba85e02009-01-02 13:48:39 +00001017 if (tty_port_close_start(port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
1020 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 /*
1022 * Before we drop DTR, make sure the UART transmitter
1023 * has completely drained; this is especially
1024 * important if there is a transmit FIFO!
1025 */
1026 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1027 if (timeout == 0)
1028 timeout = 1;
1029 rp_wait_until_sent(tty, timeout);
1030 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1031
1032 sDisTransmit(cp);
1033 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1034 sDisCTSFlowCtl(cp);
1035 sDisTxSoftFlowCtl(cp);
1036 sClrTxXOFF(cp);
1037 sFlushRxFIFO(cp);
1038 sFlushTxFIFO(cp);
1039 sClrRTS(cp);
1040 if (C_HUPCL(tty))
1041 sClrDTR(cp);
1042
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001043 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 tty_ldisc_flush(tty);
1046
1047 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1048
Alan Coxfba85e02009-01-02 13:48:39 +00001049 /* We can't yet use tty_port_close_end as the buffer handling in this
1050 driver is a bit different to the usual */
1051
Alan Coxc1314a42009-01-02 13:48:17 +00001052 if (port->blocked_open) {
1053 if (port->close_delay) {
1054 msleep_interruptible(jiffies_to_msecs(port->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 }
Alan Coxc1314a42009-01-02 13:48:17 +00001056 wake_up_interruptible(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 } else {
1058 if (info->xmit_buf) {
1059 free_page((unsigned long) info->xmit_buf);
1060 info->xmit_buf = NULL;
1061 }
1062 }
Alan Cox21bed702009-01-02 13:48:23 +00001063 info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 tty->closing = 0;
Alan Coxfba85e02009-01-02 13:48:39 +00001065 tty_port_tty_set(port, NULL);
1066 wake_up_interruptible(&port->close_wait);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001067 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 atomic_dec(&rp_num_ports_open);
1069
1070#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001071 printk(KERN_INFO "rocket mod-- = %d...\n",
1072 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1074#endif
1075
1076}
1077
1078static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001079 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080{
Alan Coxc9f19e92009-01-02 13:47:26 +00001081 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 CHANNEL_t *cp;
1083 unsigned cflag;
1084
1085 if (rocket_paranoia_check(info, "rp_set_termios"))
1086 return;
1087
1088 cflag = tty->termios->c_cflag;
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 /*
1091 * This driver doesn't support CS5 or CS6
1092 */
1093 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
1094 tty->termios->c_cflag =
1095 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001096 /* Or CMSPAR */
1097 tty->termios->c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Alan Cox47b01b32009-01-02 13:48:30 +00001099 configure_r_port(tty, info, old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 cp = &info->channel;
1102
1103 /* Handle transition to B0 status */
1104 if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
1105 sClrDTR(cp);
1106 sClrRTS(cp);
1107 }
1108
1109 /* Handle transition away from B0 status */
1110 if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
1111 if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
1112 sSetRTS(cp);
1113 sSetDTR(cp);
1114 }
1115
1116 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
1117 tty->hw_stopped = 0;
1118 rp_start(tty);
1119 }
1120}
1121
Alan Cox9e989662008-07-22 11:18:03 +01001122static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123{
Alan Coxc9f19e92009-01-02 13:47:26 +00001124 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 unsigned long flags;
1126
1127 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001128 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 spin_lock_irqsave(&info->slock, flags);
1131 if (break_state == -1)
1132 sSendBreak(&info->channel);
1133 else
1134 sClrBreak(&info->channel);
1135 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001136 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139/*
1140 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1141 * the UPCI boards was added, it was decided to make this a function because
1142 * the macro was getting too complicated. All cases except the first one
1143 * (UPCIRingInd) are taken directly from the original macro.
1144 */
1145static int sGetChanRI(CHANNEL_T * ChP)
1146{
1147 CONTROLLER_t *CtlP = ChP->CtlP;
1148 int ChanNum = ChP->ChanNum;
1149 int RingInd = 0;
1150
1151 if (CtlP->UPCIRingInd)
1152 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1153 else if (CtlP->AltChanRingIndicator)
1154 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1155 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1156 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1157
1158 return RingInd;
1159}
1160
1161/********************************************************************************************/
1162/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1163
1164/*
1165 * Returns the state of the serial modem control lines. These next 2 functions
1166 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1167 */
1168static int rp_tiocmget(struct tty_struct *tty, struct file *file)
1169{
Alan Coxc9f19e92009-01-02 13:47:26 +00001170 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 unsigned int control, result, ChanStatus;
1172
1173 ChanStatus = sGetChanStatusLo(&info->channel);
1174 control = info->channel.TxControl[3];
1175 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1176 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1177 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1178 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1179 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1180 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1181
1182 return result;
1183}
1184
1185/*
1186 * Sets the modem control lines
1187 */
1188static int rp_tiocmset(struct tty_struct *tty, struct file *file,
1189 unsigned int set, unsigned int clear)
1190{
Alan Coxc9f19e92009-01-02 13:47:26 +00001191 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 if (set & TIOCM_RTS)
1194 info->channel.TxControl[3] |= SET_RTS;
1195 if (set & TIOCM_DTR)
1196 info->channel.TxControl[3] |= SET_DTR;
1197 if (clear & TIOCM_RTS)
1198 info->channel.TxControl[3] &= ~SET_RTS;
1199 if (clear & TIOCM_DTR)
1200 info->channel.TxControl[3] &= ~SET_DTR;
1201
Al Viro457fb602008-03-19 16:27:48 +00001202 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return 0;
1204}
1205
1206static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1207{
1208 struct rocket_config tmp;
1209
1210 if (!retinfo)
1211 return -EFAULT;
1212 memset(&tmp, 0, sizeof (tmp));
1213 tmp.line = info->line;
1214 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001215 tmp.close_delay = info->port.close_delay;
1216 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
1218
1219 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1220 return -EFAULT;
1221 return 0;
1222}
1223
Alan Cox47b01b32009-01-02 13:48:30 +00001224static int set_config(struct tty_struct *tty, struct r_port *info,
1225 struct rocket_config __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 struct rocket_config new_serial;
1228
1229 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1230 return -EFAULT;
1231
1232 if (!capable(CAP_SYS_ADMIN))
1233 {
1234 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
1235 return -EPERM;
1236 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
Alan Cox47b01b32009-01-02 13:48:30 +00001237 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 return 0;
1239 }
1240
1241 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001242 info->port.close_delay = new_serial.close_delay;
1243 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
1245 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +00001246 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001248 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001250 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +00001252 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Alan Cox47b01b32009-01-02 13:48:30 +00001254 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return 0;
1256}
1257
1258/*
1259 * This function fills in a rocket_ports struct with information
1260 * about what boards/ports are in the system. This info is passed
1261 * to user space. See setrocket.c where the info is used to create
1262 * the /dev/ttyRx ports.
1263 */
1264static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1265{
1266 struct rocket_ports tmp;
1267 int board;
1268
1269 if (!retports)
1270 return -EFAULT;
1271 memset(&tmp, 0, sizeof (tmp));
1272 tmp.tty_major = rocket_driver->major;
1273
1274 for (board = 0; board < 4; board++) {
1275 tmp.rocketModel[board].model = rocketModel[board].model;
1276 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1277 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1278 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1279 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1280 }
1281 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1282 return -EFAULT;
1283 return 0;
1284}
1285
1286static int reset_rm2(struct r_port *info, void __user *arg)
1287{
1288 int reset;
1289
Alan Cox4129a642008-02-08 04:18:45 -08001290 if (!capable(CAP_SYS_ADMIN))
1291 return -EPERM;
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (copy_from_user(&reset, arg, sizeof (int)))
1294 return -EFAULT;
1295 if (reset)
1296 reset = 1;
1297
1298 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1299 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1300 return -EINVAL;
1301
1302 if (info->ctlp->BusType == isISA)
1303 sModemReset(info->ctlp, info->chan, reset);
1304 else
1305 sPCIModemReset(info->ctlp, info->chan, reset);
1306
1307 return 0;
1308}
1309
1310static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1311{
1312 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1313 return -EFAULT;
1314 return 0;
1315}
1316
1317/* IOCTL call handler into the driver */
1318static int rp_ioctl(struct tty_struct *tty, struct file *file,
1319 unsigned int cmd, unsigned long arg)
1320{
Alan Coxc9f19e92009-01-02 13:47:26 +00001321 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001323 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
1325 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1326 return -ENXIO;
1327
Alan Coxbdf183a2008-04-30 00:53:21 -07001328 lock_kernel();
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 switch (cmd) {
1331 case RCKP_GET_STRUCT:
1332 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001333 ret = -EFAULT;
1334 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001336 ret = get_config(info, argp);
1337 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 case RCKP_SET_CONFIG:
Alan Cox47b01b32009-01-02 13:48:30 +00001339 ret = set_config(tty, info, argp);
Alan Coxbdf183a2008-04-30 00:53:21 -07001340 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001342 ret = get_ports(info, argp);
1343 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001345 ret = reset_rm2(info, argp);
1346 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001348 ret = get_version(info, argp);
1349 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001351 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001353 unlock_kernel();
1354 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355}
1356
1357static void rp_send_xchar(struct tty_struct *tty, char ch)
1358{
Alan Coxc9f19e92009-01-02 13:47:26 +00001359 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 CHANNEL_t *cp;
1361
1362 if (rocket_paranoia_check(info, "rp_send_xchar"))
1363 return;
1364
1365 cp = &info->channel;
1366 if (sGetTxCnt(cp))
1367 sWriteTxPrioByte(cp, ch);
1368 else
1369 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1370}
1371
1372static void rp_throttle(struct tty_struct *tty)
1373{
Alan Coxc9f19e92009-01-02 13:47:26 +00001374 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 CHANNEL_t *cp;
1376
1377#ifdef ROCKET_DEBUG_THROTTLE
1378 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1379 tty->ldisc.chars_in_buffer(tty));
1380#endif
1381
1382 if (rocket_paranoia_check(info, "rp_throttle"))
1383 return;
1384
1385 cp = &info->channel;
1386 if (I_IXOFF(tty))
1387 rp_send_xchar(tty, STOP_CHAR(tty));
1388
1389 sClrRTS(&info->channel);
1390}
1391
1392static void rp_unthrottle(struct tty_struct *tty)
1393{
Alan Coxc9f19e92009-01-02 13:47:26 +00001394 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 CHANNEL_t *cp;
1396#ifdef ROCKET_DEBUG_THROTTLE
1397 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1398 tty->ldisc.chars_in_buffer(tty));
1399#endif
1400
1401 if (rocket_paranoia_check(info, "rp_throttle"))
1402 return;
1403
1404 cp = &info->channel;
1405 if (I_IXOFF(tty))
1406 rp_send_xchar(tty, START_CHAR(tty));
1407
1408 sSetRTS(&info->channel);
1409}
1410
1411/*
1412 * ------------------------------------------------------------
1413 * rp_stop() and rp_start()
1414 *
1415 * This routines are called before setting or resetting tty->stopped.
1416 * They enable or disable transmitter interrupts, as necessary.
1417 * ------------------------------------------------------------
1418 */
1419static void rp_stop(struct tty_struct *tty)
1420{
Alan Coxc9f19e92009-01-02 13:47:26 +00001421 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
1423#ifdef ROCKET_DEBUG_FLOW
1424 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1425 info->xmit_cnt, info->xmit_fifo_room);
1426#endif
1427
1428 if (rocket_paranoia_check(info, "rp_stop"))
1429 return;
1430
1431 if (sGetTxCnt(&info->channel))
1432 sDisTransmit(&info->channel);
1433}
1434
1435static void rp_start(struct tty_struct *tty)
1436{
Alan Coxc9f19e92009-01-02 13:47:26 +00001437 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
1439#ifdef ROCKET_DEBUG_FLOW
1440 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1441 info->xmit_cnt, info->xmit_fifo_room);
1442#endif
1443
1444 if (rocket_paranoia_check(info, "rp_stop"))
1445 return;
1446
1447 sEnTransmit(&info->channel);
1448 set_bit((info->aiop * 8) + info->chan,
1449 (void *) &xmit_flags[info->board]);
1450}
1451
1452/*
1453 * rp_wait_until_sent() --- wait until the transmitter is empty
1454 */
1455static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1456{
Alan Coxc9f19e92009-01-02 13:47:26 +00001457 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 CHANNEL_t *cp;
1459 unsigned long orig_jiffies;
1460 int check_time, exit_time;
1461 int txcnt;
1462
1463 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1464 return;
1465
1466 cp = &info->channel;
1467
1468 orig_jiffies = jiffies;
1469#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001470 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001472 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473#endif
Alan Cox978e5952008-04-30 00:53:59 -07001474 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 while (1) {
1476 txcnt = sGetTxCnt(cp);
1477 if (!txcnt) {
1478 if (sGetChanStatusLo(cp) & TXSHRMT)
1479 break;
1480 check_time = (HZ / info->cps) / 5;
1481 } else {
1482 check_time = HZ * txcnt / info->cps;
1483 }
1484 if (timeout) {
1485 exit_time = orig_jiffies + timeout - jiffies;
1486 if (exit_time <= 0)
1487 break;
1488 if (exit_time < check_time)
1489 check_time = exit_time;
1490 }
1491 if (check_time == 0)
1492 check_time = 1;
1493#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001494 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1495 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496#endif
1497 msleep_interruptible(jiffies_to_msecs(check_time));
1498 if (signal_pending(current))
1499 break;
1500 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001501 __set_current_state(TASK_RUNNING);
Alan Cox978e5952008-04-30 00:53:59 -07001502 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1504 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1505#endif
1506}
1507
1508/*
1509 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1510 */
1511static void rp_hangup(struct tty_struct *tty)
1512{
1513 CHANNEL_t *cp;
Alan Coxc9f19e92009-01-02 13:47:26 +00001514 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 if (rocket_paranoia_check(info, "rp_hangup"))
1517 return;
1518
1519#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001520 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521#endif
1522 rp_flush_buffer(tty);
Alan Cox21bed702009-01-02 13:48:23 +00001523 if (info->port.flags & ASYNC_CLOSING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 return;
Alan Coxe60a1082008-07-16 21:56:18 +01001525 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 atomic_dec(&rp_num_ports_open);
1527 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1528
Alan Coxfba85e02009-01-02 13:48:39 +00001529 tty_port_hangup(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 cp = &info->channel;
1532 sDisRxFIFO(cp);
1533 sDisTransmit(cp);
1534 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1535 sDisCTSFlowCtl(cp);
1536 sDisTxSoftFlowCtl(cp);
1537 sClrTxXOFF(cp);
Alan Cox21bed702009-01-02 13:48:23 +00001538 info->port.flags &= ~ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Alan Coxe60a1082008-07-16 21:56:18 +01001540 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541}
1542
1543/*
1544 * Exception handler - write char routine. The RocketPort driver uses a
1545 * double-buffering strategy, with the twist that if the in-memory CPU
1546 * buffer is empty, and there's space in the transmit FIFO, the
1547 * writing routines will write directly to transmit FIFO.
1548 * Write buffer and counters protected by spinlocks
1549 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001550static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551{
Alan Coxc9f19e92009-01-02 13:47:26 +00001552 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 CHANNEL_t *cp;
1554 unsigned long flags;
1555
1556 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001557 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001559 /*
1560 * Grab the port write mutex, locking out other processes that try to
1561 * write to this port
1562 */
1563 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
1565#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001566 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567#endif
1568
1569 spin_lock_irqsave(&info->slock, flags);
1570 cp = &info->channel;
1571
1572 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1573 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1574
1575 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1576 info->xmit_buf[info->xmit_head++] = ch;
1577 info->xmit_head &= XMIT_BUF_SIZE - 1;
1578 info->xmit_cnt++;
1579 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1580 } else {
1581 sOutB(sGetTxRxDataIO(cp), ch);
1582 info->xmit_fifo_room--;
1583 }
1584 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001585 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001586 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587}
1588
1589/*
1590 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001591 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 * this port at the same time. This other process could be running on the other CPU
1593 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1594 * Spinlocks protect the info xmit members.
1595 */
1596static int rp_write(struct tty_struct *tty,
1597 const unsigned char *buf, int count)
1598{
Alan Coxc9f19e92009-01-02 13:47:26 +00001599 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 CHANNEL_t *cp;
1601 const unsigned char *b;
1602 int c, retval = 0;
1603 unsigned long flags;
1604
1605 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1606 return 0;
1607
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001608 if (mutex_lock_interruptible(&info->write_mtx))
1609 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
1611#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001612 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613#endif
1614 cp = &info->channel;
1615
1616 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1617 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1618
1619 /*
1620 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1621 * into FIFO. Use the write queue for temp storage.
1622 */
1623 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1624 c = min(count, info->xmit_fifo_room);
1625 b = buf;
1626
1627 /* Push data into FIFO, 2 bytes at a time */
1628 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1629
1630 /* If there is a byte remaining, write it */
1631 if (c & 1)
1632 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1633
1634 retval += c;
1635 buf += c;
1636 count -= c;
1637
1638 spin_lock_irqsave(&info->slock, flags);
1639 info->xmit_fifo_room -= c;
1640 spin_unlock_irqrestore(&info->slock, flags);
1641 }
1642
1643 /* If count is zero, we wrote it all and are done */
1644 if (!count)
1645 goto end;
1646
1647 /* Write remaining data into the port's xmit_buf */
1648 while (1) {
Alan Cox47b01b32009-01-02 13:48:30 +00001649 /* Hung up ? */
Jiri Slabya391ad02009-06-11 12:40:17 +01001650 if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001652 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1653 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 if (c <= 0)
1655 break;
1656
1657 b = buf;
1658 memcpy(info->xmit_buf + info->xmit_head, b, c);
1659
1660 spin_lock_irqsave(&info->slock, flags);
1661 info->xmit_head =
1662 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1663 info->xmit_cnt += c;
1664 spin_unlock_irqrestore(&info->slock, flags);
1665
1666 buf += c;
1667 count -= c;
1668 retval += c;
1669 }
1670
1671 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1672 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1673
1674end:
1675 if (info->xmit_cnt < WAKEUP_CHARS) {
1676 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677#ifdef ROCKETPORT_HAVE_POLL_WAIT
1678 wake_up_interruptible(&tty->poll_wait);
1679#endif
1680 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001681 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 return retval;
1683}
1684
1685/*
1686 * Return the number of characters that can be sent. We estimate
1687 * only using the in-memory transmit buffer only, and ignore the
1688 * potential space in the transmit FIFO.
1689 */
1690static int rp_write_room(struct tty_struct *tty)
1691{
Alan Coxc9f19e92009-01-02 13:47:26 +00001692 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 int ret;
1694
1695 if (rocket_paranoia_check(info, "rp_write_room"))
1696 return 0;
1697
1698 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1699 if (ret < 0)
1700 ret = 0;
1701#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001702 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703#endif
1704 return ret;
1705}
1706
1707/*
1708 * Return the number of characters in the buffer. Again, this only
1709 * counts those characters in the in-memory transmit buffer.
1710 */
1711static int rp_chars_in_buffer(struct tty_struct *tty)
1712{
Alan Coxc9f19e92009-01-02 13:47:26 +00001713 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 CHANNEL_t *cp;
1715
1716 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1717 return 0;
1718
1719 cp = &info->channel;
1720
1721#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001722 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723#endif
1724 return info->xmit_cnt;
1725}
1726
1727/*
1728 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1729 * r_port struct for the port. Note that spinlock are used to protect info members,
1730 * do not call this function if the spinlock is already held.
1731 */
1732static void rp_flush_buffer(struct tty_struct *tty)
1733{
Alan Coxc9f19e92009-01-02 13:47:26 +00001734 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 CHANNEL_t *cp;
1736 unsigned long flags;
1737
1738 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1739 return;
1740
1741 spin_lock_irqsave(&info->slock, flags);
1742 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1743 spin_unlock_irqrestore(&info->slock, flags);
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745#ifdef ROCKETPORT_HAVE_POLL_WAIT
1746 wake_up_interruptible(&tty->poll_wait);
1747#endif
1748 tty_wakeup(tty);
1749
1750 cp = &info->channel;
1751 sFlushTxFIFO(cp);
1752}
1753
1754#ifdef CONFIG_PCI
1755
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001756static struct pci_device_id __devinitdata rocket_pci_ids[] = {
1757 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
1758 { }
1759};
1760MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762/*
1763 * Called when a PCI card is found. Retrieves and stores model information,
1764 * init's aiopic and serial port hardware.
1765 * Inputs: i is the board number (0-n)
1766 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001767static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1770 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1771 char *str, *board_type;
1772 CONTROLLER_t *ctlp;
1773
1774 int fast_clock = 0;
1775 int altChanRingIndicator = 0;
1776 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 WordIO_t ConfigIO = 0;
1778 ByteIO_t UPCIRingInd = 0;
1779
1780 if (!dev || pci_enable_device(dev))
1781 return 0;
1782
1783 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1786 rocketModel[i].loadrm2 = 0;
1787 rocketModel[i].startingPortNumber = nextLineNumber;
1788
1789 /* Depending on the model, set up some config variables */
1790 switch (dev->device) {
1791 case PCI_DEVICE_ID_RP4QUAD:
1792 str = "Quadcable";
1793 max_num_aiops = 1;
1794 ports_per_aiop = 4;
1795 rocketModel[i].model = MODEL_RP4QUAD;
1796 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1797 rocketModel[i].numPorts = 4;
1798 break;
1799 case PCI_DEVICE_ID_RP8OCTA:
1800 str = "Octacable";
1801 max_num_aiops = 1;
1802 rocketModel[i].model = MODEL_RP8OCTA;
1803 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1804 rocketModel[i].numPorts = 8;
1805 break;
1806 case PCI_DEVICE_ID_URP8OCTA:
1807 str = "Octacable";
1808 max_num_aiops = 1;
1809 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1810 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1811 rocketModel[i].numPorts = 8;
1812 break;
1813 case PCI_DEVICE_ID_RP8INTF:
1814 str = "8";
1815 max_num_aiops = 1;
1816 rocketModel[i].model = MODEL_RP8INTF;
1817 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1818 rocketModel[i].numPorts = 8;
1819 break;
1820 case PCI_DEVICE_ID_URP8INTF:
1821 str = "8";
1822 max_num_aiops = 1;
1823 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1824 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1825 rocketModel[i].numPorts = 8;
1826 break;
1827 case PCI_DEVICE_ID_RP8J:
1828 str = "8J";
1829 max_num_aiops = 1;
1830 rocketModel[i].model = MODEL_RP8J;
1831 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1832 rocketModel[i].numPorts = 8;
1833 break;
1834 case PCI_DEVICE_ID_RP4J:
1835 str = "4J";
1836 max_num_aiops = 1;
1837 ports_per_aiop = 4;
1838 rocketModel[i].model = MODEL_RP4J;
1839 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1840 rocketModel[i].numPorts = 4;
1841 break;
1842 case PCI_DEVICE_ID_RP8SNI:
1843 str = "8 (DB78 Custom)";
1844 max_num_aiops = 1;
1845 rocketModel[i].model = MODEL_RP8SNI;
1846 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1847 rocketModel[i].numPorts = 8;
1848 break;
1849 case PCI_DEVICE_ID_RP16SNI:
1850 str = "16 (DB78 Custom)";
1851 max_num_aiops = 2;
1852 rocketModel[i].model = MODEL_RP16SNI;
1853 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1854 rocketModel[i].numPorts = 16;
1855 break;
1856 case PCI_DEVICE_ID_RP16INTF:
1857 str = "16";
1858 max_num_aiops = 2;
1859 rocketModel[i].model = MODEL_RP16INTF;
1860 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1861 rocketModel[i].numPorts = 16;
1862 break;
1863 case PCI_DEVICE_ID_URP16INTF:
1864 str = "16";
1865 max_num_aiops = 2;
1866 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1867 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1868 rocketModel[i].numPorts = 16;
1869 break;
1870 case PCI_DEVICE_ID_CRP16INTF:
1871 str = "16";
1872 max_num_aiops = 2;
1873 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1874 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
1875 rocketModel[i].numPorts = 16;
1876 break;
1877 case PCI_DEVICE_ID_RP32INTF:
1878 str = "32";
1879 max_num_aiops = 4;
1880 rocketModel[i].model = MODEL_RP32INTF;
1881 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
1882 rocketModel[i].numPorts = 32;
1883 break;
1884 case PCI_DEVICE_ID_URP32INTF:
1885 str = "32";
1886 max_num_aiops = 4;
1887 rocketModel[i].model = MODEL_UPCI_RP32INTF;
1888 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
1889 rocketModel[i].numPorts = 32;
1890 break;
1891 case PCI_DEVICE_ID_RPP4:
1892 str = "Plus Quadcable";
1893 max_num_aiops = 1;
1894 ports_per_aiop = 4;
1895 altChanRingIndicator++;
1896 fast_clock++;
1897 rocketModel[i].model = MODEL_RPP4;
1898 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
1899 rocketModel[i].numPorts = 4;
1900 break;
1901 case PCI_DEVICE_ID_RPP8:
1902 str = "Plus Octacable";
1903 max_num_aiops = 2;
1904 ports_per_aiop = 4;
1905 altChanRingIndicator++;
1906 fast_clock++;
1907 rocketModel[i].model = MODEL_RPP8;
1908 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
1909 rocketModel[i].numPorts = 8;
1910 break;
1911 case PCI_DEVICE_ID_RP2_232:
1912 str = "Plus 2 (RS-232)";
1913 max_num_aiops = 1;
1914 ports_per_aiop = 2;
1915 altChanRingIndicator++;
1916 fast_clock++;
1917 rocketModel[i].model = MODEL_RP2_232;
1918 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
1919 rocketModel[i].numPorts = 2;
1920 break;
1921 case PCI_DEVICE_ID_RP2_422:
1922 str = "Plus 2 (RS-422)";
1923 max_num_aiops = 1;
1924 ports_per_aiop = 2;
1925 altChanRingIndicator++;
1926 fast_clock++;
1927 rocketModel[i].model = MODEL_RP2_422;
1928 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
1929 rocketModel[i].numPorts = 2;
1930 break;
1931 case PCI_DEVICE_ID_RP6M:
1932
1933 max_num_aiops = 1;
1934 ports_per_aiop = 6;
1935 str = "6-port";
1936
Jiri Slaby57fedc72007-10-18 03:06:28 -07001937 /* If revision is 1, the rocketmodem flash must be loaded.
1938 * If it is 2 it is a "socketed" version. */
1939 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
1941 rocketModel[i].loadrm2 = 1;
1942 } else {
1943 rcktpt_type[i] = ROCKET_TYPE_MODEM;
1944 }
1945
1946 rocketModel[i].model = MODEL_RP6M;
1947 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
1948 rocketModel[i].numPorts = 6;
1949 break;
1950 case PCI_DEVICE_ID_RP4M:
1951 max_num_aiops = 1;
1952 ports_per_aiop = 4;
1953 str = "4-port";
Jiri Slaby57fedc72007-10-18 03:06:28 -07001954 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
1956 rocketModel[i].loadrm2 = 1;
1957 } else {
1958 rcktpt_type[i] = ROCKET_TYPE_MODEM;
1959 }
1960
1961 rocketModel[i].model = MODEL_RP4M;
1962 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
1963 rocketModel[i].numPorts = 4;
1964 break;
1965 default:
1966 str = "(unknown/unsupported)";
1967 max_num_aiops = 0;
1968 break;
1969 }
1970
1971 /*
1972 * Check for UPCI boards.
1973 */
1974
1975 switch (dev->device) {
1976 case PCI_DEVICE_ID_URP32INTF:
1977 case PCI_DEVICE_ID_URP8INTF:
1978 case PCI_DEVICE_ID_URP16INTF:
1979 case PCI_DEVICE_ID_CRP16INTF:
1980 case PCI_DEVICE_ID_URP8OCTA:
1981 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
1982 ConfigIO = pci_resource_start(dev, 1);
1983 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
1984 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
1985
1986 /*
1987 * Check for octa or quad cable.
1988 */
1989 if (!
1990 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
1991 PCI_GPIO_CTRL_8PORT)) {
1992 str = "Quadcable";
1993 ports_per_aiop = 4;
1994 rocketModel[i].numPorts = 4;
1995 }
1996 }
1997 break;
1998 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
1999 str = "8 ports";
2000 max_num_aiops = 1;
2001 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
2002 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
2003 rocketModel[i].numPorts = 8;
2004 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2005 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2006 ConfigIO = pci_resource_start(dev, 1);
2007 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2008 break;
2009 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
2010 str = "4 ports";
2011 max_num_aiops = 1;
2012 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2013 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2014 rocketModel[i].numPorts = 4;
2015 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2016 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2017 ConfigIO = pci_resource_start(dev, 1);
2018 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2019 break;
2020 default:
2021 break;
2022 }
2023
2024 switch (rcktpt_type[i]) {
2025 case ROCKET_TYPE_MODEM:
2026 board_type = "RocketModem";
2027 break;
2028 case ROCKET_TYPE_MODEMII:
2029 board_type = "RocketModem II";
2030 break;
2031 case ROCKET_TYPE_MODEMIII:
2032 board_type = "RocketModem III";
2033 break;
2034 default:
2035 board_type = "RocketPort";
2036 break;
2037 }
2038
2039 if (fast_clock) {
2040 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2041 rp_baud_base[i] = 921600;
2042 } else {
2043 /*
2044 * If support_low_speed is set, use the slow clock
2045 * prescale, which supports 50 bps
2046 */
2047 if (support_low_speed) {
2048 /* mod 9 (divide by 10) prescale */
2049 sClockPrescale = 0x19;
2050 rp_baud_base[i] = 230400;
2051 } else {
2052 /* mod 4 (devide by 5) prescale */
2053 sClockPrescale = 0x14;
2054 rp_baud_base[i] = 460800;
2055 }
2056 }
2057
2058 for (aiop = 0; aiop < max_num_aiops; aiop++)
2059 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2060 ctlp = sCtlNumToCtlPtr(i);
2061 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2062 for (aiop = 0; aiop < max_num_aiops; aiop++)
2063 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2064
Jiri Slaby68562b72008-02-07 00:16:33 -08002065 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2066 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2067 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2068 rocketModel[i].startingPortNumber,
2069 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 if (num_aiops <= 0) {
2072 rcktpt_io_addr[i] = 0;
2073 return (0);
2074 }
2075 is_PCI[i] = 1;
2076
2077 /* Reset the AIOPIC, init the serial ports */
2078 for (aiop = 0; aiop < num_aiops; aiop++) {
2079 sResetAiopByNum(ctlp, aiop);
2080 num_chan = ports_per_aiop;
2081 for (chan = 0; chan < num_chan; chan++)
2082 init_r_port(i, aiop, chan, dev);
2083 }
2084
2085 /* Rocket modems must be reset */
2086 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2087 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2088 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2089 num_chan = ports_per_aiop;
2090 for (chan = 0; chan < num_chan; chan++)
2091 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002092 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 for (chan = 0; chan < num_chan; chan++)
2094 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002095 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 rmSpeakerReset(ctlp, rocketModel[i].model);
2097 }
2098 return (1);
2099}
2100
2101/*
2102 * Probes for PCI cards, inits them if found
2103 * Input: board_found = number of ISA boards already found, or the
2104 * starting board number
2105 * Returns: Number of PCI boards found
2106 */
2107static int __init init_PCI(int boards_found)
2108{
2109 struct pci_dev *dev = NULL;
2110 int count = 0;
2111
2112 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002113 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 if (register_PCI(count + boards_found, dev))
2115 count++;
2116 }
2117 return (count);
2118}
2119
2120#endif /* CONFIG_PCI */
2121
2122/*
2123 * Probes for ISA cards
2124 * Input: i = the board number to look for
2125 * Returns: 1 if board found, 0 else
2126 */
2127static int __init init_ISA(int i)
2128{
2129 int num_aiops, num_chan = 0, total_num_chan = 0;
2130 int aiop, chan;
2131 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2132 CONTROLLER_t *ctlp;
2133 char *type_string;
2134
2135 /* If io_addr is zero, no board configured */
2136 if (rcktpt_io_addr[i] == 0)
2137 return (0);
2138
2139 /* Reserve the IO region */
2140 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002141 printk(KERN_ERR "Unable to reserve IO region for configured "
2142 "ISA RocketPort at address 0x%lx, board not "
2143 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 rcktpt_io_addr[i] = 0;
2145 return (0);
2146 }
2147
2148 ctlp = sCtlNumToCtlPtr(i);
2149
2150 ctlp->boardType = rcktpt_type[i];
2151
2152 switch (rcktpt_type[i]) {
2153 case ROCKET_TYPE_PC104:
2154 type_string = "(PC104)";
2155 break;
2156 case ROCKET_TYPE_MODEM:
2157 type_string = "(RocketModem)";
2158 break;
2159 case ROCKET_TYPE_MODEMII:
2160 type_string = "(RocketModem II)";
2161 break;
2162 default:
2163 type_string = "";
2164 break;
2165 }
2166
2167 /*
2168 * If support_low_speed is set, use the slow clock prescale,
2169 * which supports 50 bps
2170 */
2171 if (support_low_speed) {
2172 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2173 rp_baud_base[i] = 230400;
2174 } else {
2175 sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */
2176 rp_baud_base[i] = 460800;
2177 }
2178
2179 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2180 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2181
2182 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2183
2184 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2185 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2186 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2187 }
2188
2189 /* If something went wrong initing the AIOP's release the ISA IO memory */
2190 if (num_aiops <= 0) {
2191 release_region(rcktpt_io_addr[i], 64);
2192 rcktpt_io_addr[i] = 0;
2193 return (0);
2194 }
2195
2196 rocketModel[i].startingPortNumber = nextLineNumber;
2197
2198 for (aiop = 0; aiop < num_aiops; aiop++) {
2199 sResetAiopByNum(ctlp, aiop);
2200 sEnAiop(ctlp, aiop);
2201 num_chan = sGetAiopNumChan(ctlp, aiop);
2202 total_num_chan += num_chan;
2203 for (chan = 0; chan < num_chan; chan++)
2204 init_r_port(i, aiop, chan, NULL);
2205 }
2206 is_PCI[i] = 0;
2207 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2208 num_chan = sGetAiopNumChan(ctlp, 0);
2209 total_num_chan = num_chan;
2210 for (chan = 0; chan < num_chan; chan++)
2211 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002212 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 for (chan = 0; chan < num_chan; chan++)
2214 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002215 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2217 } else {
2218 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2219 }
2220 rocketModel[i].numPorts = total_num_chan;
2221 rocketModel[i].model = MODEL_ISA;
2222
2223 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2224 i, rcktpt_io_addr[i], num_aiops, type_string);
2225
2226 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2227 rocketModel[i].modelString,
2228 rocketModel[i].startingPortNumber,
2229 rocketModel[i].startingPortNumber +
2230 rocketModel[i].numPorts - 1);
2231
2232 return (1);
2233}
2234
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002235static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 .open = rp_open,
2237 .close = rp_close,
2238 .write = rp_write,
2239 .put_char = rp_put_char,
2240 .write_room = rp_write_room,
2241 .chars_in_buffer = rp_chars_in_buffer,
2242 .flush_buffer = rp_flush_buffer,
2243 .ioctl = rp_ioctl,
2244 .throttle = rp_throttle,
2245 .unthrottle = rp_unthrottle,
2246 .set_termios = rp_set_termios,
2247 .stop = rp_stop,
2248 .start = rp_start,
2249 .hangup = rp_hangup,
2250 .break_ctl = rp_break,
2251 .send_xchar = rp_send_xchar,
2252 .wait_until_sent = rp_wait_until_sent,
2253 .tiocmget = rp_tiocmget,
2254 .tiocmset = rp_tiocmset,
2255};
2256
Alan Cox31f35932009-01-02 13:45:05 +00002257static const struct tty_port_operations rocket_port_ops = {
2258 .carrier_raised = carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +01002259 .dtr_rts = dtr_rts,
Alan Cox31f35932009-01-02 13:45:05 +00002260};
2261
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262/*
2263 * The module "startup" routine; it's run when the module is loaded.
2264 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002265static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002267 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
2269 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2270 ROCKET_VERSION, ROCKET_DATE);
2271
2272 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2273 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002274 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
2276 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2278 * zero, use the default controller IO address of board1 + 0x40.
2279 */
2280 if (board1) {
2281 if (controller == 0)
2282 controller = board1 + 0x40;
2283 } else {
2284 controller = 0; /* Used as a flag, meaning no ISA boards */
2285 }
2286
2287 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2288 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002289 printk(KERN_ERR "Unable to reserve IO region for first "
2290 "configured ISA RocketPort controller 0x%lx. "
2291 "Driver exiting\n", controller);
2292 ret = -EBUSY;
2293 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 }
2295
2296 /* Store ISA variable retrieved from command line or .conf file. */
2297 rcktpt_io_addr[0] = board1;
2298 rcktpt_io_addr[1] = board2;
2299 rcktpt_io_addr[2] = board3;
2300 rcktpt_io_addr[3] = board4;
2301
2302 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2303 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2304 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2305 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2306 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2307 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2308 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2309 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2310
2311 /*
2312 * Set up the tty driver structure and then register this
2313 * driver with the tty layer.
2314 */
2315
2316 rocket_driver->owner = THIS_MODULE;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002317 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 rocket_driver->name = "ttyR";
2319 rocket_driver->driver_name = "Comtrol RocketPort";
2320 rocket_driver->major = TTY_ROCKET_MAJOR;
2321 rocket_driver->minor_start = 0;
2322 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2323 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2324 rocket_driver->init_termios = tty_std_termios;
2325 rocket_driver->init_termios.c_cflag =
2326 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002327 rocket_driver->init_termios.c_ispeed = 9600;
2328 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002330 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331#endif
2332 tty_set_operations(rocket_driver, &rocket_ops);
2333
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002334 ret = tty_register_driver(rocket_driver);
2335 if (ret < 0) {
2336 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
2337 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 }
2339
2340#ifdef ROCKET_DEBUG_OPEN
2341 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2342#endif
2343
2344 /*
2345 * OK, let's probe each of the controllers looking for boards. Any boards found
2346 * will be initialized here.
2347 */
2348 isa_boards_found = 0;
2349 pci_boards_found = 0;
2350
2351 for (i = 0; i < NUM_BOARDS; i++) {
2352 if (init_ISA(i))
2353 isa_boards_found++;
2354 }
2355
2356#ifdef CONFIG_PCI
2357 if (isa_boards_found < NUM_BOARDS)
2358 pci_boards_found = init_PCI(isa_boards_found);
2359#endif
2360
2361 max_board = pci_boards_found + isa_boards_found;
2362
2363 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002364 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2365 ret = -ENXIO;
2366 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 }
2368
2369 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002370err_ttyu:
2371 tty_unregister_driver(rocket_driver);
2372err_tty:
2373 put_tty_driver(rocket_driver);
2374err:
2375 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376}
2377
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
2379static void rp_cleanup_module(void)
2380{
2381 int retval;
2382 int i;
2383
2384 del_timer_sync(&rocket_timer);
2385
2386 retval = tty_unregister_driver(rocket_driver);
2387 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002388 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Jesper Juhl735d5662005-11-07 01:01:29 -08002391 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002392 if (rp_table[i]) {
2393 tty_unregister_device(rocket_driver, i);
2394 kfree(rp_table[i]);
2395 }
2396
2397 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399 for (i = 0; i < NUM_BOARDS; i++) {
2400 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2401 continue;
2402 release_region(rcktpt_io_addr[i], 64);
2403 }
2404 if (controller)
2405 release_region(controller, 4);
2406}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408/***************************************************************************
2409Function: sInitController
2410Purpose: Initialization of controller global registers and controller
2411 structure.
2412Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2413 IRQNum,Frequency,PeriodicOnly)
2414 CONTROLLER_T *CtlP; Ptr to controller structure
2415 int CtlNum; Controller number
2416 ByteIO_t MudbacIO; Mudbac base I/O address.
2417 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2418 This list must be in the order the AIOPs will be found on the
2419 controller. Once an AIOP in the list is not found, it is
2420 assumed that there are no more AIOPs on the controller.
2421 int AiopIOListSize; Number of addresses in AiopIOList
2422 int IRQNum; Interrupt Request number. Can be any of the following:
2423 0: Disable global interrupts
2424 3: IRQ 3
2425 4: IRQ 4
2426 5: IRQ 5
2427 9: IRQ 9
2428 10: IRQ 10
2429 11: IRQ 11
2430 12: IRQ 12
2431 15: IRQ 15
2432 Byte_t Frequency: A flag identifying the frequency
2433 of the periodic interrupt, can be any one of the following:
2434 FREQ_DIS - periodic interrupt disabled
2435 FREQ_137HZ - 137 Hertz
2436 FREQ_69HZ - 69 Hertz
2437 FREQ_34HZ - 34 Hertz
2438 FREQ_17HZ - 17 Hertz
2439 FREQ_9HZ - 9 Hertz
2440 FREQ_4HZ - 4 Hertz
2441 If IRQNum is set to 0 the Frequency parameter is
2442 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002443 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002445 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 other channel interrupts are allowed.
2447 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002448 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2450 initialization failed.
2451
2452Comments:
2453 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002454 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 If interrupts are to be completely disabled set IRQNum to 0.
2457
Adrian Bunkf15313b2005-06-25 14:59:05 -07002458 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 invalid combination.
2460
2461 This function performs initialization of global interrupt modes,
2462 but it does not actually enable global interrupts. To enable
2463 and disable global interrupts use functions sEnGlobalInt() and
2464 sDisGlobalInt(). Enabling of global interrupts is normally not
2465 done until all other initializations are complete.
2466
2467 Even if interrupts are globally enabled, they must also be
2468 individually enabled for each channel that is to generate
2469 interrupts.
2470
2471Warnings: No range checking on any of the parameters is done.
2472
2473 No context switches are allowed while executing this function.
2474
2475 After this function all AIOPs on the controller are disabled,
2476 they can be enabled with sEnAiop().
2477*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002478static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2479 ByteIO_t * AiopIOList, int AiopIOListSize,
2480 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481{
2482 int i;
2483 ByteIO_t io;
2484 int done;
2485
2486 CtlP->AiopIntrBits = aiop_intr_bits;
2487 CtlP->AltChanRingIndicator = 0;
2488 CtlP->CtlNum = CtlNum;
2489 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2490 CtlP->BusType = isISA;
2491 CtlP->MBaseIO = MudbacIO;
2492 CtlP->MReg1IO = MudbacIO + 1;
2493 CtlP->MReg2IO = MudbacIO + 2;
2494 CtlP->MReg3IO = MudbacIO + 3;
2495#if 1
2496 CtlP->MReg2 = 0; /* interrupt disable */
2497 CtlP->MReg3 = 0; /* no periodic interrupts */
2498#else
2499 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2500 CtlP->MReg2 = 0; /* interrupt disable */
2501 CtlP->MReg3 = 0; /* no periodic interrupts */
2502 } else {
2503 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2504 CtlP->MReg3 = Frequency; /* set frequency */
2505 if (PeriodicOnly) { /* periodic interrupt only */
2506 CtlP->MReg3 |= PERIODIC_ONLY;
2507 }
2508 }
2509#endif
2510 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2511 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2512 sControllerEOI(CtlP); /* clear EOI if warm init */
2513 /* Init AIOPs */
2514 CtlP->NumAiop = 0;
2515 for (i = done = 0; i < AiopIOListSize; i++) {
2516 io = AiopIOList[i];
2517 CtlP->AiopIO[i] = (WordIO_t) io;
2518 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2519 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2520 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2521 if (done)
2522 continue;
2523 sEnAiop(CtlP, i); /* enable the AIOP */
2524 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2525 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2526 done = 1; /* done looking for AIOPs */
2527 else {
2528 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2529 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2530 sOutB(io + _INDX_DATA, sClockPrescale);
2531 CtlP->NumAiop++; /* bump count of AIOPs */
2532 }
2533 sDisAiop(CtlP, i); /* disable AIOP */
2534 }
2535
2536 if (CtlP->NumAiop == 0)
2537 return (-1);
2538 else
2539 return (CtlP->NumAiop);
2540}
2541
2542/***************************************************************************
2543Function: sPCIInitController
2544Purpose: Initialization of controller global registers and controller
2545 structure.
2546Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2547 IRQNum,Frequency,PeriodicOnly)
2548 CONTROLLER_T *CtlP; Ptr to controller structure
2549 int CtlNum; Controller number
2550 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2551 This list must be in the order the AIOPs will be found on the
2552 controller. Once an AIOP in the list is not found, it is
2553 assumed that there are no more AIOPs on the controller.
2554 int AiopIOListSize; Number of addresses in AiopIOList
2555 int IRQNum; Interrupt Request number. Can be any of the following:
2556 0: Disable global interrupts
2557 3: IRQ 3
2558 4: IRQ 4
2559 5: IRQ 5
2560 9: IRQ 9
2561 10: IRQ 10
2562 11: IRQ 11
2563 12: IRQ 12
2564 15: IRQ 15
2565 Byte_t Frequency: A flag identifying the frequency
2566 of the periodic interrupt, can be any one of the following:
2567 FREQ_DIS - periodic interrupt disabled
2568 FREQ_137HZ - 137 Hertz
2569 FREQ_69HZ - 69 Hertz
2570 FREQ_34HZ - 34 Hertz
2571 FREQ_17HZ - 17 Hertz
2572 FREQ_9HZ - 9 Hertz
2573 FREQ_4HZ - 4 Hertz
2574 If IRQNum is set to 0 the Frequency parameter is
2575 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002576 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002578 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 other channel interrupts are allowed.
2580 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002581 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2583 initialization failed.
2584
2585Comments:
2586 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002587 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 If interrupts are to be completely disabled set IRQNum to 0.
2590
Adrian Bunkf15313b2005-06-25 14:59:05 -07002591 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 invalid combination.
2593
2594 This function performs initialization of global interrupt modes,
2595 but it does not actually enable global interrupts. To enable
2596 and disable global interrupts use functions sEnGlobalInt() and
2597 sDisGlobalInt(). Enabling of global interrupts is normally not
2598 done until all other initializations are complete.
2599
2600 Even if interrupts are globally enabled, they must also be
2601 individually enabled for each channel that is to generate
2602 interrupts.
2603
2604Warnings: No range checking on any of the parameters is done.
2605
2606 No context switches are allowed while executing this function.
2607
2608 After this function all AIOPs on the controller are disabled,
2609 they can be enabled with sEnAiop().
2610*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002611static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2612 ByteIO_t * AiopIOList, int AiopIOListSize,
2613 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2614 int PeriodicOnly, int altChanRingIndicator,
2615 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616{
2617 int i;
2618 ByteIO_t io;
2619
2620 CtlP->AltChanRingIndicator = altChanRingIndicator;
2621 CtlP->UPCIRingInd = UPCIRingInd;
2622 CtlP->CtlNum = CtlNum;
2623 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2624 CtlP->BusType = isPCI; /* controller release 1 */
2625
2626 if (ConfigIO) {
2627 CtlP->isUPCI = 1;
2628 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2629 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2630 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2631 } else {
2632 CtlP->isUPCI = 0;
2633 CtlP->PCIIO =
2634 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2635 CtlP->AiopIntrBits = aiop_intr_bits;
2636 }
2637
2638 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2639 /* Init AIOPs */
2640 CtlP->NumAiop = 0;
2641 for (i = 0; i < AiopIOListSize; i++) {
2642 io = AiopIOList[i];
2643 CtlP->AiopIO[i] = (WordIO_t) io;
2644 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2645
2646 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2647 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2648 break; /* done looking for AIOPs */
2649
2650 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2651 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2652 sOutB(io + _INDX_DATA, sClockPrescale);
2653 CtlP->NumAiop++; /* bump count of AIOPs */
2654 }
2655
2656 if (CtlP->NumAiop == 0)
2657 return (-1);
2658 else
2659 return (CtlP->NumAiop);
2660}
2661
2662/***************************************************************************
2663Function: sReadAiopID
2664Purpose: Read the AIOP idenfication number directly from an AIOP.
2665Call: sReadAiopID(io)
2666 ByteIO_t io: AIOP base I/O address
2667Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2668 is replace by an identifying number.
2669 Flag AIOPID_NULL if no valid AIOP is found
2670Warnings: No context switches are allowed while executing this function.
2671
2672*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002673static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674{
2675 Byte_t AiopID; /* ID byte from AIOP */
2676
2677 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2678 sOutB(io + _CMD_REG, 0x0);
2679 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2680 if (AiopID == 0x06)
2681 return (1);
2682 else /* AIOP does not exist */
2683 return (-1);
2684}
2685
2686/***************************************************************************
2687Function: sReadAiopNumChan
2688Purpose: Read the number of channels available in an AIOP directly from
2689 an AIOP.
2690Call: sReadAiopNumChan(io)
2691 WordIO_t io: AIOP base I/O address
2692Return: int: The number of channels available
2693Comments: The number of channels is determined by write/reads from identical
2694 offsets within the SRAM address spaces for channels 0 and 4.
2695 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2696 AIOP, otherwise it is an 8 channel.
2697Warnings: No context switches are allowed while executing this function.
2698*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002699static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 Word_t x;
2702 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2703
2704 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002705 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2707 x = sInW(io + _INDX_DATA);
2708 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2709 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2710 return (8);
2711 else
2712 return (4);
2713}
2714
2715/***************************************************************************
2716Function: sInitChan
2717Purpose: Initialization of a channel and channel structure
2718Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2719 CONTROLLER_T *CtlP; Ptr to controller structure
2720 CHANNEL_T *ChP; Ptr to channel structure
2721 int AiopNum; AIOP number within controller
2722 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002723Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 number exceeds number of channels available in AIOP.
2725Comments: This function must be called before a channel can be used.
2726Warnings: No range checking on any of the parameters is done.
2727
2728 No context switches are allowed while executing this function.
2729*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002730static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2731 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
2733 int i;
2734 WordIO_t AiopIO;
2735 WordIO_t ChIOOff;
2736 Byte_t *ChR;
2737 Word_t ChOff;
2738 static Byte_t R[4];
2739 int brd9600;
2740
2741 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002742 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744 /* Channel, AIOP, and controller identifiers */
2745 ChP->CtlP = CtlP;
2746 ChP->ChanID = CtlP->AiopID[AiopNum];
2747 ChP->AiopNum = AiopNum;
2748 ChP->ChanNum = ChanNum;
2749
2750 /* Global direct addresses */
2751 AiopIO = CtlP->AiopIO[AiopNum];
2752 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2753 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2754 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2755 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2756 ChP->IndexData = AiopIO + _INDX_DATA;
2757
2758 /* Channel direct addresses */
2759 ChIOOff = AiopIO + ChP->ChanNum * 2;
2760 ChP->TxRxData = ChIOOff + _TD0;
2761 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2762 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2763 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2764
2765 /* Initialize the channel from the RData array */
2766 for (i = 0; i < RDATASIZE; i += 4) {
2767 R[0] = RData[i];
2768 R[1] = RData[i + 1] + 0x10 * ChanNum;
2769 R[2] = RData[i + 2];
2770 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002771 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 }
2773
2774 ChR = ChP->R;
2775 for (i = 0; i < RREGDATASIZE; i += 4) {
2776 ChR[i] = RRegData[i];
2777 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2778 ChR[i + 2] = RRegData[i + 2];
2779 ChR[i + 3] = RRegData[i + 3];
2780 }
2781
2782 /* Indexed registers */
2783 ChOff = (Word_t) ChanNum *0x1000;
2784
2785 if (sClockPrescale == 0x14)
2786 brd9600 = 47;
2787 else
2788 brd9600 = 23;
2789
2790 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2791 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2792 ChP->BaudDiv[2] = (Byte_t) brd9600;
2793 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002794 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795
2796 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2797 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2798 ChP->TxControl[2] = 0;
2799 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002800 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2803 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2804 ChP->RxControl[2] = 0;
2805 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002806 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2809 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2810 ChP->TxEnables[2] = 0;
2811 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002812 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2815 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2816 ChP->TxCompare[2] = 0;
2817 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002818 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819
2820 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2821 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2822 ChP->TxReplace1[2] = 0;
2823 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002824 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
2826 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2827 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2828 ChP->TxReplace2[2] = 0;
2829 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002830 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
2832 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2833 ChP->TxFIFO = ChOff + _TX_FIFO;
2834
2835 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2836 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2837 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2838 sOutW(ChP->IndexData, 0);
2839 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2840 ChP->RxFIFO = ChOff + _RX_FIFO;
2841
2842 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2843 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2844 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2845 sOutW(ChP->IndexData, 0);
2846 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2847 sOutW(ChP->IndexData, 0);
2848 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2849 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2850 sOutB(ChP->IndexData, 0);
2851 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2852 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2853 sOutB(ChP->IndexData, 0);
2854 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2855 sEnRxProcessor(ChP); /* start the Rx processor */
2856
Adrian Bunkf15313b2005-06-25 14:59:05 -07002857 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858}
2859
2860/***************************************************************************
2861Function: sStopRxProcessor
2862Purpose: Stop the receive processor from processing a channel.
2863Call: sStopRxProcessor(ChP)
2864 CHANNEL_T *ChP; Ptr to channel structure
2865
2866Comments: The receive processor can be started again with sStartRxProcessor().
2867 This function causes the receive processor to skip over the
2868 stopped channel. It does not stop it from processing other channels.
2869
2870Warnings: No context switches are allowed while executing this function.
2871
2872 Do not leave the receive processor stopped for more than one
2873 character time.
2874
2875 After calling this function a delay of 4 uS is required to ensure
2876 that the receive processor is no longer processing this channel.
2877*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002878static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879{
2880 Byte_t R[4];
2881
2882 R[0] = ChP->R[0];
2883 R[1] = ChP->R[1];
2884 R[2] = 0x0a;
2885 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00002886 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887}
2888
2889/***************************************************************************
2890Function: sFlushRxFIFO
2891Purpose: Flush the Rx FIFO
2892Call: sFlushRxFIFO(ChP)
2893 CHANNEL_T *ChP; Ptr to channel structure
2894Return: void
2895Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2896 while it is being flushed the receive processor is stopped
2897 and the transmitter is disabled. After these operations a
2898 4 uS delay is done before clearing the pointers to allow
2899 the receive processor to stop. These items are handled inside
2900 this function.
2901Warnings: No context switches are allowed while executing this function.
2902*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002903static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904{
2905 int i;
2906 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002907 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
2910 return; /* don't need to flush */
2911
Adrian Bunkf15313b2005-06-25 14:59:05 -07002912 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002914 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 sDisRxFIFO(ChP); /* disable it */
2916 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
2917 sInB(ChP->IntChan); /* depends on bus i/o timing */
2918 }
2919 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
2920 Ch = (Byte_t) sGetChanNum(ChP);
2921 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
2922 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
2923 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2924 sOutW(ChP->IndexData, 0);
2925 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2926 sOutW(ChP->IndexData, 0);
2927 if (RxFIFOEnabled)
2928 sEnRxFIFO(ChP); /* enable Rx FIFO */
2929}
2930
2931/***************************************************************************
2932Function: sFlushTxFIFO
2933Purpose: Flush the Tx FIFO
2934Call: sFlushTxFIFO(ChP)
2935 CHANNEL_T *ChP; Ptr to channel structure
2936Return: void
2937Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2938 while it is being flushed the receive processor is stopped
2939 and the transmitter is disabled. After these operations a
2940 4 uS delay is done before clearing the pointers to allow
2941 the receive processor to stop. These items are handled inside
2942 this function.
2943Warnings: No context switches are allowed while executing this function.
2944*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002945static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946{
2947 int i;
2948 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002949 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
2952 return; /* don't need to flush */
2953
Adrian Bunkf15313b2005-06-25 14:59:05 -07002954 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07002956 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 sDisTransmit(ChP); /* disable transmitter */
2958 }
2959 sStopRxProcessor(ChP); /* stop Rx processor */
2960 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
2961 sInB(ChP->IntChan); /* depends on bus i/o timing */
2962 Ch = (Byte_t) sGetChanNum(ChP);
2963 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
2964 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
2965 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2966 sOutW(ChP->IndexData, 0);
2967 if (TxEnabled)
2968 sEnTransmit(ChP); /* enable transmitter */
2969 sStartRxProcessor(ChP); /* restart Rx processor */
2970}
2971
2972/***************************************************************************
2973Function: sWriteTxPrioByte
2974Purpose: Write a byte of priority transmit data to a channel
2975Call: sWriteTxPrioByte(ChP,Data)
2976 CHANNEL_T *ChP; Ptr to channel structure
2977 Byte_t Data; The transmit data byte
2978
2979Return: int: 1 if the bytes is successfully written, otherwise 0.
2980
2981Comments: The priority byte is transmitted before any data in the Tx FIFO.
2982
2983Warnings: No context switches are allowed while executing this function.
2984*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002985static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 Byte_t DWBuf[4]; /* buffer for double word writes */
2988 Word_t *WordPtr; /* must be far because Win SS != DS */
2989 register DWordIO_t IndexAddr;
2990
2991 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
2992 IndexAddr = ChP->IndexAddr;
2993 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
2994 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
2995 return (0); /* nothing sent */
2996
2997 WordPtr = (Word_t *) (&DWBuf[0]);
2998 *WordPtr = ChP->TxPrioBuf; /* data byte address */
2999
3000 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00003001 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
3003 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
3004
3005 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
3006 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00003007 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 } else { /* write it to Tx FIFO */
3009
3010 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
3011 }
3012 return (1); /* 1 byte sent */
3013}
3014
3015/***************************************************************************
3016Function: sEnInterrupts
3017Purpose: Enable one or more interrupts for a channel
3018Call: sEnInterrupts(ChP,Flags)
3019 CHANNEL_T *ChP; Ptr to channel structure
3020 Word_t Flags: Interrupt enable flags, can be any combination
3021 of the following flags:
3022 TXINT_EN: Interrupt on Tx FIFO empty
3023 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3024 sSetRxTrigger())
3025 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3026 MCINT_EN: Interrupt on modem input change
3027 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3028 Interrupt Channel Register.
3029Return: void
3030Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3031 enabled. If an interrupt enable flag is not set in Flags, that
3032 interrupt will not be changed. Interrupts can be disabled with
3033 function sDisInterrupts().
3034
3035 This function sets the appropriate bit for the channel in the AIOP's
3036 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3037 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3038
3039 Interrupts must also be globally enabled before channel interrupts
3040 will be passed on to the host. This is done with function
3041 sEnGlobalInt().
3042
3043 In some cases it may be desirable to disable interrupts globally but
3044 enable channel interrupts. This would allow the global interrupt
3045 status register to be used to determine which AIOPs need service.
3046*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003047static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048{
3049 Byte_t Mask; /* Interrupt Mask Register */
3050
3051 ChP->RxControl[2] |=
3052 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3053
Al Viro457fb602008-03-19 16:27:48 +00003054 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055
3056 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3057
Al Viro457fb602008-03-19 16:27:48 +00003058 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059
3060 if (Flags & CHANINT_EN) {
3061 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3062 sOutB(ChP->IntMask, Mask);
3063 }
3064}
3065
3066/***************************************************************************
3067Function: sDisInterrupts
3068Purpose: Disable one or more interrupts for a channel
3069Call: sDisInterrupts(ChP,Flags)
3070 CHANNEL_T *ChP; Ptr to channel structure
3071 Word_t Flags: Interrupt flags, can be any combination
3072 of the following flags:
3073 TXINT_EN: Interrupt on Tx FIFO empty
3074 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3075 sSetRxTrigger())
3076 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3077 MCINT_EN: Interrupt on modem input change
3078 CHANINT_EN: Disable channel interrupt signal to the
3079 AIOP's Interrupt Channel Register.
3080Return: void
3081Comments: If an interrupt flag is set in Flags, that interrupt will be
3082 disabled. If an interrupt flag is not set in Flags, that
3083 interrupt will not be changed. Interrupts can be enabled with
3084 function sEnInterrupts().
3085
3086 This function clears the appropriate bit for the channel in the AIOP's
3087 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3088 this channel's bit from being set in the AIOP's Interrupt Channel
3089 Register.
3090*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003091static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092{
3093 Byte_t Mask; /* Interrupt Mask Register */
3094
3095 ChP->RxControl[2] &=
3096 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003097 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003099 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
3101 if (Flags & CHANINT_EN) {
3102 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3103 sOutB(ChP->IntMask, Mask);
3104 }
3105}
3106
Adrian Bunkf15313b2005-06-25 14:59:05 -07003107static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108{
3109 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3110}
3111
3112/*
3113 * Not an official SSCI function, but how to reset RocketModems.
3114 * ISA bus version
3115 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003116static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117{
3118 ByteIO_t addr;
3119 Byte_t val;
3120
3121 addr = CtlP->AiopIO[0] + 0x400;
3122 val = sInB(CtlP->MReg3IO);
3123 /* if AIOP[1] is not enabled, enable it */
3124 if ((val & 2) == 0) {
3125 val = sInB(CtlP->MReg2IO);
3126 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3127 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3128 }
3129
3130 sEnAiop(CtlP, 1);
3131 if (!on)
3132 addr += 8;
3133 sOutB(addr + chan, 0); /* apply or remove reset */
3134 sDisAiop(CtlP, 1);
3135}
3136
3137/*
3138 * Not an official SSCI function, but how to reset RocketModems.
3139 * PCI bus version
3140 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003141static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142{
3143 ByteIO_t addr;
3144
3145 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3146 if (!on)
3147 addr += 8;
3148 sOutB(addr + chan, 0); /* apply or remove reset */
3149}
3150
3151/* Resets the speaker controller on RocketModem II and III devices */
3152static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3153{
3154 ByteIO_t addr;
3155
3156 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3157 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3158 addr = CtlP->AiopIO[0] + 0x4F;
3159 sOutB(addr, 0);
3160 }
3161
3162 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3163 if ((model == MODEL_UPCI_RM3_8PORT)
3164 || (model == MODEL_UPCI_RM3_4PORT)) {
3165 addr = CtlP->AiopIO[0] + 0x88;
3166 sOutB(addr, 0);
3167 }
3168}
3169
3170/* Returns the line number given the controller (board), aiop and channel number */
3171static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3172{
3173 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3174}
3175
3176/*
3177 * Stores the line number associated with a given controller (board), aiop
3178 * and channel number.
3179 * Returns: The line number assigned
3180 */
3181static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3182{
3183 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3184 return (nextLineNumber - 1);
3185}