blob: ffb34c43a1c24fbfd7fb74c76bdd28e63c255c58 [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 ******/
43#ifdef PCI_NUM_RESOURCES
44#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
45#else
46#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r])
47#endif
48
49#define ROCKET_PARANOIA_CHECK
50#define ROCKET_DISABLE_SIMUSAGE
51
52#undef ROCKET_SOFT_FLOW
53#undef ROCKET_DEBUG_OPEN
54#undef ROCKET_DEBUG_INTR
55#undef ROCKET_DEBUG_WRITE
56#undef ROCKET_DEBUG_FLOW
57#undef ROCKET_DEBUG_THROTTLE
58#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
59#undef ROCKET_DEBUG_RECEIVE
60#undef ROCKET_DEBUG_HANGUP
61#undef REV_PCI_ORDER
62#undef ROCKET_DEBUG_IO
63
64#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */
65
66/****** Kernel includes ******/
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include <linux/module.h>
69#include <linux/errno.h>
70#include <linux/major.h>
71#include <linux/kernel.h>
72#include <linux/signal.h>
73#include <linux/slab.h>
74#include <linux/mm.h>
75#include <linux/sched.h>
76#include <linux/timer.h>
77#include <linux/interrupt.h>
78#include <linux/tty.h>
79#include <linux/tty_driver.h>
80#include <linux/tty_flip.h>
81#include <linux/string.h>
82#include <linux/fcntl.h>
83#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070084#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#include <linux/ioport.h>
86#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070087#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/wait.h>
89#include <linux/pci.h>
90#include <asm/uaccess.h>
91#include <asm/atomic.h>
92#include <linux/bitops.h>
93#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070094#include <linux/init.h>
95
96/****** RocketPort includes ******/
97
98#include "rocket_int.h"
99#include "rocket.h"
100
101#define ROCKET_VERSION "2.09"
102#define ROCKET_DATE "12-June-2003"
103
104/****** RocketPort Local Variables ******/
105
Jiri Slaby40565f12007-02-12 00:52:31 -0800106static void rp_do_poll(unsigned long dummy);
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108static struct tty_driver *rocket_driver;
109
110static struct rocket_version driver_version = {
111 ROCKET_VERSION, ROCKET_DATE
112};
113
114static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
115static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
116 /* eg. Bit 0 indicates port 0 has xmit data, ... */
117static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800118static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
121static unsigned long board2;
122static unsigned long board3;
123static unsigned long board4;
124static unsigned long controller;
125static int support_low_speed;
126static unsigned long modem1;
127static unsigned long modem2;
128static unsigned long modem3;
129static unsigned long modem4;
130static unsigned long pc104_1[8];
131static unsigned long pc104_2[8];
132static unsigned long pc104_3[8];
133static unsigned long pc104_4[8];
134static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
135
136static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
137static unsigned long rcktpt_io_addr[NUM_BOARDS];
138static int rcktpt_type[NUM_BOARDS];
139static int is_PCI[NUM_BOARDS];
140static rocketModel_t rocketModel[NUM_BOARDS];
141static int max_board;
142
143/*
144 * The following arrays define the interrupt bits corresponding to each AIOP.
145 * These bits are different between the ISA and regular PCI boards and the
146 * Universal PCI boards.
147 */
148
149static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
150 AIOP_INTR_BIT_0,
151 AIOP_INTR_BIT_1,
152 AIOP_INTR_BIT_2,
153 AIOP_INTR_BIT_3
154};
155
156static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
157 UPCI_AIOP_INTR_BIT_0,
158 UPCI_AIOP_INTR_BIT_1,
159 UPCI_AIOP_INTR_BIT_2,
160 UPCI_AIOP_INTR_BIT_3
161};
162
Adrian Bunkf15313b2005-06-25 14:59:05 -0700163static Byte_t RData[RDATASIZE] = {
164 0x00, 0x09, 0xf6, 0x82,
165 0x02, 0x09, 0x86, 0xfb,
166 0x04, 0x09, 0x00, 0x0a,
167 0x06, 0x09, 0x01, 0x0a,
168 0x08, 0x09, 0x8a, 0x13,
169 0x0a, 0x09, 0xc5, 0x11,
170 0x0c, 0x09, 0x86, 0x85,
171 0x0e, 0x09, 0x20, 0x0a,
172 0x10, 0x09, 0x21, 0x0a,
173 0x12, 0x09, 0x41, 0xff,
174 0x14, 0x09, 0x82, 0x00,
175 0x16, 0x09, 0x82, 0x7b,
176 0x18, 0x09, 0x8a, 0x7d,
177 0x1a, 0x09, 0x88, 0x81,
178 0x1c, 0x09, 0x86, 0x7a,
179 0x1e, 0x09, 0x84, 0x81,
180 0x20, 0x09, 0x82, 0x7c,
181 0x22, 0x09, 0x0a, 0x0a
182};
183
184static Byte_t RRegData[RREGDATASIZE] = {
185 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
186 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
187 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
188 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
189 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
190 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
191 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
192 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
193 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
194 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
195 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
196 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
197 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
198};
199
200static CONTROLLER_T sController[CTL_SIZE] = {
201 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
202 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
203 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
204 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
205 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
206 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
207 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
208 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
209};
210
211static Byte_t sBitMapClrTbl[8] = {
212 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
213};
214
215static Byte_t sBitMapSetTbl[8] = {
216 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
217};
218
219static int sClockPrescale = 0x14;
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221/*
222 * Line number is the ttySIx number (x), the Minor number. We
223 * assign them sequentially, starting at zero. The following
224 * array keeps track of the line number assigned to a given board/aiop/channel.
225 */
226static unsigned char lineNumbers[MAX_RP_PORTS];
227static unsigned long nextLineNumber;
228
229/***** RocketPort Static Prototypes *********/
230static int __init init_ISA(int i);
231static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
232static void rp_flush_buffer(struct tty_struct *tty);
233static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
234static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
235static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
236static void rp_start(struct tty_struct *tty);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700237static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
238 int ChanNum);
239static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
240static void sFlushRxFIFO(CHANNEL_T * ChP);
241static void sFlushTxFIFO(CHANNEL_T * ChP);
242static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
243static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
244static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
245static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
246static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
247static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
248 ByteIO_t * AiopIOList, int AiopIOListSize,
249 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
250 int PeriodicOnly, int altChanRingIndicator,
251 int UPCIRingInd);
252static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
253 ByteIO_t * AiopIOList, int AiopIOListSize,
254 int IRQNum, Byte_t Frequency, int PeriodicOnly);
255static int sReadAiopID(ByteIO_t io);
256static int sReadAiopNumChan(WordIO_t io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258MODULE_AUTHOR("Theodore Ts'o");
259MODULE_DESCRIPTION("Comtrol RocketPort driver");
260module_param(board1, ulong, 0);
261MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
262module_param(board2, ulong, 0);
263MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
264module_param(board3, ulong, 0);
265MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
266module_param(board4, ulong, 0);
267MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
268module_param(controller, ulong, 0);
269MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
270module_param(support_low_speed, bool, 0);
271MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
272module_param(modem1, ulong, 0);
273MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem");
274module_param(modem2, ulong, 0);
275MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem");
276module_param(modem3, ulong, 0);
277MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem");
278module_param(modem4, ulong, 0);
279MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem");
280module_param_array(pc104_1, ulong, NULL, 0);
281MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,...");
282module_param_array(pc104_2, ulong, NULL, 0);
283MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,...");
284module_param_array(pc104_3, ulong, NULL, 0);
285MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,...");
286module_param_array(pc104_4, ulong, NULL, 0);
287MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
288
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -0800289static int rp_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290static void rp_cleanup_module(void);
291
292module_init(rp_init);
293module_exit(rp_cleanup_module);
294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296MODULE_LICENSE("Dual BSD/GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298/*************************************************************************/
299/* Module code starts here */
300
301static inline int rocket_paranoia_check(struct r_port *info,
302 const char *routine)
303{
304#ifdef ROCKET_PARANOIA_CHECK
305 if (!info)
306 return 1;
307 if (info->magic != RPORT_MAGIC) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800308 printk(KERN_WARNING "Warning: bad magic number for rocketport "
309 "struct in %s\n", routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return 1;
311 }
312#endif
313 return 0;
314}
315
316
317/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals
318 * that receive data is present on a serial port. Pulls data from FIFO, moves it into the
319 * tty layer.
320 */
321static void rp_do_receive(struct r_port *info,
322 struct tty_struct *tty,
323 CHANNEL_t * cp, unsigned int ChanStatus)
324{
325 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700326 int ToRecv, wRecv, space;
327 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800331 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700333 if (ToRecv == 0)
334 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800335
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 /*
337 * if status indicates there are errored characters in the
338 * FIFO, then enter status mode (a word in FIFO holds
339 * character and status).
340 */
341 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
342 if (!(ChanStatus & STATMODE)) {
343#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800344 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345#endif
346 ChanStatus |= STATMODE;
347 sEnRxStatusMode(cp);
348 }
349 }
350
351 /*
352 * if we previously entered status mode, then read down the
353 * FIFO one word at a time, pulling apart the character and
354 * the status. Update error counters depending on status
355 */
356 if (ChanStatus & STATMODE) {
357#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800358 printk(KERN_INFO "Ignore %x, read %x...\n",
359 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360#endif
361 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700362 char flag;
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 CharNStat = sInW(sGetTxRxDataIO(cp));
365#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800366 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367#endif
368 if (CharNStat & STMBREAKH)
369 CharNStat &= ~(STMFRAMEH | STMPARITYH);
370 if (CharNStat & info->ignore_status_mask) {
371 ToRecv--;
372 continue;
373 }
374 CharNStat &= info->read_status_mask;
375 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700376 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700378 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700380 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700382 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700384 flag = TTY_NORMAL;
385 tty_insert_flip_char(tty, CharNStat & 0xff, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 ToRecv--;
387 }
388
389 /*
390 * after we've emptied the FIFO in status mode, turn
391 * status mode back off
392 */
393 if (sGetRxCnt(cp) == 0) {
394#ifdef ROCKET_DEBUG_RECEIVE
395 printk(KERN_INFO "Status mode off.\n");
396#endif
397 sDisRxStatusMode(cp);
398 }
399 } else {
400 /*
401 * we aren't in status mode, so read down the FIFO two
402 * characters at time by doing repeated word IO
403 * transfer.
404 */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700405 space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
406 if (space < ToRecv) {
407#ifdef ROCKET_DEBUG_RECEIVE
408 printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
409#endif
410 if (space <= 0)
411 return;
412 ToRecv = space;
413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 wRecv = ToRecv >> 1;
415 if (wRecv)
416 sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
417 if (ToRecv & 1)
418 cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
420 /* Push the data up to the tty layer */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700421 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
423
424/*
425 * Serial port transmit data function. Called from the timer polling loop as a
426 * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready
427 * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is
428 * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks.
429 */
430static void rp_do_transmit(struct r_port *info)
431{
432 int c;
433 CHANNEL_t *cp = &info->channel;
434 struct tty_struct *tty;
435 unsigned long flags;
436
437#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800438 printk(KERN_DEBUG "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439#endif
440 if (!info)
441 return;
442 if (!info->tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800443 printk(KERN_WARNING "rp: WARNING %s called with "
444 "info->tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
446 return;
447 }
448
449 spin_lock_irqsave(&info->slock, flags);
450 tty = info->tty;
451 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
452
453 /* Loop sending data to FIFO until done or FIFO full */
454 while (1) {
455 if (tty->stopped || tty->hw_stopped)
456 break;
457 c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail));
458 if (c <= 0 || info->xmit_fifo_room <= 0)
459 break;
460 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
461 if (c & 1)
462 sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]);
463 info->xmit_tail += c;
464 info->xmit_tail &= XMIT_BUF_SIZE - 1;
465 info->xmit_cnt -= c;
466 info->xmit_fifo_room -= c;
467#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800468 printk(KERN_INFO "tx %d chars...\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469#endif
470 }
471
472 if (info->xmit_cnt == 0)
473 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
474
475 if (info->xmit_cnt < WAKEUP_CHARS) {
476 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477#ifdef ROCKETPORT_HAVE_POLL_WAIT
478 wake_up_interruptible(&tty->poll_wait);
479#endif
480 }
481
482 spin_unlock_irqrestore(&info->slock, flags);
483
484#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800485 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 info->xmit_tail, info->xmit_fifo_room);
487#endif
488}
489
490/*
491 * Called when a serial port signals it has read data in it's RX FIFO.
492 * It checks what interrupts are pending and services them, including
493 * receiving serial data.
494 */
495static void rp_handle_port(struct r_port *info)
496{
497 CHANNEL_t *cp;
498 struct tty_struct *tty;
499 unsigned int IntMask, ChanStatus;
500
501 if (!info)
502 return;
503
504 if ((info->flags & ROCKET_INITIALIZED) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800505 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
506 "info->flags & NOT_INIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 return;
508 }
509 if (!info->tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800510 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
511 "info->tty==NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 return;
513 }
514 cp = &info->channel;
515 tty = info->tty;
516
517 IntMask = sGetChanIntID(cp) & info->intmask;
518#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800519 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520#endif
521 ChanStatus = sGetChanStatus(cp);
522 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
523 rp_do_receive(info, tty, cp, ChanStatus);
524 }
525 if (IntMask & DELTA_CD) { /* CD change */
526#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800527 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 (ChanStatus & CD_ACT) ? "on" : "off");
529#endif
530 if (!(ChanStatus & CD_ACT) && info->cd_status) {
531#ifdef ROCKET_DEBUG_HANGUP
532 printk(KERN_INFO "CD drop, calling hangup.\n");
533#endif
534 tty_hangup(tty);
535 }
536 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
537 wake_up_interruptible(&info->open_wait);
538 }
539#ifdef ROCKET_DEBUG_INTR
540 if (IntMask & DELTA_CTS) { /* CTS change */
541 printk(KERN_INFO "CTS change...\n");
542 }
543 if (IntMask & DELTA_DSR) { /* DSR change */
544 printk(KERN_INFO "DSR change...\n");
545 }
546#endif
547}
548
549/*
550 * The top level polling routine. Repeats every 1/100 HZ (10ms).
551 */
552static void rp_do_poll(unsigned long dummy)
553{
554 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700555 int ctrl, aiop, ch, line;
556 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 unsigned int CtlMask;
558 unsigned char AiopMask;
559 Word_t bit;
560
561 /* Walk through all the boards (ctrl's) */
562 for (ctrl = 0; ctrl < max_board; ctrl++) {
563 if (rcktpt_io_addr[ctrl] <= 0)
564 continue;
565
566 /* Get a ptr to the board's control struct */
567 ctlp = sCtlNumToCtlPtr(ctrl);
568
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200569 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570#ifdef CONFIG_PCI
571 if (ctlp->BusType == isPCI)
572 CtlMask = sPCIGetControllerIntStatus(ctlp);
573 else
574#endif
575 CtlMask = sGetControllerIntStatus(ctlp);
576
577 /* Check if any AIOP read bits are set */
578 for (aiop = 0; CtlMask; aiop++) {
579 bit = ctlp->AiopIntrBits[aiop];
580 if (CtlMask & bit) {
581 CtlMask &= ~bit;
582 AiopMask = sGetAiopIntStatus(ctlp, aiop);
583
584 /* Check if any port read bits are set */
585 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
586 if (AiopMask & 1) {
587
588 /* Get the line number (/dev/ttyRx number). */
589 /* Read the data from the port. */
590 line = GetLineNumber(ctrl, aiop, ch);
591 rp_handle_port(rp_table[line]);
592 }
593 }
594 }
595 }
596
597 xmitmask = xmit_flags[ctrl];
598
599 /*
600 * xmit_flags contains bit-significant flags, indicating there is data
601 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
602 * 1, ... (32 total possible). The variable i has the aiop and ch
603 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
604 */
605 if (xmitmask) {
606 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
607 if (xmitmask & (1 << i)) {
608 aiop = (i & 0x18) >> 3;
609 ch = i & 0x07;
610 line = GetLineNumber(ctrl, aiop, ch);
611 rp_do_transmit(rp_table[line]);
612 }
613 }
614 }
615 }
616
617 /*
618 * Reset the timer so we get called at the next clock tick (10ms).
619 */
620 if (atomic_read(&rp_num_ports_open))
621 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
622}
623
624/*
625 * Initializes the r_port structure for a port, as well as enabling the port on
626 * the board.
627 * Inputs: board, aiop, chan numbers
628 */
629static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
630{
631 unsigned rocketMode;
632 struct r_port *info;
633 int line;
634 CONTROLLER_T *ctlp;
635
636 /* Get the next available line number */
637 line = SetLineNumber(board, aiop, chan);
638
639 ctlp = sCtlNumToCtlPtr(board);
640
641 /* 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 -0700642 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800644 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
645 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return;
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 info->magic = RPORT_MAGIC;
650 info->line = line;
651 info->ctlp = ctlp;
652 info->board = board;
653 info->aiop = aiop;
654 info->chan = chan;
655 info->closing_wait = 3000;
656 info->close_delay = 50;
657 init_waitqueue_head(&info->open_wait);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700658 init_completion(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 info->flags &= ~ROCKET_MODE_MASK;
660 switch (pc104[board][line]) {
661 case 422:
662 info->flags |= ROCKET_MODE_RS422;
663 break;
664 case 485:
665 info->flags |= ROCKET_MODE_RS485;
666 break;
667 case 232:
668 default:
669 info->flags |= ROCKET_MODE_RS232;
670 break;
671 }
672
673 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
674 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800675 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
676 board, aiop, chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 kfree(info);
678 return;
679 }
680
681 rocketMode = info->flags & ROCKET_MODE_MASK;
682
683 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
684 sEnRTSToggle(&info->channel);
685 else
686 sDisRTSToggle(&info->channel);
687
688 if (ctlp->boardType == ROCKET_TYPE_PC104) {
689 switch (rocketMode) {
690 case ROCKET_MODE_RS485:
691 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
692 break;
693 case ROCKET_MODE_RS422:
694 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
695 break;
696 case ROCKET_MODE_RS232:
697 default:
698 if (info->flags & ROCKET_RTS_TOGGLE)
699 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
700 else
701 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
702 break;
703 }
704 }
705 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700706 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 rp_table[line] = info;
Jiri Slabyac6aec22007-10-18 03:06:26 -0700708 tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
709 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710}
711
712/*
713 * Configures a rocketport port according to its termio settings. Called from
714 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
715 */
716static void configure_r_port(struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800717 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 unsigned cflag;
720 unsigned long flags;
721 unsigned rocketMode;
722 int bits, baud, divisor;
723 CHANNEL_t *cp;
724
725 if (!info->tty || !info->tty->termios)
726 return;
727 cp = &info->channel;
728 cflag = info->tty->termios->c_cflag;
729
730 /* Byte size and parity */
731 if ((cflag & CSIZE) == CS8) {
732 sSetData8(cp);
733 bits = 10;
734 } else {
735 sSetData7(cp);
736 bits = 9;
737 }
738 if (cflag & CSTOPB) {
739 sSetStop2(cp);
740 bits++;
741 } else {
742 sSetStop1(cp);
743 }
744
745 if (cflag & PARENB) {
746 sEnParity(cp);
747 bits++;
748 if (cflag & PARODD) {
749 sSetOddParity(cp);
750 } else {
751 sSetEvenParity(cp);
752 }
753 } else {
754 sDisParity(cp);
755 }
756
757 /* baud rate */
758 baud = tty_get_baud_rate(info->tty);
759 if (!baud)
760 baud = 9600;
761 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
762 if ((divisor >= 8192 || divisor < 0) && old_termios) {
763 info->tty->termios->c_cflag &= ~CBAUD;
764 info->tty->termios->c_cflag |=
765 (old_termios->c_cflag & CBAUD);
766 baud = tty_get_baud_rate(info->tty);
767 if (!baud)
768 baud = 9600;
769 divisor = (rp_baud_base[info->board] / baud) - 1;
770 }
771 if (divisor >= 8192 || divisor < 0) {
772 baud = 9600;
773 divisor = (rp_baud_base[info->board] / baud) - 1;
774 }
775 info->cps = baud / bits;
776 sSetBaud(cp, divisor);
777
778 if (cflag & CRTSCTS) {
779 info->intmask |= DELTA_CTS;
780 sEnCTSFlowCtl(cp);
781 } else {
782 info->intmask &= ~DELTA_CTS;
783 sDisCTSFlowCtl(cp);
784 }
785 if (cflag & CLOCAL) {
786 info->intmask &= ~DELTA_CD;
787 } else {
788 spin_lock_irqsave(&info->slock, flags);
789 if (sGetChanStatus(cp) & CD_ACT)
790 info->cd_status = 1;
791 else
792 info->cd_status = 0;
793 info->intmask |= DELTA_CD;
794 spin_unlock_irqrestore(&info->slock, flags);
795 }
796
797 /*
798 * Handle software flow control in the board
799 */
800#ifdef ROCKET_SOFT_FLOW
801 if (I_IXON(info->tty)) {
802 sEnTxSoftFlowCtl(cp);
803 if (I_IXANY(info->tty)) {
804 sEnIXANY(cp);
805 } else {
806 sDisIXANY(cp);
807 }
808 sSetTxXONChar(cp, START_CHAR(info->tty));
809 sSetTxXOFFChar(cp, STOP_CHAR(info->tty));
810 } else {
811 sDisTxSoftFlowCtl(cp);
812 sDisIXANY(cp);
813 sClrTxXOFF(cp);
814 }
815#endif
816
817 /*
818 * Set up ignore/read mask words
819 */
820 info->read_status_mask = STMRCVROVRH | 0xFF;
821 if (I_INPCK(info->tty))
822 info->read_status_mask |= STMFRAMEH | STMPARITYH;
823 if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
824 info->read_status_mask |= STMBREAKH;
825
826 /*
827 * Characters to ignore
828 */
829 info->ignore_status_mask = 0;
830 if (I_IGNPAR(info->tty))
831 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
832 if (I_IGNBRK(info->tty)) {
833 info->ignore_status_mask |= STMBREAKH;
834 /*
835 * If we're ignoring parity and break indicators,
836 * ignore overruns too. (For real raw support).
837 */
838 if (I_IGNPAR(info->tty))
839 info->ignore_status_mask |= STMRCVROVRH;
840 }
841
842 rocketMode = info->flags & ROCKET_MODE_MASK;
843
844 if ((info->flags & ROCKET_RTS_TOGGLE)
845 || (rocketMode == ROCKET_MODE_RS485))
846 sEnRTSToggle(cp);
847 else
848 sDisRTSToggle(cp);
849
850 sSetRTS(&info->channel);
851
852 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
853 switch (rocketMode) {
854 case ROCKET_MODE_RS485:
855 sSetInterfaceMode(cp, InterfaceModeRS485);
856 break;
857 case ROCKET_MODE_RS422:
858 sSetInterfaceMode(cp, InterfaceModeRS422);
859 break;
860 case ROCKET_MODE_RS232:
861 default:
862 if (info->flags & ROCKET_RTS_TOGGLE)
863 sSetInterfaceMode(cp, InterfaceModeRS232T);
864 else
865 sSetInterfaceMode(cp, InterfaceModeRS232);
866 break;
867 }
868 }
869}
870
871/* info->count is considered critical, protected by spinlocks. */
872static int block_til_ready(struct tty_struct *tty, struct file *filp,
873 struct r_port *info)
874{
875 DECLARE_WAITQUEUE(wait, current);
876 int retval;
877 int do_clocal = 0, extra_count = 0;
878 unsigned long flags;
879
880 /*
881 * If the device is in the middle of being closed, then block
882 * until it's done, and then try again.
883 */
884 if (tty_hung_up_p(filp))
885 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
886 if (info->flags & ROCKET_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700887 if (wait_for_completion_interruptible(&info->close_wait))
888 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
890 }
891
892 /*
893 * If non-blocking mode is set, or the port is not enabled,
894 * then make the check up front and then exit.
895 */
896 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
897 info->flags |= ROCKET_NORMAL_ACTIVE;
898 return 0;
899 }
900 if (tty->termios->c_cflag & CLOCAL)
901 do_clocal = 1;
902
903 /*
904 * Block waiting for the carrier detect and the line to become free. While we are in
905 * this loop, info->count is dropped by one, so that rp_close() knows when to free things.
906 * We restore it upon exit, either normal or abnormal.
907 */
908 retval = 0;
909 add_wait_queue(&info->open_wait, &wait);
910#ifdef ROCKET_DEBUG_OPEN
911 printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count);
912#endif
913 spin_lock_irqsave(&info->slock, flags);
914
915#ifdef ROCKET_DISABLE_SIMUSAGE
916 info->flags |= ROCKET_NORMAL_ACTIVE;
917#else
918 if (!tty_hung_up_p(filp)) {
919 extra_count = 1;
920 info->count--;
921 }
922#endif
923 info->blocked_open++;
924
925 spin_unlock_irqrestore(&info->slock, flags);
926
927 while (1) {
928 if (tty->termios->c_cflag & CBAUD) {
929 sSetDTR(&info->channel);
930 sSetRTS(&info->channel);
931 }
932 set_current_state(TASK_INTERRUPTIBLE);
933 if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) {
934 if (info->flags & ROCKET_HUP_NOTIFY)
935 retval = -EAGAIN;
936 else
937 retval = -ERESTARTSYS;
938 break;
939 }
940 if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT)))
941 break;
942 if (signal_pending(current)) {
943 retval = -ERESTARTSYS;
944 break;
945 }
946#ifdef ROCKET_DEBUG_OPEN
947 printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
948 info->line, info->count, info->flags);
949#endif
950 schedule(); /* Don't hold spinlock here, will hang PC */
951 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700952 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 remove_wait_queue(&info->open_wait, &wait);
954
955 spin_lock_irqsave(&info->slock, flags);
956
957 if (extra_count)
958 info->count++;
959 info->blocked_open--;
960
961 spin_unlock_irqrestore(&info->slock, flags);
962
963#ifdef ROCKET_DEBUG_OPEN
964 printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
965 info->line, info->count);
966#endif
967 if (retval)
968 return retval;
969 info->flags |= ROCKET_NORMAL_ACTIVE;
970 return 0;
971}
972
973/*
974 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
975 * port's r_port struct. Initializes the port hardware.
976 */
977static int rp_open(struct tty_struct *tty, struct file *filp)
978{
979 struct r_port *info;
980 int line = 0, retval;
981 CHANNEL_t *cp;
982 unsigned long page;
983
984 line = TTY_GET_LINE(tty);
985 if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
986 return -ENXIO;
987
988 page = __get_free_page(GFP_KERNEL);
989 if (!page)
990 return -ENOMEM;
991
992 if (info->flags & ROCKET_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700993 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700995 if (retval)
996 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
998 }
999
1000 /*
1001 * We must not sleep from here until the port is marked fully in use.
1002 */
1003 if (info->xmit_buf)
1004 free_page(page);
1005 else
1006 info->xmit_buf = (unsigned char *) page;
1007
1008 tty->driver_data = info;
1009 info->tty = tty;
1010
1011 if (info->count++ == 0) {
1012 atomic_inc(&rp_num_ports_open);
1013
1014#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001015 printk(KERN_INFO "rocket mod++ = %d...\n",
1016 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017#endif
1018 }
1019#ifdef ROCKET_DEBUG_OPEN
1020 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count);
1021#endif
1022
1023 /*
1024 * Info->count is now 1; so it's safe to sleep now.
1025 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if ((info->flags & ROCKET_INITIALIZED) == 0) {
1027 cp = &info->channel;
1028 sSetRxTrigger(cp, TRIG_1);
1029 if (sGetChanStatus(cp) & CD_ACT)
1030 info->cd_status = 1;
1031 else
1032 info->cd_status = 0;
1033 sDisRxStatusMode(cp);
1034 sFlushRxFIFO(cp);
1035 sFlushTxFIFO(cp);
1036
1037 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1038 sSetRxTrigger(cp, TRIG_1);
1039
1040 sGetChanStatus(cp);
1041 sDisRxStatusMode(cp);
1042 sClrTxXOFF(cp);
1043
1044 sDisCTSFlowCtl(cp);
1045 sDisTxSoftFlowCtl(cp);
1046
1047 sEnRxFIFO(cp);
1048 sEnTransmit(cp);
1049
1050 info->flags |= ROCKET_INITIALIZED;
1051
1052 /*
1053 * Set up the tty->alt_speed kludge
1054 */
1055 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
1056 info->tty->alt_speed = 57600;
1057 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
1058 info->tty->alt_speed = 115200;
1059 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
1060 info->tty->alt_speed = 230400;
1061 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
1062 info->tty->alt_speed = 460800;
1063
1064 configure_r_port(info, NULL);
1065 if (tty->termios->c_cflag & CBAUD) {
1066 sSetDTR(cp);
1067 sSetRTS(cp);
1068 }
1069 }
1070 /* Starts (or resets) the maint polling loop */
1071 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
1072
1073 retval = block_til_ready(tty, filp, info);
1074 if (retval) {
1075#ifdef ROCKET_DEBUG_OPEN
1076 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
1077#endif
1078 return retval;
1079 }
1080 return 0;
1081}
1082
1083/*
1084 * Exception handler that closes a serial port. info->count is considered critical.
1085 */
1086static void rp_close(struct tty_struct *tty, struct file *filp)
1087{
1088 struct r_port *info = (struct r_port *) tty->driver_data;
1089 unsigned long flags;
1090 int timeout;
1091 CHANNEL_t *cp;
1092
1093 if (rocket_paranoia_check(info, "rp_close"))
1094 return;
1095
1096#ifdef ROCKET_DEBUG_OPEN
1097 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count);
1098#endif
1099
1100 if (tty_hung_up_p(filp))
1101 return;
1102 spin_lock_irqsave(&info->slock, flags);
1103
1104 if ((tty->count == 1) && (info->count != 1)) {
1105 /*
1106 * Uh, oh. tty->count is 1, which means that the tty
1107 * structure will be freed. Info->count should always
1108 * be one in these conditions. If it's greater than
1109 * one, we've got real problems, since it means the
1110 * serial port won't be shutdown.
1111 */
Jiri Slaby68562b72008-02-07 00:16:33 -08001112 printk(KERN_WARNING "rp_close: bad serial port count; "
1113 "tty->count is 1, info->count is %d\n", info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 info->count = 1;
1115 }
1116 if (--info->count < 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -08001117 printk(KERN_WARNING "rp_close: bad serial port count for "
1118 "ttyR%d: %d\n", info->line, info->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 info->count = 0;
1120 }
1121 if (info->count) {
1122 spin_unlock_irqrestore(&info->slock, flags);
1123 return;
1124 }
1125 info->flags |= ROCKET_CLOSING;
1126 spin_unlock_irqrestore(&info->slock, flags);
1127
1128 cp = &info->channel;
1129
1130 /*
1131 * Notify the line discpline to only process XON/XOFF characters
1132 */
1133 tty->closing = 1;
1134
1135 /*
1136 * If transmission was throttled by the application request,
1137 * just flush the xmit buffer.
1138 */
1139 if (tty->flow_stopped)
1140 rp_flush_buffer(tty);
1141
1142 /*
1143 * Wait for the transmit buffer to clear
1144 */
1145 if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE)
1146 tty_wait_until_sent(tty, info->closing_wait);
1147 /*
1148 * Before we drop DTR, make sure the UART transmitter
1149 * has completely drained; this is especially
1150 * important if there is a transmit FIFO!
1151 */
1152 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1153 if (timeout == 0)
1154 timeout = 1;
1155 rp_wait_until_sent(tty, timeout);
1156 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1157
1158 sDisTransmit(cp);
1159 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1160 sDisCTSFlowCtl(cp);
1161 sDisTxSoftFlowCtl(cp);
1162 sClrTxXOFF(cp);
1163 sFlushRxFIFO(cp);
1164 sFlushTxFIFO(cp);
1165 sClrRTS(cp);
1166 if (C_HUPCL(tty))
1167 sClrDTR(cp);
1168
1169 if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty))
1170 TTY_DRIVER_FLUSH_BUFFER(tty);
1171
1172 tty_ldisc_flush(tty);
1173
1174 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1175
1176 if (info->blocked_open) {
1177 if (info->close_delay) {
1178 msleep_interruptible(jiffies_to_msecs(info->close_delay));
1179 }
1180 wake_up_interruptible(&info->open_wait);
1181 } else {
1182 if (info->xmit_buf) {
1183 free_page((unsigned long) info->xmit_buf);
1184 info->xmit_buf = NULL;
1185 }
1186 }
1187 info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
1188 tty->closing = 0;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001189 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 atomic_dec(&rp_num_ports_open);
1191
1192#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001193 printk(KERN_INFO "rocket mod-- = %d...\n",
1194 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1196#endif
1197
1198}
1199
1200static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001201 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 struct r_port *info = (struct r_port *) tty->driver_data;
1204 CHANNEL_t *cp;
1205 unsigned cflag;
1206
1207 if (rocket_paranoia_check(info, "rp_set_termios"))
1208 return;
1209
1210 cflag = tty->termios->c_cflag;
1211
1212 if (cflag == old_termios->c_cflag)
1213 return;
1214
1215 /*
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));
1221
1222 configure_r_port(info, old_termios);
1223
1224 cp = &info->channel;
1225
1226 /* Handle transition to B0 status */
1227 if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
1228 sClrDTR(cp);
1229 sClrRTS(cp);
1230 }
1231
1232 /* Handle transition away from B0 status */
1233 if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
1234 if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
1235 sSetRTS(cp);
1236 sSetDTR(cp);
1237 }
1238
1239 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
1240 tty->hw_stopped = 0;
1241 rp_start(tty);
1242 }
1243}
1244
1245static void rp_break(struct tty_struct *tty, int break_state)
1246{
1247 struct r_port *info = (struct r_port *) tty->driver_data;
1248 unsigned long flags;
1249
1250 if (rocket_paranoia_check(info, "rp_break"))
1251 return;
1252
1253 spin_lock_irqsave(&info->slock, flags);
1254 if (break_state == -1)
1255 sSendBreak(&info->channel);
1256 else
1257 sClrBreak(&info->channel);
1258 spin_unlock_irqrestore(&info->slock, flags);
1259}
1260
1261/*
1262 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1263 * the UPCI boards was added, it was decided to make this a function because
1264 * the macro was getting too complicated. All cases except the first one
1265 * (UPCIRingInd) are taken directly from the original macro.
1266 */
1267static int sGetChanRI(CHANNEL_T * ChP)
1268{
1269 CONTROLLER_t *CtlP = ChP->CtlP;
1270 int ChanNum = ChP->ChanNum;
1271 int RingInd = 0;
1272
1273 if (CtlP->UPCIRingInd)
1274 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1275 else if (CtlP->AltChanRingIndicator)
1276 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1277 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1278 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1279
1280 return RingInd;
1281}
1282
1283/********************************************************************************************/
1284/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1285
1286/*
1287 * Returns the state of the serial modem control lines. These next 2 functions
1288 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1289 */
1290static int rp_tiocmget(struct tty_struct *tty, struct file *file)
1291{
1292 struct r_port *info = (struct r_port *)tty->driver_data;
1293 unsigned int control, result, ChanStatus;
1294
1295 ChanStatus = sGetChanStatusLo(&info->channel);
1296 control = info->channel.TxControl[3];
1297 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1298 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1299 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1300 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1301 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1302 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1303
1304 return result;
1305}
1306
1307/*
1308 * Sets the modem control lines
1309 */
1310static int rp_tiocmset(struct tty_struct *tty, struct file *file,
1311 unsigned int set, unsigned int clear)
1312{
1313 struct r_port *info = (struct r_port *)tty->driver_data;
1314
1315 if (set & TIOCM_RTS)
1316 info->channel.TxControl[3] |= SET_RTS;
1317 if (set & TIOCM_DTR)
1318 info->channel.TxControl[3] |= SET_DTR;
1319 if (clear & TIOCM_RTS)
1320 info->channel.TxControl[3] &= ~SET_RTS;
1321 if (clear & TIOCM_DTR)
1322 info->channel.TxControl[3] &= ~SET_DTR;
1323
1324 sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0]));
1325 return 0;
1326}
1327
1328static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1329{
1330 struct rocket_config tmp;
1331
1332 if (!retinfo)
1333 return -EFAULT;
1334 memset(&tmp, 0, sizeof (tmp));
1335 tmp.line = info->line;
1336 tmp.flags = info->flags;
1337 tmp.close_delay = info->close_delay;
1338 tmp.closing_wait = info->closing_wait;
1339 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
1340
1341 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1342 return -EFAULT;
1343 return 0;
1344}
1345
1346static int set_config(struct r_port *info, struct rocket_config __user *new_info)
1347{
1348 struct rocket_config new_serial;
1349
1350 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1351 return -EFAULT;
1352
1353 if (!capable(CAP_SYS_ADMIN))
1354 {
1355 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
1356 return -EPERM;
1357 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
1358 configure_r_port(info, NULL);
1359 return 0;
1360 }
1361
1362 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
1363 info->close_delay = new_serial.close_delay;
1364 info->closing_wait = new_serial.closing_wait;
1365
1366 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
1367 info->tty->alt_speed = 57600;
1368 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
1369 info->tty->alt_speed = 115200;
1370 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
1371 info->tty->alt_speed = 230400;
1372 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
1373 info->tty->alt_speed = 460800;
1374
1375 configure_r_port(info, NULL);
1376 return 0;
1377}
1378
1379/*
1380 * This function fills in a rocket_ports struct with information
1381 * about what boards/ports are in the system. This info is passed
1382 * to user space. See setrocket.c where the info is used to create
1383 * the /dev/ttyRx ports.
1384 */
1385static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1386{
1387 struct rocket_ports tmp;
1388 int board;
1389
1390 if (!retports)
1391 return -EFAULT;
1392 memset(&tmp, 0, sizeof (tmp));
1393 tmp.tty_major = rocket_driver->major;
1394
1395 for (board = 0; board < 4; board++) {
1396 tmp.rocketModel[board].model = rocketModel[board].model;
1397 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1398 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1399 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1400 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1401 }
1402 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1403 return -EFAULT;
1404 return 0;
1405}
1406
1407static int reset_rm2(struct r_port *info, void __user *arg)
1408{
1409 int reset;
1410
1411 if (copy_from_user(&reset, arg, sizeof (int)))
1412 return -EFAULT;
1413 if (reset)
1414 reset = 1;
1415
1416 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1417 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1418 return -EINVAL;
1419
1420 if (info->ctlp->BusType == isISA)
1421 sModemReset(info->ctlp, info->chan, reset);
1422 else
1423 sPCIModemReset(info->ctlp, info->chan, reset);
1424
1425 return 0;
1426}
1427
1428static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1429{
1430 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1431 return -EFAULT;
1432 return 0;
1433}
1434
1435/* IOCTL call handler into the driver */
1436static int rp_ioctl(struct tty_struct *tty, struct file *file,
1437 unsigned int cmd, unsigned long arg)
1438{
1439 struct r_port *info = (struct r_port *) tty->driver_data;
1440 void __user *argp = (void __user *)arg;
1441
1442 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1443 return -ENXIO;
1444
1445 switch (cmd) {
1446 case RCKP_GET_STRUCT:
1447 if (copy_to_user(argp, info, sizeof (struct r_port)))
1448 return -EFAULT;
1449 return 0;
1450 case RCKP_GET_CONFIG:
1451 return get_config(info, argp);
1452 case RCKP_SET_CONFIG:
1453 return set_config(info, argp);
1454 case RCKP_GET_PORTS:
1455 return get_ports(info, argp);
1456 case RCKP_RESET_RM2:
1457 return reset_rm2(info, argp);
1458 case RCKP_GET_VERSION:
1459 return get_version(info, argp);
1460 default:
1461 return -ENOIOCTLCMD;
1462 }
1463 return 0;
1464}
1465
1466static void rp_send_xchar(struct tty_struct *tty, char ch)
1467{
1468 struct r_port *info = (struct r_port *) tty->driver_data;
1469 CHANNEL_t *cp;
1470
1471 if (rocket_paranoia_check(info, "rp_send_xchar"))
1472 return;
1473
1474 cp = &info->channel;
1475 if (sGetTxCnt(cp))
1476 sWriteTxPrioByte(cp, ch);
1477 else
1478 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1479}
1480
1481static void rp_throttle(struct tty_struct *tty)
1482{
1483 struct r_port *info = (struct r_port *) tty->driver_data;
1484 CHANNEL_t *cp;
1485
1486#ifdef ROCKET_DEBUG_THROTTLE
1487 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1488 tty->ldisc.chars_in_buffer(tty));
1489#endif
1490
1491 if (rocket_paranoia_check(info, "rp_throttle"))
1492 return;
1493
1494 cp = &info->channel;
1495 if (I_IXOFF(tty))
1496 rp_send_xchar(tty, STOP_CHAR(tty));
1497
1498 sClrRTS(&info->channel);
1499}
1500
1501static void rp_unthrottle(struct tty_struct *tty)
1502{
1503 struct r_port *info = (struct r_port *) tty->driver_data;
1504 CHANNEL_t *cp;
1505#ifdef ROCKET_DEBUG_THROTTLE
1506 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1507 tty->ldisc.chars_in_buffer(tty));
1508#endif
1509
1510 if (rocket_paranoia_check(info, "rp_throttle"))
1511 return;
1512
1513 cp = &info->channel;
1514 if (I_IXOFF(tty))
1515 rp_send_xchar(tty, START_CHAR(tty));
1516
1517 sSetRTS(&info->channel);
1518}
1519
1520/*
1521 * ------------------------------------------------------------
1522 * rp_stop() and rp_start()
1523 *
1524 * This routines are called before setting or resetting tty->stopped.
1525 * They enable or disable transmitter interrupts, as necessary.
1526 * ------------------------------------------------------------
1527 */
1528static void rp_stop(struct tty_struct *tty)
1529{
1530 struct r_port *info = (struct r_port *) tty->driver_data;
1531
1532#ifdef ROCKET_DEBUG_FLOW
1533 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1534 info->xmit_cnt, info->xmit_fifo_room);
1535#endif
1536
1537 if (rocket_paranoia_check(info, "rp_stop"))
1538 return;
1539
1540 if (sGetTxCnt(&info->channel))
1541 sDisTransmit(&info->channel);
1542}
1543
1544static void rp_start(struct tty_struct *tty)
1545{
1546 struct r_port *info = (struct r_port *) tty->driver_data;
1547
1548#ifdef ROCKET_DEBUG_FLOW
1549 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1550 info->xmit_cnt, info->xmit_fifo_room);
1551#endif
1552
1553 if (rocket_paranoia_check(info, "rp_stop"))
1554 return;
1555
1556 sEnTransmit(&info->channel);
1557 set_bit((info->aiop * 8) + info->chan,
1558 (void *) &xmit_flags[info->board]);
1559}
1560
1561/*
1562 * rp_wait_until_sent() --- wait until the transmitter is empty
1563 */
1564static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1565{
1566 struct r_port *info = (struct r_port *) tty->driver_data;
1567 CHANNEL_t *cp;
1568 unsigned long orig_jiffies;
1569 int check_time, exit_time;
1570 int txcnt;
1571
1572 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1573 return;
1574
1575 cp = &info->channel;
1576
1577 orig_jiffies = jiffies;
1578#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001579 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001581 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582#endif
1583 while (1) {
1584 txcnt = sGetTxCnt(cp);
1585 if (!txcnt) {
1586 if (sGetChanStatusLo(cp) & TXSHRMT)
1587 break;
1588 check_time = (HZ / info->cps) / 5;
1589 } else {
1590 check_time = HZ * txcnt / info->cps;
1591 }
1592 if (timeout) {
1593 exit_time = orig_jiffies + timeout - jiffies;
1594 if (exit_time <= 0)
1595 break;
1596 if (exit_time < check_time)
1597 check_time = exit_time;
1598 }
1599 if (check_time == 0)
1600 check_time = 1;
1601#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001602 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1603 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604#endif
1605 msleep_interruptible(jiffies_to_msecs(check_time));
1606 if (signal_pending(current))
1607 break;
1608 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001609 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1611 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1612#endif
1613}
1614
1615/*
1616 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1617 */
1618static void rp_hangup(struct tty_struct *tty)
1619{
1620 CHANNEL_t *cp;
1621 struct r_port *info = (struct r_port *) tty->driver_data;
1622
1623 if (rocket_paranoia_check(info, "rp_hangup"))
1624 return;
1625
1626#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001627 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628#endif
1629 rp_flush_buffer(tty);
1630 if (info->flags & ROCKET_CLOSING)
1631 return;
1632 if (info->count)
1633 atomic_dec(&rp_num_ports_open);
1634 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1635
1636 info->count = 0;
1637 info->flags &= ~ROCKET_NORMAL_ACTIVE;
1638 info->tty = NULL;
1639
1640 cp = &info->channel;
1641 sDisRxFIFO(cp);
1642 sDisTransmit(cp);
1643 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1644 sDisCTSFlowCtl(cp);
1645 sDisTxSoftFlowCtl(cp);
1646 sClrTxXOFF(cp);
1647 info->flags &= ~ROCKET_INITIALIZED;
1648
1649 wake_up_interruptible(&info->open_wait);
1650}
1651
1652/*
1653 * Exception handler - write char routine. The RocketPort driver uses a
1654 * double-buffering strategy, with the twist that if the in-memory CPU
1655 * buffer is empty, and there's space in the transmit FIFO, the
1656 * writing routines will write directly to transmit FIFO.
1657 * Write buffer and counters protected by spinlocks
1658 */
1659static void rp_put_char(struct tty_struct *tty, unsigned char ch)
1660{
1661 struct r_port *info = (struct r_port *) tty->driver_data;
1662 CHANNEL_t *cp;
1663 unsigned long flags;
1664
1665 if (rocket_paranoia_check(info, "rp_put_char"))
1666 return;
1667
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001668 /*
1669 * Grab the port write mutex, locking out other processes that try to
1670 * write to this port
1671 */
1672 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001675 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676#endif
1677
1678 spin_lock_irqsave(&info->slock, flags);
1679 cp = &info->channel;
1680
1681 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1682 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1683
1684 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1685 info->xmit_buf[info->xmit_head++] = ch;
1686 info->xmit_head &= XMIT_BUF_SIZE - 1;
1687 info->xmit_cnt++;
1688 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1689 } else {
1690 sOutB(sGetTxRxDataIO(cp), ch);
1691 info->xmit_fifo_room--;
1692 }
1693 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001694 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695}
1696
1697/*
1698 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001699 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 * this port at the same time. This other process could be running on the other CPU
1701 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1702 * Spinlocks protect the info xmit members.
1703 */
1704static int rp_write(struct tty_struct *tty,
1705 const unsigned char *buf, int count)
1706{
1707 struct r_port *info = (struct r_port *) tty->driver_data;
1708 CHANNEL_t *cp;
1709 const unsigned char *b;
1710 int c, retval = 0;
1711 unsigned long flags;
1712
1713 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1714 return 0;
1715
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001716 if (mutex_lock_interruptible(&info->write_mtx))
1717 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718
1719#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001720 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721#endif
1722 cp = &info->channel;
1723
1724 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1725 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1726
1727 /*
1728 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1729 * into FIFO. Use the write queue for temp storage.
1730 */
1731 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1732 c = min(count, info->xmit_fifo_room);
1733 b = buf;
1734
1735 /* Push data into FIFO, 2 bytes at a time */
1736 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1737
1738 /* If there is a byte remaining, write it */
1739 if (c & 1)
1740 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1741
1742 retval += c;
1743 buf += c;
1744 count -= c;
1745
1746 spin_lock_irqsave(&info->slock, flags);
1747 info->xmit_fifo_room -= c;
1748 spin_unlock_irqrestore(&info->slock, flags);
1749 }
1750
1751 /* If count is zero, we wrote it all and are done */
1752 if (!count)
1753 goto end;
1754
1755 /* Write remaining data into the port's xmit_buf */
1756 while (1) {
1757 if (info->tty == 0) /* Seemingly obligatory check... */
1758 goto end;
1759
1760 c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head));
1761 if (c <= 0)
1762 break;
1763
1764 b = buf;
1765 memcpy(info->xmit_buf + info->xmit_head, b, c);
1766
1767 spin_lock_irqsave(&info->slock, flags);
1768 info->xmit_head =
1769 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1770 info->xmit_cnt += c;
1771 spin_unlock_irqrestore(&info->slock, flags);
1772
1773 buf += c;
1774 count -= c;
1775 retval += c;
1776 }
1777
1778 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1779 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1780
1781end:
1782 if (info->xmit_cnt < WAKEUP_CHARS) {
1783 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784#ifdef ROCKETPORT_HAVE_POLL_WAIT
1785 wake_up_interruptible(&tty->poll_wait);
1786#endif
1787 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001788 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 return retval;
1790}
1791
1792/*
1793 * Return the number of characters that can be sent. We estimate
1794 * only using the in-memory transmit buffer only, and ignore the
1795 * potential space in the transmit FIFO.
1796 */
1797static int rp_write_room(struct tty_struct *tty)
1798{
1799 struct r_port *info = (struct r_port *) tty->driver_data;
1800 int ret;
1801
1802 if (rocket_paranoia_check(info, "rp_write_room"))
1803 return 0;
1804
1805 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1806 if (ret < 0)
1807 ret = 0;
1808#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001809 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810#endif
1811 return ret;
1812}
1813
1814/*
1815 * Return the number of characters in the buffer. Again, this only
1816 * counts those characters in the in-memory transmit buffer.
1817 */
1818static int rp_chars_in_buffer(struct tty_struct *tty)
1819{
1820 struct r_port *info = (struct r_port *) tty->driver_data;
1821 CHANNEL_t *cp;
1822
1823 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1824 return 0;
1825
1826 cp = &info->channel;
1827
1828#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001829 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830#endif
1831 return info->xmit_cnt;
1832}
1833
1834/*
1835 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1836 * r_port struct for the port. Note that spinlock are used to protect info members,
1837 * do not call this function if the spinlock is already held.
1838 */
1839static void rp_flush_buffer(struct tty_struct *tty)
1840{
1841 struct r_port *info = (struct r_port *) tty->driver_data;
1842 CHANNEL_t *cp;
1843 unsigned long flags;
1844
1845 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1846 return;
1847
1848 spin_lock_irqsave(&info->slock, flags);
1849 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1850 spin_unlock_irqrestore(&info->slock, flags);
1851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852#ifdef ROCKETPORT_HAVE_POLL_WAIT
1853 wake_up_interruptible(&tty->poll_wait);
1854#endif
1855 tty_wakeup(tty);
1856
1857 cp = &info->channel;
1858 sFlushTxFIFO(cp);
1859}
1860
1861#ifdef CONFIG_PCI
1862
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001863static struct pci_device_id __devinitdata rocket_pci_ids[] = {
1864 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
1865 { }
1866};
1867MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869/*
1870 * Called when a PCI card is found. Retrieves and stores model information,
1871 * init's aiopic and serial port hardware.
1872 * Inputs: i is the board number (0-n)
1873 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001874static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
1876 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1877 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1878 char *str, *board_type;
1879 CONTROLLER_t *ctlp;
1880
1881 int fast_clock = 0;
1882 int altChanRingIndicator = 0;
1883 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 WordIO_t ConfigIO = 0;
1885 ByteIO_t UPCIRingInd = 0;
1886
1887 if (!dev || pci_enable_device(dev))
1888 return 0;
1889
1890 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
1892 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1893 rocketModel[i].loadrm2 = 0;
1894 rocketModel[i].startingPortNumber = nextLineNumber;
1895
1896 /* Depending on the model, set up some config variables */
1897 switch (dev->device) {
1898 case PCI_DEVICE_ID_RP4QUAD:
1899 str = "Quadcable";
1900 max_num_aiops = 1;
1901 ports_per_aiop = 4;
1902 rocketModel[i].model = MODEL_RP4QUAD;
1903 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1904 rocketModel[i].numPorts = 4;
1905 break;
1906 case PCI_DEVICE_ID_RP8OCTA:
1907 str = "Octacable";
1908 max_num_aiops = 1;
1909 rocketModel[i].model = MODEL_RP8OCTA;
1910 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1911 rocketModel[i].numPorts = 8;
1912 break;
1913 case PCI_DEVICE_ID_URP8OCTA:
1914 str = "Octacable";
1915 max_num_aiops = 1;
1916 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1917 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1918 rocketModel[i].numPorts = 8;
1919 break;
1920 case PCI_DEVICE_ID_RP8INTF:
1921 str = "8";
1922 max_num_aiops = 1;
1923 rocketModel[i].model = MODEL_RP8INTF;
1924 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1925 rocketModel[i].numPorts = 8;
1926 break;
1927 case PCI_DEVICE_ID_URP8INTF:
1928 str = "8";
1929 max_num_aiops = 1;
1930 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1931 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1932 rocketModel[i].numPorts = 8;
1933 break;
1934 case PCI_DEVICE_ID_RP8J:
1935 str = "8J";
1936 max_num_aiops = 1;
1937 rocketModel[i].model = MODEL_RP8J;
1938 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1939 rocketModel[i].numPorts = 8;
1940 break;
1941 case PCI_DEVICE_ID_RP4J:
1942 str = "4J";
1943 max_num_aiops = 1;
1944 ports_per_aiop = 4;
1945 rocketModel[i].model = MODEL_RP4J;
1946 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1947 rocketModel[i].numPorts = 4;
1948 break;
1949 case PCI_DEVICE_ID_RP8SNI:
1950 str = "8 (DB78 Custom)";
1951 max_num_aiops = 1;
1952 rocketModel[i].model = MODEL_RP8SNI;
1953 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1954 rocketModel[i].numPorts = 8;
1955 break;
1956 case PCI_DEVICE_ID_RP16SNI:
1957 str = "16 (DB78 Custom)";
1958 max_num_aiops = 2;
1959 rocketModel[i].model = MODEL_RP16SNI;
1960 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1961 rocketModel[i].numPorts = 16;
1962 break;
1963 case PCI_DEVICE_ID_RP16INTF:
1964 str = "16";
1965 max_num_aiops = 2;
1966 rocketModel[i].model = MODEL_RP16INTF;
1967 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1968 rocketModel[i].numPorts = 16;
1969 break;
1970 case PCI_DEVICE_ID_URP16INTF:
1971 str = "16";
1972 max_num_aiops = 2;
1973 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1974 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1975 rocketModel[i].numPorts = 16;
1976 break;
1977 case PCI_DEVICE_ID_CRP16INTF:
1978 str = "16";
1979 max_num_aiops = 2;
1980 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1981 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
1982 rocketModel[i].numPorts = 16;
1983 break;
1984 case PCI_DEVICE_ID_RP32INTF:
1985 str = "32";
1986 max_num_aiops = 4;
1987 rocketModel[i].model = MODEL_RP32INTF;
1988 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
1989 rocketModel[i].numPorts = 32;
1990 break;
1991 case PCI_DEVICE_ID_URP32INTF:
1992 str = "32";
1993 max_num_aiops = 4;
1994 rocketModel[i].model = MODEL_UPCI_RP32INTF;
1995 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
1996 rocketModel[i].numPorts = 32;
1997 break;
1998 case PCI_DEVICE_ID_RPP4:
1999 str = "Plus Quadcable";
2000 max_num_aiops = 1;
2001 ports_per_aiop = 4;
2002 altChanRingIndicator++;
2003 fast_clock++;
2004 rocketModel[i].model = MODEL_RPP4;
2005 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
2006 rocketModel[i].numPorts = 4;
2007 break;
2008 case PCI_DEVICE_ID_RPP8:
2009 str = "Plus Octacable";
2010 max_num_aiops = 2;
2011 ports_per_aiop = 4;
2012 altChanRingIndicator++;
2013 fast_clock++;
2014 rocketModel[i].model = MODEL_RPP8;
2015 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
2016 rocketModel[i].numPorts = 8;
2017 break;
2018 case PCI_DEVICE_ID_RP2_232:
2019 str = "Plus 2 (RS-232)";
2020 max_num_aiops = 1;
2021 ports_per_aiop = 2;
2022 altChanRingIndicator++;
2023 fast_clock++;
2024 rocketModel[i].model = MODEL_RP2_232;
2025 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
2026 rocketModel[i].numPorts = 2;
2027 break;
2028 case PCI_DEVICE_ID_RP2_422:
2029 str = "Plus 2 (RS-422)";
2030 max_num_aiops = 1;
2031 ports_per_aiop = 2;
2032 altChanRingIndicator++;
2033 fast_clock++;
2034 rocketModel[i].model = MODEL_RP2_422;
2035 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
2036 rocketModel[i].numPorts = 2;
2037 break;
2038 case PCI_DEVICE_ID_RP6M:
2039
2040 max_num_aiops = 1;
2041 ports_per_aiop = 6;
2042 str = "6-port";
2043
Jiri Slaby57fedc72007-10-18 03:06:28 -07002044 /* If revision is 1, the rocketmodem flash must be loaded.
2045 * If it is 2 it is a "socketed" version. */
2046 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2048 rocketModel[i].loadrm2 = 1;
2049 } else {
2050 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2051 }
2052
2053 rocketModel[i].model = MODEL_RP6M;
2054 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
2055 rocketModel[i].numPorts = 6;
2056 break;
2057 case PCI_DEVICE_ID_RP4M:
2058 max_num_aiops = 1;
2059 ports_per_aiop = 4;
2060 str = "4-port";
Jiri Slaby57fedc72007-10-18 03:06:28 -07002061 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2063 rocketModel[i].loadrm2 = 1;
2064 } else {
2065 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2066 }
2067
2068 rocketModel[i].model = MODEL_RP4M;
2069 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
2070 rocketModel[i].numPorts = 4;
2071 break;
2072 default:
2073 str = "(unknown/unsupported)";
2074 max_num_aiops = 0;
2075 break;
2076 }
2077
2078 /*
2079 * Check for UPCI boards.
2080 */
2081
2082 switch (dev->device) {
2083 case PCI_DEVICE_ID_URP32INTF:
2084 case PCI_DEVICE_ID_URP8INTF:
2085 case PCI_DEVICE_ID_URP16INTF:
2086 case PCI_DEVICE_ID_CRP16INTF:
2087 case PCI_DEVICE_ID_URP8OCTA:
2088 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2089 ConfigIO = pci_resource_start(dev, 1);
2090 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
2091 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2092
2093 /*
2094 * Check for octa or quad cable.
2095 */
2096 if (!
2097 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
2098 PCI_GPIO_CTRL_8PORT)) {
2099 str = "Quadcable";
2100 ports_per_aiop = 4;
2101 rocketModel[i].numPorts = 4;
2102 }
2103 }
2104 break;
2105 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
2106 str = "8 ports";
2107 max_num_aiops = 1;
2108 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
2109 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
2110 rocketModel[i].numPorts = 8;
2111 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2112 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2113 ConfigIO = pci_resource_start(dev, 1);
2114 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2115 break;
2116 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
2117 str = "4 ports";
2118 max_num_aiops = 1;
2119 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2120 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2121 rocketModel[i].numPorts = 4;
2122 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2123 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2124 ConfigIO = pci_resource_start(dev, 1);
2125 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2126 break;
2127 default:
2128 break;
2129 }
2130
2131 switch (rcktpt_type[i]) {
2132 case ROCKET_TYPE_MODEM:
2133 board_type = "RocketModem";
2134 break;
2135 case ROCKET_TYPE_MODEMII:
2136 board_type = "RocketModem II";
2137 break;
2138 case ROCKET_TYPE_MODEMIII:
2139 board_type = "RocketModem III";
2140 break;
2141 default:
2142 board_type = "RocketPort";
2143 break;
2144 }
2145
2146 if (fast_clock) {
2147 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2148 rp_baud_base[i] = 921600;
2149 } else {
2150 /*
2151 * If support_low_speed is set, use the slow clock
2152 * prescale, which supports 50 bps
2153 */
2154 if (support_low_speed) {
2155 /* mod 9 (divide by 10) prescale */
2156 sClockPrescale = 0x19;
2157 rp_baud_base[i] = 230400;
2158 } else {
2159 /* mod 4 (devide by 5) prescale */
2160 sClockPrescale = 0x14;
2161 rp_baud_base[i] = 460800;
2162 }
2163 }
2164
2165 for (aiop = 0; aiop < max_num_aiops; aiop++)
2166 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2167 ctlp = sCtlNumToCtlPtr(i);
2168 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2169 for (aiop = 0; aiop < max_num_aiops; aiop++)
2170 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2171
Jiri Slaby68562b72008-02-07 00:16:33 -08002172 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2173 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2174 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2175 rocketModel[i].startingPortNumber,
2176 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
2178 if (num_aiops <= 0) {
2179 rcktpt_io_addr[i] = 0;
2180 return (0);
2181 }
2182 is_PCI[i] = 1;
2183
2184 /* Reset the AIOPIC, init the serial ports */
2185 for (aiop = 0; aiop < num_aiops; aiop++) {
2186 sResetAiopByNum(ctlp, aiop);
2187 num_chan = ports_per_aiop;
2188 for (chan = 0; chan < num_chan; chan++)
2189 init_r_port(i, aiop, chan, dev);
2190 }
2191
2192 /* Rocket modems must be reset */
2193 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2194 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2195 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2196 num_chan = ports_per_aiop;
2197 for (chan = 0; chan < num_chan; chan++)
2198 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002199 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 for (chan = 0; chan < num_chan; chan++)
2201 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002202 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 rmSpeakerReset(ctlp, rocketModel[i].model);
2204 }
2205 return (1);
2206}
2207
2208/*
2209 * Probes for PCI cards, inits them if found
2210 * Input: board_found = number of ISA boards already found, or the
2211 * starting board number
2212 * Returns: Number of PCI boards found
2213 */
2214static int __init init_PCI(int boards_found)
2215{
2216 struct pci_dev *dev = NULL;
2217 int count = 0;
2218
2219 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002220 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (register_PCI(count + boards_found, dev))
2222 count++;
2223 }
2224 return (count);
2225}
2226
2227#endif /* CONFIG_PCI */
2228
2229/*
2230 * Probes for ISA cards
2231 * Input: i = the board number to look for
2232 * Returns: 1 if board found, 0 else
2233 */
2234static int __init init_ISA(int i)
2235{
2236 int num_aiops, num_chan = 0, total_num_chan = 0;
2237 int aiop, chan;
2238 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2239 CONTROLLER_t *ctlp;
2240 char *type_string;
2241
2242 /* If io_addr is zero, no board configured */
2243 if (rcktpt_io_addr[i] == 0)
2244 return (0);
2245
2246 /* Reserve the IO region */
2247 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002248 printk(KERN_ERR "Unable to reserve IO region for configured "
2249 "ISA RocketPort at address 0x%lx, board not "
2250 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 rcktpt_io_addr[i] = 0;
2252 return (0);
2253 }
2254
2255 ctlp = sCtlNumToCtlPtr(i);
2256
2257 ctlp->boardType = rcktpt_type[i];
2258
2259 switch (rcktpt_type[i]) {
2260 case ROCKET_TYPE_PC104:
2261 type_string = "(PC104)";
2262 break;
2263 case ROCKET_TYPE_MODEM:
2264 type_string = "(RocketModem)";
2265 break;
2266 case ROCKET_TYPE_MODEMII:
2267 type_string = "(RocketModem II)";
2268 break;
2269 default:
2270 type_string = "";
2271 break;
2272 }
2273
2274 /*
2275 * If support_low_speed is set, use the slow clock prescale,
2276 * which supports 50 bps
2277 */
2278 if (support_low_speed) {
2279 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2280 rp_baud_base[i] = 230400;
2281 } else {
2282 sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */
2283 rp_baud_base[i] = 460800;
2284 }
2285
2286 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2287 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2288
2289 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2290
2291 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2292 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2293 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2294 }
2295
2296 /* If something went wrong initing the AIOP's release the ISA IO memory */
2297 if (num_aiops <= 0) {
2298 release_region(rcktpt_io_addr[i], 64);
2299 rcktpt_io_addr[i] = 0;
2300 return (0);
2301 }
2302
2303 rocketModel[i].startingPortNumber = nextLineNumber;
2304
2305 for (aiop = 0; aiop < num_aiops; aiop++) {
2306 sResetAiopByNum(ctlp, aiop);
2307 sEnAiop(ctlp, aiop);
2308 num_chan = sGetAiopNumChan(ctlp, aiop);
2309 total_num_chan += num_chan;
2310 for (chan = 0; chan < num_chan; chan++)
2311 init_r_port(i, aiop, chan, NULL);
2312 }
2313 is_PCI[i] = 0;
2314 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2315 num_chan = sGetAiopNumChan(ctlp, 0);
2316 total_num_chan = num_chan;
2317 for (chan = 0; chan < num_chan; chan++)
2318 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002319 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 for (chan = 0; chan < num_chan; chan++)
2321 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002322 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2324 } else {
2325 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2326 }
2327 rocketModel[i].numPorts = total_num_chan;
2328 rocketModel[i].model = MODEL_ISA;
2329
2330 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2331 i, rcktpt_io_addr[i], num_aiops, type_string);
2332
2333 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2334 rocketModel[i].modelString,
2335 rocketModel[i].startingPortNumber,
2336 rocketModel[i].startingPortNumber +
2337 rocketModel[i].numPorts - 1);
2338
2339 return (1);
2340}
2341
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002342static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 .open = rp_open,
2344 .close = rp_close,
2345 .write = rp_write,
2346 .put_char = rp_put_char,
2347 .write_room = rp_write_room,
2348 .chars_in_buffer = rp_chars_in_buffer,
2349 .flush_buffer = rp_flush_buffer,
2350 .ioctl = rp_ioctl,
2351 .throttle = rp_throttle,
2352 .unthrottle = rp_unthrottle,
2353 .set_termios = rp_set_termios,
2354 .stop = rp_stop,
2355 .start = rp_start,
2356 .hangup = rp_hangup,
2357 .break_ctl = rp_break,
2358 .send_xchar = rp_send_xchar,
2359 .wait_until_sent = rp_wait_until_sent,
2360 .tiocmget = rp_tiocmget,
2361 .tiocmset = rp_tiocmset,
2362};
2363
2364/*
2365 * The module "startup" routine; it's run when the module is loaded.
2366 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002367static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002369 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
2371 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2372 ROCKET_VERSION, ROCKET_DATE);
2373
2374 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2375 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002376 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
2378 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2380 * zero, use the default controller IO address of board1 + 0x40.
2381 */
2382 if (board1) {
2383 if (controller == 0)
2384 controller = board1 + 0x40;
2385 } else {
2386 controller = 0; /* Used as a flag, meaning no ISA boards */
2387 }
2388
2389 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2390 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002391 printk(KERN_ERR "Unable to reserve IO region for first "
2392 "configured ISA RocketPort controller 0x%lx. "
2393 "Driver exiting\n", controller);
2394 ret = -EBUSY;
2395 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
2397
2398 /* Store ISA variable retrieved from command line or .conf file. */
2399 rcktpt_io_addr[0] = board1;
2400 rcktpt_io_addr[1] = board2;
2401 rcktpt_io_addr[2] = board3;
2402 rcktpt_io_addr[3] = board4;
2403
2404 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2405 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2406 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2407 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2408 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2409 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2410 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2411 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2412
2413 /*
2414 * Set up the tty driver structure and then register this
2415 * driver with the tty layer.
2416 */
2417
2418 rocket_driver->owner = THIS_MODULE;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002419 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 rocket_driver->name = "ttyR";
2421 rocket_driver->driver_name = "Comtrol RocketPort";
2422 rocket_driver->major = TTY_ROCKET_MAJOR;
2423 rocket_driver->minor_start = 0;
2424 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2425 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2426 rocket_driver->init_termios = tty_std_termios;
2427 rocket_driver->init_termios.c_cflag =
2428 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002429 rocket_driver->init_termios.c_ispeed = 9600;
2430 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002432 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433#endif
2434 tty_set_operations(rocket_driver, &rocket_ops);
2435
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002436 ret = tty_register_driver(rocket_driver);
2437 if (ret < 0) {
2438 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
2439 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 }
2441
2442#ifdef ROCKET_DEBUG_OPEN
2443 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2444#endif
2445
2446 /*
2447 * OK, let's probe each of the controllers looking for boards. Any boards found
2448 * will be initialized here.
2449 */
2450 isa_boards_found = 0;
2451 pci_boards_found = 0;
2452
2453 for (i = 0; i < NUM_BOARDS; i++) {
2454 if (init_ISA(i))
2455 isa_boards_found++;
2456 }
2457
2458#ifdef CONFIG_PCI
2459 if (isa_boards_found < NUM_BOARDS)
2460 pci_boards_found = init_PCI(isa_boards_found);
2461#endif
2462
2463 max_board = pci_boards_found + isa_boards_found;
2464
2465 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002466 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2467 ret = -ENXIO;
2468 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470
2471 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002472err_ttyu:
2473 tty_unregister_driver(rocket_driver);
2474err_tty:
2475 put_tty_driver(rocket_driver);
2476err:
2477 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478}
2479
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
2481static void rp_cleanup_module(void)
2482{
2483 int retval;
2484 int i;
2485
2486 del_timer_sync(&rocket_timer);
2487
2488 retval = tty_unregister_driver(rocket_driver);
2489 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002490 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
Jesper Juhl735d5662005-11-07 01:01:29 -08002493 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002494 if (rp_table[i]) {
2495 tty_unregister_device(rocket_driver, i);
2496 kfree(rp_table[i]);
2497 }
2498
2499 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 for (i = 0; i < NUM_BOARDS; i++) {
2502 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2503 continue;
2504 release_region(rcktpt_io_addr[i], 64);
2505 }
2506 if (controller)
2507 release_region(controller, 4);
2508}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510/***************************************************************************
2511Function: sInitController
2512Purpose: Initialization of controller global registers and controller
2513 structure.
2514Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2515 IRQNum,Frequency,PeriodicOnly)
2516 CONTROLLER_T *CtlP; Ptr to controller structure
2517 int CtlNum; Controller number
2518 ByteIO_t MudbacIO; Mudbac base I/O address.
2519 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2520 This list must be in the order the AIOPs will be found on the
2521 controller. Once an AIOP in the list is not found, it is
2522 assumed that there are no more AIOPs on the controller.
2523 int AiopIOListSize; Number of addresses in AiopIOList
2524 int IRQNum; Interrupt Request number. Can be any of the following:
2525 0: Disable global interrupts
2526 3: IRQ 3
2527 4: IRQ 4
2528 5: IRQ 5
2529 9: IRQ 9
2530 10: IRQ 10
2531 11: IRQ 11
2532 12: IRQ 12
2533 15: IRQ 15
2534 Byte_t Frequency: A flag identifying the frequency
2535 of the periodic interrupt, can be any one of the following:
2536 FREQ_DIS - periodic interrupt disabled
2537 FREQ_137HZ - 137 Hertz
2538 FREQ_69HZ - 69 Hertz
2539 FREQ_34HZ - 34 Hertz
2540 FREQ_17HZ - 17 Hertz
2541 FREQ_9HZ - 9 Hertz
2542 FREQ_4HZ - 4 Hertz
2543 If IRQNum is set to 0 the Frequency parameter is
2544 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002545 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002547 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 other channel interrupts are allowed.
2549 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002550 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2552 initialization failed.
2553
2554Comments:
2555 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002556 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558 If interrupts are to be completely disabled set IRQNum to 0.
2559
Adrian Bunkf15313b2005-06-25 14:59:05 -07002560 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 invalid combination.
2562
2563 This function performs initialization of global interrupt modes,
2564 but it does not actually enable global interrupts. To enable
2565 and disable global interrupts use functions sEnGlobalInt() and
2566 sDisGlobalInt(). Enabling of global interrupts is normally not
2567 done until all other initializations are complete.
2568
2569 Even if interrupts are globally enabled, they must also be
2570 individually enabled for each channel that is to generate
2571 interrupts.
2572
2573Warnings: No range checking on any of the parameters is done.
2574
2575 No context switches are allowed while executing this function.
2576
2577 After this function all AIOPs on the controller are disabled,
2578 they can be enabled with sEnAiop().
2579*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002580static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2581 ByteIO_t * AiopIOList, int AiopIOListSize,
2582 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583{
2584 int i;
2585 ByteIO_t io;
2586 int done;
2587
2588 CtlP->AiopIntrBits = aiop_intr_bits;
2589 CtlP->AltChanRingIndicator = 0;
2590 CtlP->CtlNum = CtlNum;
2591 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2592 CtlP->BusType = isISA;
2593 CtlP->MBaseIO = MudbacIO;
2594 CtlP->MReg1IO = MudbacIO + 1;
2595 CtlP->MReg2IO = MudbacIO + 2;
2596 CtlP->MReg3IO = MudbacIO + 3;
2597#if 1
2598 CtlP->MReg2 = 0; /* interrupt disable */
2599 CtlP->MReg3 = 0; /* no periodic interrupts */
2600#else
2601 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2602 CtlP->MReg2 = 0; /* interrupt disable */
2603 CtlP->MReg3 = 0; /* no periodic interrupts */
2604 } else {
2605 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2606 CtlP->MReg3 = Frequency; /* set frequency */
2607 if (PeriodicOnly) { /* periodic interrupt only */
2608 CtlP->MReg3 |= PERIODIC_ONLY;
2609 }
2610 }
2611#endif
2612 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2613 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2614 sControllerEOI(CtlP); /* clear EOI if warm init */
2615 /* Init AIOPs */
2616 CtlP->NumAiop = 0;
2617 for (i = done = 0; i < AiopIOListSize; i++) {
2618 io = AiopIOList[i];
2619 CtlP->AiopIO[i] = (WordIO_t) io;
2620 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2621 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2622 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2623 if (done)
2624 continue;
2625 sEnAiop(CtlP, i); /* enable the AIOP */
2626 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2627 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2628 done = 1; /* done looking for AIOPs */
2629 else {
2630 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2631 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2632 sOutB(io + _INDX_DATA, sClockPrescale);
2633 CtlP->NumAiop++; /* bump count of AIOPs */
2634 }
2635 sDisAiop(CtlP, i); /* disable AIOP */
2636 }
2637
2638 if (CtlP->NumAiop == 0)
2639 return (-1);
2640 else
2641 return (CtlP->NumAiop);
2642}
2643
2644/***************************************************************************
2645Function: sPCIInitController
2646Purpose: Initialization of controller global registers and controller
2647 structure.
2648Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2649 IRQNum,Frequency,PeriodicOnly)
2650 CONTROLLER_T *CtlP; Ptr to controller structure
2651 int CtlNum; Controller number
2652 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2653 This list must be in the order the AIOPs will be found on the
2654 controller. Once an AIOP in the list is not found, it is
2655 assumed that there are no more AIOPs on the controller.
2656 int AiopIOListSize; Number of addresses in AiopIOList
2657 int IRQNum; Interrupt Request number. Can be any of the following:
2658 0: Disable global interrupts
2659 3: IRQ 3
2660 4: IRQ 4
2661 5: IRQ 5
2662 9: IRQ 9
2663 10: IRQ 10
2664 11: IRQ 11
2665 12: IRQ 12
2666 15: IRQ 15
2667 Byte_t Frequency: A flag identifying the frequency
2668 of the periodic interrupt, can be any one of the following:
2669 FREQ_DIS - periodic interrupt disabled
2670 FREQ_137HZ - 137 Hertz
2671 FREQ_69HZ - 69 Hertz
2672 FREQ_34HZ - 34 Hertz
2673 FREQ_17HZ - 17 Hertz
2674 FREQ_9HZ - 9 Hertz
2675 FREQ_4HZ - 4 Hertz
2676 If IRQNum is set to 0 the Frequency parameter is
2677 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002678 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002680 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 other channel interrupts are allowed.
2682 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002683 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2685 initialization failed.
2686
2687Comments:
2688 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002689 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
2691 If interrupts are to be completely disabled set IRQNum to 0.
2692
Adrian Bunkf15313b2005-06-25 14:59:05 -07002693 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 invalid combination.
2695
2696 This function performs initialization of global interrupt modes,
2697 but it does not actually enable global interrupts. To enable
2698 and disable global interrupts use functions sEnGlobalInt() and
2699 sDisGlobalInt(). Enabling of global interrupts is normally not
2700 done until all other initializations are complete.
2701
2702 Even if interrupts are globally enabled, they must also be
2703 individually enabled for each channel that is to generate
2704 interrupts.
2705
2706Warnings: No range checking on any of the parameters is done.
2707
2708 No context switches are allowed while executing this function.
2709
2710 After this function all AIOPs on the controller are disabled,
2711 they can be enabled with sEnAiop().
2712*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002713static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2714 ByteIO_t * AiopIOList, int AiopIOListSize,
2715 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2716 int PeriodicOnly, int altChanRingIndicator,
2717 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718{
2719 int i;
2720 ByteIO_t io;
2721
2722 CtlP->AltChanRingIndicator = altChanRingIndicator;
2723 CtlP->UPCIRingInd = UPCIRingInd;
2724 CtlP->CtlNum = CtlNum;
2725 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2726 CtlP->BusType = isPCI; /* controller release 1 */
2727
2728 if (ConfigIO) {
2729 CtlP->isUPCI = 1;
2730 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2731 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2732 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2733 } else {
2734 CtlP->isUPCI = 0;
2735 CtlP->PCIIO =
2736 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2737 CtlP->AiopIntrBits = aiop_intr_bits;
2738 }
2739
2740 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2741 /* Init AIOPs */
2742 CtlP->NumAiop = 0;
2743 for (i = 0; i < AiopIOListSize; i++) {
2744 io = AiopIOList[i];
2745 CtlP->AiopIO[i] = (WordIO_t) io;
2746 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2747
2748 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2749 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2750 break; /* done looking for AIOPs */
2751
2752 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2753 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2754 sOutB(io + _INDX_DATA, sClockPrescale);
2755 CtlP->NumAiop++; /* bump count of AIOPs */
2756 }
2757
2758 if (CtlP->NumAiop == 0)
2759 return (-1);
2760 else
2761 return (CtlP->NumAiop);
2762}
2763
2764/***************************************************************************
2765Function: sReadAiopID
2766Purpose: Read the AIOP idenfication number directly from an AIOP.
2767Call: sReadAiopID(io)
2768 ByteIO_t io: AIOP base I/O address
2769Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2770 is replace by an identifying number.
2771 Flag AIOPID_NULL if no valid AIOP is found
2772Warnings: No context switches are allowed while executing this function.
2773
2774*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002775static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776{
2777 Byte_t AiopID; /* ID byte from AIOP */
2778
2779 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2780 sOutB(io + _CMD_REG, 0x0);
2781 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2782 if (AiopID == 0x06)
2783 return (1);
2784 else /* AIOP does not exist */
2785 return (-1);
2786}
2787
2788/***************************************************************************
2789Function: sReadAiopNumChan
2790Purpose: Read the number of channels available in an AIOP directly from
2791 an AIOP.
2792Call: sReadAiopNumChan(io)
2793 WordIO_t io: AIOP base I/O address
2794Return: int: The number of channels available
2795Comments: The number of channels is determined by write/reads from identical
2796 offsets within the SRAM address spaces for channels 0 and 4.
2797 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2798 AIOP, otherwise it is an 8 channel.
2799Warnings: No context switches are allowed while executing this function.
2800*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002801static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 Word_t x;
2804 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2805
2806 /* write to chan 0 SRAM */
2807 sOutDW((DWordIO_t) io + _INDX_ADDR, *((DWord_t *) & R[0]));
2808 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2809 x = sInW(io + _INDX_DATA);
2810 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2811 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2812 return (8);
2813 else
2814 return (4);
2815}
2816
2817/***************************************************************************
2818Function: sInitChan
2819Purpose: Initialization of a channel and channel structure
2820Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2821 CONTROLLER_T *CtlP; Ptr to controller structure
2822 CHANNEL_T *ChP; Ptr to channel structure
2823 int AiopNum; AIOP number within controller
2824 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002825Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 number exceeds number of channels available in AIOP.
2827Comments: This function must be called before a channel can be used.
2828Warnings: No range checking on any of the parameters is done.
2829
2830 No context switches are allowed while executing this function.
2831*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002832static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2833 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834{
2835 int i;
2836 WordIO_t AiopIO;
2837 WordIO_t ChIOOff;
2838 Byte_t *ChR;
2839 Word_t ChOff;
2840 static Byte_t R[4];
2841 int brd9600;
2842
2843 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002844 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846 /* Channel, AIOP, and controller identifiers */
2847 ChP->CtlP = CtlP;
2848 ChP->ChanID = CtlP->AiopID[AiopNum];
2849 ChP->AiopNum = AiopNum;
2850 ChP->ChanNum = ChanNum;
2851
2852 /* Global direct addresses */
2853 AiopIO = CtlP->AiopIO[AiopNum];
2854 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2855 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2856 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2857 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2858 ChP->IndexData = AiopIO + _INDX_DATA;
2859
2860 /* Channel direct addresses */
2861 ChIOOff = AiopIO + ChP->ChanNum * 2;
2862 ChP->TxRxData = ChIOOff + _TD0;
2863 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2864 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2865 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2866
2867 /* Initialize the channel from the RData array */
2868 for (i = 0; i < RDATASIZE; i += 4) {
2869 R[0] = RData[i];
2870 R[1] = RData[i + 1] + 0x10 * ChanNum;
2871 R[2] = RData[i + 2];
2872 R[3] = RData[i + 3];
2873 sOutDW(ChP->IndexAddr, *((DWord_t *) & R[0]));
2874 }
2875
2876 ChR = ChP->R;
2877 for (i = 0; i < RREGDATASIZE; i += 4) {
2878 ChR[i] = RRegData[i];
2879 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2880 ChR[i + 2] = RRegData[i + 2];
2881 ChR[i + 3] = RRegData[i + 3];
2882 }
2883
2884 /* Indexed registers */
2885 ChOff = (Word_t) ChanNum *0x1000;
2886
2887 if (sClockPrescale == 0x14)
2888 brd9600 = 47;
2889 else
2890 brd9600 = 23;
2891
2892 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2893 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2894 ChP->BaudDiv[2] = (Byte_t) brd9600;
2895 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
2896 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->BaudDiv[0]);
2897
2898 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2899 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2900 ChP->TxControl[2] = 0;
2901 ChP->TxControl[3] = 0;
2902 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]);
2903
2904 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2905 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2906 ChP->RxControl[2] = 0;
2907 ChP->RxControl[3] = 0;
2908 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]);
2909
2910 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2911 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2912 ChP->TxEnables[2] = 0;
2913 ChP->TxEnables[3] = 0;
2914 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxEnables[0]);
2915
2916 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2917 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2918 ChP->TxCompare[2] = 0;
2919 ChP->TxCompare[3] = 0;
2920 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxCompare[0]);
2921
2922 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2923 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2924 ChP->TxReplace1[2] = 0;
2925 ChP->TxReplace1[3] = 0;
2926 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace1[0]);
2927
2928 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2929 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2930 ChP->TxReplace2[2] = 0;
2931 ChP->TxReplace2[3] = 0;
2932 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace2[0]);
2933
2934 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2935 ChP->TxFIFO = ChOff + _TX_FIFO;
2936
2937 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2938 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2939 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2940 sOutW(ChP->IndexData, 0);
2941 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2942 ChP->RxFIFO = ChOff + _RX_FIFO;
2943
2944 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2945 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2946 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2947 sOutW(ChP->IndexData, 0);
2948 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2949 sOutW(ChP->IndexData, 0);
2950 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2951 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2952 sOutB(ChP->IndexData, 0);
2953 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2954 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2955 sOutB(ChP->IndexData, 0);
2956 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2957 sEnRxProcessor(ChP); /* start the Rx processor */
2958
Adrian Bunkf15313b2005-06-25 14:59:05 -07002959 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960}
2961
2962/***************************************************************************
2963Function: sStopRxProcessor
2964Purpose: Stop the receive processor from processing a channel.
2965Call: sStopRxProcessor(ChP)
2966 CHANNEL_T *ChP; Ptr to channel structure
2967
2968Comments: The receive processor can be started again with sStartRxProcessor().
2969 This function causes the receive processor to skip over the
2970 stopped channel. It does not stop it from processing other channels.
2971
2972Warnings: No context switches are allowed while executing this function.
2973
2974 Do not leave the receive processor stopped for more than one
2975 character time.
2976
2977 After calling this function a delay of 4 uS is required to ensure
2978 that the receive processor is no longer processing this channel.
2979*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002980static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982 Byte_t R[4];
2983
2984 R[0] = ChP->R[0];
2985 R[1] = ChP->R[1];
2986 R[2] = 0x0a;
2987 R[3] = ChP->R[3];
2988 sOutDW(ChP->IndexAddr, *(DWord_t *) & R[0]);
2989}
2990
2991/***************************************************************************
2992Function: sFlushRxFIFO
2993Purpose: Flush the Rx FIFO
2994Call: sFlushRxFIFO(ChP)
2995 CHANNEL_T *ChP; Ptr to channel structure
2996Return: void
2997Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2998 while it is being flushed the receive processor is stopped
2999 and the transmitter is disabled. After these operations a
3000 4 uS delay is done before clearing the pointers to allow
3001 the receive processor to stop. These items are handled inside
3002 this function.
3003Warnings: No context switches are allowed while executing this function.
3004*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003005static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006{
3007 int i;
3008 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003009 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010
3011 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
3012 return; /* don't need to flush */
3013
Adrian Bunkf15313b2005-06-25 14:59:05 -07003014 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003016 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 sDisRxFIFO(ChP); /* disable it */
3018 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
3019 sInB(ChP->IntChan); /* depends on bus i/o timing */
3020 }
3021 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
3022 Ch = (Byte_t) sGetChanNum(ChP);
3023 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
3024 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
3025 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
3026 sOutW(ChP->IndexData, 0);
3027 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
3028 sOutW(ChP->IndexData, 0);
3029 if (RxFIFOEnabled)
3030 sEnRxFIFO(ChP); /* enable Rx FIFO */
3031}
3032
3033/***************************************************************************
3034Function: sFlushTxFIFO
3035Purpose: Flush the Tx FIFO
3036Call: sFlushTxFIFO(ChP)
3037 CHANNEL_T *ChP; Ptr to channel structure
3038Return: void
3039Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
3040 while it is being flushed the receive processor is stopped
3041 and the transmitter is disabled. After these operations a
3042 4 uS delay is done before clearing the pointers to allow
3043 the receive processor to stop. These items are handled inside
3044 this function.
3045Warnings: No context switches are allowed while executing this function.
3046*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003047static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048{
3049 int i;
3050 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003051 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052
3053 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
3054 return; /* don't need to flush */
3055
Adrian Bunkf15313b2005-06-25 14:59:05 -07003056 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07003058 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 sDisTransmit(ChP); /* disable transmitter */
3060 }
3061 sStopRxProcessor(ChP); /* stop Rx processor */
3062 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
3063 sInB(ChP->IntChan); /* depends on bus i/o timing */
3064 Ch = (Byte_t) sGetChanNum(ChP);
3065 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
3066 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
3067 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
3068 sOutW(ChP->IndexData, 0);
3069 if (TxEnabled)
3070 sEnTransmit(ChP); /* enable transmitter */
3071 sStartRxProcessor(ChP); /* restart Rx processor */
3072}
3073
3074/***************************************************************************
3075Function: sWriteTxPrioByte
3076Purpose: Write a byte of priority transmit data to a channel
3077Call: sWriteTxPrioByte(ChP,Data)
3078 CHANNEL_T *ChP; Ptr to channel structure
3079 Byte_t Data; The transmit data byte
3080
3081Return: int: 1 if the bytes is successfully written, otherwise 0.
3082
3083Comments: The priority byte is transmitted before any data in the Tx FIFO.
3084
3085Warnings: No context switches are allowed while executing this function.
3086*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003087static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088{
3089 Byte_t DWBuf[4]; /* buffer for double word writes */
3090 Word_t *WordPtr; /* must be far because Win SS != DS */
3091 register DWordIO_t IndexAddr;
3092
3093 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
3094 IndexAddr = ChP->IndexAddr;
3095 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
3096 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
3097 return (0); /* nothing sent */
3098
3099 WordPtr = (Word_t *) (&DWBuf[0]);
3100 *WordPtr = ChP->TxPrioBuf; /* data byte address */
3101
3102 DWBuf[2] = Data; /* data byte value */
3103 sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */
3104
3105 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
3106
3107 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
3108 DWBuf[3] = 0; /* priority buffer pointer */
3109 sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */
3110 } else { /* write it to Tx FIFO */
3111
3112 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
3113 }
3114 return (1); /* 1 byte sent */
3115}
3116
3117/***************************************************************************
3118Function: sEnInterrupts
3119Purpose: Enable one or more interrupts for a channel
3120Call: sEnInterrupts(ChP,Flags)
3121 CHANNEL_T *ChP; Ptr to channel structure
3122 Word_t Flags: Interrupt enable flags, can be any combination
3123 of the following flags:
3124 TXINT_EN: Interrupt on Tx FIFO empty
3125 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3126 sSetRxTrigger())
3127 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3128 MCINT_EN: Interrupt on modem input change
3129 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3130 Interrupt Channel Register.
3131Return: void
3132Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3133 enabled. If an interrupt enable flag is not set in Flags, that
3134 interrupt will not be changed. Interrupts can be disabled with
3135 function sDisInterrupts().
3136
3137 This function sets the appropriate bit for the channel in the AIOP's
3138 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3139 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3140
3141 Interrupts must also be globally enabled before channel interrupts
3142 will be passed on to the host. This is done with function
3143 sEnGlobalInt().
3144
3145 In some cases it may be desirable to disable interrupts globally but
3146 enable channel interrupts. This would allow the global interrupt
3147 status register to be used to determine which AIOPs need service.
3148*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003149static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150{
3151 Byte_t Mask; /* Interrupt Mask Register */
3152
3153 ChP->RxControl[2] |=
3154 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3155
3156 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]);
3157
3158 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3159
3160 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]);
3161
3162 if (Flags & CHANINT_EN) {
3163 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3164 sOutB(ChP->IntMask, Mask);
3165 }
3166}
3167
3168/***************************************************************************
3169Function: sDisInterrupts
3170Purpose: Disable one or more interrupts for a channel
3171Call: sDisInterrupts(ChP,Flags)
3172 CHANNEL_T *ChP; Ptr to channel structure
3173 Word_t Flags: Interrupt flags, can be any combination
3174 of the following flags:
3175 TXINT_EN: Interrupt on Tx FIFO empty
3176 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3177 sSetRxTrigger())
3178 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3179 MCINT_EN: Interrupt on modem input change
3180 CHANINT_EN: Disable channel interrupt signal to the
3181 AIOP's Interrupt Channel Register.
3182Return: void
3183Comments: If an interrupt flag is set in Flags, that interrupt will be
3184 disabled. If an interrupt flag is not set in Flags, that
3185 interrupt will not be changed. Interrupts can be enabled with
3186 function sEnInterrupts().
3187
3188 This function clears the appropriate bit for the channel in the AIOP's
3189 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3190 this channel's bit from being set in the AIOP's Interrupt Channel
3191 Register.
3192*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003193static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194{
3195 Byte_t Mask; /* Interrupt Mask Register */
3196
3197 ChP->RxControl[2] &=
3198 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3199 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]);
3200 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
3201 sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]);
3202
3203 if (Flags & CHANINT_EN) {
3204 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3205 sOutB(ChP->IntMask, Mask);
3206 }
3207}
3208
Adrian Bunkf15313b2005-06-25 14:59:05 -07003209static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210{
3211 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3212}
3213
3214/*
3215 * Not an official SSCI function, but how to reset RocketModems.
3216 * ISA bus version
3217 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003218static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
3220 ByteIO_t addr;
3221 Byte_t val;
3222
3223 addr = CtlP->AiopIO[0] + 0x400;
3224 val = sInB(CtlP->MReg3IO);
3225 /* if AIOP[1] is not enabled, enable it */
3226 if ((val & 2) == 0) {
3227 val = sInB(CtlP->MReg2IO);
3228 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3229 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3230 }
3231
3232 sEnAiop(CtlP, 1);
3233 if (!on)
3234 addr += 8;
3235 sOutB(addr + chan, 0); /* apply or remove reset */
3236 sDisAiop(CtlP, 1);
3237}
3238
3239/*
3240 * Not an official SSCI function, but how to reset RocketModems.
3241 * PCI bus version
3242 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003243static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244{
3245 ByteIO_t addr;
3246
3247 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3248 if (!on)
3249 addr += 8;
3250 sOutB(addr + chan, 0); /* apply or remove reset */
3251}
3252
3253/* Resets the speaker controller on RocketModem II and III devices */
3254static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3255{
3256 ByteIO_t addr;
3257
3258 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3259 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3260 addr = CtlP->AiopIO[0] + 0x4F;
3261 sOutB(addr, 0);
3262 }
3263
3264 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3265 if ((model == MODEL_UPCI_RM3_8PORT)
3266 || (model == MODEL_UPCI_RM3_4PORT)) {
3267 addr = CtlP->AiopIO[0] + 0x88;
3268 sOutB(addr, 0);
3269 }
3270}
3271
3272/* Returns the line number given the controller (board), aiop and channel number */
3273static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3274{
3275 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3276}
3277
3278/*
3279 * Stores the line number associated with a given controller (board), aiop
3280 * and channel number.
3281 * Returns: The line number assigned
3282 */
3283static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3284{
3285 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3286 return (nextLineNumber - 1);
3287}