blob: 4a4110e703a59cbd47933e40f2a29e8d189770b6 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <asm/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;
121static int support_low_speed;
122static 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;
382 tty_insert_flip_char(tty, CharNStat & 0xff, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 ToRecv--;
384 }
385
386 /*
387 * after we've emptied the FIFO in status mode, turn
388 * status mode back off
389 */
390 if (sGetRxCnt(cp) == 0) {
391#ifdef ROCKET_DEBUG_RECEIVE
392 printk(KERN_INFO "Status mode off.\n");
393#endif
394 sDisRxStatusMode(cp);
395 }
396 } else {
397 /*
398 * we aren't in status mode, so read down the FIFO two
399 * characters at time by doing repeated word IO
400 * transfer.
401 */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700402 space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
403 if (space < ToRecv) {
404#ifdef ROCKET_DEBUG_RECEIVE
405 printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
406#endif
407 if (space <= 0)
408 return;
409 ToRecv = space;
410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 wRecv = ToRecv >> 1;
412 if (wRecv)
413 sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
414 if (ToRecv & 1)
415 cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
417 /* Push the data up to the tty layer */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700418 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420
421/*
422 * Serial port transmit data function. Called from the timer polling loop as a
423 * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready
424 * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is
425 * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks.
426 */
427static void rp_do_transmit(struct r_port *info)
428{
429 int c;
430 CHANNEL_t *cp = &info->channel;
431 struct tty_struct *tty;
432 unsigned long flags;
433
434#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800435 printk(KERN_DEBUG "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436#endif
437 if (!info)
438 return;
Alan Coxe60a1082008-07-16 21:56:18 +0100439 if (!info->port.tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800440 printk(KERN_WARNING "rp: WARNING %s called with "
Alan Coxe60a1082008-07-16 21:56:18 +0100441 "info->port.tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
443 return;
444 }
445
446 spin_lock_irqsave(&info->slock, flags);
Alan Coxe60a1082008-07-16 21:56:18 +0100447 tty = info->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
449
450 /* Loop sending data to FIFO until done or FIFO full */
451 while (1) {
452 if (tty->stopped || tty->hw_stopped)
453 break;
Harvey Harrison709107f2008-04-30 00:53:51 -0700454 c = min(info->xmit_fifo_room, info->xmit_cnt);
455 c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (c <= 0 || info->xmit_fifo_room <= 0)
457 break;
458 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
459 if (c & 1)
460 sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]);
461 info->xmit_tail += c;
462 info->xmit_tail &= XMIT_BUF_SIZE - 1;
463 info->xmit_cnt -= c;
464 info->xmit_fifo_room -= c;
465#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800466 printk(KERN_INFO "tx %d chars...\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467#endif
468 }
469
470 if (info->xmit_cnt == 0)
471 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
472
473 if (info->xmit_cnt < WAKEUP_CHARS) {
474 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475#ifdef ROCKETPORT_HAVE_POLL_WAIT
476 wake_up_interruptible(&tty->poll_wait);
477#endif
478 }
479
480 spin_unlock_irqrestore(&info->slock, flags);
481
482#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800483 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 info->xmit_tail, info->xmit_fifo_room);
485#endif
486}
487
488/*
489 * Called when a serial port signals it has read data in it's RX FIFO.
490 * It checks what interrupts are pending and services them, including
491 * receiving serial data.
492 */
493static void rp_handle_port(struct r_port *info)
494{
495 CHANNEL_t *cp;
496 struct tty_struct *tty;
497 unsigned int IntMask, ChanStatus;
498
499 if (!info)
500 return;
501
502 if ((info->flags & ROCKET_INITIALIZED) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800503 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
504 "info->flags & NOT_INIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return;
506 }
Alan Coxe60a1082008-07-16 21:56:18 +0100507 if (!info->port.tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800508 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
Alan Coxe60a1082008-07-16 21:56:18 +0100509 "info->port.tty==NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return;
511 }
512 cp = &info->channel;
Alan Coxe60a1082008-07-16 21:56:18 +0100513 tty = info->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 IntMask = sGetChanIntID(cp) & info->intmask;
516#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800517 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518#endif
519 ChanStatus = sGetChanStatus(cp);
520 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
521 rp_do_receive(info, tty, cp, ChanStatus);
522 }
523 if (IntMask & DELTA_CD) { /* CD change */
524#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800525 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 (ChanStatus & CD_ACT) ? "on" : "off");
527#endif
528 if (!(ChanStatus & CD_ACT) && info->cd_status) {
529#ifdef ROCKET_DEBUG_HANGUP
530 printk(KERN_INFO "CD drop, calling hangup.\n");
531#endif
532 tty_hangup(tty);
533 }
534 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100535 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
537#ifdef ROCKET_DEBUG_INTR
538 if (IntMask & DELTA_CTS) { /* CTS change */
539 printk(KERN_INFO "CTS change...\n");
540 }
541 if (IntMask & DELTA_DSR) { /* DSR change */
542 printk(KERN_INFO "DSR change...\n");
543 }
544#endif
545}
546
547/*
548 * The top level polling routine. Repeats every 1/100 HZ (10ms).
549 */
550static void rp_do_poll(unsigned long dummy)
551{
552 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700553 int ctrl, aiop, ch, line;
554 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 unsigned int CtlMask;
556 unsigned char AiopMask;
557 Word_t bit;
558
559 /* Walk through all the boards (ctrl's) */
560 for (ctrl = 0; ctrl < max_board; ctrl++) {
561 if (rcktpt_io_addr[ctrl] <= 0)
562 continue;
563
564 /* Get a ptr to the board's control struct */
565 ctlp = sCtlNumToCtlPtr(ctrl);
566
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200567 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_PCI
569 if (ctlp->BusType == isPCI)
570 CtlMask = sPCIGetControllerIntStatus(ctlp);
571 else
572#endif
573 CtlMask = sGetControllerIntStatus(ctlp);
574
575 /* Check if any AIOP read bits are set */
576 for (aiop = 0; CtlMask; aiop++) {
577 bit = ctlp->AiopIntrBits[aiop];
578 if (CtlMask & bit) {
579 CtlMask &= ~bit;
580 AiopMask = sGetAiopIntStatus(ctlp, aiop);
581
582 /* Check if any port read bits are set */
583 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
584 if (AiopMask & 1) {
585
586 /* Get the line number (/dev/ttyRx number). */
587 /* Read the data from the port. */
588 line = GetLineNumber(ctrl, aiop, ch);
589 rp_handle_port(rp_table[line]);
590 }
591 }
592 }
593 }
594
595 xmitmask = xmit_flags[ctrl];
596
597 /*
598 * xmit_flags contains bit-significant flags, indicating there is data
599 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
600 * 1, ... (32 total possible). The variable i has the aiop and ch
601 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
602 */
603 if (xmitmask) {
604 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
605 if (xmitmask & (1 << i)) {
606 aiop = (i & 0x18) >> 3;
607 ch = i & 0x07;
608 line = GetLineNumber(ctrl, aiop, ch);
609 rp_do_transmit(rp_table[line]);
610 }
611 }
612 }
613 }
614
615 /*
616 * Reset the timer so we get called at the next clock tick (10ms).
617 */
618 if (atomic_read(&rp_num_ports_open))
619 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
620}
621
622/*
623 * Initializes the r_port structure for a port, as well as enabling the port on
624 * the board.
625 * Inputs: board, aiop, chan numbers
626 */
627static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
628{
629 unsigned rocketMode;
630 struct r_port *info;
631 int line;
632 CONTROLLER_T *ctlp;
633
634 /* Get the next available line number */
635 line = SetLineNumber(board, aiop, chan);
636
637 ctlp = sCtlNumToCtlPtr(board);
638
639 /* 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 -0700640 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800642 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
643 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return;
645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 info->magic = RPORT_MAGIC;
648 info->line = line;
649 info->ctlp = ctlp;
650 info->board = board;
651 info->aiop = aiop;
652 info->chan = chan;
Alan Cox31f35932009-01-02 13:45:05 +0000653 tty_port_init(&info->port);
654 info->port.ops = &rocket_port_ops;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700655 init_completion(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 info->flags &= ~ROCKET_MODE_MASK;
657 switch (pc104[board][line]) {
658 case 422:
659 info->flags |= ROCKET_MODE_RS422;
660 break;
661 case 485:
662 info->flags |= ROCKET_MODE_RS485;
663 break;
664 case 232:
665 default:
666 info->flags |= ROCKET_MODE_RS232;
667 break;
668 }
669
670 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
671 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800672 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
673 board, aiop, chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 kfree(info);
675 return;
676 }
677
678 rocketMode = info->flags & ROCKET_MODE_MASK;
679
680 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
681 sEnRTSToggle(&info->channel);
682 else
683 sDisRTSToggle(&info->channel);
684
685 if (ctlp->boardType == ROCKET_TYPE_PC104) {
686 switch (rocketMode) {
687 case ROCKET_MODE_RS485:
688 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
689 break;
690 case ROCKET_MODE_RS422:
691 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
692 break;
693 case ROCKET_MODE_RS232:
694 default:
695 if (info->flags & ROCKET_RTS_TOGGLE)
696 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
697 else
698 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
699 break;
700 }
701 }
702 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700703 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 rp_table[line] = info;
Jiri Slabyac6aec22007-10-18 03:06:26 -0700705 tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
706 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
709/*
710 * Configures a rocketport port according to its termio settings. Called from
711 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
712 */
713static void configure_r_port(struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800714 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 unsigned cflag;
717 unsigned long flags;
718 unsigned rocketMode;
719 int bits, baud, divisor;
720 CHANNEL_t *cp;
Alan Coxe60a1082008-07-16 21:56:18 +0100721 struct ktermios *t = info->port.tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800724 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /* Byte size and parity */
727 if ((cflag & CSIZE) == CS8) {
728 sSetData8(cp);
729 bits = 10;
730 } else {
731 sSetData7(cp);
732 bits = 9;
733 }
734 if (cflag & CSTOPB) {
735 sSetStop2(cp);
736 bits++;
737 } else {
738 sSetStop1(cp);
739 }
740
741 if (cflag & PARENB) {
742 sEnParity(cp);
743 bits++;
744 if (cflag & PARODD) {
745 sSetOddParity(cp);
746 } else {
747 sSetEvenParity(cp);
748 }
749 } else {
750 sDisParity(cp);
751 }
752
753 /* baud rate */
Alan Coxe60a1082008-07-16 21:56:18 +0100754 baud = tty_get_baud_rate(info->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (!baud)
756 baud = 9600;
757 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
758 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800759 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (!baud)
761 baud = 9600;
762 divisor = (rp_baud_base[info->board] / baud) - 1;
763 }
764 if (divisor >= 8192 || divisor < 0) {
765 baud = 9600;
766 divisor = (rp_baud_base[info->board] / baud) - 1;
767 }
768 info->cps = baud / bits;
769 sSetBaud(cp, divisor);
770
Alan Cox6df35262008-02-08 04:18:45 -0800771 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Coxe60a1082008-07-16 21:56:18 +0100772 tty_encode_baud_rate(info->port.tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (cflag & CRTSCTS) {
775 info->intmask |= DELTA_CTS;
776 sEnCTSFlowCtl(cp);
777 } else {
778 info->intmask &= ~DELTA_CTS;
779 sDisCTSFlowCtl(cp);
780 }
781 if (cflag & CLOCAL) {
782 info->intmask &= ~DELTA_CD;
783 } else {
784 spin_lock_irqsave(&info->slock, flags);
785 if (sGetChanStatus(cp) & CD_ACT)
786 info->cd_status = 1;
787 else
788 info->cd_status = 0;
789 info->intmask |= DELTA_CD;
790 spin_unlock_irqrestore(&info->slock, flags);
791 }
792
793 /*
794 * Handle software flow control in the board
795 */
796#ifdef ROCKET_SOFT_FLOW
Alan Coxe60a1082008-07-16 21:56:18 +0100797 if (I_IXON(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 sEnTxSoftFlowCtl(cp);
Alan Coxe60a1082008-07-16 21:56:18 +0100799 if (I_IXANY(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 sEnIXANY(cp);
801 } else {
802 sDisIXANY(cp);
803 }
Alan Coxe60a1082008-07-16 21:56:18 +0100804 sSetTxXONChar(cp, START_CHAR(info->port.tty));
805 sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 } else {
807 sDisTxSoftFlowCtl(cp);
808 sDisIXANY(cp);
809 sClrTxXOFF(cp);
810 }
811#endif
812
813 /*
814 * Set up ignore/read mask words
815 */
816 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Coxe60a1082008-07-16 21:56:18 +0100817 if (I_INPCK(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Coxe60a1082008-07-16 21:56:18 +0100819 if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 info->read_status_mask |= STMBREAKH;
821
822 /*
823 * Characters to ignore
824 */
825 info->ignore_status_mask = 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100826 if (I_IGNPAR(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Coxe60a1082008-07-16 21:56:18 +0100828 if (I_IGNBRK(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 info->ignore_status_mask |= STMBREAKH;
830 /*
831 * If we're ignoring parity and break indicators,
832 * ignore overruns too. (For real raw support).
833 */
Alan Coxe60a1082008-07-16 21:56:18 +0100834 if (I_IGNPAR(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 info->ignore_status_mask |= STMRCVROVRH;
836 }
837
838 rocketMode = info->flags & ROCKET_MODE_MASK;
839
840 if ((info->flags & ROCKET_RTS_TOGGLE)
841 || (rocketMode == ROCKET_MODE_RS485))
842 sEnRTSToggle(cp);
843 else
844 sDisRTSToggle(cp);
845
846 sSetRTS(&info->channel);
847
848 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
849 switch (rocketMode) {
850 case ROCKET_MODE_RS485:
851 sSetInterfaceMode(cp, InterfaceModeRS485);
852 break;
853 case ROCKET_MODE_RS422:
854 sSetInterfaceMode(cp, InterfaceModeRS422);
855 break;
856 case ROCKET_MODE_RS232:
857 default:
858 if (info->flags & ROCKET_RTS_TOGGLE)
859 sSetInterfaceMode(cp, InterfaceModeRS232T);
860 else
861 sSetInterfaceMode(cp, InterfaceModeRS232);
862 break;
863 }
864 }
865}
866
Alan Cox31f35932009-01-02 13:45:05 +0000867static int carrier_raised(struct tty_port *port)
868{
869 struct r_port *info = container_of(port, struct r_port, port);
870 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
871}
872
Alan Coxe60a1082008-07-16 21:56:18 +0100873/* info->port.count is considered critical, protected by spinlocks. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874static int block_til_ready(struct tty_struct *tty, struct file *filp,
875 struct r_port *info)
876{
877 DECLARE_WAITQUEUE(wait, current);
Alan Cox31f35932009-01-02 13:45:05 +0000878 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 int retval;
880 int do_clocal = 0, extra_count = 0;
881 unsigned long flags;
882
883 /*
884 * If the device is in the middle of being closed, then block
885 * until it's done, and then try again.
886 */
887 if (tty_hung_up_p(filp))
888 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
889 if (info->flags & ROCKET_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700890 if (wait_for_completion_interruptible(&info->close_wait))
891 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
893 }
894
895 /*
896 * If non-blocking mode is set, or the port is not enabled,
897 * then make the check up front and then exit.
898 */
899 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
900 info->flags |= ROCKET_NORMAL_ACTIVE;
901 return 0;
902 }
903 if (tty->termios->c_cflag & CLOCAL)
904 do_clocal = 1;
905
906 /*
907 * Block waiting for the carrier detect and the line to become free. While we are in
Alan Cox31f35932009-01-02 13:45:05 +0000908 * this loop, port->count is dropped by one, so that rp_close() knows when to free things.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 * We restore it upon exit, either normal or abnormal.
910 */
911 retval = 0;
Alan Cox31f35932009-01-02 13:45:05 +0000912 add_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913#ifdef ROCKET_DEBUG_OPEN
Alan Cox31f35932009-01-02 13:45:05 +0000914 printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, port->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915#endif
916 spin_lock_irqsave(&info->slock, flags);
917
918#ifdef ROCKET_DISABLE_SIMUSAGE
919 info->flags |= ROCKET_NORMAL_ACTIVE;
920#else
921 if (!tty_hung_up_p(filp)) {
922 extra_count = 1;
Alan Cox31f35932009-01-02 13:45:05 +0000923 port->count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 }
925#endif
Alan Cox31f35932009-01-02 13:45:05 +0000926 port->blocked_open++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 spin_unlock_irqrestore(&info->slock, flags);
929
930 while (1) {
931 if (tty->termios->c_cflag & CBAUD) {
932 sSetDTR(&info->channel);
933 sSetRTS(&info->channel);
934 }
935 set_current_state(TASK_INTERRUPTIBLE);
936 if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) {
937 if (info->flags & ROCKET_HUP_NOTIFY)
938 retval = -EAGAIN;
939 else
940 retval = -ERESTARTSYS;
941 break;
942 }
Alan Cox31f35932009-01-02 13:45:05 +0000943 if (!(info->flags & ROCKET_CLOSING) &&
944 (do_clocal || tty_port_carrier_raised(port)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 break;
946 if (signal_pending(current)) {
947 retval = -ERESTARTSYS;
948 break;
949 }
950#ifdef ROCKET_DEBUG_OPEN
951 printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
Alan Cox31f35932009-01-02 13:45:05 +0000952 info->line, port->count, info->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953#endif
954 schedule(); /* Don't hold spinlock here, will hang PC */
955 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700956 __set_current_state(TASK_RUNNING);
Alan Cox31f35932009-01-02 13:45:05 +0000957 remove_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 spin_lock_irqsave(&info->slock, flags);
960
961 if (extra_count)
Alan Cox31f35932009-01-02 13:45:05 +0000962 port->count++;
963 port->blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 spin_unlock_irqrestore(&info->slock, flags);
966
967#ifdef ROCKET_DEBUG_OPEN
968 printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
Alan Cox31f35932009-01-02 13:45:05 +0000969 info->line, port->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970#endif
971 if (retval)
972 return retval;
973 info->flags |= ROCKET_NORMAL_ACTIVE;
974 return 0;
975}
976
977/*
978 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
979 * port's r_port struct. Initializes the port hardware.
980 */
981static int rp_open(struct tty_struct *tty, struct file *filp)
982{
983 struct r_port *info;
984 int line = 0, retval;
985 CHANNEL_t *cp;
986 unsigned long page;
987
Jiri Slabyf6de0c92008-02-07 00:16:33 -0800988 line = tty->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
990 return -ENXIO;
991
992 page = __get_free_page(GFP_KERNEL);
993 if (!page)
994 return -ENOMEM;
995
996 if (info->flags & ROCKET_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700997 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700999 if (retval)
1000 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
1002 }
1003
1004 /*
1005 * We must not sleep from here until the port is marked fully in use.
1006 */
1007 if (info->xmit_buf)
1008 free_page(page);
1009 else
1010 info->xmit_buf = (unsigned char *) page;
1011
1012 tty->driver_data = info;
Alan Coxe60a1082008-07-16 21:56:18 +01001013 info->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Alan Coxe60a1082008-07-16 21:56:18 +01001015 if (info->port.count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 atomic_inc(&rp_num_ports_open);
1017
1018#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001019 printk(KERN_INFO "rocket mod++ = %d...\n",
1020 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021#endif
1022 }
1023#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001024 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025#endif
1026
1027 /*
1028 * Info->count is now 1; so it's safe to sleep now.
1029 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if ((info->flags & ROCKET_INITIALIZED) == 0) {
1031 cp = &info->channel;
1032 sSetRxTrigger(cp, TRIG_1);
1033 if (sGetChanStatus(cp) & CD_ACT)
1034 info->cd_status = 1;
1035 else
1036 info->cd_status = 0;
1037 sDisRxStatusMode(cp);
1038 sFlushRxFIFO(cp);
1039 sFlushTxFIFO(cp);
1040
1041 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1042 sSetRxTrigger(cp, TRIG_1);
1043
1044 sGetChanStatus(cp);
1045 sDisRxStatusMode(cp);
1046 sClrTxXOFF(cp);
1047
1048 sDisCTSFlowCtl(cp);
1049 sDisTxSoftFlowCtl(cp);
1050
1051 sEnRxFIFO(cp);
1052 sEnTransmit(cp);
1053
1054 info->flags |= ROCKET_INITIALIZED;
1055
1056 /*
1057 * Set up the tty->alt_speed kludge
1058 */
1059 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Coxe60a1082008-07-16 21:56:18 +01001060 info->port.tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001062 info->port.tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001064 info->port.tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Coxe60a1082008-07-16 21:56:18 +01001066 info->port.tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
1068 configure_r_port(info, NULL);
1069 if (tty->termios->c_cflag & CBAUD) {
1070 sSetDTR(cp);
1071 sSetRTS(cp);
1072 }
1073 }
1074 /* Starts (or resets) the maint polling loop */
1075 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
1076
1077 retval = block_til_ready(tty, filp, info);
1078 if (retval) {
1079#ifdef ROCKET_DEBUG_OPEN
1080 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
1081#endif
1082 return retval;
1083 }
1084 return 0;
1085}
1086
1087/*
Alan Coxe60a1082008-07-16 21:56:18 +01001088 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 */
1090static void rp_close(struct tty_struct *tty, struct file *filp)
1091{
1092 struct r_port *info = (struct r_port *) tty->driver_data;
1093 unsigned long flags;
1094 int timeout;
1095 CHANNEL_t *cp;
1096
1097 if (rocket_paranoia_check(info, "rp_close"))
1098 return;
1099
1100#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001101 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102#endif
1103
1104 if (tty_hung_up_p(filp))
1105 return;
1106 spin_lock_irqsave(&info->slock, flags);
1107
Alan Coxe60a1082008-07-16 21:56:18 +01001108 if ((tty->count == 1) && (info->port.count != 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 /*
1110 * Uh, oh. tty->count is 1, which means that the tty
1111 * structure will be freed. Info->count should always
1112 * be one in these conditions. If it's greater than
1113 * one, we've got real problems, since it means the
1114 * serial port won't be shutdown.
1115 */
Jiri Slaby68562b72008-02-07 00:16:33 -08001116 printk(KERN_WARNING "rp_close: bad serial port count; "
Alan Coxe60a1082008-07-16 21:56:18 +01001117 "tty->count is 1, info->port.count is %d\n", info->port.count);
1118 info->port.count = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
Alan Coxe60a1082008-07-16 21:56:18 +01001120 if (--info->port.count < 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -08001121 printk(KERN_WARNING "rp_close: bad serial port count for "
Alan Coxe60a1082008-07-16 21:56:18 +01001122 "ttyR%d: %d\n", info->line, info->port.count);
1123 info->port.count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
Alan Coxe60a1082008-07-16 21:56:18 +01001125 if (info->port.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 spin_unlock_irqrestore(&info->slock, flags);
1127 return;
1128 }
1129 info->flags |= ROCKET_CLOSING;
1130 spin_unlock_irqrestore(&info->slock, flags);
1131
1132 cp = &info->channel;
1133
1134 /*
1135 * Notify the line discpline to only process XON/XOFF characters
1136 */
1137 tty->closing = 1;
1138
1139 /*
1140 * If transmission was throttled by the application request,
1141 * just flush the xmit buffer.
1142 */
1143 if (tty->flow_stopped)
1144 rp_flush_buffer(tty);
1145
1146 /*
1147 * Wait for the transmit buffer to clear
1148 */
Alan Cox44b7d1b2008-07-16 21:57:18 +01001149 if (info->port.closing_wait != ROCKET_CLOSING_WAIT_NONE)
1150 tty_wait_until_sent(tty, info->port.closing_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 /*
1152 * Before we drop DTR, make sure the UART transmitter
1153 * has completely drained; this is especially
1154 * important if there is a transmit FIFO!
1155 */
1156 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1157 if (timeout == 0)
1158 timeout = 1;
1159 rp_wait_until_sent(tty, timeout);
1160 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1161
1162 sDisTransmit(cp);
1163 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1164 sDisCTSFlowCtl(cp);
1165 sDisTxSoftFlowCtl(cp);
1166 sClrTxXOFF(cp);
1167 sFlushRxFIFO(cp);
1168 sFlushTxFIFO(cp);
1169 sClrRTS(cp);
1170 if (C_HUPCL(tty))
1171 sClrDTR(cp);
1172
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001173 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 tty_ldisc_flush(tty);
1176
1177 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1178
Alan Coxe60a1082008-07-16 21:56:18 +01001179 if (info->port.blocked_open) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01001180 if (info->port.close_delay) {
1181 msleep_interruptible(jiffies_to_msecs(info->port.close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 }
Alan Coxe60a1082008-07-16 21:56:18 +01001183 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 } else {
1185 if (info->xmit_buf) {
1186 free_page((unsigned long) info->xmit_buf);
1187 info->xmit_buf = NULL;
1188 }
1189 }
1190 info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
1191 tty->closing = 0;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001192 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 atomic_dec(&rp_num_ports_open);
1194
1195#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001196 printk(KERN_INFO "rocket mod-- = %d...\n",
1197 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1199#endif
1200
1201}
1202
1203static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001204 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
1206 struct r_port *info = (struct r_port *) tty->driver_data;
1207 CHANNEL_t *cp;
1208 unsigned cflag;
1209
1210 if (rocket_paranoia_check(info, "rp_set_termios"))
1211 return;
1212
1213 cflag = tty->termios->c_cflag;
1214
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 /*
1216 * This driver doesn't support CS5 or CS6
1217 */
1218 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
1219 tty->termios->c_cflag =
1220 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001221 /* Or CMSPAR */
1222 tty->termios->c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
1224 configure_r_port(info, old_termios);
1225
1226 cp = &info->channel;
1227
1228 /* Handle transition to B0 status */
1229 if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
1230 sClrDTR(cp);
1231 sClrRTS(cp);
1232 }
1233
1234 /* Handle transition away from B0 status */
1235 if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
1236 if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
1237 sSetRTS(cp);
1238 sSetDTR(cp);
1239 }
1240
1241 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
1242 tty->hw_stopped = 0;
1243 rp_start(tty);
1244 }
1245}
1246
Alan Cox9e989662008-07-22 11:18:03 +01001247static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248{
1249 struct r_port *info = (struct r_port *) tty->driver_data;
1250 unsigned long flags;
1251
1252 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001253 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 spin_lock_irqsave(&info->slock, flags);
1256 if (break_state == -1)
1257 sSendBreak(&info->channel);
1258 else
1259 sClrBreak(&info->channel);
1260 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001261 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262}
1263
1264/*
1265 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1266 * the UPCI boards was added, it was decided to make this a function because
1267 * the macro was getting too complicated. All cases except the first one
1268 * (UPCIRingInd) are taken directly from the original macro.
1269 */
1270static int sGetChanRI(CHANNEL_T * ChP)
1271{
1272 CONTROLLER_t *CtlP = ChP->CtlP;
1273 int ChanNum = ChP->ChanNum;
1274 int RingInd = 0;
1275
1276 if (CtlP->UPCIRingInd)
1277 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1278 else if (CtlP->AltChanRingIndicator)
1279 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1280 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1281 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1282
1283 return RingInd;
1284}
1285
1286/********************************************************************************************/
1287/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1288
1289/*
1290 * Returns the state of the serial modem control lines. These next 2 functions
1291 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1292 */
1293static int rp_tiocmget(struct tty_struct *tty, struct file *file)
1294{
1295 struct r_port *info = (struct r_port *)tty->driver_data;
1296 unsigned int control, result, ChanStatus;
1297
1298 ChanStatus = sGetChanStatusLo(&info->channel);
1299 control = info->channel.TxControl[3];
1300 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1301 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1302 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1303 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1304 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1305 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1306
1307 return result;
1308}
1309
1310/*
1311 * Sets the modem control lines
1312 */
1313static int rp_tiocmset(struct tty_struct *tty, struct file *file,
1314 unsigned int set, unsigned int clear)
1315{
1316 struct r_port *info = (struct r_port *)tty->driver_data;
1317
1318 if (set & TIOCM_RTS)
1319 info->channel.TxControl[3] |= SET_RTS;
1320 if (set & TIOCM_DTR)
1321 info->channel.TxControl[3] |= SET_DTR;
1322 if (clear & TIOCM_RTS)
1323 info->channel.TxControl[3] &= ~SET_RTS;
1324 if (clear & TIOCM_DTR)
1325 info->channel.TxControl[3] &= ~SET_DTR;
1326
Al Viro457fb602008-03-19 16:27:48 +00001327 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 return 0;
1329}
1330
1331static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1332{
1333 struct rocket_config tmp;
1334
1335 if (!retinfo)
1336 return -EFAULT;
1337 memset(&tmp, 0, sizeof (tmp));
1338 tmp.line = info->line;
1339 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001340 tmp.close_delay = info->port.close_delay;
1341 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
1343
1344 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1345 return -EFAULT;
1346 return 0;
1347}
1348
1349static int set_config(struct r_port *info, struct rocket_config __user *new_info)
1350{
1351 struct rocket_config new_serial;
1352
1353 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1354 return -EFAULT;
1355
1356 if (!capable(CAP_SYS_ADMIN))
1357 {
1358 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
1359 return -EPERM;
1360 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
1361 configure_r_port(info, NULL);
1362 return 0;
1363 }
1364
1365 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001366 info->port.close_delay = new_serial.close_delay;
1367 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Coxe60a1082008-07-16 21:56:18 +01001370 info->port.tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001372 info->port.tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001374 info->port.tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Coxe60a1082008-07-16 21:56:18 +01001376 info->port.tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 configure_r_port(info, NULL);
1379 return 0;
1380}
1381
1382/*
1383 * This function fills in a rocket_ports struct with information
1384 * about what boards/ports are in the system. This info is passed
1385 * to user space. See setrocket.c where the info is used to create
1386 * the /dev/ttyRx ports.
1387 */
1388static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1389{
1390 struct rocket_ports tmp;
1391 int board;
1392
1393 if (!retports)
1394 return -EFAULT;
1395 memset(&tmp, 0, sizeof (tmp));
1396 tmp.tty_major = rocket_driver->major;
1397
1398 for (board = 0; board < 4; board++) {
1399 tmp.rocketModel[board].model = rocketModel[board].model;
1400 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1401 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1402 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1403 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1404 }
1405 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1406 return -EFAULT;
1407 return 0;
1408}
1409
1410static int reset_rm2(struct r_port *info, void __user *arg)
1411{
1412 int reset;
1413
Alan Cox4129a6452008-02-08 04:18:45 -08001414 if (!capable(CAP_SYS_ADMIN))
1415 return -EPERM;
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 if (copy_from_user(&reset, arg, sizeof (int)))
1418 return -EFAULT;
1419 if (reset)
1420 reset = 1;
1421
1422 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1423 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1424 return -EINVAL;
1425
1426 if (info->ctlp->BusType == isISA)
1427 sModemReset(info->ctlp, info->chan, reset);
1428 else
1429 sPCIModemReset(info->ctlp, info->chan, reset);
1430
1431 return 0;
1432}
1433
1434static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1435{
1436 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1437 return -EFAULT;
1438 return 0;
1439}
1440
1441/* IOCTL call handler into the driver */
1442static int rp_ioctl(struct tty_struct *tty, struct file *file,
1443 unsigned int cmd, unsigned long arg)
1444{
1445 struct r_port *info = (struct r_port *) tty->driver_data;
1446 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001447 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1450 return -ENXIO;
1451
Alan Coxbdf183a2008-04-30 00:53:21 -07001452 lock_kernel();
1453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 switch (cmd) {
1455 case RCKP_GET_STRUCT:
1456 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001457 ret = -EFAULT;
1458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001460 ret = get_config(info, argp);
1461 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 case RCKP_SET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001463 ret = set_config(info, argp);
1464 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001466 ret = get_ports(info, argp);
1467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001469 ret = reset_rm2(info, argp);
1470 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001472 ret = get_version(info, argp);
1473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001475 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001477 unlock_kernel();
1478 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479}
1480
1481static void rp_send_xchar(struct tty_struct *tty, char ch)
1482{
1483 struct r_port *info = (struct r_port *) tty->driver_data;
1484 CHANNEL_t *cp;
1485
1486 if (rocket_paranoia_check(info, "rp_send_xchar"))
1487 return;
1488
1489 cp = &info->channel;
1490 if (sGetTxCnt(cp))
1491 sWriteTxPrioByte(cp, ch);
1492 else
1493 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1494}
1495
1496static void rp_throttle(struct tty_struct *tty)
1497{
1498 struct r_port *info = (struct r_port *) tty->driver_data;
1499 CHANNEL_t *cp;
1500
1501#ifdef ROCKET_DEBUG_THROTTLE
1502 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1503 tty->ldisc.chars_in_buffer(tty));
1504#endif
1505
1506 if (rocket_paranoia_check(info, "rp_throttle"))
1507 return;
1508
1509 cp = &info->channel;
1510 if (I_IXOFF(tty))
1511 rp_send_xchar(tty, STOP_CHAR(tty));
1512
1513 sClrRTS(&info->channel);
1514}
1515
1516static void rp_unthrottle(struct tty_struct *tty)
1517{
1518 struct r_port *info = (struct r_port *) tty->driver_data;
1519 CHANNEL_t *cp;
1520#ifdef ROCKET_DEBUG_THROTTLE
1521 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1522 tty->ldisc.chars_in_buffer(tty));
1523#endif
1524
1525 if (rocket_paranoia_check(info, "rp_throttle"))
1526 return;
1527
1528 cp = &info->channel;
1529 if (I_IXOFF(tty))
1530 rp_send_xchar(tty, START_CHAR(tty));
1531
1532 sSetRTS(&info->channel);
1533}
1534
1535/*
1536 * ------------------------------------------------------------
1537 * rp_stop() and rp_start()
1538 *
1539 * This routines are called before setting or resetting tty->stopped.
1540 * They enable or disable transmitter interrupts, as necessary.
1541 * ------------------------------------------------------------
1542 */
1543static void rp_stop(struct tty_struct *tty)
1544{
1545 struct r_port *info = (struct r_port *) tty->driver_data;
1546
1547#ifdef ROCKET_DEBUG_FLOW
1548 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1549 info->xmit_cnt, info->xmit_fifo_room);
1550#endif
1551
1552 if (rocket_paranoia_check(info, "rp_stop"))
1553 return;
1554
1555 if (sGetTxCnt(&info->channel))
1556 sDisTransmit(&info->channel);
1557}
1558
1559static void rp_start(struct tty_struct *tty)
1560{
1561 struct r_port *info = (struct r_port *) tty->driver_data;
1562
1563#ifdef ROCKET_DEBUG_FLOW
1564 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1565 info->xmit_cnt, info->xmit_fifo_room);
1566#endif
1567
1568 if (rocket_paranoia_check(info, "rp_stop"))
1569 return;
1570
1571 sEnTransmit(&info->channel);
1572 set_bit((info->aiop * 8) + info->chan,
1573 (void *) &xmit_flags[info->board]);
1574}
1575
1576/*
1577 * rp_wait_until_sent() --- wait until the transmitter is empty
1578 */
1579static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1580{
1581 struct r_port *info = (struct r_port *) tty->driver_data;
1582 CHANNEL_t *cp;
1583 unsigned long orig_jiffies;
1584 int check_time, exit_time;
1585 int txcnt;
1586
1587 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1588 return;
1589
1590 cp = &info->channel;
1591
1592 orig_jiffies = jiffies;
1593#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001594 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001596 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597#endif
Alan Cox978e5952008-04-30 00:53:59 -07001598 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 while (1) {
1600 txcnt = sGetTxCnt(cp);
1601 if (!txcnt) {
1602 if (sGetChanStatusLo(cp) & TXSHRMT)
1603 break;
1604 check_time = (HZ / info->cps) / 5;
1605 } else {
1606 check_time = HZ * txcnt / info->cps;
1607 }
1608 if (timeout) {
1609 exit_time = orig_jiffies + timeout - jiffies;
1610 if (exit_time <= 0)
1611 break;
1612 if (exit_time < check_time)
1613 check_time = exit_time;
1614 }
1615 if (check_time == 0)
1616 check_time = 1;
1617#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001618 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1619 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620#endif
1621 msleep_interruptible(jiffies_to_msecs(check_time));
1622 if (signal_pending(current))
1623 break;
1624 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001625 __set_current_state(TASK_RUNNING);
Alan Cox978e5952008-04-30 00:53:59 -07001626 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1628 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1629#endif
1630}
1631
1632/*
1633 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1634 */
1635static void rp_hangup(struct tty_struct *tty)
1636{
1637 CHANNEL_t *cp;
1638 struct r_port *info = (struct r_port *) tty->driver_data;
1639
1640 if (rocket_paranoia_check(info, "rp_hangup"))
1641 return;
1642
1643#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001644 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645#endif
1646 rp_flush_buffer(tty);
1647 if (info->flags & ROCKET_CLOSING)
1648 return;
Alan Coxe60a1082008-07-16 21:56:18 +01001649 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 atomic_dec(&rp_num_ports_open);
1651 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1652
Alan Coxe60a1082008-07-16 21:56:18 +01001653 info->port.count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 info->flags &= ~ROCKET_NORMAL_ACTIVE;
Alan Coxe60a1082008-07-16 21:56:18 +01001655 info->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656
1657 cp = &info->channel;
1658 sDisRxFIFO(cp);
1659 sDisTransmit(cp);
1660 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1661 sDisCTSFlowCtl(cp);
1662 sDisTxSoftFlowCtl(cp);
1663 sClrTxXOFF(cp);
1664 info->flags &= ~ROCKET_INITIALIZED;
1665
Alan Coxe60a1082008-07-16 21:56:18 +01001666 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667}
1668
1669/*
1670 * Exception handler - write char routine. The RocketPort driver uses a
1671 * double-buffering strategy, with the twist that if the in-memory CPU
1672 * buffer is empty, and there's space in the transmit FIFO, the
1673 * writing routines will write directly to transmit FIFO.
1674 * Write buffer and counters protected by spinlocks
1675 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001676static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677{
1678 struct r_port *info = (struct r_port *) tty->driver_data;
1679 CHANNEL_t *cp;
1680 unsigned long flags;
1681
1682 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001685 /*
1686 * Grab the port write mutex, locking out other processes that try to
1687 * write to this port
1688 */
1689 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
1691#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001692 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693#endif
1694
1695 spin_lock_irqsave(&info->slock, flags);
1696 cp = &info->channel;
1697
1698 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1699 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1700
1701 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1702 info->xmit_buf[info->xmit_head++] = ch;
1703 info->xmit_head &= XMIT_BUF_SIZE - 1;
1704 info->xmit_cnt++;
1705 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1706 } else {
1707 sOutB(sGetTxRxDataIO(cp), ch);
1708 info->xmit_fifo_room--;
1709 }
1710 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001711 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001712 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713}
1714
1715/*
1716 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001717 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 * this port at the same time. This other process could be running on the other CPU
1719 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1720 * Spinlocks protect the info xmit members.
1721 */
1722static int rp_write(struct tty_struct *tty,
1723 const unsigned char *buf, int count)
1724{
1725 struct r_port *info = (struct r_port *) tty->driver_data;
1726 CHANNEL_t *cp;
1727 const unsigned char *b;
1728 int c, retval = 0;
1729 unsigned long flags;
1730
1731 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1732 return 0;
1733
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001734 if (mutex_lock_interruptible(&info->write_mtx))
1735 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001738 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739#endif
1740 cp = &info->channel;
1741
1742 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1743 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1744
1745 /*
1746 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1747 * into FIFO. Use the write queue for temp storage.
1748 */
1749 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1750 c = min(count, info->xmit_fifo_room);
1751 b = buf;
1752
1753 /* Push data into FIFO, 2 bytes at a time */
1754 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1755
1756 /* If there is a byte remaining, write it */
1757 if (c & 1)
1758 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1759
1760 retval += c;
1761 buf += c;
1762 count -= c;
1763
1764 spin_lock_irqsave(&info->slock, flags);
1765 info->xmit_fifo_room -= c;
1766 spin_unlock_irqrestore(&info->slock, flags);
1767 }
1768
1769 /* If count is zero, we wrote it all and are done */
1770 if (!count)
1771 goto end;
1772
1773 /* Write remaining data into the port's xmit_buf */
1774 while (1) {
Alan Coxe60a1082008-07-16 21:56:18 +01001775 if (!info->port.tty) /* Seemingly obligatory check... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001777 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1778 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 if (c <= 0)
1780 break;
1781
1782 b = buf;
1783 memcpy(info->xmit_buf + info->xmit_head, b, c);
1784
1785 spin_lock_irqsave(&info->slock, flags);
1786 info->xmit_head =
1787 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1788 info->xmit_cnt += c;
1789 spin_unlock_irqrestore(&info->slock, flags);
1790
1791 buf += c;
1792 count -= c;
1793 retval += c;
1794 }
1795
1796 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1797 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1798
1799end:
1800 if (info->xmit_cnt < WAKEUP_CHARS) {
1801 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802#ifdef ROCKETPORT_HAVE_POLL_WAIT
1803 wake_up_interruptible(&tty->poll_wait);
1804#endif
1805 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001806 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 return retval;
1808}
1809
1810/*
1811 * Return the number of characters that can be sent. We estimate
1812 * only using the in-memory transmit buffer only, and ignore the
1813 * potential space in the transmit FIFO.
1814 */
1815static int rp_write_room(struct tty_struct *tty)
1816{
1817 struct r_port *info = (struct r_port *) tty->driver_data;
1818 int ret;
1819
1820 if (rocket_paranoia_check(info, "rp_write_room"))
1821 return 0;
1822
1823 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1824 if (ret < 0)
1825 ret = 0;
1826#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001827 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828#endif
1829 return ret;
1830}
1831
1832/*
1833 * Return the number of characters in the buffer. Again, this only
1834 * counts those characters in the in-memory transmit buffer.
1835 */
1836static int rp_chars_in_buffer(struct tty_struct *tty)
1837{
1838 struct r_port *info = (struct r_port *) tty->driver_data;
1839 CHANNEL_t *cp;
1840
1841 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1842 return 0;
1843
1844 cp = &info->channel;
1845
1846#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001847 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848#endif
1849 return info->xmit_cnt;
1850}
1851
1852/*
1853 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1854 * r_port struct for the port. Note that spinlock are used to protect info members,
1855 * do not call this function if the spinlock is already held.
1856 */
1857static void rp_flush_buffer(struct tty_struct *tty)
1858{
1859 struct r_port *info = (struct r_port *) tty->driver_data;
1860 CHANNEL_t *cp;
1861 unsigned long flags;
1862
1863 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1864 return;
1865
1866 spin_lock_irqsave(&info->slock, flags);
1867 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1868 spin_unlock_irqrestore(&info->slock, flags);
1869
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870#ifdef ROCKETPORT_HAVE_POLL_WAIT
1871 wake_up_interruptible(&tty->poll_wait);
1872#endif
1873 tty_wakeup(tty);
1874
1875 cp = &info->channel;
1876 sFlushTxFIFO(cp);
1877}
1878
1879#ifdef CONFIG_PCI
1880
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001881static struct pci_device_id __devinitdata rocket_pci_ids[] = {
1882 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
1883 { }
1884};
1885MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1886
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887/*
1888 * Called when a PCI card is found. Retrieves and stores model information,
1889 * init's aiopic and serial port hardware.
1890 * Inputs: i is the board number (0-n)
1891 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001892static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893{
1894 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1895 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1896 char *str, *board_type;
1897 CONTROLLER_t *ctlp;
1898
1899 int fast_clock = 0;
1900 int altChanRingIndicator = 0;
1901 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 WordIO_t ConfigIO = 0;
1903 ByteIO_t UPCIRingInd = 0;
1904
1905 if (!dev || pci_enable_device(dev))
1906 return 0;
1907
1908 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1911 rocketModel[i].loadrm2 = 0;
1912 rocketModel[i].startingPortNumber = nextLineNumber;
1913
1914 /* Depending on the model, set up some config variables */
1915 switch (dev->device) {
1916 case PCI_DEVICE_ID_RP4QUAD:
1917 str = "Quadcable";
1918 max_num_aiops = 1;
1919 ports_per_aiop = 4;
1920 rocketModel[i].model = MODEL_RP4QUAD;
1921 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1922 rocketModel[i].numPorts = 4;
1923 break;
1924 case PCI_DEVICE_ID_RP8OCTA:
1925 str = "Octacable";
1926 max_num_aiops = 1;
1927 rocketModel[i].model = MODEL_RP8OCTA;
1928 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1929 rocketModel[i].numPorts = 8;
1930 break;
1931 case PCI_DEVICE_ID_URP8OCTA:
1932 str = "Octacable";
1933 max_num_aiops = 1;
1934 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1935 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1936 rocketModel[i].numPorts = 8;
1937 break;
1938 case PCI_DEVICE_ID_RP8INTF:
1939 str = "8";
1940 max_num_aiops = 1;
1941 rocketModel[i].model = MODEL_RP8INTF;
1942 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1943 rocketModel[i].numPorts = 8;
1944 break;
1945 case PCI_DEVICE_ID_URP8INTF:
1946 str = "8";
1947 max_num_aiops = 1;
1948 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1949 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1950 rocketModel[i].numPorts = 8;
1951 break;
1952 case PCI_DEVICE_ID_RP8J:
1953 str = "8J";
1954 max_num_aiops = 1;
1955 rocketModel[i].model = MODEL_RP8J;
1956 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1957 rocketModel[i].numPorts = 8;
1958 break;
1959 case PCI_DEVICE_ID_RP4J:
1960 str = "4J";
1961 max_num_aiops = 1;
1962 ports_per_aiop = 4;
1963 rocketModel[i].model = MODEL_RP4J;
1964 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1965 rocketModel[i].numPorts = 4;
1966 break;
1967 case PCI_DEVICE_ID_RP8SNI:
1968 str = "8 (DB78 Custom)";
1969 max_num_aiops = 1;
1970 rocketModel[i].model = MODEL_RP8SNI;
1971 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1972 rocketModel[i].numPorts = 8;
1973 break;
1974 case PCI_DEVICE_ID_RP16SNI:
1975 str = "16 (DB78 Custom)";
1976 max_num_aiops = 2;
1977 rocketModel[i].model = MODEL_RP16SNI;
1978 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1979 rocketModel[i].numPorts = 16;
1980 break;
1981 case PCI_DEVICE_ID_RP16INTF:
1982 str = "16";
1983 max_num_aiops = 2;
1984 rocketModel[i].model = MODEL_RP16INTF;
1985 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1986 rocketModel[i].numPorts = 16;
1987 break;
1988 case PCI_DEVICE_ID_URP16INTF:
1989 str = "16";
1990 max_num_aiops = 2;
1991 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1992 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1993 rocketModel[i].numPorts = 16;
1994 break;
1995 case PCI_DEVICE_ID_CRP16INTF:
1996 str = "16";
1997 max_num_aiops = 2;
1998 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1999 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
2000 rocketModel[i].numPorts = 16;
2001 break;
2002 case PCI_DEVICE_ID_RP32INTF:
2003 str = "32";
2004 max_num_aiops = 4;
2005 rocketModel[i].model = MODEL_RP32INTF;
2006 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
2007 rocketModel[i].numPorts = 32;
2008 break;
2009 case PCI_DEVICE_ID_URP32INTF:
2010 str = "32";
2011 max_num_aiops = 4;
2012 rocketModel[i].model = MODEL_UPCI_RP32INTF;
2013 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
2014 rocketModel[i].numPorts = 32;
2015 break;
2016 case PCI_DEVICE_ID_RPP4:
2017 str = "Plus Quadcable";
2018 max_num_aiops = 1;
2019 ports_per_aiop = 4;
2020 altChanRingIndicator++;
2021 fast_clock++;
2022 rocketModel[i].model = MODEL_RPP4;
2023 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
2024 rocketModel[i].numPorts = 4;
2025 break;
2026 case PCI_DEVICE_ID_RPP8:
2027 str = "Plus Octacable";
2028 max_num_aiops = 2;
2029 ports_per_aiop = 4;
2030 altChanRingIndicator++;
2031 fast_clock++;
2032 rocketModel[i].model = MODEL_RPP8;
2033 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
2034 rocketModel[i].numPorts = 8;
2035 break;
2036 case PCI_DEVICE_ID_RP2_232:
2037 str = "Plus 2 (RS-232)";
2038 max_num_aiops = 1;
2039 ports_per_aiop = 2;
2040 altChanRingIndicator++;
2041 fast_clock++;
2042 rocketModel[i].model = MODEL_RP2_232;
2043 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
2044 rocketModel[i].numPorts = 2;
2045 break;
2046 case PCI_DEVICE_ID_RP2_422:
2047 str = "Plus 2 (RS-422)";
2048 max_num_aiops = 1;
2049 ports_per_aiop = 2;
2050 altChanRingIndicator++;
2051 fast_clock++;
2052 rocketModel[i].model = MODEL_RP2_422;
2053 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
2054 rocketModel[i].numPorts = 2;
2055 break;
2056 case PCI_DEVICE_ID_RP6M:
2057
2058 max_num_aiops = 1;
2059 ports_per_aiop = 6;
2060 str = "6-port";
2061
Jiri Slaby57fedc72007-10-18 03:06:28 -07002062 /* If revision is 1, the rocketmodem flash must be loaded.
2063 * If it is 2 it is a "socketed" version. */
2064 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2066 rocketModel[i].loadrm2 = 1;
2067 } else {
2068 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2069 }
2070
2071 rocketModel[i].model = MODEL_RP6M;
2072 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
2073 rocketModel[i].numPorts = 6;
2074 break;
2075 case PCI_DEVICE_ID_RP4M:
2076 max_num_aiops = 1;
2077 ports_per_aiop = 4;
2078 str = "4-port";
Jiri Slaby57fedc72007-10-18 03:06:28 -07002079 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2081 rocketModel[i].loadrm2 = 1;
2082 } else {
2083 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2084 }
2085
2086 rocketModel[i].model = MODEL_RP4M;
2087 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
2088 rocketModel[i].numPorts = 4;
2089 break;
2090 default:
2091 str = "(unknown/unsupported)";
2092 max_num_aiops = 0;
2093 break;
2094 }
2095
2096 /*
2097 * Check for UPCI boards.
2098 */
2099
2100 switch (dev->device) {
2101 case PCI_DEVICE_ID_URP32INTF:
2102 case PCI_DEVICE_ID_URP8INTF:
2103 case PCI_DEVICE_ID_URP16INTF:
2104 case PCI_DEVICE_ID_CRP16INTF:
2105 case PCI_DEVICE_ID_URP8OCTA:
2106 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2107 ConfigIO = pci_resource_start(dev, 1);
2108 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
2109 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2110
2111 /*
2112 * Check for octa or quad cable.
2113 */
2114 if (!
2115 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
2116 PCI_GPIO_CTRL_8PORT)) {
2117 str = "Quadcable";
2118 ports_per_aiop = 4;
2119 rocketModel[i].numPorts = 4;
2120 }
2121 }
2122 break;
2123 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
2124 str = "8 ports";
2125 max_num_aiops = 1;
2126 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
2127 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
2128 rocketModel[i].numPorts = 8;
2129 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2130 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2131 ConfigIO = pci_resource_start(dev, 1);
2132 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2133 break;
2134 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
2135 str = "4 ports";
2136 max_num_aiops = 1;
2137 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2138 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2139 rocketModel[i].numPorts = 4;
2140 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2141 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2142 ConfigIO = pci_resource_start(dev, 1);
2143 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2144 break;
2145 default:
2146 break;
2147 }
2148
2149 switch (rcktpt_type[i]) {
2150 case ROCKET_TYPE_MODEM:
2151 board_type = "RocketModem";
2152 break;
2153 case ROCKET_TYPE_MODEMII:
2154 board_type = "RocketModem II";
2155 break;
2156 case ROCKET_TYPE_MODEMIII:
2157 board_type = "RocketModem III";
2158 break;
2159 default:
2160 board_type = "RocketPort";
2161 break;
2162 }
2163
2164 if (fast_clock) {
2165 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2166 rp_baud_base[i] = 921600;
2167 } else {
2168 /*
2169 * If support_low_speed is set, use the slow clock
2170 * prescale, which supports 50 bps
2171 */
2172 if (support_low_speed) {
2173 /* mod 9 (divide by 10) prescale */
2174 sClockPrescale = 0x19;
2175 rp_baud_base[i] = 230400;
2176 } else {
2177 /* mod 4 (devide by 5) prescale */
2178 sClockPrescale = 0x14;
2179 rp_baud_base[i] = 460800;
2180 }
2181 }
2182
2183 for (aiop = 0; aiop < max_num_aiops; aiop++)
2184 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2185 ctlp = sCtlNumToCtlPtr(i);
2186 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2187 for (aiop = 0; aiop < max_num_aiops; aiop++)
2188 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2189
Jiri Slaby68562b72008-02-07 00:16:33 -08002190 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2191 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2192 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2193 rocketModel[i].startingPortNumber,
2194 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196 if (num_aiops <= 0) {
2197 rcktpt_io_addr[i] = 0;
2198 return (0);
2199 }
2200 is_PCI[i] = 1;
2201
2202 /* Reset the AIOPIC, init the serial ports */
2203 for (aiop = 0; aiop < num_aiops; aiop++) {
2204 sResetAiopByNum(ctlp, aiop);
2205 num_chan = ports_per_aiop;
2206 for (chan = 0; chan < num_chan; chan++)
2207 init_r_port(i, aiop, chan, dev);
2208 }
2209
2210 /* Rocket modems must be reset */
2211 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2212 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2213 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2214 num_chan = ports_per_aiop;
2215 for (chan = 0; chan < num_chan; chan++)
2216 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002217 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 for (chan = 0; chan < num_chan; chan++)
2219 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002220 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 rmSpeakerReset(ctlp, rocketModel[i].model);
2222 }
2223 return (1);
2224}
2225
2226/*
2227 * Probes for PCI cards, inits them if found
2228 * Input: board_found = number of ISA boards already found, or the
2229 * starting board number
2230 * Returns: Number of PCI boards found
2231 */
2232static int __init init_PCI(int boards_found)
2233{
2234 struct pci_dev *dev = NULL;
2235 int count = 0;
2236
2237 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002238 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 if (register_PCI(count + boards_found, dev))
2240 count++;
2241 }
2242 return (count);
2243}
2244
2245#endif /* CONFIG_PCI */
2246
2247/*
2248 * Probes for ISA cards
2249 * Input: i = the board number to look for
2250 * Returns: 1 if board found, 0 else
2251 */
2252static int __init init_ISA(int i)
2253{
2254 int num_aiops, num_chan = 0, total_num_chan = 0;
2255 int aiop, chan;
2256 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2257 CONTROLLER_t *ctlp;
2258 char *type_string;
2259
2260 /* If io_addr is zero, no board configured */
2261 if (rcktpt_io_addr[i] == 0)
2262 return (0);
2263
2264 /* Reserve the IO region */
2265 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002266 printk(KERN_ERR "Unable to reserve IO region for configured "
2267 "ISA RocketPort at address 0x%lx, board not "
2268 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 rcktpt_io_addr[i] = 0;
2270 return (0);
2271 }
2272
2273 ctlp = sCtlNumToCtlPtr(i);
2274
2275 ctlp->boardType = rcktpt_type[i];
2276
2277 switch (rcktpt_type[i]) {
2278 case ROCKET_TYPE_PC104:
2279 type_string = "(PC104)";
2280 break;
2281 case ROCKET_TYPE_MODEM:
2282 type_string = "(RocketModem)";
2283 break;
2284 case ROCKET_TYPE_MODEMII:
2285 type_string = "(RocketModem II)";
2286 break;
2287 default:
2288 type_string = "";
2289 break;
2290 }
2291
2292 /*
2293 * If support_low_speed is set, use the slow clock prescale,
2294 * which supports 50 bps
2295 */
2296 if (support_low_speed) {
2297 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2298 rp_baud_base[i] = 230400;
2299 } else {
2300 sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */
2301 rp_baud_base[i] = 460800;
2302 }
2303
2304 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2305 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2306
2307 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2308
2309 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2310 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2311 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2312 }
2313
2314 /* If something went wrong initing the AIOP's release the ISA IO memory */
2315 if (num_aiops <= 0) {
2316 release_region(rcktpt_io_addr[i], 64);
2317 rcktpt_io_addr[i] = 0;
2318 return (0);
2319 }
2320
2321 rocketModel[i].startingPortNumber = nextLineNumber;
2322
2323 for (aiop = 0; aiop < num_aiops; aiop++) {
2324 sResetAiopByNum(ctlp, aiop);
2325 sEnAiop(ctlp, aiop);
2326 num_chan = sGetAiopNumChan(ctlp, aiop);
2327 total_num_chan += num_chan;
2328 for (chan = 0; chan < num_chan; chan++)
2329 init_r_port(i, aiop, chan, NULL);
2330 }
2331 is_PCI[i] = 0;
2332 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2333 num_chan = sGetAiopNumChan(ctlp, 0);
2334 total_num_chan = num_chan;
2335 for (chan = 0; chan < num_chan; chan++)
2336 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002337 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 for (chan = 0; chan < num_chan; chan++)
2339 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002340 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2342 } else {
2343 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2344 }
2345 rocketModel[i].numPorts = total_num_chan;
2346 rocketModel[i].model = MODEL_ISA;
2347
2348 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2349 i, rcktpt_io_addr[i], num_aiops, type_string);
2350
2351 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2352 rocketModel[i].modelString,
2353 rocketModel[i].startingPortNumber,
2354 rocketModel[i].startingPortNumber +
2355 rocketModel[i].numPorts - 1);
2356
2357 return (1);
2358}
2359
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002360static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 .open = rp_open,
2362 .close = rp_close,
2363 .write = rp_write,
2364 .put_char = rp_put_char,
2365 .write_room = rp_write_room,
2366 .chars_in_buffer = rp_chars_in_buffer,
2367 .flush_buffer = rp_flush_buffer,
2368 .ioctl = rp_ioctl,
2369 .throttle = rp_throttle,
2370 .unthrottle = rp_unthrottle,
2371 .set_termios = rp_set_termios,
2372 .stop = rp_stop,
2373 .start = rp_start,
2374 .hangup = rp_hangup,
2375 .break_ctl = rp_break,
2376 .send_xchar = rp_send_xchar,
2377 .wait_until_sent = rp_wait_until_sent,
2378 .tiocmget = rp_tiocmget,
2379 .tiocmset = rp_tiocmset,
2380};
2381
Alan Cox31f35932009-01-02 13:45:05 +00002382static const struct tty_port_operations rocket_port_ops = {
2383 .carrier_raised = carrier_raised,
2384};
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386/*
2387 * The module "startup" routine; it's run when the module is loaded.
2388 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002389static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002391 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
2393 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2394 ROCKET_VERSION, ROCKET_DATE);
2395
2396 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2397 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002398 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
2400 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2402 * zero, use the default controller IO address of board1 + 0x40.
2403 */
2404 if (board1) {
2405 if (controller == 0)
2406 controller = board1 + 0x40;
2407 } else {
2408 controller = 0; /* Used as a flag, meaning no ISA boards */
2409 }
2410
2411 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2412 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002413 printk(KERN_ERR "Unable to reserve IO region for first "
2414 "configured ISA RocketPort controller 0x%lx. "
2415 "Driver exiting\n", controller);
2416 ret = -EBUSY;
2417 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
2419
2420 /* Store ISA variable retrieved from command line or .conf file. */
2421 rcktpt_io_addr[0] = board1;
2422 rcktpt_io_addr[1] = board2;
2423 rcktpt_io_addr[2] = board3;
2424 rcktpt_io_addr[3] = board4;
2425
2426 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2427 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2428 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2429 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2430 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2431 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2432 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2433 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2434
2435 /*
2436 * Set up the tty driver structure and then register this
2437 * driver with the tty layer.
2438 */
2439
2440 rocket_driver->owner = THIS_MODULE;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002441 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 rocket_driver->name = "ttyR";
2443 rocket_driver->driver_name = "Comtrol RocketPort";
2444 rocket_driver->major = TTY_ROCKET_MAJOR;
2445 rocket_driver->minor_start = 0;
2446 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2447 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2448 rocket_driver->init_termios = tty_std_termios;
2449 rocket_driver->init_termios.c_cflag =
2450 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002451 rocket_driver->init_termios.c_ispeed = 9600;
2452 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002454 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455#endif
2456 tty_set_operations(rocket_driver, &rocket_ops);
2457
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002458 ret = tty_register_driver(rocket_driver);
2459 if (ret < 0) {
2460 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
2461 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 }
2463
2464#ifdef ROCKET_DEBUG_OPEN
2465 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2466#endif
2467
2468 /*
2469 * OK, let's probe each of the controllers looking for boards. Any boards found
2470 * will be initialized here.
2471 */
2472 isa_boards_found = 0;
2473 pci_boards_found = 0;
2474
2475 for (i = 0; i < NUM_BOARDS; i++) {
2476 if (init_ISA(i))
2477 isa_boards_found++;
2478 }
2479
2480#ifdef CONFIG_PCI
2481 if (isa_boards_found < NUM_BOARDS)
2482 pci_boards_found = init_PCI(isa_boards_found);
2483#endif
2484
2485 max_board = pci_boards_found + isa_boards_found;
2486
2487 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002488 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2489 ret = -ENXIO;
2490 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
2492
2493 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002494err_ttyu:
2495 tty_unregister_driver(rocket_driver);
2496err_tty:
2497 put_tty_driver(rocket_driver);
2498err:
2499 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500}
2501
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
2503static void rp_cleanup_module(void)
2504{
2505 int retval;
2506 int i;
2507
2508 del_timer_sync(&rocket_timer);
2509
2510 retval = tty_unregister_driver(rocket_driver);
2511 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002512 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
Jesper Juhl735d5662005-11-07 01:01:29 -08002515 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002516 if (rp_table[i]) {
2517 tty_unregister_device(rocket_driver, i);
2518 kfree(rp_table[i]);
2519 }
2520
2521 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 for (i = 0; i < NUM_BOARDS; i++) {
2524 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2525 continue;
2526 release_region(rcktpt_io_addr[i], 64);
2527 }
2528 if (controller)
2529 release_region(controller, 4);
2530}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532/***************************************************************************
2533Function: sInitController
2534Purpose: Initialization of controller global registers and controller
2535 structure.
2536Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2537 IRQNum,Frequency,PeriodicOnly)
2538 CONTROLLER_T *CtlP; Ptr to controller structure
2539 int CtlNum; Controller number
2540 ByteIO_t MudbacIO; Mudbac base I/O address.
2541 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2542 This list must be in the order the AIOPs will be found on the
2543 controller. Once an AIOP in the list is not found, it is
2544 assumed that there are no more AIOPs on the controller.
2545 int AiopIOListSize; Number of addresses in AiopIOList
2546 int IRQNum; Interrupt Request number. Can be any of the following:
2547 0: Disable global interrupts
2548 3: IRQ 3
2549 4: IRQ 4
2550 5: IRQ 5
2551 9: IRQ 9
2552 10: IRQ 10
2553 11: IRQ 11
2554 12: IRQ 12
2555 15: IRQ 15
2556 Byte_t Frequency: A flag identifying the frequency
2557 of the periodic interrupt, can be any one of the following:
2558 FREQ_DIS - periodic interrupt disabled
2559 FREQ_137HZ - 137 Hertz
2560 FREQ_69HZ - 69 Hertz
2561 FREQ_34HZ - 34 Hertz
2562 FREQ_17HZ - 17 Hertz
2563 FREQ_9HZ - 9 Hertz
2564 FREQ_4HZ - 4 Hertz
2565 If IRQNum is set to 0 the Frequency parameter is
2566 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002567 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002569 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 other channel interrupts are allowed.
2571 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002572 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2574 initialization failed.
2575
2576Comments:
2577 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002578 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 If interrupts are to be completely disabled set IRQNum to 0.
2581
Adrian Bunkf15313b2005-06-25 14:59:05 -07002582 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 invalid combination.
2584
2585 This function performs initialization of global interrupt modes,
2586 but it does not actually enable global interrupts. To enable
2587 and disable global interrupts use functions sEnGlobalInt() and
2588 sDisGlobalInt(). Enabling of global interrupts is normally not
2589 done until all other initializations are complete.
2590
2591 Even if interrupts are globally enabled, they must also be
2592 individually enabled for each channel that is to generate
2593 interrupts.
2594
2595Warnings: No range checking on any of the parameters is done.
2596
2597 No context switches are allowed while executing this function.
2598
2599 After this function all AIOPs on the controller are disabled,
2600 they can be enabled with sEnAiop().
2601*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002602static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2603 ByteIO_t * AiopIOList, int AiopIOListSize,
2604 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605{
2606 int i;
2607 ByteIO_t io;
2608 int done;
2609
2610 CtlP->AiopIntrBits = aiop_intr_bits;
2611 CtlP->AltChanRingIndicator = 0;
2612 CtlP->CtlNum = CtlNum;
2613 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2614 CtlP->BusType = isISA;
2615 CtlP->MBaseIO = MudbacIO;
2616 CtlP->MReg1IO = MudbacIO + 1;
2617 CtlP->MReg2IO = MudbacIO + 2;
2618 CtlP->MReg3IO = MudbacIO + 3;
2619#if 1
2620 CtlP->MReg2 = 0; /* interrupt disable */
2621 CtlP->MReg3 = 0; /* no periodic interrupts */
2622#else
2623 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2624 CtlP->MReg2 = 0; /* interrupt disable */
2625 CtlP->MReg3 = 0; /* no periodic interrupts */
2626 } else {
2627 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2628 CtlP->MReg3 = Frequency; /* set frequency */
2629 if (PeriodicOnly) { /* periodic interrupt only */
2630 CtlP->MReg3 |= PERIODIC_ONLY;
2631 }
2632 }
2633#endif
2634 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2635 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2636 sControllerEOI(CtlP); /* clear EOI if warm init */
2637 /* Init AIOPs */
2638 CtlP->NumAiop = 0;
2639 for (i = done = 0; i < AiopIOListSize; i++) {
2640 io = AiopIOList[i];
2641 CtlP->AiopIO[i] = (WordIO_t) io;
2642 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2643 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2644 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2645 if (done)
2646 continue;
2647 sEnAiop(CtlP, i); /* enable the AIOP */
2648 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2649 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2650 done = 1; /* done looking for AIOPs */
2651 else {
2652 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2653 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2654 sOutB(io + _INDX_DATA, sClockPrescale);
2655 CtlP->NumAiop++; /* bump count of AIOPs */
2656 }
2657 sDisAiop(CtlP, i); /* disable AIOP */
2658 }
2659
2660 if (CtlP->NumAiop == 0)
2661 return (-1);
2662 else
2663 return (CtlP->NumAiop);
2664}
2665
2666/***************************************************************************
2667Function: sPCIInitController
2668Purpose: Initialization of controller global registers and controller
2669 structure.
2670Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2671 IRQNum,Frequency,PeriodicOnly)
2672 CONTROLLER_T *CtlP; Ptr to controller structure
2673 int CtlNum; Controller number
2674 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2675 This list must be in the order the AIOPs will be found on the
2676 controller. Once an AIOP in the list is not found, it is
2677 assumed that there are no more AIOPs on the controller.
2678 int AiopIOListSize; Number of addresses in AiopIOList
2679 int IRQNum; Interrupt Request number. Can be any of the following:
2680 0: Disable global interrupts
2681 3: IRQ 3
2682 4: IRQ 4
2683 5: IRQ 5
2684 9: IRQ 9
2685 10: IRQ 10
2686 11: IRQ 11
2687 12: IRQ 12
2688 15: IRQ 15
2689 Byte_t Frequency: A flag identifying the frequency
2690 of the periodic interrupt, can be any one of the following:
2691 FREQ_DIS - periodic interrupt disabled
2692 FREQ_137HZ - 137 Hertz
2693 FREQ_69HZ - 69 Hertz
2694 FREQ_34HZ - 34 Hertz
2695 FREQ_17HZ - 17 Hertz
2696 FREQ_9HZ - 9 Hertz
2697 FREQ_4HZ - 4 Hertz
2698 If IRQNum is set to 0 the Frequency parameter is
2699 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002700 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002702 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 other channel interrupts are allowed.
2704 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002705 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2707 initialization failed.
2708
2709Comments:
2710 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002711 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712
2713 If interrupts are to be completely disabled set IRQNum to 0.
2714
Adrian Bunkf15313b2005-06-25 14:59:05 -07002715 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 invalid combination.
2717
2718 This function performs initialization of global interrupt modes,
2719 but it does not actually enable global interrupts. To enable
2720 and disable global interrupts use functions sEnGlobalInt() and
2721 sDisGlobalInt(). Enabling of global interrupts is normally not
2722 done until all other initializations are complete.
2723
2724 Even if interrupts are globally enabled, they must also be
2725 individually enabled for each channel that is to generate
2726 interrupts.
2727
2728Warnings: No range checking on any of the parameters is done.
2729
2730 No context switches are allowed while executing this function.
2731
2732 After this function all AIOPs on the controller are disabled,
2733 they can be enabled with sEnAiop().
2734*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002735static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2736 ByteIO_t * AiopIOList, int AiopIOListSize,
2737 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2738 int PeriodicOnly, int altChanRingIndicator,
2739 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740{
2741 int i;
2742 ByteIO_t io;
2743
2744 CtlP->AltChanRingIndicator = altChanRingIndicator;
2745 CtlP->UPCIRingInd = UPCIRingInd;
2746 CtlP->CtlNum = CtlNum;
2747 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2748 CtlP->BusType = isPCI; /* controller release 1 */
2749
2750 if (ConfigIO) {
2751 CtlP->isUPCI = 1;
2752 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2753 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2754 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2755 } else {
2756 CtlP->isUPCI = 0;
2757 CtlP->PCIIO =
2758 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2759 CtlP->AiopIntrBits = aiop_intr_bits;
2760 }
2761
2762 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2763 /* Init AIOPs */
2764 CtlP->NumAiop = 0;
2765 for (i = 0; i < AiopIOListSize; i++) {
2766 io = AiopIOList[i];
2767 CtlP->AiopIO[i] = (WordIO_t) io;
2768 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2769
2770 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2771 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2772 break; /* done looking for AIOPs */
2773
2774 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2775 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2776 sOutB(io + _INDX_DATA, sClockPrescale);
2777 CtlP->NumAiop++; /* bump count of AIOPs */
2778 }
2779
2780 if (CtlP->NumAiop == 0)
2781 return (-1);
2782 else
2783 return (CtlP->NumAiop);
2784}
2785
2786/***************************************************************************
2787Function: sReadAiopID
2788Purpose: Read the AIOP idenfication number directly from an AIOP.
2789Call: sReadAiopID(io)
2790 ByteIO_t io: AIOP base I/O address
2791Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2792 is replace by an identifying number.
2793 Flag AIOPID_NULL if no valid AIOP is found
2794Warnings: No context switches are allowed while executing this function.
2795
2796*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002797static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798{
2799 Byte_t AiopID; /* ID byte from AIOP */
2800
2801 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2802 sOutB(io + _CMD_REG, 0x0);
2803 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2804 if (AiopID == 0x06)
2805 return (1);
2806 else /* AIOP does not exist */
2807 return (-1);
2808}
2809
2810/***************************************************************************
2811Function: sReadAiopNumChan
2812Purpose: Read the number of channels available in an AIOP directly from
2813 an AIOP.
2814Call: sReadAiopNumChan(io)
2815 WordIO_t io: AIOP base I/O address
2816Return: int: The number of channels available
2817Comments: The number of channels is determined by write/reads from identical
2818 offsets within the SRAM address spaces for channels 0 and 4.
2819 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2820 AIOP, otherwise it is an 8 channel.
2821Warnings: No context switches are allowed while executing this function.
2822*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002823static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824{
2825 Word_t x;
2826 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2827
2828 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002829 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2831 x = sInW(io + _INDX_DATA);
2832 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2833 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2834 return (8);
2835 else
2836 return (4);
2837}
2838
2839/***************************************************************************
2840Function: sInitChan
2841Purpose: Initialization of a channel and channel structure
2842Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2843 CONTROLLER_T *CtlP; Ptr to controller structure
2844 CHANNEL_T *ChP; Ptr to channel structure
2845 int AiopNum; AIOP number within controller
2846 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002847Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 number exceeds number of channels available in AIOP.
2849Comments: This function must be called before a channel can be used.
2850Warnings: No range checking on any of the parameters is done.
2851
2852 No context switches are allowed while executing this function.
2853*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002854static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2855 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856{
2857 int i;
2858 WordIO_t AiopIO;
2859 WordIO_t ChIOOff;
2860 Byte_t *ChR;
2861 Word_t ChOff;
2862 static Byte_t R[4];
2863 int brd9600;
2864
2865 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002866 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
2868 /* Channel, AIOP, and controller identifiers */
2869 ChP->CtlP = CtlP;
2870 ChP->ChanID = CtlP->AiopID[AiopNum];
2871 ChP->AiopNum = AiopNum;
2872 ChP->ChanNum = ChanNum;
2873
2874 /* Global direct addresses */
2875 AiopIO = CtlP->AiopIO[AiopNum];
2876 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2877 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2878 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2879 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2880 ChP->IndexData = AiopIO + _INDX_DATA;
2881
2882 /* Channel direct addresses */
2883 ChIOOff = AiopIO + ChP->ChanNum * 2;
2884 ChP->TxRxData = ChIOOff + _TD0;
2885 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2886 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2887 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2888
2889 /* Initialize the channel from the RData array */
2890 for (i = 0; i < RDATASIZE; i += 4) {
2891 R[0] = RData[i];
2892 R[1] = RData[i + 1] + 0x10 * ChanNum;
2893 R[2] = RData[i + 2];
2894 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002895 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 }
2897
2898 ChR = ChP->R;
2899 for (i = 0; i < RREGDATASIZE; i += 4) {
2900 ChR[i] = RRegData[i];
2901 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2902 ChR[i + 2] = RRegData[i + 2];
2903 ChR[i + 3] = RRegData[i + 3];
2904 }
2905
2906 /* Indexed registers */
2907 ChOff = (Word_t) ChanNum *0x1000;
2908
2909 if (sClockPrescale == 0x14)
2910 brd9600 = 47;
2911 else
2912 brd9600 = 23;
2913
2914 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2915 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2916 ChP->BaudDiv[2] = (Byte_t) brd9600;
2917 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002918 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2921 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2922 ChP->TxControl[2] = 0;
2923 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002924 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
2926 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2927 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2928 ChP->RxControl[2] = 0;
2929 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002930 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
2932 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2933 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2934 ChP->TxEnables[2] = 0;
2935 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002936 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
2938 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2939 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2940 ChP->TxCompare[2] = 0;
2941 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002942 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2945 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2946 ChP->TxReplace1[2] = 0;
2947 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002948 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2951 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2952 ChP->TxReplace2[2] = 0;
2953 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002954 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
2956 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2957 ChP->TxFIFO = ChOff + _TX_FIFO;
2958
2959 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2960 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2961 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2962 sOutW(ChP->IndexData, 0);
2963 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2964 ChP->RxFIFO = ChOff + _RX_FIFO;
2965
2966 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2967 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2968 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2969 sOutW(ChP->IndexData, 0);
2970 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2971 sOutW(ChP->IndexData, 0);
2972 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2973 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2974 sOutB(ChP->IndexData, 0);
2975 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2976 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2977 sOutB(ChP->IndexData, 0);
2978 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2979 sEnRxProcessor(ChP); /* start the Rx processor */
2980
Adrian Bunkf15313b2005-06-25 14:59:05 -07002981 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982}
2983
2984/***************************************************************************
2985Function: sStopRxProcessor
2986Purpose: Stop the receive processor from processing a channel.
2987Call: sStopRxProcessor(ChP)
2988 CHANNEL_T *ChP; Ptr to channel structure
2989
2990Comments: The receive processor can be started again with sStartRxProcessor().
2991 This function causes the receive processor to skip over the
2992 stopped channel. It does not stop it from processing other channels.
2993
2994Warnings: No context switches are allowed while executing this function.
2995
2996 Do not leave the receive processor stopped for more than one
2997 character time.
2998
2999 After calling this function a delay of 4 uS is required to ensure
3000 that the receive processor is no longer processing this channel.
3001*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003002static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003{
3004 Byte_t R[4];
3005
3006 R[0] = ChP->R[0];
3007 R[1] = ChP->R[1];
3008 R[2] = 0x0a;
3009 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00003010 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011}
3012
3013/***************************************************************************
3014Function: sFlushRxFIFO
3015Purpose: Flush the Rx FIFO
3016Call: sFlushRxFIFO(ChP)
3017 CHANNEL_T *ChP; Ptr to channel structure
3018Return: void
3019Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
3020 while it is being flushed the receive processor is stopped
3021 and the transmitter is disabled. After these operations a
3022 4 uS delay is done before clearing the pointers to allow
3023 the receive processor to stop. These items are handled inside
3024 this function.
3025Warnings: No context switches are allowed while executing this function.
3026*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003027static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028{
3029 int i;
3030 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003031 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032
3033 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
3034 return; /* don't need to flush */
3035
Adrian Bunkf15313b2005-06-25 14:59:05 -07003036 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003038 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 sDisRxFIFO(ChP); /* disable it */
3040 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
3041 sInB(ChP->IntChan); /* depends on bus i/o timing */
3042 }
3043 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
3044 Ch = (Byte_t) sGetChanNum(ChP);
3045 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
3046 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
3047 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
3048 sOutW(ChP->IndexData, 0);
3049 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
3050 sOutW(ChP->IndexData, 0);
3051 if (RxFIFOEnabled)
3052 sEnRxFIFO(ChP); /* enable Rx FIFO */
3053}
3054
3055/***************************************************************************
3056Function: sFlushTxFIFO
3057Purpose: Flush the Tx FIFO
3058Call: sFlushTxFIFO(ChP)
3059 CHANNEL_T *ChP; Ptr to channel structure
3060Return: void
3061Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
3062 while it is being flushed the receive processor is stopped
3063 and the transmitter is disabled. After these operations a
3064 4 uS delay is done before clearing the pointers to allow
3065 the receive processor to stop. These items are handled inside
3066 this function.
3067Warnings: No context switches are allowed while executing this function.
3068*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003069static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070{
3071 int i;
3072 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003073 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074
3075 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
3076 return; /* don't need to flush */
3077
Adrian Bunkf15313b2005-06-25 14:59:05 -07003078 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07003080 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 sDisTransmit(ChP); /* disable transmitter */
3082 }
3083 sStopRxProcessor(ChP); /* stop Rx processor */
3084 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
3085 sInB(ChP->IntChan); /* depends on bus i/o timing */
3086 Ch = (Byte_t) sGetChanNum(ChP);
3087 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
3088 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
3089 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
3090 sOutW(ChP->IndexData, 0);
3091 if (TxEnabled)
3092 sEnTransmit(ChP); /* enable transmitter */
3093 sStartRxProcessor(ChP); /* restart Rx processor */
3094}
3095
3096/***************************************************************************
3097Function: sWriteTxPrioByte
3098Purpose: Write a byte of priority transmit data to a channel
3099Call: sWriteTxPrioByte(ChP,Data)
3100 CHANNEL_T *ChP; Ptr to channel structure
3101 Byte_t Data; The transmit data byte
3102
3103Return: int: 1 if the bytes is successfully written, otherwise 0.
3104
3105Comments: The priority byte is transmitted before any data in the Tx FIFO.
3106
3107Warnings: No context switches are allowed while executing this function.
3108*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003109static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110{
3111 Byte_t DWBuf[4]; /* buffer for double word writes */
3112 Word_t *WordPtr; /* must be far because Win SS != DS */
3113 register DWordIO_t IndexAddr;
3114
3115 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
3116 IndexAddr = ChP->IndexAddr;
3117 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
3118 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
3119 return (0); /* nothing sent */
3120
3121 WordPtr = (Word_t *) (&DWBuf[0]);
3122 *WordPtr = ChP->TxPrioBuf; /* data byte address */
3123
3124 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00003125 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
3127 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
3128
3129 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
3130 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00003131 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 } else { /* write it to Tx FIFO */
3133
3134 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
3135 }
3136 return (1); /* 1 byte sent */
3137}
3138
3139/***************************************************************************
3140Function: sEnInterrupts
3141Purpose: Enable one or more interrupts for a channel
3142Call: sEnInterrupts(ChP,Flags)
3143 CHANNEL_T *ChP; Ptr to channel structure
3144 Word_t Flags: Interrupt enable flags, can be any combination
3145 of the following flags:
3146 TXINT_EN: Interrupt on Tx FIFO empty
3147 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3148 sSetRxTrigger())
3149 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3150 MCINT_EN: Interrupt on modem input change
3151 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3152 Interrupt Channel Register.
3153Return: void
3154Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3155 enabled. If an interrupt enable flag is not set in Flags, that
3156 interrupt will not be changed. Interrupts can be disabled with
3157 function sDisInterrupts().
3158
3159 This function sets the appropriate bit for the channel in the AIOP's
3160 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3161 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3162
3163 Interrupts must also be globally enabled before channel interrupts
3164 will be passed on to the host. This is done with function
3165 sEnGlobalInt().
3166
3167 In some cases it may be desirable to disable interrupts globally but
3168 enable channel interrupts. This would allow the global interrupt
3169 status register to be used to determine which AIOPs need service.
3170*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003171static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172{
3173 Byte_t Mask; /* Interrupt Mask Register */
3174
3175 ChP->RxControl[2] |=
3176 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3177
Al Viro457fb602008-03-19 16:27:48 +00003178 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
3180 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3181
Al Viro457fb602008-03-19 16:27:48 +00003182 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
3184 if (Flags & CHANINT_EN) {
3185 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3186 sOutB(ChP->IntMask, Mask);
3187 }
3188}
3189
3190/***************************************************************************
3191Function: sDisInterrupts
3192Purpose: Disable one or more interrupts for a channel
3193Call: sDisInterrupts(ChP,Flags)
3194 CHANNEL_T *ChP; Ptr to channel structure
3195 Word_t Flags: Interrupt flags, can be any combination
3196 of the following flags:
3197 TXINT_EN: Interrupt on Tx FIFO empty
3198 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3199 sSetRxTrigger())
3200 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3201 MCINT_EN: Interrupt on modem input change
3202 CHANINT_EN: Disable channel interrupt signal to the
3203 AIOP's Interrupt Channel Register.
3204Return: void
3205Comments: If an interrupt flag is set in Flags, that interrupt will be
3206 disabled. If an interrupt flag is not set in Flags, that
3207 interrupt will not be changed. Interrupts can be enabled with
3208 function sEnInterrupts().
3209
3210 This function clears the appropriate bit for the channel in the AIOP's
3211 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3212 this channel's bit from being set in the AIOP's Interrupt Channel
3213 Register.
3214*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003215static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216{
3217 Byte_t Mask; /* Interrupt Mask Register */
3218
3219 ChP->RxControl[2] &=
3220 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003221 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003223 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
3225 if (Flags & CHANINT_EN) {
3226 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3227 sOutB(ChP->IntMask, Mask);
3228 }
3229}
3230
Adrian Bunkf15313b2005-06-25 14:59:05 -07003231static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232{
3233 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3234}
3235
3236/*
3237 * Not an official SSCI function, but how to reset RocketModems.
3238 * ISA bus version
3239 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003240static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241{
3242 ByteIO_t addr;
3243 Byte_t val;
3244
3245 addr = CtlP->AiopIO[0] + 0x400;
3246 val = sInB(CtlP->MReg3IO);
3247 /* if AIOP[1] is not enabled, enable it */
3248 if ((val & 2) == 0) {
3249 val = sInB(CtlP->MReg2IO);
3250 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3251 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3252 }
3253
3254 sEnAiop(CtlP, 1);
3255 if (!on)
3256 addr += 8;
3257 sOutB(addr + chan, 0); /* apply or remove reset */
3258 sDisAiop(CtlP, 1);
3259}
3260
3261/*
3262 * Not an official SSCI function, but how to reset RocketModems.
3263 * PCI bus version
3264 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003265static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266{
3267 ByteIO_t addr;
3268
3269 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3270 if (!on)
3271 addr += 8;
3272 sOutB(addr + chan, 0); /* apply or remove reset */
3273}
3274
3275/* Resets the speaker controller on RocketModem II and III devices */
3276static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3277{
3278 ByteIO_t addr;
3279
3280 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3281 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3282 addr = CtlP->AiopIO[0] + 0x4F;
3283 sOutB(addr, 0);
3284 }
3285
3286 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3287 if ((model == MODEL_UPCI_RM3_8PORT)
3288 || (model == MODEL_UPCI_RM3_4PORT)) {
3289 addr = CtlP->AiopIO[0] + 0x88;
3290 sOutB(addr, 0);
3291 }
3292}
3293
3294/* Returns the line number given the controller (board), aiop and channel number */
3295static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3296{
3297 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3298}
3299
3300/*
3301 * Stores the line number associated with a given controller (board), aiop
3302 * and channel number.
3303 * Returns: The line number assigned
3304 */
3305static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3306{
3307 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3308 return (nextLineNumber - 1);
3309}