blob: 5848a767001aeaf48934af58f1c8491141f1dd9c [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/string.h>
77#include <linux/fcntl.h>
78#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070079#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include <linux/ioport.h>
81#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070082#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/wait.h>
84#include <linux/pci.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010085#include <linux/uaccess.h>
Arun Sharma600634972011-07-26 16:09:06 -070086#include <linux/atomic.h>
Al Viro457fb602008-03-19 16:27:48 +000087#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/bitops.h>
89#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/init.h>
91
92/****** RocketPort includes ******/
93
94#include "rocket_int.h"
95#include "rocket.h"
96
97#define ROCKET_VERSION "2.09"
98#define ROCKET_DATE "12-June-2003"
99
100/****** RocketPort Local Variables ******/
101
Jiri Slaby40565f12007-02-12 00:52:31 -0800102static void rp_do_poll(unsigned long dummy);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static struct tty_driver *rocket_driver;
105
106static struct rocket_version driver_version = {
107 ROCKET_VERSION, ROCKET_DATE
108};
109
110static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
111static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
112 /* eg. Bit 0 indicates port 0 has xmit data, ... */
113static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800114static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
117static unsigned long board2;
118static unsigned long board3;
119static unsigned long board4;
120static unsigned long controller;
Rusty Russell90ab5ee2012-01-13 09:32:20 +1030121static bool support_low_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static unsigned long modem1;
123static unsigned long modem2;
124static unsigned long modem3;
125static unsigned long modem4;
126static unsigned long pc104_1[8];
127static unsigned long pc104_2[8];
128static unsigned long pc104_3[8];
129static unsigned long pc104_4[8];
130static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
131
132static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
133static unsigned long rcktpt_io_addr[NUM_BOARDS];
134static int rcktpt_type[NUM_BOARDS];
135static int is_PCI[NUM_BOARDS];
136static rocketModel_t rocketModel[NUM_BOARDS];
137static int max_board;
Alan Cox31f35932009-01-02 13:45:05 +0000138static const struct tty_port_operations rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140/*
141 * The following arrays define the interrupt bits corresponding to each AIOP.
142 * These bits are different between the ISA and regular PCI boards and the
143 * Universal PCI boards.
144 */
145
146static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
147 AIOP_INTR_BIT_0,
148 AIOP_INTR_BIT_1,
149 AIOP_INTR_BIT_2,
150 AIOP_INTR_BIT_3
151};
152
153static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
154 UPCI_AIOP_INTR_BIT_0,
155 UPCI_AIOP_INTR_BIT_1,
156 UPCI_AIOP_INTR_BIT_2,
157 UPCI_AIOP_INTR_BIT_3
158};
159
Adrian Bunkf15313b2005-06-25 14:59:05 -0700160static Byte_t RData[RDATASIZE] = {
161 0x00, 0x09, 0xf6, 0x82,
162 0x02, 0x09, 0x86, 0xfb,
163 0x04, 0x09, 0x00, 0x0a,
164 0x06, 0x09, 0x01, 0x0a,
165 0x08, 0x09, 0x8a, 0x13,
166 0x0a, 0x09, 0xc5, 0x11,
167 0x0c, 0x09, 0x86, 0x85,
168 0x0e, 0x09, 0x20, 0x0a,
169 0x10, 0x09, 0x21, 0x0a,
170 0x12, 0x09, 0x41, 0xff,
171 0x14, 0x09, 0x82, 0x00,
172 0x16, 0x09, 0x82, 0x7b,
173 0x18, 0x09, 0x8a, 0x7d,
174 0x1a, 0x09, 0x88, 0x81,
175 0x1c, 0x09, 0x86, 0x7a,
176 0x1e, 0x09, 0x84, 0x81,
177 0x20, 0x09, 0x82, 0x7c,
178 0x22, 0x09, 0x0a, 0x0a
179};
180
181static Byte_t RRegData[RREGDATASIZE] = {
182 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
183 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
184 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
185 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
186 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
187 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
188 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
189 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
190 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
191 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
192 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
193 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
194 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
195};
196
197static CONTROLLER_T sController[CTL_SIZE] = {
198 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
199 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
200 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
201 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
202 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
203 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
204 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
205 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
206};
207
208static Byte_t sBitMapClrTbl[8] = {
209 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
210};
211
212static Byte_t sBitMapSetTbl[8] = {
213 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
214};
215
216static int sClockPrescale = 0x14;
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218/*
219 * Line number is the ttySIx number (x), the Minor number. We
220 * assign them sequentially, starting at zero. The following
221 * array keeps track of the line number assigned to a given board/aiop/channel.
222 */
223static unsigned char lineNumbers[MAX_RP_PORTS];
224static unsigned long nextLineNumber;
225
226/***** RocketPort Static Prototypes *********/
227static int __init init_ISA(int i);
228static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
229static void rp_flush_buffer(struct tty_struct *tty);
230static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
231static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
232static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
233static void rp_start(struct tty_struct *tty);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700234static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
235 int ChanNum);
236static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
237static void sFlushRxFIFO(CHANNEL_T * ChP);
238static void sFlushTxFIFO(CHANNEL_T * ChP);
239static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
240static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
241static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
242static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
243static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
244static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
245 ByteIO_t * AiopIOList, int AiopIOListSize,
246 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
247 int PeriodicOnly, int altChanRingIndicator,
248 int UPCIRingInd);
249static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
250 ByteIO_t * AiopIOList, int AiopIOListSize,
251 int IRQNum, Byte_t Frequency, int PeriodicOnly);
252static int sReadAiopID(ByteIO_t io);
253static int sReadAiopNumChan(WordIO_t io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255MODULE_AUTHOR("Theodore Ts'o");
256MODULE_DESCRIPTION("Comtrol RocketPort driver");
257module_param(board1, ulong, 0);
258MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
259module_param(board2, ulong, 0);
260MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
261module_param(board3, ulong, 0);
262MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
263module_param(board4, ulong, 0);
264MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
265module_param(controller, ulong, 0);
266MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
267module_param(support_low_speed, bool, 0);
268MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
269module_param(modem1, ulong, 0);
270MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem");
271module_param(modem2, ulong, 0);
272MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem");
273module_param(modem3, ulong, 0);
274MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem");
275module_param(modem4, ulong, 0);
276MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem");
277module_param_array(pc104_1, ulong, NULL, 0);
278MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,...");
279module_param_array(pc104_2, ulong, NULL, 0);
280MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,...");
281module_param_array(pc104_3, ulong, NULL, 0);
282MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,...");
283module_param_array(pc104_4, ulong, NULL, 0);
284MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
285
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -0800286static int rp_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void rp_cleanup_module(void);
288
289module_init(rp_init);
290module_exit(rp_cleanup_module);
291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293MODULE_LICENSE("Dual BSD/GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295/*************************************************************************/
296/* Module code starts here */
297
298static inline int rocket_paranoia_check(struct r_port *info,
299 const char *routine)
300{
301#ifdef ROCKET_PARANOIA_CHECK
302 if (!info)
303 return 1;
304 if (info->magic != RPORT_MAGIC) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800305 printk(KERN_WARNING "Warning: bad magic number for rocketport "
306 "struct in %s\n", routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return 1;
308 }
309#endif
310 return 0;
311}
312
313
314/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals
315 * that receive data is present on a serial port. Pulls data from FIFO, moves it into the
316 * tty layer.
317 */
318static void rp_do_receive(struct r_port *info,
319 struct tty_struct *tty,
320 CHANNEL_t * cp, unsigned int ChanStatus)
321{
322 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700323 int ToRecv, wRecv, space;
324 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800328 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700330 if (ToRecv == 0)
331 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /*
334 * if status indicates there are errored characters in the
335 * FIFO, then enter status mode (a word in FIFO holds
336 * character and status).
337 */
338 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
339 if (!(ChanStatus & STATMODE)) {
340#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800341 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342#endif
343 ChanStatus |= STATMODE;
344 sEnRxStatusMode(cp);
345 }
346 }
347
348 /*
349 * if we previously entered status mode, then read down the
350 * FIFO one word at a time, pulling apart the character and
351 * the status. Update error counters depending on status
352 */
353 if (ChanStatus & STATMODE) {
354#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800355 printk(KERN_INFO "Ignore %x, read %x...\n",
356 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#endif
358 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700359 char flag;
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 CharNStat = sInW(sGetTxRxDataIO(cp));
362#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800363 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364#endif
365 if (CharNStat & STMBREAKH)
366 CharNStat &= ~(STMFRAMEH | STMPARITYH);
367 if (CharNStat & info->ignore_status_mask) {
368 ToRecv--;
369 continue;
370 }
371 CharNStat &= info->read_status_mask;
372 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700373 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700375 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700377 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700379 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700381 flag = TTY_NORMAL;
Jiri Slaby92a19f92013-01-03 15:53:03 +0100382 tty_insert_flip_char(&info->port, CharNStat & 0xff,
383 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 */
Jiri Slaby2f693352013-01-03 15:53:02 +0100403 space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv);
Paul Fulghumcc44a812006-06-25 05:49:12 -0700404 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);
Jiri Slaby191c5f12012-11-15 09:49:56 +0100677 tty_port_destroy(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 kfree(info);
679 return;
680 }
681
682 rocketMode = info->flags & ROCKET_MODE_MASK;
683
684 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
685 sEnRTSToggle(&info->channel);
686 else
687 sDisRTSToggle(&info->channel);
688
689 if (ctlp->boardType == ROCKET_TYPE_PC104) {
690 switch (rocketMode) {
691 case ROCKET_MODE_RS485:
692 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
693 break;
694 case ROCKET_MODE_RS422:
695 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
696 break;
697 case ROCKET_MODE_RS232:
698 default:
699 if (info->flags & ROCKET_RTS_TOGGLE)
700 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
701 else
702 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
703 break;
704 }
705 }
706 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700707 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 rp_table[line] = info;
Jiri Slaby734cc172012-08-07 21:47:47 +0200709 tty_port_register_device(&info->port, rocket_driver, line,
710 pci_dev ? &pci_dev->dev : NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
713/*
714 * Configures a rocketport port according to its termio settings. Called from
715 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
716 */
Alan Cox47b01b32009-01-02 13:48:30 +0000717static void configure_r_port(struct tty_struct *tty, struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800718 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719{
720 unsigned cflag;
721 unsigned long flags;
722 unsigned rocketMode;
723 int bits, baud, divisor;
724 CHANNEL_t *cp;
Alan Coxadc8d742012-07-14 15:31:47 +0100725 struct ktermios *t = &tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800728 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
730 /* Byte size and parity */
731 if ((cflag & CSIZE) == CS8) {
732 sSetData8(cp);
733 bits = 10;
734 } else {
735 sSetData7(cp);
736 bits = 9;
737 }
738 if (cflag & CSTOPB) {
739 sSetStop2(cp);
740 bits++;
741 } else {
742 sSetStop1(cp);
743 }
744
745 if (cflag & PARENB) {
746 sEnParity(cp);
747 bits++;
748 if (cflag & PARODD) {
749 sSetOddParity(cp);
750 } else {
751 sSetEvenParity(cp);
752 }
753 } else {
754 sDisParity(cp);
755 }
756
757 /* baud rate */
Alan Cox47b01b32009-01-02 13:48:30 +0000758 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if (!baud)
760 baud = 9600;
761 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
762 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800763 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if (!baud)
765 baud = 9600;
766 divisor = (rp_baud_base[info->board] / baud) - 1;
767 }
768 if (divisor >= 8192 || divisor < 0) {
769 baud = 9600;
770 divisor = (rp_baud_base[info->board] / baud) - 1;
771 }
772 info->cps = baud / bits;
773 sSetBaud(cp, divisor);
774
Alan Cox6df35262008-02-08 04:18:45 -0800775 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Cox47b01b32009-01-02 13:48:30 +0000776 tty_encode_baud_rate(tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (cflag & CRTSCTS) {
779 info->intmask |= DELTA_CTS;
780 sEnCTSFlowCtl(cp);
781 } else {
782 info->intmask &= ~DELTA_CTS;
783 sDisCTSFlowCtl(cp);
784 }
785 if (cflag & CLOCAL) {
786 info->intmask &= ~DELTA_CD;
787 } else {
788 spin_lock_irqsave(&info->slock, flags);
789 if (sGetChanStatus(cp) & CD_ACT)
790 info->cd_status = 1;
791 else
792 info->cd_status = 0;
793 info->intmask |= DELTA_CD;
794 spin_unlock_irqrestore(&info->slock, flags);
795 }
796
797 /*
798 * Handle software flow control in the board
799 */
800#ifdef ROCKET_SOFT_FLOW
Alan Cox47b01b32009-01-02 13:48:30 +0000801 if (I_IXON(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 sEnTxSoftFlowCtl(cp);
Alan Cox47b01b32009-01-02 13:48:30 +0000803 if (I_IXANY(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 sEnIXANY(cp);
805 } else {
806 sDisIXANY(cp);
807 }
Alan Cox47b01b32009-01-02 13:48:30 +0000808 sSetTxXONChar(cp, START_CHAR(tty));
809 sSetTxXOFFChar(cp, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 } else {
811 sDisTxSoftFlowCtl(cp);
812 sDisIXANY(cp);
813 sClrTxXOFF(cp);
814 }
815#endif
816
817 /*
818 * Set up ignore/read mask words
819 */
820 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Cox47b01b32009-01-02 13:48:30 +0000821 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000823 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 info->read_status_mask |= STMBREAKH;
825
826 /*
827 * Characters to ignore
828 */
829 info->ignore_status_mask = 0;
Alan Cox47b01b32009-01-02 13:48:30 +0000830 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000832 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 info->ignore_status_mask |= STMBREAKH;
834 /*
835 * If we're ignoring parity and break indicators,
836 * ignore overruns too. (For real raw support).
837 */
Alan Cox47b01b32009-01-02 13:48:30 +0000838 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 info->ignore_status_mask |= STMRCVROVRH;
840 }
841
842 rocketMode = info->flags & ROCKET_MODE_MASK;
843
844 if ((info->flags & ROCKET_RTS_TOGGLE)
845 || (rocketMode == ROCKET_MODE_RS485))
846 sEnRTSToggle(cp);
847 else
848 sDisRTSToggle(cp);
849
850 sSetRTS(&info->channel);
851
852 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
853 switch (rocketMode) {
854 case ROCKET_MODE_RS485:
855 sSetInterfaceMode(cp, InterfaceModeRS485);
856 break;
857 case ROCKET_MODE_RS422:
858 sSetInterfaceMode(cp, InterfaceModeRS422);
859 break;
860 case ROCKET_MODE_RS232:
861 default:
862 if (info->flags & ROCKET_RTS_TOGGLE)
863 sSetInterfaceMode(cp, InterfaceModeRS232T);
864 else
865 sSetInterfaceMode(cp, InterfaceModeRS232);
866 break;
867 }
868 }
869}
870
Alan Cox31f35932009-01-02 13:45:05 +0000871static int carrier_raised(struct tty_port *port)
872{
873 struct r_port *info = container_of(port, struct r_port, port);
874 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
875}
876
Alan Coxfcc8ac12009-06-11 12:24:17 +0100877static void dtr_rts(struct tty_port *port, int on)
Alan Cox5d951fb2009-01-02 13:45:19 +0000878{
879 struct r_port *info = container_of(port, struct r_port, port);
Alan Coxfcc8ac12009-06-11 12:24:17 +0100880 if (on) {
881 sSetDTR(&info->channel);
882 sSetRTS(&info->channel);
883 } else {
884 sClrDTR(&info->channel);
885 sClrRTS(&info->channel);
886 }
Alan Cox5d951fb2009-01-02 13:45:19 +0000887}
888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889/*
890 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
891 * port's r_port struct. Initializes the port hardware.
892 */
893static int rp_open(struct tty_struct *tty, struct file *filp)
894{
895 struct r_port *info;
Alan Coxfba85e02009-01-02 13:48:39 +0000896 struct tty_port *port;
Jiri Slaby410235f2012-03-05 14:52:01 +0100897 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 CHANNEL_t *cp;
899 unsigned long page;
900
Jiri Slaby410235f2012-03-05 14:52:01 +0100901 info = rp_table[tty->index];
902 if (info == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return -ENXIO;
Alan Coxfba85e02009-01-02 13:48:39 +0000904 port = &info->port;
905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 page = __get_free_page(GFP_KERNEL);
907 if (!page)
908 return -ENOMEM;
909
Alan Coxfba85e02009-01-02 13:48:39 +0000910 if (port->flags & ASYNC_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700911 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700913 if (retval)
914 return retval;
Alan Coxfba85e02009-01-02 13:48:39 +0000915 return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917
918 /*
919 * We must not sleep from here until the port is marked fully in use.
920 */
921 if (info->xmit_buf)
922 free_page(page);
923 else
924 info->xmit_buf = (unsigned char *) page;
925
926 tty->driver_data = info;
Alan Coxfba85e02009-01-02 13:48:39 +0000927 tty_port_tty_set(port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Alan Coxfba85e02009-01-02 13:48:39 +0000929 if (port->count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 atomic_inc(&rp_num_ports_open);
931
932#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -0800933 printk(KERN_INFO "rocket mod++ = %d...\n",
934 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935#endif
936 }
937#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +0100938 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939#endif
940
941 /*
942 * Info->count is now 1; so it's safe to sleep now.
943 */
Jiri Slabya391ad02009-06-11 12:40:17 +0100944 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 cp = &info->channel;
946 sSetRxTrigger(cp, TRIG_1);
947 if (sGetChanStatus(cp) & CD_ACT)
948 info->cd_status = 1;
949 else
950 info->cd_status = 0;
951 sDisRxStatusMode(cp);
952 sFlushRxFIFO(cp);
953 sFlushTxFIFO(cp);
954
955 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
956 sSetRxTrigger(cp, TRIG_1);
957
958 sGetChanStatus(cp);
959 sDisRxStatusMode(cp);
960 sClrTxXOFF(cp);
961
962 sDisCTSFlowCtl(cp);
963 sDisTxSoftFlowCtl(cp);
964
965 sEnRxFIFO(cp);
966 sEnTransmit(cp);
967
Jiri Slabya391ad02009-06-11 12:40:17 +0100968 set_bit(ASYNCB_INITIALIZED, &info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970 /*
971 * Set up the tty->alt_speed kludge
972 */
973 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +0000974 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000976 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000978 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +0000980 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Alan Cox47b01b32009-01-02 13:48:30 +0000982 configure_r_port(tty, info, NULL);
Alan Coxadc8d742012-07-14 15:31:47 +0100983 if (tty->termios.c_cflag & CBAUD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 sSetDTR(cp);
985 sSetRTS(cp);
986 }
987 }
988 /* Starts (or resets) the maint polling loop */
989 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
990
Alan Coxfba85e02009-01-02 13:48:39 +0000991 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (retval) {
993#ifdef ROCKET_DEBUG_OPEN
994 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
995#endif
996 return retval;
997 }
998 return 0;
999}
1000
1001/*
Alan Coxe60a1082008-07-16 21:56:18 +01001002 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 */
1004static void rp_close(struct tty_struct *tty, struct file *filp)
1005{
Alan Coxc9f19e92009-01-02 13:47:26 +00001006 struct r_port *info = tty->driver_data;
Alan Coxc1314a42009-01-02 13:48:17 +00001007 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 int timeout;
1009 CHANNEL_t *cp;
1010
1011 if (rocket_paranoia_check(info, "rp_close"))
1012 return;
1013
1014#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001015 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016#endif
1017
Alan Coxfba85e02009-01-02 13:48:39 +00001018 if (tty_port_close_start(port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Alan Cox417b6e02010-06-01 22:52:45 +02001021 mutex_lock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 /*
1024 * Before we drop DTR, make sure the UART transmitter
1025 * has completely drained; this is especially
1026 * important if there is a transmit FIFO!
1027 */
1028 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1029 if (timeout == 0)
1030 timeout = 1;
1031 rp_wait_until_sent(tty, timeout);
1032 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1033
1034 sDisTransmit(cp);
1035 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1036 sDisCTSFlowCtl(cp);
1037 sDisTxSoftFlowCtl(cp);
1038 sClrTxXOFF(cp);
1039 sFlushRxFIFO(cp);
1040 sFlushTxFIFO(cp);
1041 sClrRTS(cp);
1042 if (C_HUPCL(tty))
1043 sClrDTR(cp);
1044
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001045 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
1047 tty_ldisc_flush(tty);
1048
1049 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1050
Alan Coxfba85e02009-01-02 13:48:39 +00001051 /* We can't yet use tty_port_close_end as the buffer handling in this
1052 driver is a bit different to the usual */
1053
Alan Coxc1314a42009-01-02 13:48:17 +00001054 if (port->blocked_open) {
1055 if (port->close_delay) {
1056 msleep_interruptible(jiffies_to_msecs(port->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
Alan Coxc1314a42009-01-02 13:48:17 +00001058 wake_up_interruptible(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 } else {
1060 if (info->xmit_buf) {
1061 free_page((unsigned long) info->xmit_buf);
1062 info->xmit_buf = NULL;
1063 }
1064 }
Alan Cox417b6e02010-06-01 22:52:45 +02001065 spin_lock_irq(&port->lock);
Alan Cox21bed702009-01-02 13:48:23 +00001066 info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 tty->closing = 0;
Alan Cox417b6e02010-06-01 22:52:45 +02001068 spin_unlock_irq(&port->lock);
1069 mutex_unlock(&port->mutex);
Alan Coxfba85e02009-01-02 13:48:39 +00001070 tty_port_tty_set(port, NULL);
Alan Cox417b6e02010-06-01 22:52:45 +02001071
Alan Coxfba85e02009-01-02 13:48:39 +00001072 wake_up_interruptible(&port->close_wait);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001073 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 atomic_dec(&rp_num_ports_open);
1075
1076#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001077 printk(KERN_INFO "rocket mod-- = %d...\n",
1078 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1080#endif
1081
1082}
1083
1084static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001085 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
Alan Coxc9f19e92009-01-02 13:47:26 +00001087 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 CHANNEL_t *cp;
1089 unsigned cflag;
1090
1091 if (rocket_paranoia_check(info, "rp_set_termios"))
1092 return;
1093
Alan Coxadc8d742012-07-14 15:31:47 +01001094 cflag = tty->termios.c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 /*
1097 * This driver doesn't support CS5 or CS6
1098 */
1099 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
Alan Coxadc8d742012-07-14 15:31:47 +01001100 tty->termios.c_cflag =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001102 /* Or CMSPAR */
Alan Coxadc8d742012-07-14 15:31:47 +01001103 tty->termios.c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Alan Cox47b01b32009-01-02 13:48:30 +00001105 configure_r_port(tty, info, old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107 cp = &info->channel;
1108
1109 /* Handle transition to B0 status */
Alan Coxadc8d742012-07-14 15:31:47 +01001110 if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 sClrDTR(cp);
1112 sClrRTS(cp);
1113 }
1114
1115 /* Handle transition away from B0 status */
Alan Coxadc8d742012-07-14 15:31:47 +01001116 if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
1117 if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 sSetRTS(cp);
1119 sSetDTR(cp);
1120 }
1121
Alan Coxadc8d742012-07-14 15:31:47 +01001122 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 tty->hw_stopped = 0;
1124 rp_start(tty);
1125 }
1126}
1127
Alan Cox9e989662008-07-22 11:18:03 +01001128static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Alan Coxc9f19e92009-01-02 13:47:26 +00001130 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 unsigned long flags;
1132
1133 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001134 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 spin_lock_irqsave(&info->slock, flags);
1137 if (break_state == -1)
1138 sSendBreak(&info->channel);
1139 else
1140 sClrBreak(&info->channel);
1141 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001142 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143}
1144
1145/*
1146 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1147 * the UPCI boards was added, it was decided to make this a function because
1148 * the macro was getting too complicated. All cases except the first one
1149 * (UPCIRingInd) are taken directly from the original macro.
1150 */
1151static int sGetChanRI(CHANNEL_T * ChP)
1152{
1153 CONTROLLER_t *CtlP = ChP->CtlP;
1154 int ChanNum = ChP->ChanNum;
1155 int RingInd = 0;
1156
1157 if (CtlP->UPCIRingInd)
1158 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1159 else if (CtlP->AltChanRingIndicator)
1160 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1161 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1162 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1163
1164 return RingInd;
1165}
1166
1167/********************************************************************************************/
1168/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1169
1170/*
1171 * Returns the state of the serial modem control lines. These next 2 functions
1172 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1173 */
Alan Cox60b33c12011-02-14 16:26:14 +00001174static int rp_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175{
Alan Coxc9f19e92009-01-02 13:47:26 +00001176 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 unsigned int control, result, ChanStatus;
1178
1179 ChanStatus = sGetChanStatusLo(&info->channel);
1180 control = info->channel.TxControl[3];
1181 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1182 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1183 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1184 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1185 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1186 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1187
1188 return result;
1189}
1190
1191/*
1192 * Sets the modem control lines
1193 */
Alan Cox20b9d172011-02-14 16:26:50 +00001194static int rp_tiocmset(struct tty_struct *tty,
1195 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Alan Coxc9f19e92009-01-02 13:47:26 +00001197 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 if (set & TIOCM_RTS)
1200 info->channel.TxControl[3] |= SET_RTS;
1201 if (set & TIOCM_DTR)
1202 info->channel.TxControl[3] |= SET_DTR;
1203 if (clear & TIOCM_RTS)
1204 info->channel.TxControl[3] &= ~SET_RTS;
1205 if (clear & TIOCM_DTR)
1206 info->channel.TxControl[3] &= ~SET_DTR;
1207
Al Viro457fb602008-03-19 16:27:48 +00001208 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 return 0;
1210}
1211
1212static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1213{
1214 struct rocket_config tmp;
1215
1216 if (!retinfo)
1217 return -EFAULT;
1218 memset(&tmp, 0, sizeof (tmp));
Alan Cox417b6e02010-06-01 22:52:45 +02001219 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 tmp.line = info->line;
1221 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001222 tmp.close_delay = info->port.close_delay;
1223 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
Alan Cox417b6e02010-06-01 22:52:45 +02001225 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1228 return -EFAULT;
1229 return 0;
1230}
1231
Alan Cox47b01b32009-01-02 13:48:30 +00001232static int set_config(struct tty_struct *tty, struct r_port *info,
1233 struct rocket_config __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
1235 struct rocket_config new_serial;
1236
1237 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1238 return -EFAULT;
1239
Alan Cox417b6e02010-06-01 22:52:45 +02001240 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 if (!capable(CAP_SYS_ADMIN))
1242 {
Alan Cox417b6e02010-06-01 22:52:45 +02001243 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) {
1244 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 return -EPERM;
Alan Cox417b6e02010-06-01 22:52:45 +02001246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
Alan Cox47b01b32009-01-02 13:48:30 +00001248 configure_r_port(tty, info, NULL);
Dan Carpenter49bf7ea2010-08-11 20:00:09 +02001249 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return 0;
1251 }
1252
1253 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001254 info->port.close_delay = new_serial.close_delay;
1255 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +00001258 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001260 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001262 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +00001264 tty->alt_speed = 460800;
Alan Cox417b6e02010-06-01 22:52:45 +02001265 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Alan Cox47b01b32009-01-02 13:48:30 +00001267 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return 0;
1269}
1270
1271/*
1272 * This function fills in a rocket_ports struct with information
1273 * about what boards/ports are in the system. This info is passed
1274 * to user space. See setrocket.c where the info is used to create
1275 * the /dev/ttyRx ports.
1276 */
1277static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1278{
1279 struct rocket_ports tmp;
1280 int board;
1281
1282 if (!retports)
1283 return -EFAULT;
1284 memset(&tmp, 0, sizeof (tmp));
1285 tmp.tty_major = rocket_driver->major;
1286
1287 for (board = 0; board < 4; board++) {
1288 tmp.rocketModel[board].model = rocketModel[board].model;
1289 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1290 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1291 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1292 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1293 }
1294 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1295 return -EFAULT;
1296 return 0;
1297}
1298
1299static int reset_rm2(struct r_port *info, void __user *arg)
1300{
1301 int reset;
1302
Alan Cox4129a6452008-02-08 04:18:45 -08001303 if (!capable(CAP_SYS_ADMIN))
1304 return -EPERM;
1305
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (copy_from_user(&reset, arg, sizeof (int)))
1307 return -EFAULT;
1308 if (reset)
1309 reset = 1;
1310
1311 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1312 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1313 return -EINVAL;
1314
1315 if (info->ctlp->BusType == isISA)
1316 sModemReset(info->ctlp, info->chan, reset);
1317 else
1318 sPCIModemReset(info->ctlp, info->chan, reset);
1319
1320 return 0;
1321}
1322
1323static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1324{
1325 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1326 return -EFAULT;
1327 return 0;
1328}
1329
1330/* IOCTL call handler into the driver */
Alan Cox6caa76b2011-02-14 16:27:22 +00001331static int rp_ioctl(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 unsigned int cmd, unsigned long arg)
1333{
Alan Coxc9f19e92009-01-02 13:47:26 +00001334 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001336 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1339 return -ENXIO;
1340
1341 switch (cmd) {
1342 case RCKP_GET_STRUCT:
1343 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001344 ret = -EFAULT;
1345 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001347 ret = get_config(info, argp);
1348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 case RCKP_SET_CONFIG:
Alan Cox47b01b32009-01-02 13:48:30 +00001350 ret = set_config(tty, info, argp);
Alan Coxbdf183a2008-04-30 00:53:21 -07001351 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001353 ret = get_ports(info, argp);
1354 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001356 ret = reset_rm2(info, argp);
1357 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001359 ret = get_version(info, argp);
1360 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001362 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001364 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365}
1366
1367static void rp_send_xchar(struct tty_struct *tty, char ch)
1368{
Alan Coxc9f19e92009-01-02 13:47:26 +00001369 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 CHANNEL_t *cp;
1371
1372 if (rocket_paranoia_check(info, "rp_send_xchar"))
1373 return;
1374
1375 cp = &info->channel;
1376 if (sGetTxCnt(cp))
1377 sWriteTxPrioByte(cp, ch);
1378 else
1379 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1380}
1381
1382static void rp_throttle(struct tty_struct *tty)
1383{
Alan Coxc9f19e92009-01-02 13:47:26 +00001384 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
1386#ifdef ROCKET_DEBUG_THROTTLE
1387 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1388 tty->ldisc.chars_in_buffer(tty));
1389#endif
1390
1391 if (rocket_paranoia_check(info, "rp_throttle"))
1392 return;
1393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (I_IXOFF(tty))
1395 rp_send_xchar(tty, STOP_CHAR(tty));
1396
1397 sClrRTS(&info->channel);
1398}
1399
1400static void rp_unthrottle(struct tty_struct *tty)
1401{
Alan Coxc9f19e92009-01-02 13:47:26 +00001402 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403#ifdef ROCKET_DEBUG_THROTTLE
1404 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1405 tty->ldisc.chars_in_buffer(tty));
1406#endif
1407
1408 if (rocket_paranoia_check(info, "rp_throttle"))
1409 return;
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (I_IXOFF(tty))
1412 rp_send_xchar(tty, START_CHAR(tty));
1413
1414 sSetRTS(&info->channel);
1415}
1416
1417/*
1418 * ------------------------------------------------------------
1419 * rp_stop() and rp_start()
1420 *
1421 * This routines are called before setting or resetting tty->stopped.
1422 * They enable or disable transmitter interrupts, as necessary.
1423 * ------------------------------------------------------------
1424 */
1425static void rp_stop(struct tty_struct *tty)
1426{
Alan Coxc9f19e92009-01-02 13:47:26 +00001427 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428
1429#ifdef ROCKET_DEBUG_FLOW
1430 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1431 info->xmit_cnt, info->xmit_fifo_room);
1432#endif
1433
1434 if (rocket_paranoia_check(info, "rp_stop"))
1435 return;
1436
1437 if (sGetTxCnt(&info->channel))
1438 sDisTransmit(&info->channel);
1439}
1440
1441static void rp_start(struct tty_struct *tty)
1442{
Alan Coxc9f19e92009-01-02 13:47:26 +00001443 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445#ifdef ROCKET_DEBUG_FLOW
1446 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1447 info->xmit_cnt, info->xmit_fifo_room);
1448#endif
1449
1450 if (rocket_paranoia_check(info, "rp_stop"))
1451 return;
1452
1453 sEnTransmit(&info->channel);
1454 set_bit((info->aiop * 8) + info->chan,
1455 (void *) &xmit_flags[info->board]);
1456}
1457
1458/*
1459 * rp_wait_until_sent() --- wait until the transmitter is empty
1460 */
1461static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1462{
Alan Coxc9f19e92009-01-02 13:47:26 +00001463 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 CHANNEL_t *cp;
1465 unsigned long orig_jiffies;
1466 int check_time, exit_time;
1467 int txcnt;
1468
1469 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1470 return;
1471
1472 cp = &info->channel;
1473
1474 orig_jiffies = jiffies;
1475#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001476 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001478 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479#endif
1480 while (1) {
1481 txcnt = sGetTxCnt(cp);
1482 if (!txcnt) {
1483 if (sGetChanStatusLo(cp) & TXSHRMT)
1484 break;
1485 check_time = (HZ / info->cps) / 5;
1486 } else {
1487 check_time = HZ * txcnt / info->cps;
1488 }
1489 if (timeout) {
1490 exit_time = orig_jiffies + timeout - jiffies;
1491 if (exit_time <= 0)
1492 break;
1493 if (exit_time < check_time)
1494 check_time = exit_time;
1495 }
1496 if (check_time == 0)
1497 check_time = 1;
1498#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001499 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1500 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501#endif
1502 msleep_interruptible(jiffies_to_msecs(check_time));
1503 if (signal_pending(current))
1504 break;
1505 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001506 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1508 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1509#endif
1510}
1511
1512/*
1513 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1514 */
1515static void rp_hangup(struct tty_struct *tty)
1516{
1517 CHANNEL_t *cp;
Alan Coxc9f19e92009-01-02 13:47:26 +00001518 struct r_port *info = tty->driver_data;
Alan Cox417b6e02010-06-01 22:52:45 +02001519 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
1521 if (rocket_paranoia_check(info, "rp_hangup"))
1522 return;
1523
1524#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001525 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526#endif
1527 rp_flush_buffer(tty);
Alan Cox417b6e02010-06-01 22:52:45 +02001528 spin_lock_irqsave(&info->port.lock, flags);
1529 if (info->port.flags & ASYNC_CLOSING) {
1530 spin_unlock_irqrestore(&info->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 return;
Alan Cox417b6e02010-06-01 22:52:45 +02001532 }
Alan Coxe60a1082008-07-16 21:56:18 +01001533 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 atomic_dec(&rp_num_ports_open);
1535 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
Alan Cox417b6e02010-06-01 22:52:45 +02001536 spin_unlock_irqrestore(&info->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Alan Coxfba85e02009-01-02 13:48:39 +00001538 tty_port_hangup(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
1540 cp = &info->channel;
1541 sDisRxFIFO(cp);
1542 sDisTransmit(cp);
1543 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1544 sDisCTSFlowCtl(cp);
1545 sDisTxSoftFlowCtl(cp);
1546 sClrTxXOFF(cp);
Alan Cox417b6e02010-06-01 22:52:45 +02001547 clear_bit(ASYNCB_INITIALIZED, &info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Alan Coxe60a1082008-07-16 21:56:18 +01001549 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550}
1551
1552/*
1553 * Exception handler - write char routine. The RocketPort driver uses a
1554 * double-buffering strategy, with the twist that if the in-memory CPU
1555 * buffer is empty, and there's space in the transmit FIFO, the
1556 * writing routines will write directly to transmit FIFO.
1557 * Write buffer and counters protected by spinlocks
1558 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001559static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
Alan Coxc9f19e92009-01-02 13:47:26 +00001561 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 CHANNEL_t *cp;
1563 unsigned long flags;
1564
1565 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001566 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001568 /*
1569 * Grab the port write mutex, locking out other processes that try to
1570 * write to this port
1571 */
1572 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
1574#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001575 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576#endif
1577
1578 spin_lock_irqsave(&info->slock, flags);
1579 cp = &info->channel;
1580
1581 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1582 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1583
1584 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1585 info->xmit_buf[info->xmit_head++] = ch;
1586 info->xmit_head &= XMIT_BUF_SIZE - 1;
1587 info->xmit_cnt++;
1588 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1589 } else {
1590 sOutB(sGetTxRxDataIO(cp), ch);
1591 info->xmit_fifo_room--;
1592 }
1593 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001594 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001595 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596}
1597
1598/*
1599 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001600 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 * this port at the same time. This other process could be running on the other CPU
1602 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1603 * Spinlocks protect the info xmit members.
1604 */
1605static int rp_write(struct tty_struct *tty,
1606 const unsigned char *buf, int count)
1607{
Alan Coxc9f19e92009-01-02 13:47:26 +00001608 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 CHANNEL_t *cp;
1610 const unsigned char *b;
1611 int c, retval = 0;
1612 unsigned long flags;
1613
1614 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1615 return 0;
1616
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001617 if (mutex_lock_interruptible(&info->write_mtx))
1618 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001621 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622#endif
1623 cp = &info->channel;
1624
1625 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1626 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1627
1628 /*
1629 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1630 * into FIFO. Use the write queue for temp storage.
1631 */
1632 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1633 c = min(count, info->xmit_fifo_room);
1634 b = buf;
1635
1636 /* Push data into FIFO, 2 bytes at a time */
1637 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1638
1639 /* If there is a byte remaining, write it */
1640 if (c & 1)
1641 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1642
1643 retval += c;
1644 buf += c;
1645 count -= c;
1646
1647 spin_lock_irqsave(&info->slock, flags);
1648 info->xmit_fifo_room -= c;
1649 spin_unlock_irqrestore(&info->slock, flags);
1650 }
1651
1652 /* If count is zero, we wrote it all and are done */
1653 if (!count)
1654 goto end;
1655
1656 /* Write remaining data into the port's xmit_buf */
1657 while (1) {
Alan Cox47b01b32009-01-02 13:48:30 +00001658 /* Hung up ? */
Jiri Slabya391ad02009-06-11 12:40:17 +01001659 if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001661 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1662 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (c <= 0)
1664 break;
1665
1666 b = buf;
1667 memcpy(info->xmit_buf + info->xmit_head, b, c);
1668
1669 spin_lock_irqsave(&info->slock, flags);
1670 info->xmit_head =
1671 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1672 info->xmit_cnt += c;
1673 spin_unlock_irqrestore(&info->slock, flags);
1674
1675 buf += c;
1676 count -= c;
1677 retval += c;
1678 }
1679
1680 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1681 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1682
1683end:
1684 if (info->xmit_cnt < WAKEUP_CHARS) {
1685 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686#ifdef ROCKETPORT_HAVE_POLL_WAIT
1687 wake_up_interruptible(&tty->poll_wait);
1688#endif
1689 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001690 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 return retval;
1692}
1693
1694/*
1695 * Return the number of characters that can be sent. We estimate
1696 * only using the in-memory transmit buffer only, and ignore the
1697 * potential space in the transmit FIFO.
1698 */
1699static int rp_write_room(struct tty_struct *tty)
1700{
Alan Coxc9f19e92009-01-02 13:47:26 +00001701 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 int ret;
1703
1704 if (rocket_paranoia_check(info, "rp_write_room"))
1705 return 0;
1706
1707 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1708 if (ret < 0)
1709 ret = 0;
1710#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001711 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712#endif
1713 return ret;
1714}
1715
1716/*
1717 * Return the number of characters in the buffer. Again, this only
1718 * counts those characters in the in-memory transmit buffer.
1719 */
1720static int rp_chars_in_buffer(struct tty_struct *tty)
1721{
Alan Coxc9f19e92009-01-02 13:47:26 +00001722 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1725 return 0;
1726
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001728 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729#endif
1730 return info->xmit_cnt;
1731}
1732
1733/*
1734 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1735 * r_port struct for the port. Note that spinlock are used to protect info members,
1736 * do not call this function if the spinlock is already held.
1737 */
1738static void rp_flush_buffer(struct tty_struct *tty)
1739{
Alan Coxc9f19e92009-01-02 13:47:26 +00001740 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 CHANNEL_t *cp;
1742 unsigned long flags;
1743
1744 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1745 return;
1746
1747 spin_lock_irqsave(&info->slock, flags);
1748 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1749 spin_unlock_irqrestore(&info->slock, flags);
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751#ifdef ROCKETPORT_HAVE_POLL_WAIT
1752 wake_up_interruptible(&tty->poll_wait);
1753#endif
1754 tty_wakeup(tty);
1755
1756 cp = &info->channel;
1757 sFlushTxFIFO(cp);
1758}
1759
1760#ifdef CONFIG_PCI
1761
Bill Pembertonde88b342012-11-19 13:24:32 -05001762static struct pci_device_id __used rocket_pci_ids[] = {
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001763 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
1764 { }
1765};
1766MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768/*
1769 * Called when a PCI card is found. Retrieves and stores model information,
1770 * init's aiopic and serial port hardware.
1771 * Inputs: i is the board number (0-n)
1772 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001773static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774{
1775 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1776 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 CONTROLLER_t *ctlp;
1778
1779 int fast_clock = 0;
1780 int altChanRingIndicator = 0;
1781 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 WordIO_t ConfigIO = 0;
1783 ByteIO_t UPCIRingInd = 0;
1784
1785 if (!dev || pci_enable_device(dev))
1786 return 0;
1787
1788 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
1790 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1791 rocketModel[i].loadrm2 = 0;
1792 rocketModel[i].startingPortNumber = nextLineNumber;
1793
1794 /* Depending on the model, set up some config variables */
1795 switch (dev->device) {
1796 case PCI_DEVICE_ID_RP4QUAD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 max_num_aiops = 1;
1798 ports_per_aiop = 4;
1799 rocketModel[i].model = MODEL_RP4QUAD;
1800 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1801 rocketModel[i].numPorts = 4;
1802 break;
1803 case PCI_DEVICE_ID_RP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 max_num_aiops = 1;
1805 rocketModel[i].model = MODEL_RP8OCTA;
1806 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1807 rocketModel[i].numPorts = 8;
1808 break;
1809 case PCI_DEVICE_ID_URP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 max_num_aiops = 1;
1811 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1812 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1813 rocketModel[i].numPorts = 8;
1814 break;
1815 case PCI_DEVICE_ID_RP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 max_num_aiops = 1;
1817 rocketModel[i].model = MODEL_RP8INTF;
1818 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1819 rocketModel[i].numPorts = 8;
1820 break;
1821 case PCI_DEVICE_ID_URP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 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:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 max_num_aiops = 1;
1829 rocketModel[i].model = MODEL_RP8J;
1830 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1831 rocketModel[i].numPorts = 8;
1832 break;
1833 case PCI_DEVICE_ID_RP4J:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 max_num_aiops = 1;
1835 ports_per_aiop = 4;
1836 rocketModel[i].model = MODEL_RP4J;
1837 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1838 rocketModel[i].numPorts = 4;
1839 break;
1840 case PCI_DEVICE_ID_RP8SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 max_num_aiops = 1;
1842 rocketModel[i].model = MODEL_RP8SNI;
1843 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1844 rocketModel[i].numPorts = 8;
1845 break;
1846 case PCI_DEVICE_ID_RP16SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 max_num_aiops = 2;
1848 rocketModel[i].model = MODEL_RP16SNI;
1849 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1850 rocketModel[i].numPorts = 16;
1851 break;
1852 case PCI_DEVICE_ID_RP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 max_num_aiops = 2;
1854 rocketModel[i].model = MODEL_RP16INTF;
1855 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1856 rocketModel[i].numPorts = 16;
1857 break;
1858 case PCI_DEVICE_ID_URP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 max_num_aiops = 2;
1860 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1861 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1862 rocketModel[i].numPorts = 16;
1863 break;
1864 case PCI_DEVICE_ID_CRP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 max_num_aiops = 2;
1866 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1867 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
1868 rocketModel[i].numPorts = 16;
1869 break;
1870 case PCI_DEVICE_ID_RP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 max_num_aiops = 4;
1872 rocketModel[i].model = MODEL_RP32INTF;
1873 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
1874 rocketModel[i].numPorts = 32;
1875 break;
1876 case PCI_DEVICE_ID_URP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 max_num_aiops = 4;
1878 rocketModel[i].model = MODEL_UPCI_RP32INTF;
1879 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
1880 rocketModel[i].numPorts = 32;
1881 break;
1882 case PCI_DEVICE_ID_RPP4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 max_num_aiops = 1;
1884 ports_per_aiop = 4;
1885 altChanRingIndicator++;
1886 fast_clock++;
1887 rocketModel[i].model = MODEL_RPP4;
1888 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
1889 rocketModel[i].numPorts = 4;
1890 break;
1891 case PCI_DEVICE_ID_RPP8:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 max_num_aiops = 2;
1893 ports_per_aiop = 4;
1894 altChanRingIndicator++;
1895 fast_clock++;
1896 rocketModel[i].model = MODEL_RPP8;
1897 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
1898 rocketModel[i].numPorts = 8;
1899 break;
1900 case PCI_DEVICE_ID_RP2_232:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 max_num_aiops = 1;
1902 ports_per_aiop = 2;
1903 altChanRingIndicator++;
1904 fast_clock++;
1905 rocketModel[i].model = MODEL_RP2_232;
1906 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
1907 rocketModel[i].numPorts = 2;
1908 break;
1909 case PCI_DEVICE_ID_RP2_422:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 max_num_aiops = 1;
1911 ports_per_aiop = 2;
1912 altChanRingIndicator++;
1913 fast_clock++;
1914 rocketModel[i].model = MODEL_RP2_422;
1915 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
1916 rocketModel[i].numPorts = 2;
1917 break;
1918 case PCI_DEVICE_ID_RP6M:
1919
1920 max_num_aiops = 1;
1921 ports_per_aiop = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Jiri Slaby57fedc72007-10-18 03:06:28 -07001923 /* If revision is 1, the rocketmodem flash must be loaded.
1924 * If it is 2 it is a "socketed" version. */
1925 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
1927 rocketModel[i].loadrm2 = 1;
1928 } else {
1929 rcktpt_type[i] = ROCKET_TYPE_MODEM;
1930 }
1931
1932 rocketModel[i].model = MODEL_RP6M;
1933 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
1934 rocketModel[i].numPorts = 6;
1935 break;
1936 case PCI_DEVICE_ID_RP4M:
1937 max_num_aiops = 1;
1938 ports_per_aiop = 4;
Jiri Slaby57fedc72007-10-18 03:06:28 -07001939 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_RP4M;
1947 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
1948 rocketModel[i].numPorts = 4;
1949 break;
1950 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 max_num_aiops = 0;
1952 break;
1953 }
1954
1955 /*
1956 * Check for UPCI boards.
1957 */
1958
1959 switch (dev->device) {
1960 case PCI_DEVICE_ID_URP32INTF:
1961 case PCI_DEVICE_ID_URP8INTF:
1962 case PCI_DEVICE_ID_URP16INTF:
1963 case PCI_DEVICE_ID_CRP16INTF:
1964 case PCI_DEVICE_ID_URP8OCTA:
1965 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
1966 ConfigIO = pci_resource_start(dev, 1);
1967 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
1968 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
1969
1970 /*
1971 * Check for octa or quad cable.
1972 */
1973 if (!
1974 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
1975 PCI_GPIO_CTRL_8PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 ports_per_aiop = 4;
1977 rocketModel[i].numPorts = 4;
1978 }
1979 }
1980 break;
1981 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 max_num_aiops = 1;
1983 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
1984 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
1985 rocketModel[i].numPorts = 8;
1986 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
1987 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
1988 ConfigIO = pci_resource_start(dev, 1);
1989 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
1990 break;
1991 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 max_num_aiops = 1;
1993 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
1994 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
1995 rocketModel[i].numPorts = 4;
1996 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
1997 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
1998 ConfigIO = pci_resource_start(dev, 1);
1999 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2000 break;
2001 default:
2002 break;
2003 }
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (fast_clock) {
2006 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2007 rp_baud_base[i] = 921600;
2008 } else {
2009 /*
2010 * If support_low_speed is set, use the slow clock
2011 * prescale, which supports 50 bps
2012 */
2013 if (support_low_speed) {
2014 /* mod 9 (divide by 10) prescale */
2015 sClockPrescale = 0x19;
2016 rp_baud_base[i] = 230400;
2017 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002018 /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 sClockPrescale = 0x14;
2020 rp_baud_base[i] = 460800;
2021 }
2022 }
2023
2024 for (aiop = 0; aiop < max_num_aiops; aiop++)
2025 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2026 ctlp = sCtlNumToCtlPtr(i);
2027 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2028 for (aiop = 0; aiop < max_num_aiops; aiop++)
2029 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2030
Jiri Slaby68562b72008-02-07 00:16:33 -08002031 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2032 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2033 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2034 rocketModel[i].startingPortNumber,
2035 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
2037 if (num_aiops <= 0) {
2038 rcktpt_io_addr[i] = 0;
2039 return (0);
2040 }
2041 is_PCI[i] = 1;
2042
2043 /* Reset the AIOPIC, init the serial ports */
2044 for (aiop = 0; aiop < num_aiops; aiop++) {
2045 sResetAiopByNum(ctlp, aiop);
2046 num_chan = ports_per_aiop;
2047 for (chan = 0; chan < num_chan; chan++)
2048 init_r_port(i, aiop, chan, dev);
2049 }
2050
2051 /* Rocket modems must be reset */
2052 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2053 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2054 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2055 num_chan = ports_per_aiop;
2056 for (chan = 0; chan < num_chan; chan++)
2057 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002058 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 for (chan = 0; chan < num_chan; chan++)
2060 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002061 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 rmSpeakerReset(ctlp, rocketModel[i].model);
2063 }
2064 return (1);
2065}
2066
2067/*
2068 * Probes for PCI cards, inits them if found
2069 * Input: board_found = number of ISA boards already found, or the
2070 * starting board number
2071 * Returns: Number of PCI boards found
2072 */
2073static int __init init_PCI(int boards_found)
2074{
2075 struct pci_dev *dev = NULL;
2076 int count = 0;
2077
2078 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002079 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 if (register_PCI(count + boards_found, dev))
2081 count++;
2082 }
2083 return (count);
2084}
2085
2086#endif /* CONFIG_PCI */
2087
2088/*
2089 * Probes for ISA cards
2090 * Input: i = the board number to look for
2091 * Returns: 1 if board found, 0 else
2092 */
2093static int __init init_ISA(int i)
2094{
2095 int num_aiops, num_chan = 0, total_num_chan = 0;
2096 int aiop, chan;
2097 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2098 CONTROLLER_t *ctlp;
2099 char *type_string;
2100
2101 /* If io_addr is zero, no board configured */
2102 if (rcktpt_io_addr[i] == 0)
2103 return (0);
2104
2105 /* Reserve the IO region */
2106 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002107 printk(KERN_ERR "Unable to reserve IO region for configured "
2108 "ISA RocketPort at address 0x%lx, board not "
2109 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 rcktpt_io_addr[i] = 0;
2111 return (0);
2112 }
2113
2114 ctlp = sCtlNumToCtlPtr(i);
2115
2116 ctlp->boardType = rcktpt_type[i];
2117
2118 switch (rcktpt_type[i]) {
2119 case ROCKET_TYPE_PC104:
2120 type_string = "(PC104)";
2121 break;
2122 case ROCKET_TYPE_MODEM:
2123 type_string = "(RocketModem)";
2124 break;
2125 case ROCKET_TYPE_MODEMII:
2126 type_string = "(RocketModem II)";
2127 break;
2128 default:
2129 type_string = "";
2130 break;
2131 }
2132
2133 /*
2134 * If support_low_speed is set, use the slow clock prescale,
2135 * which supports 50 bps
2136 */
2137 if (support_low_speed) {
2138 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2139 rp_baud_base[i] = 230400;
2140 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002141 sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 rp_baud_base[i] = 460800;
2143 }
2144
2145 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2146 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2147
2148 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2149
2150 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2151 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2152 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2153 }
2154
2155 /* If something went wrong initing the AIOP's release the ISA IO memory */
2156 if (num_aiops <= 0) {
2157 release_region(rcktpt_io_addr[i], 64);
2158 rcktpt_io_addr[i] = 0;
2159 return (0);
2160 }
2161
2162 rocketModel[i].startingPortNumber = nextLineNumber;
2163
2164 for (aiop = 0; aiop < num_aiops; aiop++) {
2165 sResetAiopByNum(ctlp, aiop);
2166 sEnAiop(ctlp, aiop);
2167 num_chan = sGetAiopNumChan(ctlp, aiop);
2168 total_num_chan += num_chan;
2169 for (chan = 0; chan < num_chan; chan++)
2170 init_r_port(i, aiop, chan, NULL);
2171 }
2172 is_PCI[i] = 0;
2173 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2174 num_chan = sGetAiopNumChan(ctlp, 0);
2175 total_num_chan = num_chan;
2176 for (chan = 0; chan < num_chan; chan++)
2177 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002178 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 for (chan = 0; chan < num_chan; chan++)
2180 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002181 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2183 } else {
2184 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2185 }
2186 rocketModel[i].numPorts = total_num_chan;
2187 rocketModel[i].model = MODEL_ISA;
2188
2189 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2190 i, rcktpt_io_addr[i], num_aiops, type_string);
2191
2192 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2193 rocketModel[i].modelString,
2194 rocketModel[i].startingPortNumber,
2195 rocketModel[i].startingPortNumber +
2196 rocketModel[i].numPorts - 1);
2197
2198 return (1);
2199}
2200
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002201static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 .open = rp_open,
2203 .close = rp_close,
2204 .write = rp_write,
2205 .put_char = rp_put_char,
2206 .write_room = rp_write_room,
2207 .chars_in_buffer = rp_chars_in_buffer,
2208 .flush_buffer = rp_flush_buffer,
2209 .ioctl = rp_ioctl,
2210 .throttle = rp_throttle,
2211 .unthrottle = rp_unthrottle,
2212 .set_termios = rp_set_termios,
2213 .stop = rp_stop,
2214 .start = rp_start,
2215 .hangup = rp_hangup,
2216 .break_ctl = rp_break,
2217 .send_xchar = rp_send_xchar,
2218 .wait_until_sent = rp_wait_until_sent,
2219 .tiocmget = rp_tiocmget,
2220 .tiocmset = rp_tiocmset,
2221};
2222
Alan Cox31f35932009-01-02 13:45:05 +00002223static const struct tty_port_operations rocket_port_ops = {
2224 .carrier_raised = carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +01002225 .dtr_rts = dtr_rts,
Alan Cox31f35932009-01-02 13:45:05 +00002226};
2227
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228/*
2229 * The module "startup" routine; it's run when the module is loaded.
2230 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002231static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002233 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2236 ROCKET_VERSION, ROCKET_DATE);
2237
2238 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2239 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002240 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
2242 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2244 * zero, use the default controller IO address of board1 + 0x40.
2245 */
2246 if (board1) {
2247 if (controller == 0)
2248 controller = board1 + 0x40;
2249 } else {
2250 controller = 0; /* Used as a flag, meaning no ISA boards */
2251 }
2252
2253 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2254 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002255 printk(KERN_ERR "Unable to reserve IO region for first "
2256 "configured ISA RocketPort controller 0x%lx. "
2257 "Driver exiting\n", controller);
2258 ret = -EBUSY;
2259 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
2261
2262 /* Store ISA variable retrieved from command line or .conf file. */
2263 rcktpt_io_addr[0] = board1;
2264 rcktpt_io_addr[1] = board2;
2265 rcktpt_io_addr[2] = board3;
2266 rcktpt_io_addr[3] = board4;
2267
2268 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2269 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2270 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2271 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2272 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2273 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2274 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2275 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2276
2277 /*
2278 * Set up the tty driver structure and then register this
2279 * driver with the tty layer.
2280 */
2281
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002282 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 rocket_driver->name = "ttyR";
2284 rocket_driver->driver_name = "Comtrol RocketPort";
2285 rocket_driver->major = TTY_ROCKET_MAJOR;
2286 rocket_driver->minor_start = 0;
2287 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2288 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2289 rocket_driver->init_termios = tty_std_termios;
2290 rocket_driver->init_termios.c_cflag =
2291 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002292 rocket_driver->init_termios.c_ispeed = 9600;
2293 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002295 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296#endif
2297 tty_set_operations(rocket_driver, &rocket_ops);
2298
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002299 ret = tty_register_driver(rocket_driver);
2300 if (ret < 0) {
2301 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
Dan Carpenter713efa92010-10-27 15:34:18 -07002302 goto err_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 }
2304
2305#ifdef ROCKET_DEBUG_OPEN
2306 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2307#endif
2308
2309 /*
2310 * OK, let's probe each of the controllers looking for boards. Any boards found
2311 * will be initialized here.
2312 */
2313 isa_boards_found = 0;
2314 pci_boards_found = 0;
2315
2316 for (i = 0; i < NUM_BOARDS; i++) {
2317 if (init_ISA(i))
2318 isa_boards_found++;
2319 }
2320
2321#ifdef CONFIG_PCI
2322 if (isa_boards_found < NUM_BOARDS)
2323 pci_boards_found = init_PCI(isa_boards_found);
2324#endif
2325
2326 max_board = pci_boards_found + isa_boards_found;
2327
2328 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002329 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2330 ret = -ENXIO;
2331 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 }
2333
2334 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002335err_ttyu:
2336 tty_unregister_driver(rocket_driver);
Dan Carpenter713efa92010-10-27 15:34:18 -07002337err_controller:
2338 if (controller)
2339 release_region(controller, 4);
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002340err_tty:
2341 put_tty_driver(rocket_driver);
2342err:
2343 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344}
2345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347static void rp_cleanup_module(void)
2348{
2349 int retval;
2350 int i;
2351
2352 del_timer_sync(&rocket_timer);
2353
2354 retval = tty_unregister_driver(rocket_driver);
2355 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002356 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
Jesper Juhl735d5662005-11-07 01:01:29 -08002359 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002360 if (rp_table[i]) {
2361 tty_unregister_device(rocket_driver, i);
Jiri Slaby191c5f12012-11-15 09:49:56 +01002362 tty_port_destroy(&rp_table[i]->port);
Jiri Slabyac6aec22007-10-18 03:06:26 -07002363 kfree(rp_table[i]);
2364 }
2365
2366 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
2368 for (i = 0; i < NUM_BOARDS; i++) {
2369 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2370 continue;
2371 release_region(rcktpt_io_addr[i], 64);
2372 }
2373 if (controller)
2374 release_region(controller, 4);
2375}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377/***************************************************************************
2378Function: sInitController
2379Purpose: Initialization of controller global registers and controller
2380 structure.
2381Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2382 IRQNum,Frequency,PeriodicOnly)
2383 CONTROLLER_T *CtlP; Ptr to controller structure
2384 int CtlNum; Controller number
2385 ByteIO_t MudbacIO; Mudbac base I/O address.
2386 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2387 This list must be in the order the AIOPs will be found on the
2388 controller. Once an AIOP in the list is not found, it is
2389 assumed that there are no more AIOPs on the controller.
2390 int AiopIOListSize; Number of addresses in AiopIOList
2391 int IRQNum; Interrupt Request number. Can be any of the following:
2392 0: Disable global interrupts
2393 3: IRQ 3
2394 4: IRQ 4
2395 5: IRQ 5
2396 9: IRQ 9
2397 10: IRQ 10
2398 11: IRQ 11
2399 12: IRQ 12
2400 15: IRQ 15
2401 Byte_t Frequency: A flag identifying the frequency
2402 of the periodic interrupt, can be any one of the following:
2403 FREQ_DIS - periodic interrupt disabled
2404 FREQ_137HZ - 137 Hertz
2405 FREQ_69HZ - 69 Hertz
2406 FREQ_34HZ - 34 Hertz
2407 FREQ_17HZ - 17 Hertz
2408 FREQ_9HZ - 9 Hertz
2409 FREQ_4HZ - 4 Hertz
2410 If IRQNum is set to 0 the Frequency parameter is
2411 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002412 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002414 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 other channel interrupts are allowed.
2416 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002417 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2419 initialization failed.
2420
2421Comments:
2422 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002423 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 If interrupts are to be completely disabled set IRQNum to 0.
2426
Adrian Bunkf15313b2005-06-25 14:59:05 -07002427 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 invalid combination.
2429
2430 This function performs initialization of global interrupt modes,
2431 but it does not actually enable global interrupts. To enable
2432 and disable global interrupts use functions sEnGlobalInt() and
2433 sDisGlobalInt(). Enabling of global interrupts is normally not
2434 done until all other initializations are complete.
2435
2436 Even if interrupts are globally enabled, they must also be
2437 individually enabled for each channel that is to generate
2438 interrupts.
2439
2440Warnings: No range checking on any of the parameters is done.
2441
2442 No context switches are allowed while executing this function.
2443
2444 After this function all AIOPs on the controller are disabled,
2445 they can be enabled with sEnAiop().
2446*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002447static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2448 ByteIO_t * AiopIOList, int AiopIOListSize,
2449 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
2451 int i;
2452 ByteIO_t io;
2453 int done;
2454
2455 CtlP->AiopIntrBits = aiop_intr_bits;
2456 CtlP->AltChanRingIndicator = 0;
2457 CtlP->CtlNum = CtlNum;
2458 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2459 CtlP->BusType = isISA;
2460 CtlP->MBaseIO = MudbacIO;
2461 CtlP->MReg1IO = MudbacIO + 1;
2462 CtlP->MReg2IO = MudbacIO + 2;
2463 CtlP->MReg3IO = MudbacIO + 3;
2464#if 1
2465 CtlP->MReg2 = 0; /* interrupt disable */
2466 CtlP->MReg3 = 0; /* no periodic interrupts */
2467#else
2468 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2469 CtlP->MReg2 = 0; /* interrupt disable */
2470 CtlP->MReg3 = 0; /* no periodic interrupts */
2471 } else {
2472 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2473 CtlP->MReg3 = Frequency; /* set frequency */
2474 if (PeriodicOnly) { /* periodic interrupt only */
2475 CtlP->MReg3 |= PERIODIC_ONLY;
2476 }
2477 }
2478#endif
2479 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2480 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2481 sControllerEOI(CtlP); /* clear EOI if warm init */
2482 /* Init AIOPs */
2483 CtlP->NumAiop = 0;
2484 for (i = done = 0; i < AiopIOListSize; i++) {
2485 io = AiopIOList[i];
2486 CtlP->AiopIO[i] = (WordIO_t) io;
2487 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2488 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2489 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2490 if (done)
2491 continue;
2492 sEnAiop(CtlP, i); /* enable the AIOP */
2493 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2494 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2495 done = 1; /* done looking for AIOPs */
2496 else {
2497 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2498 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2499 sOutB(io + _INDX_DATA, sClockPrescale);
2500 CtlP->NumAiop++; /* bump count of AIOPs */
2501 }
2502 sDisAiop(CtlP, i); /* disable AIOP */
2503 }
2504
2505 if (CtlP->NumAiop == 0)
2506 return (-1);
2507 else
2508 return (CtlP->NumAiop);
2509}
2510
2511/***************************************************************************
2512Function: sPCIInitController
2513Purpose: Initialization of controller global registers and controller
2514 structure.
2515Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2516 IRQNum,Frequency,PeriodicOnly)
2517 CONTROLLER_T *CtlP; Ptr to controller structure
2518 int CtlNum; Controller number
2519 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2520 This list must be in the order the AIOPs will be found on the
2521 controller. Once an AIOP in the list is not found, it is
2522 assumed that there are no more AIOPs on the controller.
2523 int AiopIOListSize; Number of addresses in AiopIOList
2524 int IRQNum; Interrupt Request number. Can be any of the following:
2525 0: Disable global interrupts
2526 3: IRQ 3
2527 4: IRQ 4
2528 5: IRQ 5
2529 9: IRQ 9
2530 10: IRQ 10
2531 11: IRQ 11
2532 12: IRQ 12
2533 15: IRQ 15
2534 Byte_t Frequency: A flag identifying the frequency
2535 of the periodic interrupt, can be any one of the following:
2536 FREQ_DIS - periodic interrupt disabled
2537 FREQ_137HZ - 137 Hertz
2538 FREQ_69HZ - 69 Hertz
2539 FREQ_34HZ - 34 Hertz
2540 FREQ_17HZ - 17 Hertz
2541 FREQ_9HZ - 9 Hertz
2542 FREQ_4HZ - 4 Hertz
2543 If IRQNum is set to 0 the Frequency parameter is
2544 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002545 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002547 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 other channel interrupts are allowed.
2549 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002550 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2552 initialization failed.
2553
2554Comments:
2555 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002556 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558 If interrupts are to be completely disabled set IRQNum to 0.
2559
Adrian Bunkf15313b2005-06-25 14:59:05 -07002560 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 invalid combination.
2562
2563 This function performs initialization of global interrupt modes,
2564 but it does not actually enable global interrupts. To enable
2565 and disable global interrupts use functions sEnGlobalInt() and
2566 sDisGlobalInt(). Enabling of global interrupts is normally not
2567 done until all other initializations are complete.
2568
2569 Even if interrupts are globally enabled, they must also be
2570 individually enabled for each channel that is to generate
2571 interrupts.
2572
2573Warnings: No range checking on any of the parameters is done.
2574
2575 No context switches are allowed while executing this function.
2576
2577 After this function all AIOPs on the controller are disabled,
2578 they can be enabled with sEnAiop().
2579*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002580static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2581 ByteIO_t * AiopIOList, int AiopIOListSize,
2582 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2583 int PeriodicOnly, int altChanRingIndicator,
2584 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585{
2586 int i;
2587 ByteIO_t io;
2588
2589 CtlP->AltChanRingIndicator = altChanRingIndicator;
2590 CtlP->UPCIRingInd = UPCIRingInd;
2591 CtlP->CtlNum = CtlNum;
2592 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2593 CtlP->BusType = isPCI; /* controller release 1 */
2594
2595 if (ConfigIO) {
2596 CtlP->isUPCI = 1;
2597 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2598 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2599 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2600 } else {
2601 CtlP->isUPCI = 0;
2602 CtlP->PCIIO =
2603 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2604 CtlP->AiopIntrBits = aiop_intr_bits;
2605 }
2606
2607 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2608 /* Init AIOPs */
2609 CtlP->NumAiop = 0;
2610 for (i = 0; i < AiopIOListSize; i++) {
2611 io = AiopIOList[i];
2612 CtlP->AiopIO[i] = (WordIO_t) io;
2613 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2614
2615 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2616 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2617 break; /* done looking for AIOPs */
2618
2619 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2620 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2621 sOutB(io + _INDX_DATA, sClockPrescale);
2622 CtlP->NumAiop++; /* bump count of AIOPs */
2623 }
2624
2625 if (CtlP->NumAiop == 0)
2626 return (-1);
2627 else
2628 return (CtlP->NumAiop);
2629}
2630
2631/***************************************************************************
2632Function: sReadAiopID
2633Purpose: Read the AIOP idenfication number directly from an AIOP.
2634Call: sReadAiopID(io)
2635 ByteIO_t io: AIOP base I/O address
2636Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2637 is replace by an identifying number.
2638 Flag AIOPID_NULL if no valid AIOP is found
2639Warnings: No context switches are allowed while executing this function.
2640
2641*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002642static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
2644 Byte_t AiopID; /* ID byte from AIOP */
2645
2646 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2647 sOutB(io + _CMD_REG, 0x0);
2648 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2649 if (AiopID == 0x06)
2650 return (1);
2651 else /* AIOP does not exist */
2652 return (-1);
2653}
2654
2655/***************************************************************************
2656Function: sReadAiopNumChan
2657Purpose: Read the number of channels available in an AIOP directly from
2658 an AIOP.
2659Call: sReadAiopNumChan(io)
2660 WordIO_t io: AIOP base I/O address
2661Return: int: The number of channels available
2662Comments: The number of channels is determined by write/reads from identical
2663 offsets within the SRAM address spaces for channels 0 and 4.
2664 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2665 AIOP, otherwise it is an 8 channel.
2666Warnings: No context switches are allowed while executing this function.
2667*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002668static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
2670 Word_t x;
2671 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2672
2673 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002674 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2676 x = sInW(io + _INDX_DATA);
2677 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2678 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2679 return (8);
2680 else
2681 return (4);
2682}
2683
2684/***************************************************************************
2685Function: sInitChan
2686Purpose: Initialization of a channel and channel structure
2687Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2688 CONTROLLER_T *CtlP; Ptr to controller structure
2689 CHANNEL_T *ChP; Ptr to channel structure
2690 int AiopNum; AIOP number within controller
2691 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002692Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 number exceeds number of channels available in AIOP.
2694Comments: This function must be called before a channel can be used.
2695Warnings: No range checking on any of the parameters is done.
2696
2697 No context switches are allowed while executing this function.
2698*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002699static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2700 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
2702 int i;
2703 WordIO_t AiopIO;
2704 WordIO_t ChIOOff;
2705 Byte_t *ChR;
2706 Word_t ChOff;
2707 static Byte_t R[4];
2708 int brd9600;
2709
2710 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002711 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 /* Channel, AIOP, and controller identifiers */
2714 ChP->CtlP = CtlP;
2715 ChP->ChanID = CtlP->AiopID[AiopNum];
2716 ChP->AiopNum = AiopNum;
2717 ChP->ChanNum = ChanNum;
2718
2719 /* Global direct addresses */
2720 AiopIO = CtlP->AiopIO[AiopNum];
2721 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2722 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2723 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2724 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2725 ChP->IndexData = AiopIO + _INDX_DATA;
2726
2727 /* Channel direct addresses */
2728 ChIOOff = AiopIO + ChP->ChanNum * 2;
2729 ChP->TxRxData = ChIOOff + _TD0;
2730 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2731 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2732 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2733
2734 /* Initialize the channel from the RData array */
2735 for (i = 0; i < RDATASIZE; i += 4) {
2736 R[0] = RData[i];
2737 R[1] = RData[i + 1] + 0x10 * ChanNum;
2738 R[2] = RData[i + 2];
2739 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002740 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 }
2742
2743 ChR = ChP->R;
2744 for (i = 0; i < RREGDATASIZE; i += 4) {
2745 ChR[i] = RRegData[i];
2746 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2747 ChR[i + 2] = RRegData[i + 2];
2748 ChR[i + 3] = RRegData[i + 3];
2749 }
2750
2751 /* Indexed registers */
2752 ChOff = (Word_t) ChanNum *0x1000;
2753
2754 if (sClockPrescale == 0x14)
2755 brd9600 = 47;
2756 else
2757 brd9600 = 23;
2758
2759 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2760 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2761 ChP->BaudDiv[2] = (Byte_t) brd9600;
2762 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002763 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764
2765 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2766 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2767 ChP->TxControl[2] = 0;
2768 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002769 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
2771 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2772 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2773 ChP->RxControl[2] = 0;
2774 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002775 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2778 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2779 ChP->TxEnables[2] = 0;
2780 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002781 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
2783 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2784 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2785 ChP->TxCompare[2] = 0;
2786 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002787 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2790 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2791 ChP->TxReplace1[2] = 0;
2792 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002793 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
2795 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2796 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2797 ChP->TxReplace2[2] = 0;
2798 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002799 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2802 ChP->TxFIFO = ChOff + _TX_FIFO;
2803
2804 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2805 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2806 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2807 sOutW(ChP->IndexData, 0);
2808 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2809 ChP->RxFIFO = ChOff + _RX_FIFO;
2810
2811 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2812 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2813 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2814 sOutW(ChP->IndexData, 0);
2815 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2816 sOutW(ChP->IndexData, 0);
2817 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2818 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2819 sOutB(ChP->IndexData, 0);
2820 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2821 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2822 sOutB(ChP->IndexData, 0);
2823 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2824 sEnRxProcessor(ChP); /* start the Rx processor */
2825
Adrian Bunkf15313b2005-06-25 14:59:05 -07002826 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827}
2828
2829/***************************************************************************
2830Function: sStopRxProcessor
2831Purpose: Stop the receive processor from processing a channel.
2832Call: sStopRxProcessor(ChP)
2833 CHANNEL_T *ChP; Ptr to channel structure
2834
2835Comments: The receive processor can be started again with sStartRxProcessor().
2836 This function causes the receive processor to skip over the
2837 stopped channel. It does not stop it from processing other channels.
2838
2839Warnings: No context switches are allowed while executing this function.
2840
2841 Do not leave the receive processor stopped for more than one
2842 character time.
2843
2844 After calling this function a delay of 4 uS is required to ensure
2845 that the receive processor is no longer processing this channel.
2846*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002847static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
2849 Byte_t R[4];
2850
2851 R[0] = ChP->R[0];
2852 R[1] = ChP->R[1];
2853 R[2] = 0x0a;
2854 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00002855 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856}
2857
2858/***************************************************************************
2859Function: sFlushRxFIFO
2860Purpose: Flush the Rx FIFO
2861Call: sFlushRxFIFO(ChP)
2862 CHANNEL_T *ChP; Ptr to channel structure
2863Return: void
2864Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2865 while it is being flushed the receive processor is stopped
2866 and the transmitter is disabled. After these operations a
2867 4 uS delay is done before clearing the pointers to allow
2868 the receive processor to stop. These items are handled inside
2869 this function.
2870Warnings: No context switches are allowed while executing this function.
2871*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002872static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873{
2874 int i;
2875 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002876 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
2879 return; /* don't need to flush */
2880
Adrian Bunkf15313b2005-06-25 14:59:05 -07002881 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002883 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 sDisRxFIFO(ChP); /* disable it */
2885 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
2886 sInB(ChP->IntChan); /* depends on bus i/o timing */
2887 }
2888 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
2889 Ch = (Byte_t) sGetChanNum(ChP);
2890 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
2891 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
2892 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2893 sOutW(ChP->IndexData, 0);
2894 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2895 sOutW(ChP->IndexData, 0);
2896 if (RxFIFOEnabled)
2897 sEnRxFIFO(ChP); /* enable Rx FIFO */
2898}
2899
2900/***************************************************************************
2901Function: sFlushTxFIFO
2902Purpose: Flush the Tx FIFO
2903Call: sFlushTxFIFO(ChP)
2904 CHANNEL_T *ChP; Ptr to channel structure
2905Return: void
2906Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2907 while it is being flushed the receive processor is stopped
2908 and the transmitter is disabled. After these operations a
2909 4 uS delay is done before clearing the pointers to allow
2910 the receive processor to stop. These items are handled inside
2911 this function.
2912Warnings: No context switches are allowed while executing this function.
2913*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002914static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 int i;
2917 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002918 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
2921 return; /* don't need to flush */
2922
Adrian Bunkf15313b2005-06-25 14:59:05 -07002923 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07002925 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 sDisTransmit(ChP); /* disable transmitter */
2927 }
2928 sStopRxProcessor(ChP); /* stop Rx processor */
2929 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
2930 sInB(ChP->IntChan); /* depends on bus i/o timing */
2931 Ch = (Byte_t) sGetChanNum(ChP);
2932 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
2933 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
2934 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2935 sOutW(ChP->IndexData, 0);
2936 if (TxEnabled)
2937 sEnTransmit(ChP); /* enable transmitter */
2938 sStartRxProcessor(ChP); /* restart Rx processor */
2939}
2940
2941/***************************************************************************
2942Function: sWriteTxPrioByte
2943Purpose: Write a byte of priority transmit data to a channel
2944Call: sWriteTxPrioByte(ChP,Data)
2945 CHANNEL_T *ChP; Ptr to channel structure
2946 Byte_t Data; The transmit data byte
2947
2948Return: int: 1 if the bytes is successfully written, otherwise 0.
2949
2950Comments: The priority byte is transmitted before any data in the Tx FIFO.
2951
2952Warnings: No context switches are allowed while executing this function.
2953*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002954static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955{
2956 Byte_t DWBuf[4]; /* buffer for double word writes */
2957 Word_t *WordPtr; /* must be far because Win SS != DS */
2958 register DWordIO_t IndexAddr;
2959
2960 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
2961 IndexAddr = ChP->IndexAddr;
2962 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
2963 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
2964 return (0); /* nothing sent */
2965
2966 WordPtr = (Word_t *) (&DWBuf[0]);
2967 *WordPtr = ChP->TxPrioBuf; /* data byte address */
2968
2969 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00002970 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
2972 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
2973
2974 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
2975 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00002976 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 } else { /* write it to Tx FIFO */
2978
2979 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
2980 }
2981 return (1); /* 1 byte sent */
2982}
2983
2984/***************************************************************************
2985Function: sEnInterrupts
2986Purpose: Enable one or more interrupts for a channel
2987Call: sEnInterrupts(ChP,Flags)
2988 CHANNEL_T *ChP; Ptr to channel structure
2989 Word_t Flags: Interrupt enable flags, can be any combination
2990 of the following flags:
2991 TXINT_EN: Interrupt on Tx FIFO empty
2992 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
2993 sSetRxTrigger())
2994 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
2995 MCINT_EN: Interrupt on modem input change
2996 CHANINT_EN: Allow channel interrupt signal to the AIOP's
2997 Interrupt Channel Register.
2998Return: void
2999Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3000 enabled. If an interrupt enable flag is not set in Flags, that
3001 interrupt will not be changed. Interrupts can be disabled with
3002 function sDisInterrupts().
3003
3004 This function sets the appropriate bit for the channel in the AIOP's
3005 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3006 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3007
3008 Interrupts must also be globally enabled before channel interrupts
3009 will be passed on to the host. This is done with function
3010 sEnGlobalInt().
3011
3012 In some cases it may be desirable to disable interrupts globally but
3013 enable channel interrupts. This would allow the global interrupt
3014 status register to be used to determine which AIOPs need service.
3015*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003016static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017{
3018 Byte_t Mask; /* Interrupt Mask Register */
3019
3020 ChP->RxControl[2] |=
3021 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3022
Al Viro457fb602008-03-19 16:27:48 +00003023 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
3025 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3026
Al Viro457fb602008-03-19 16:27:48 +00003027 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
3029 if (Flags & CHANINT_EN) {
3030 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3031 sOutB(ChP->IntMask, Mask);
3032 }
3033}
3034
3035/***************************************************************************
3036Function: sDisInterrupts
3037Purpose: Disable one or more interrupts for a channel
3038Call: sDisInterrupts(ChP,Flags)
3039 CHANNEL_T *ChP; Ptr to channel structure
3040 Word_t Flags: Interrupt flags, can be any combination
3041 of the following flags:
3042 TXINT_EN: Interrupt on Tx FIFO empty
3043 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3044 sSetRxTrigger())
3045 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3046 MCINT_EN: Interrupt on modem input change
3047 CHANINT_EN: Disable channel interrupt signal to the
3048 AIOP's Interrupt Channel Register.
3049Return: void
3050Comments: If an interrupt flag is set in Flags, that interrupt will be
3051 disabled. If an interrupt flag is not set in Flags, that
3052 interrupt will not be changed. Interrupts can be enabled with
3053 function sEnInterrupts().
3054
3055 This function clears the appropriate bit for the channel in the AIOP's
3056 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3057 this channel's bit from being set in the AIOP's Interrupt Channel
3058 Register.
3059*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003060static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061{
3062 Byte_t Mask; /* Interrupt Mask Register */
3063
3064 ChP->RxControl[2] &=
3065 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003066 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003068 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069
3070 if (Flags & CHANINT_EN) {
3071 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3072 sOutB(ChP->IntMask, Mask);
3073 }
3074}
3075
Adrian Bunkf15313b2005-06-25 14:59:05 -07003076static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077{
3078 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3079}
3080
3081/*
3082 * Not an official SSCI function, but how to reset RocketModems.
3083 * ISA bus version
3084 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003085static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
3087 ByteIO_t addr;
3088 Byte_t val;
3089
3090 addr = CtlP->AiopIO[0] + 0x400;
3091 val = sInB(CtlP->MReg3IO);
3092 /* if AIOP[1] is not enabled, enable it */
3093 if ((val & 2) == 0) {
3094 val = sInB(CtlP->MReg2IO);
3095 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3096 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3097 }
3098
3099 sEnAiop(CtlP, 1);
3100 if (!on)
3101 addr += 8;
3102 sOutB(addr + chan, 0); /* apply or remove reset */
3103 sDisAiop(CtlP, 1);
3104}
3105
3106/*
3107 * Not an official SSCI function, but how to reset RocketModems.
3108 * PCI bus version
3109 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003110static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111{
3112 ByteIO_t addr;
3113
3114 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3115 if (!on)
3116 addr += 8;
3117 sOutB(addr + chan, 0); /* apply or remove reset */
3118}
3119
3120/* Resets the speaker controller on RocketModem II and III devices */
3121static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3122{
3123 ByteIO_t addr;
3124
3125 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3126 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3127 addr = CtlP->AiopIO[0] + 0x4F;
3128 sOutB(addr, 0);
3129 }
3130
3131 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3132 if ((model == MODEL_UPCI_RM3_8PORT)
3133 || (model == MODEL_UPCI_RM3_4PORT)) {
3134 addr = CtlP->AiopIO[0] + 0x88;
3135 sOutB(addr, 0);
3136 }
3137}
3138
3139/* Returns the line number given the controller (board), aiop and channel number */
3140static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3141{
3142 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3143}
3144
3145/*
3146 * Stores the line number associated with a given controller (board), aiop
3147 * and channel number.
3148 * Returns: The line number assigned
3149 */
3150static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3151{
3152 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3153 return (nextLineNumber - 1);
3154}