blob: 7f3b1db8806130b165e823744cb9a6f3f9568beb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * RocketPort device driver for Linux
3 *
4 * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000.
5 *
6 * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * Kernel Synchronization:
25 *
26 * This driver has 2 kernel control paths - exception handlers (calls into the driver
27 * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts
28 * are not used.
29 *
30 * Critical data:
31 * - rp_table[], accessed through passed "info" pointers, is a global (static) array of
32 * serial port state information and the xmit_buf circular buffer. Protected by
33 * a per port spinlock.
34 * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there
35 * is data to be transmitted. Protected by atomic bit operations.
36 * - rp_num_ports, int indicating number of open ports, protected by atomic operations.
37 *
38 * rp_write() and rp_write_char() functions use a per port semaphore to protect against
39 * simultaneous access to the same port by more than one process.
40 */
41
42/****** Defines ******/
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define ROCKET_PARANOIA_CHECK
44#define ROCKET_DISABLE_SIMUSAGE
45
46#undef ROCKET_SOFT_FLOW
47#undef ROCKET_DEBUG_OPEN
48#undef ROCKET_DEBUG_INTR
49#undef ROCKET_DEBUG_WRITE
50#undef ROCKET_DEBUG_FLOW
51#undef ROCKET_DEBUG_THROTTLE
52#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
53#undef ROCKET_DEBUG_RECEIVE
54#undef ROCKET_DEBUG_HANGUP
55#undef REV_PCI_ORDER
56#undef ROCKET_DEBUG_IO
57
Cong Ding37c44b52013-01-12 05:42:07 +010058#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/****** Kernel includes ******/
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <linux/module.h>
63#include <linux/errno.h>
64#include <linux/major.h>
65#include <linux/kernel.h>
66#include <linux/signal.h>
67#include <linux/slab.h>
68#include <linux/mm.h>
69#include <linux/sched.h>
70#include <linux/timer.h>
71#include <linux/interrupt.h>
72#include <linux/tty.h>
73#include <linux/tty_driver.h>
74#include <linux/tty_flip.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010075#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/string.h>
77#include <linux/fcntl.h>
78#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070079#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include <linux/ioport.h>
81#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070082#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/wait.h>
84#include <linux/pci.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010085#include <linux/uaccess.h>
Arun Sharma600634972011-07-26 16:09:06 -070086#include <linux/atomic.h>
Al Viro457fb602008-03-19 16:27:48 +000087#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/bitops.h>
89#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/init.h>
91
92/****** RocketPort includes ******/
93
94#include "rocket_int.h"
95#include "rocket.h"
96
97#define ROCKET_VERSION "2.09"
98#define ROCKET_DATE "12-June-2003"
99
100/****** RocketPort Local Variables ******/
101
Jiri Slaby40565f12007-02-12 00:52:31 -0800102static void rp_do_poll(unsigned long dummy);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static struct tty_driver *rocket_driver;
105
106static struct rocket_version driver_version = {
107 ROCKET_VERSION, ROCKET_DATE
108};
109
110static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
111static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
112 /* eg. Bit 0 indicates port 0 has xmit data, ... */
113static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800114static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
117static unsigned long board2;
118static unsigned long board3;
119static unsigned long board4;
120static unsigned long controller;
Rusty Russell90ab5ee2012-01-13 09:32:20 +1030121static bool support_low_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static unsigned long modem1;
123static unsigned long modem2;
124static unsigned long modem3;
125static unsigned long modem4;
126static unsigned long pc104_1[8];
127static unsigned long pc104_2[8];
128static unsigned long pc104_3[8];
129static unsigned long pc104_4[8];
130static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
131
132static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
133static unsigned long rcktpt_io_addr[NUM_BOARDS];
134static int rcktpt_type[NUM_BOARDS];
135static int is_PCI[NUM_BOARDS];
136static rocketModel_t rocketModel[NUM_BOARDS];
137static int max_board;
Alan Cox31f35932009-01-02 13:45:05 +0000138static const struct tty_port_operations rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140/*
141 * The following arrays define the interrupt bits corresponding to each AIOP.
142 * These bits are different between the ISA and regular PCI boards and the
143 * Universal PCI boards.
144 */
145
146static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
147 AIOP_INTR_BIT_0,
148 AIOP_INTR_BIT_1,
149 AIOP_INTR_BIT_2,
150 AIOP_INTR_BIT_3
151};
152
Jiri Slaby416187c2013-04-25 15:36:48 +0200153#ifdef CONFIG_PCI
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
155 UPCI_AIOP_INTR_BIT_0,
156 UPCI_AIOP_INTR_BIT_1,
157 UPCI_AIOP_INTR_BIT_2,
158 UPCI_AIOP_INTR_BIT_3
159};
Jiri Slaby416187c2013-04-25 15:36:48 +0200160#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Adrian Bunkf15313b2005-06-25 14:59:05 -0700162static Byte_t RData[RDATASIZE] = {
163 0x00, 0x09, 0xf6, 0x82,
164 0x02, 0x09, 0x86, 0xfb,
165 0x04, 0x09, 0x00, 0x0a,
166 0x06, 0x09, 0x01, 0x0a,
167 0x08, 0x09, 0x8a, 0x13,
168 0x0a, 0x09, 0xc5, 0x11,
169 0x0c, 0x09, 0x86, 0x85,
170 0x0e, 0x09, 0x20, 0x0a,
171 0x10, 0x09, 0x21, 0x0a,
172 0x12, 0x09, 0x41, 0xff,
173 0x14, 0x09, 0x82, 0x00,
174 0x16, 0x09, 0x82, 0x7b,
175 0x18, 0x09, 0x8a, 0x7d,
176 0x1a, 0x09, 0x88, 0x81,
177 0x1c, 0x09, 0x86, 0x7a,
178 0x1e, 0x09, 0x84, 0x81,
179 0x20, 0x09, 0x82, 0x7c,
180 0x22, 0x09, 0x0a, 0x0a
181};
182
183static Byte_t RRegData[RREGDATASIZE] = {
184 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
185 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
186 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
187 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
188 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
189 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
190 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
191 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
192 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
193 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
194 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
195 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
196 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
197};
198
199static CONTROLLER_T sController[CTL_SIZE] = {
200 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
201 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
202 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
203 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
204 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
205 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
206 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
207 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
208};
209
210static Byte_t sBitMapClrTbl[8] = {
211 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
212};
213
214static Byte_t sBitMapSetTbl[8] = {
215 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
216};
217
218static int sClockPrescale = 0x14;
219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220/*
221 * Line number is the ttySIx number (x), the Minor number. We
222 * assign them sequentially, starting at zero. The following
223 * array keeps track of the line number assigned to a given board/aiop/channel.
224 */
225static unsigned char lineNumbers[MAX_RP_PORTS];
226static unsigned long nextLineNumber;
227
228/***** RocketPort Static Prototypes *********/
229static int __init init_ISA(int i);
230static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
231static void rp_flush_buffer(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
233static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
234static void rp_start(struct tty_struct *tty);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700235static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
236 int ChanNum);
237static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
238static void sFlushRxFIFO(CHANNEL_T * ChP);
239static void sFlushTxFIFO(CHANNEL_T * ChP);
240static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
241static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
242static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
243static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
244static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700245static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
246 ByteIO_t * AiopIOList, int AiopIOListSize,
247 int IRQNum, Byte_t Frequency, int PeriodicOnly);
248static int sReadAiopID(ByteIO_t io);
249static int sReadAiopNumChan(WordIO_t io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251MODULE_AUTHOR("Theodore Ts'o");
252MODULE_DESCRIPTION("Comtrol RocketPort driver");
253module_param(board1, ulong, 0);
254MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
255module_param(board2, ulong, 0);
256MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
257module_param(board3, ulong, 0);
258MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
259module_param(board4, ulong, 0);
260MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
261module_param(controller, ulong, 0);
262MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
263module_param(support_low_speed, bool, 0);
264MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
265module_param(modem1, ulong, 0);
266MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem");
267module_param(modem2, ulong, 0);
268MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem");
269module_param(modem3, ulong, 0);
270MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem");
271module_param(modem4, ulong, 0);
272MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem");
273module_param_array(pc104_1, ulong, NULL, 0);
274MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,...");
275module_param_array(pc104_2, ulong, NULL, 0);
276MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,...");
277module_param_array(pc104_3, ulong, NULL, 0);
278MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,...");
279module_param_array(pc104_4, ulong, NULL, 0);
280MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
281
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -0800282static int rp_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283static void rp_cleanup_module(void);
284
285module_init(rp_init);
286module_exit(rp_cleanup_module);
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289MODULE_LICENSE("Dual BSD/GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291/*************************************************************************/
292/* Module code starts here */
293
294static inline int rocket_paranoia_check(struct r_port *info,
295 const char *routine)
296{
297#ifdef ROCKET_PARANOIA_CHECK
298 if (!info)
299 return 1;
300 if (info->magic != RPORT_MAGIC) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800301 printk(KERN_WARNING "Warning: bad magic number for rocketport "
302 "struct in %s\n", routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 return 1;
304 }
305#endif
306 return 0;
307}
308
309
310/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals
311 * that receive data is present on a serial port. Pulls data from FIFO, moves it into the
312 * tty layer.
313 */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100314static void rp_do_receive(struct r_port *info, CHANNEL_t *cp,
315 unsigned int ChanStatus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700318 int ToRecv, wRecv, space;
319 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800323 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700325 if (ToRecv == 0)
326 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 /*
329 * if status indicates there are errored characters in the
330 * FIFO, then enter status mode (a word in FIFO holds
331 * character and status).
332 */
333 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
334 if (!(ChanStatus & STATMODE)) {
335#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800336 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337#endif
338 ChanStatus |= STATMODE;
339 sEnRxStatusMode(cp);
340 }
341 }
342
343 /*
344 * if we previously entered status mode, then read down the
345 * FIFO one word at a time, pulling apart the character and
346 * the status. Update error counters depending on status
347 */
348 if (ChanStatus & STATMODE) {
349#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800350 printk(KERN_INFO "Ignore %x, read %x...\n",
351 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352#endif
353 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700354 char flag;
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 CharNStat = sInW(sGetTxRxDataIO(cp));
357#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800358 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359#endif
360 if (CharNStat & STMBREAKH)
361 CharNStat &= ~(STMFRAMEH | STMPARITYH);
362 if (CharNStat & info->ignore_status_mask) {
363 ToRecv--;
364 continue;
365 }
366 CharNStat &= info->read_status_mask;
367 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700368 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700370 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700372 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700374 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700376 flag = TTY_NORMAL;
Jiri Slaby92a19f92013-01-03 15:53:03 +0100377 tty_insert_flip_char(&info->port, CharNStat & 0xff,
378 flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 ToRecv--;
380 }
381
382 /*
383 * after we've emptied the FIFO in status mode, turn
384 * status mode back off
385 */
386 if (sGetRxCnt(cp) == 0) {
387#ifdef ROCKET_DEBUG_RECEIVE
388 printk(KERN_INFO "Status mode off.\n");
389#endif
390 sDisRxStatusMode(cp);
391 }
392 } else {
393 /*
394 * we aren't in status mode, so read down the FIFO two
395 * characters at time by doing repeated word IO
396 * transfer.
397 */
Jiri Slaby2f693352013-01-03 15:53:02 +0100398 space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv);
Paul Fulghumcc44a812006-06-25 05:49:12 -0700399 if (space < ToRecv) {
400#ifdef ROCKET_DEBUG_RECEIVE
401 printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
402#endif
403 if (space <= 0)
404 return;
405 ToRecv = space;
406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 wRecv = ToRecv >> 1;
408 if (wRecv)
409 sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
410 if (ToRecv & 1)
411 cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 }
413 /* Push the data up to the tty layer */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100414 tty_flip_buffer_push(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415}
416
417/*
418 * Serial port transmit data function. Called from the timer polling loop as a
419 * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready
420 * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is
421 * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks.
422 */
423static void rp_do_transmit(struct r_port *info)
424{
425 int c;
426 CHANNEL_t *cp = &info->channel;
427 struct tty_struct *tty;
428 unsigned long flags;
429
430#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800431 printk(KERN_DEBUG "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432#endif
433 if (!info)
434 return;
Alan Cox47b01b32009-01-02 13:48:30 +0000435 tty = tty_port_tty_get(&info->port);
436
437 if (tty == NULL) {
438 printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
440 return;
441 }
442
443 spin_lock_irqsave(&info->slock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
445
446 /* Loop sending data to FIFO until done or FIFO full */
447 while (1) {
Jiri Slabyee797062013-03-07 13:12:34 +0100448 if (tty->stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 break;
Harvey Harrison709107f2008-04-30 00:53:51 -0700450 c = min(info->xmit_fifo_room, info->xmit_cnt);
451 c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 if (c <= 0 || info->xmit_fifo_room <= 0)
453 break;
454 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
455 if (c & 1)
456 sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]);
457 info->xmit_tail += c;
458 info->xmit_tail &= XMIT_BUF_SIZE - 1;
459 info->xmit_cnt -= c;
460 info->xmit_fifo_room -= c;
461#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800462 printk(KERN_INFO "tx %d chars...\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463#endif
464 }
465
466 if (info->xmit_cnt == 0)
467 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
468
469 if (info->xmit_cnt < WAKEUP_CHARS) {
470 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471#ifdef ROCKETPORT_HAVE_POLL_WAIT
472 wake_up_interruptible(&tty->poll_wait);
473#endif
474 }
475
476 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox47b01b32009-01-02 13:48:30 +0000477 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
479#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800480 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 info->xmit_tail, info->xmit_fifo_room);
482#endif
483}
484
485/*
486 * Called when a serial port signals it has read data in it's RX FIFO.
487 * It checks what interrupts are pending and services them, including
488 * receiving serial data.
489 */
490static void rp_handle_port(struct r_port *info)
491{
492 CHANNEL_t *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 unsigned int IntMask, ChanStatus;
494
495 if (!info)
496 return;
497
Peter Hurleyd41861c2016-04-09 17:53:25 -0700498 if (!tty_port_initialized(&info->port)) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800499 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
500 "info->flags & NOT_INIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return;
502 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
506 IntMask = sGetChanIntID(cp) & info->intmask;
507#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800508 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509#endif
510 ChanStatus = sGetChanStatus(cp);
511 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100512 rp_do_receive(info, cp, ChanStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 }
514 if (IntMask & DELTA_CD) { /* CD change */
515#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800516 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 (ChanStatus & CD_ACT) ? "on" : "off");
518#endif
519 if (!(ChanStatus & CD_ACT) && info->cd_status) {
520#ifdef ROCKET_DEBUG_HANGUP
521 printk(KERN_INFO "CD drop, calling hangup.\n");
522#endif
Jiri Slabyaa27a092013-03-07 13:12:30 +0100523 tty_port_tty_hangup(&info->port, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
525 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100526 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 }
528#ifdef ROCKET_DEBUG_INTR
529 if (IntMask & DELTA_CTS) { /* CTS change */
530 printk(KERN_INFO "CTS change...\n");
531 }
532 if (IntMask & DELTA_DSR) { /* DSR change */
533 printk(KERN_INFO "DSR change...\n");
534 }
535#endif
536}
537
538/*
539 * The top level polling routine. Repeats every 1/100 HZ (10ms).
540 */
541static void rp_do_poll(unsigned long dummy)
542{
543 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700544 int ctrl, aiop, ch, line;
545 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 unsigned int CtlMask;
547 unsigned char AiopMask;
548 Word_t bit;
549
550 /* Walk through all the boards (ctrl's) */
551 for (ctrl = 0; ctrl < max_board; ctrl++) {
552 if (rcktpt_io_addr[ctrl] <= 0)
553 continue;
554
555 /* Get a ptr to the board's control struct */
556 ctlp = sCtlNumToCtlPtr(ctrl);
557
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200558 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559#ifdef CONFIG_PCI
560 if (ctlp->BusType == isPCI)
561 CtlMask = sPCIGetControllerIntStatus(ctlp);
562 else
563#endif
564 CtlMask = sGetControllerIntStatus(ctlp);
565
566 /* Check if any AIOP read bits are set */
567 for (aiop = 0; CtlMask; aiop++) {
568 bit = ctlp->AiopIntrBits[aiop];
569 if (CtlMask & bit) {
570 CtlMask &= ~bit;
571 AiopMask = sGetAiopIntStatus(ctlp, aiop);
572
573 /* Check if any port read bits are set */
574 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
575 if (AiopMask & 1) {
576
577 /* Get the line number (/dev/ttyRx number). */
578 /* Read the data from the port. */
579 line = GetLineNumber(ctrl, aiop, ch);
580 rp_handle_port(rp_table[line]);
581 }
582 }
583 }
584 }
585
586 xmitmask = xmit_flags[ctrl];
587
588 /*
589 * xmit_flags contains bit-significant flags, indicating there is data
590 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
591 * 1, ... (32 total possible). The variable i has the aiop and ch
592 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
593 */
594 if (xmitmask) {
595 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
596 if (xmitmask & (1 << i)) {
597 aiop = (i & 0x18) >> 3;
598 ch = i & 0x07;
599 line = GetLineNumber(ctrl, aiop, ch);
600 rp_do_transmit(rp_table[line]);
601 }
602 }
603 }
604 }
605
606 /*
607 * Reset the timer so we get called at the next clock tick (10ms).
608 */
609 if (atomic_read(&rp_num_ports_open))
610 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
611}
612
613/*
614 * Initializes the r_port structure for a port, as well as enabling the port on
615 * the board.
616 * Inputs: board, aiop, chan numbers
617 */
618static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
619{
620 unsigned rocketMode;
621 struct r_port *info;
622 int line;
623 CONTROLLER_T *ctlp;
624
625 /* Get the next available line number */
626 line = SetLineNumber(board, aiop, chan);
627
628 ctlp = sCtlNumToCtlPtr(board);
629
630 /* 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 -0700631 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800633 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
634 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return;
636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 info->magic = RPORT_MAGIC;
639 info->line = line;
640 info->ctlp = ctlp;
641 info->board = board;
642 info->aiop = aiop;
643 info->chan = chan;
Alan Cox31f35932009-01-02 13:45:05 +0000644 tty_port_init(&info->port);
645 info->port.ops = &rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 info->flags &= ~ROCKET_MODE_MASK;
647 switch (pc104[board][line]) {
648 case 422:
649 info->flags |= ROCKET_MODE_RS422;
650 break;
651 case 485:
652 info->flags |= ROCKET_MODE_RS485;
653 break;
654 case 232:
655 default:
656 info->flags |= ROCKET_MODE_RS232;
657 break;
658 }
659
660 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
661 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800662 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
663 board, aiop, chan);
Jiri Slaby191c5f12012-11-15 09:49:56 +0100664 tty_port_destroy(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 kfree(info);
666 return;
667 }
668
669 rocketMode = info->flags & ROCKET_MODE_MASK;
670
671 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
672 sEnRTSToggle(&info->channel);
673 else
674 sDisRTSToggle(&info->channel);
675
676 if (ctlp->boardType == ROCKET_TYPE_PC104) {
677 switch (rocketMode) {
678 case ROCKET_MODE_RS485:
679 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
680 break;
681 case ROCKET_MODE_RS422:
682 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
683 break;
684 case ROCKET_MODE_RS232:
685 default:
686 if (info->flags & ROCKET_RTS_TOGGLE)
687 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
688 else
689 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
690 break;
691 }
692 }
693 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700694 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 rp_table[line] = info;
Jiri Slaby734cc172012-08-07 21:47:47 +0200696 tty_port_register_device(&info->port, rocket_driver, line,
697 pci_dev ? &pci_dev->dev : NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
700/*
701 * Configures a rocketport port according to its termio settings. Called from
702 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
703 */
Alan Cox47b01b32009-01-02 13:48:30 +0000704static void configure_r_port(struct tty_struct *tty, struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800705 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
707 unsigned cflag;
708 unsigned long flags;
709 unsigned rocketMode;
710 int bits, baud, divisor;
711 CHANNEL_t *cp;
Alan Coxadc8d742012-07-14 15:31:47 +0100712 struct ktermios *t = &tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800715 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 /* Byte size and parity */
718 if ((cflag & CSIZE) == CS8) {
719 sSetData8(cp);
720 bits = 10;
721 } else {
722 sSetData7(cp);
723 bits = 9;
724 }
725 if (cflag & CSTOPB) {
726 sSetStop2(cp);
727 bits++;
728 } else {
729 sSetStop1(cp);
730 }
731
732 if (cflag & PARENB) {
733 sEnParity(cp);
734 bits++;
735 if (cflag & PARODD) {
736 sSetOddParity(cp);
737 } else {
738 sSetEvenParity(cp);
739 }
740 } else {
741 sDisParity(cp);
742 }
743
744 /* baud rate */
Alan Cox47b01b32009-01-02 13:48:30 +0000745 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (!baud)
747 baud = 9600;
748 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
749 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800750 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (!baud)
752 baud = 9600;
753 divisor = (rp_baud_base[info->board] / baud) - 1;
754 }
755 if (divisor >= 8192 || divisor < 0) {
756 baud = 9600;
757 divisor = (rp_baud_base[info->board] / baud) - 1;
758 }
759 info->cps = baud / bits;
760 sSetBaud(cp, divisor);
761
Alan Cox6df35262008-02-08 04:18:45 -0800762 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Cox47b01b32009-01-02 13:48:30 +0000763 tty_encode_baud_rate(tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (cflag & CRTSCTS) {
766 info->intmask |= DELTA_CTS;
767 sEnCTSFlowCtl(cp);
768 } else {
769 info->intmask &= ~DELTA_CTS;
770 sDisCTSFlowCtl(cp);
771 }
772 if (cflag & CLOCAL) {
773 info->intmask &= ~DELTA_CD;
774 } else {
775 spin_lock_irqsave(&info->slock, flags);
776 if (sGetChanStatus(cp) & CD_ACT)
777 info->cd_status = 1;
778 else
779 info->cd_status = 0;
780 info->intmask |= DELTA_CD;
781 spin_unlock_irqrestore(&info->slock, flags);
782 }
783
784 /*
785 * Handle software flow control in the board
786 */
787#ifdef ROCKET_SOFT_FLOW
Alan Cox47b01b32009-01-02 13:48:30 +0000788 if (I_IXON(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 sEnTxSoftFlowCtl(cp);
Alan Cox47b01b32009-01-02 13:48:30 +0000790 if (I_IXANY(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 sEnIXANY(cp);
792 } else {
793 sDisIXANY(cp);
794 }
Alan Cox47b01b32009-01-02 13:48:30 +0000795 sSetTxXONChar(cp, START_CHAR(tty));
796 sSetTxXOFFChar(cp, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 } else {
798 sDisTxSoftFlowCtl(cp);
799 sDisIXANY(cp);
800 sClrTxXOFF(cp);
801 }
802#endif
803
804 /*
805 * Set up ignore/read mask words
806 */
807 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Cox47b01b32009-01-02 13:48:30 +0000808 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000810 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 info->read_status_mask |= STMBREAKH;
812
813 /*
814 * Characters to ignore
815 */
816 info->ignore_status_mask = 0;
Alan Cox47b01b32009-01-02 13:48:30 +0000817 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000819 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 info->ignore_status_mask |= STMBREAKH;
821 /*
822 * If we're ignoring parity and break indicators,
823 * ignore overruns too. (For real raw support).
824 */
Alan Cox47b01b32009-01-02 13:48:30 +0000825 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 info->ignore_status_mask |= STMRCVROVRH;
827 }
828
829 rocketMode = info->flags & ROCKET_MODE_MASK;
830
831 if ((info->flags & ROCKET_RTS_TOGGLE)
832 || (rocketMode == ROCKET_MODE_RS485))
833 sEnRTSToggle(cp);
834 else
835 sDisRTSToggle(cp);
836
837 sSetRTS(&info->channel);
838
839 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
840 switch (rocketMode) {
841 case ROCKET_MODE_RS485:
842 sSetInterfaceMode(cp, InterfaceModeRS485);
843 break;
844 case ROCKET_MODE_RS422:
845 sSetInterfaceMode(cp, InterfaceModeRS422);
846 break;
847 case ROCKET_MODE_RS232:
848 default:
849 if (info->flags & ROCKET_RTS_TOGGLE)
850 sSetInterfaceMode(cp, InterfaceModeRS232T);
851 else
852 sSetInterfaceMode(cp, InterfaceModeRS232);
853 break;
854 }
855 }
856}
857
Alan Cox31f35932009-01-02 13:45:05 +0000858static int carrier_raised(struct tty_port *port)
859{
860 struct r_port *info = container_of(port, struct r_port, port);
861 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
862}
863
Alan Coxfcc8ac12009-06-11 12:24:17 +0100864static void dtr_rts(struct tty_port *port, int on)
Alan Cox5d951fb2009-01-02 13:45:19 +0000865{
866 struct r_port *info = container_of(port, struct r_port, port);
Alan Coxfcc8ac12009-06-11 12:24:17 +0100867 if (on) {
868 sSetDTR(&info->channel);
869 sSetRTS(&info->channel);
870 } else {
871 sClrDTR(&info->channel);
872 sClrRTS(&info->channel);
873 }
Alan Cox5d951fb2009-01-02 13:45:19 +0000874}
875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876/*
877 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
878 * port's r_port struct. Initializes the port hardware.
879 */
880static int rp_open(struct tty_struct *tty, struct file *filp)
881{
882 struct r_port *info;
Alan Coxfba85e02009-01-02 13:48:39 +0000883 struct tty_port *port;
Jiri Slaby410235f2012-03-05 14:52:01 +0100884 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 CHANNEL_t *cp;
886 unsigned long page;
887
Jiri Slaby410235f2012-03-05 14:52:01 +0100888 info = rp_table[tty->index];
889 if (info == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return -ENXIO;
Alan Coxfba85e02009-01-02 13:48:39 +0000891 port = &info->port;
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 page = __get_free_page(GFP_KERNEL);
894 if (!page)
895 return -ENOMEM;
896
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 /*
898 * We must not sleep from here until the port is marked fully in use.
899 */
900 if (info->xmit_buf)
901 free_page(page);
902 else
903 info->xmit_buf = (unsigned char *) page;
904
905 tty->driver_data = info;
Alan Coxfba85e02009-01-02 13:48:39 +0000906 tty_port_tty_set(port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Alan Coxfba85e02009-01-02 13:48:39 +0000908 if (port->count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 atomic_inc(&rp_num_ports_open);
910
911#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -0800912 printk(KERN_INFO "rocket mod++ = %d...\n",
913 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914#endif
915 }
916#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +0100917 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918#endif
919
920 /*
921 * Info->count is now 1; so it's safe to sleep now.
922 */
Peter Hurleyd41861c2016-04-09 17:53:25 -0700923 if (!tty_port_initialized(port)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 cp = &info->channel;
925 sSetRxTrigger(cp, TRIG_1);
926 if (sGetChanStatus(cp) & CD_ACT)
927 info->cd_status = 1;
928 else
929 info->cd_status = 0;
930 sDisRxStatusMode(cp);
931 sFlushRxFIFO(cp);
932 sFlushTxFIFO(cp);
933
934 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
935 sSetRxTrigger(cp, TRIG_1);
936
937 sGetChanStatus(cp);
938 sDisRxStatusMode(cp);
939 sClrTxXOFF(cp);
940
941 sDisCTSFlowCtl(cp);
942 sDisTxSoftFlowCtl(cp);
943
944 sEnRxFIFO(cp);
945 sEnTransmit(cp);
946
Peter Hurleyd41861c2016-04-09 17:53:25 -0700947 tty_port_set_initialized(&info->port, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 /*
950 * Set up the tty->alt_speed kludge
951 */
952 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +0000953 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000955 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000957 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +0000959 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Alan Cox47b01b32009-01-02 13:48:30 +0000961 configure_r_port(tty, info, NULL);
Peter Hurley9db276f2016-01-10 20:36:15 -0800962 if (C_BAUD(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 sSetDTR(cp);
964 sSetRTS(cp);
965 }
966 }
967 /* Starts (or resets) the maint polling loop */
968 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
969
Alan Coxfba85e02009-01-02 13:48:39 +0000970 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (retval) {
972#ifdef ROCKET_DEBUG_OPEN
973 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
974#endif
975 return retval;
976 }
977 return 0;
978}
979
980/*
Alan Coxe60a1082008-07-16 21:56:18 +0100981 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 */
983static void rp_close(struct tty_struct *tty, struct file *filp)
984{
Alan Coxc9f19e92009-01-02 13:47:26 +0000985 struct r_port *info = tty->driver_data;
Alan Coxc1314a42009-01-02 13:48:17 +0000986 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int timeout;
988 CHANNEL_t *cp;
989
990 if (rocket_paranoia_check(info, "rp_close"))
991 return;
992
993#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +0100994 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995#endif
996
Alan Coxfba85e02009-01-02 13:48:39 +0000997 if (tty_port_close_start(port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Alan Cox417b6e02010-06-01 22:52:45 +02001000 mutex_lock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 /*
1003 * Before we drop DTR, make sure the UART transmitter
1004 * has completely drained; this is especially
1005 * important if there is a transmit FIFO!
1006 */
1007 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1008 if (timeout == 0)
1009 timeout = 1;
1010 rp_wait_until_sent(tty, timeout);
1011 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1012
1013 sDisTransmit(cp);
1014 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1015 sDisCTSFlowCtl(cp);
1016 sDisTxSoftFlowCtl(cp);
1017 sClrTxXOFF(cp);
1018 sFlushRxFIFO(cp);
1019 sFlushTxFIFO(cp);
1020 sClrRTS(cp);
1021 if (C_HUPCL(tty))
1022 sClrDTR(cp);
1023
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001024 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 tty_ldisc_flush(tty);
1027
1028 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1029
Alan Coxfba85e02009-01-02 13:48:39 +00001030 /* We can't yet use tty_port_close_end as the buffer handling in this
1031 driver is a bit different to the usual */
1032
Alan Coxc1314a42009-01-02 13:48:17 +00001033 if (port->blocked_open) {
1034 if (port->close_delay) {
1035 msleep_interruptible(jiffies_to_msecs(port->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 }
Alan Coxc1314a42009-01-02 13:48:17 +00001037 wake_up_interruptible(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 } else {
1039 if (info->xmit_buf) {
1040 free_page((unsigned long) info->xmit_buf);
1041 info->xmit_buf = NULL;
1042 }
1043 }
Alan Cox417b6e02010-06-01 22:52:45 +02001044 spin_lock_irq(&port->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 tty->closing = 0;
Alan Cox417b6e02010-06-01 22:52:45 +02001046 spin_unlock_irq(&port->lock);
Peter Hurleyd41861c2016-04-09 17:53:25 -07001047 tty_port_set_initialized(port, 0);
Peter Hurley807c8d812016-04-09 17:53:22 -07001048 tty_port_set_active(port, 0);
Alan Cox417b6e02010-06-01 22:52:45 +02001049 mutex_unlock(&port->mutex);
Alan Coxfba85e02009-01-02 13:48:39 +00001050 tty_port_tty_set(port, NULL);
Alan Cox417b6e02010-06-01 22:52:45 +02001051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 atomic_dec(&rp_num_ports_open);
1053
1054#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001055 printk(KERN_INFO "rocket mod-- = %d...\n",
1056 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1058#endif
1059
1060}
1061
1062static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001063 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Alan Coxc9f19e92009-01-02 13:47:26 +00001065 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 CHANNEL_t *cp;
1067 unsigned cflag;
1068
1069 if (rocket_paranoia_check(info, "rp_set_termios"))
1070 return;
1071
Alan Coxadc8d742012-07-14 15:31:47 +01001072 cflag = tty->termios.c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 /*
1075 * This driver doesn't support CS5 or CS6
1076 */
1077 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
Alan Coxadc8d742012-07-14 15:31:47 +01001078 tty->termios.c_cflag =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001080 /* Or CMSPAR */
Alan Coxadc8d742012-07-14 15:31:47 +01001081 tty->termios.c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Alan Cox47b01b32009-01-02 13:48:30 +00001083 configure_r_port(tty, info, old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085 cp = &info->channel;
1086
1087 /* Handle transition to B0 status */
Peter Hurley9db276f2016-01-10 20:36:15 -08001088 if ((old_termios->c_cflag & CBAUD) && !C_BAUD(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 sClrDTR(cp);
1090 sClrRTS(cp);
1091 }
1092
1093 /* Handle transition away from B0 status */
Peter Hurley9db276f2016-01-10 20:36:15 -08001094 if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
Jiri Slabyee797062013-03-07 13:12:34 +01001095 sSetRTS(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 sSetDTR(cp);
1097 }
1098
Peter Hurley9db276f2016-01-10 20:36:15 -08001099 if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 rp_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101}
1102
Alan Cox9e989662008-07-22 11:18:03 +01001103static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104{
Alan Coxc9f19e92009-01-02 13:47:26 +00001105 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 unsigned long flags;
1107
1108 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001109 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 spin_lock_irqsave(&info->slock, flags);
1112 if (break_state == -1)
1113 sSendBreak(&info->channel);
1114 else
1115 sClrBreak(&info->channel);
1116 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001117 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118}
1119
1120/*
1121 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1122 * the UPCI boards was added, it was decided to make this a function because
1123 * the macro was getting too complicated. All cases except the first one
1124 * (UPCIRingInd) are taken directly from the original macro.
1125 */
1126static int sGetChanRI(CHANNEL_T * ChP)
1127{
1128 CONTROLLER_t *CtlP = ChP->CtlP;
1129 int ChanNum = ChP->ChanNum;
1130 int RingInd = 0;
1131
1132 if (CtlP->UPCIRingInd)
1133 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1134 else if (CtlP->AltChanRingIndicator)
1135 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1136 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1137 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1138
1139 return RingInd;
1140}
1141
1142/********************************************************************************************/
1143/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1144
1145/*
1146 * Returns the state of the serial modem control lines. These next 2 functions
1147 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1148 */
Alan Cox60b33c12011-02-14 16:26:14 +00001149static int rp_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Alan Coxc9f19e92009-01-02 13:47:26 +00001151 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 unsigned int control, result, ChanStatus;
1153
1154 ChanStatus = sGetChanStatusLo(&info->channel);
1155 control = info->channel.TxControl[3];
1156 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1157 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1158 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1159 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1160 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1161 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1162
1163 return result;
1164}
1165
1166/*
1167 * Sets the modem control lines
1168 */
Alan Cox20b9d172011-02-14 16:26:50 +00001169static int rp_tiocmset(struct tty_struct *tty,
1170 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171{
Alan Coxc9f19e92009-01-02 13:47:26 +00001172 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174 if (set & TIOCM_RTS)
1175 info->channel.TxControl[3] |= SET_RTS;
1176 if (set & TIOCM_DTR)
1177 info->channel.TxControl[3] |= SET_DTR;
1178 if (clear & TIOCM_RTS)
1179 info->channel.TxControl[3] &= ~SET_RTS;
1180 if (clear & TIOCM_DTR)
1181 info->channel.TxControl[3] &= ~SET_DTR;
1182
Al Viro457fb602008-03-19 16:27:48 +00001183 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 return 0;
1185}
1186
1187static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1188{
1189 struct rocket_config tmp;
1190
1191 if (!retinfo)
1192 return -EFAULT;
1193 memset(&tmp, 0, sizeof (tmp));
Alan Cox417b6e02010-06-01 22:52:45 +02001194 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 tmp.line = info->line;
1196 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001197 tmp.close_delay = info->port.close_delay;
1198 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
Alan Cox417b6e02010-06-01 22:52:45 +02001200 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1203 return -EFAULT;
1204 return 0;
1205}
1206
Alan Cox47b01b32009-01-02 13:48:30 +00001207static int set_config(struct tty_struct *tty, struct r_port *info,
1208 struct rocket_config __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
1210 struct rocket_config new_serial;
1211
1212 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1213 return -EFAULT;
1214
Alan Cox417b6e02010-06-01 22:52:45 +02001215 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if (!capable(CAP_SYS_ADMIN))
1217 {
Alan Cox417b6e02010-06-01 22:52:45 +02001218 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) {
1219 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 return -EPERM;
Alan Cox417b6e02010-06-01 22:52:45 +02001221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
Alan Cox47b01b32009-01-02 13:48:30 +00001223 configure_r_port(tty, info, NULL);
Dan Carpenter49bf7ea2010-08-11 20:00:09 +02001224 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 return 0;
1226 }
1227
1228 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001229 info->port.close_delay = new_serial.close_delay;
1230 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +00001233 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001235 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001237 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +00001239 tty->alt_speed = 460800;
Alan Cox417b6e02010-06-01 22:52:45 +02001240 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Alan Cox47b01b32009-01-02 13:48:30 +00001242 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 return 0;
1244}
1245
1246/*
1247 * This function fills in a rocket_ports struct with information
1248 * about what boards/ports are in the system. This info is passed
1249 * to user space. See setrocket.c where the info is used to create
1250 * the /dev/ttyRx ports.
1251 */
1252static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1253{
1254 struct rocket_ports tmp;
1255 int board;
1256
1257 if (!retports)
1258 return -EFAULT;
1259 memset(&tmp, 0, sizeof (tmp));
1260 tmp.tty_major = rocket_driver->major;
1261
1262 for (board = 0; board < 4; board++) {
1263 tmp.rocketModel[board].model = rocketModel[board].model;
1264 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1265 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1266 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1267 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1268 }
1269 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1270 return -EFAULT;
1271 return 0;
1272}
1273
1274static int reset_rm2(struct r_port *info, void __user *arg)
1275{
1276 int reset;
1277
Alan Cox4129a6452008-02-08 04:18:45 -08001278 if (!capable(CAP_SYS_ADMIN))
1279 return -EPERM;
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 if (copy_from_user(&reset, arg, sizeof (int)))
1282 return -EFAULT;
1283 if (reset)
1284 reset = 1;
1285
1286 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1287 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1288 return -EINVAL;
1289
1290 if (info->ctlp->BusType == isISA)
1291 sModemReset(info->ctlp, info->chan, reset);
1292 else
1293 sPCIModemReset(info->ctlp, info->chan, reset);
1294
1295 return 0;
1296}
1297
1298static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1299{
1300 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1301 return -EFAULT;
1302 return 0;
1303}
1304
1305/* IOCTL call handler into the driver */
Alan Cox6caa76b2011-02-14 16:27:22 +00001306static int rp_ioctl(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 unsigned int cmd, unsigned long arg)
1308{
Alan Coxc9f19e92009-01-02 13:47:26 +00001309 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001311 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1314 return -ENXIO;
1315
1316 switch (cmd) {
1317 case RCKP_GET_STRUCT:
1318 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001319 ret = -EFAULT;
1320 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001322 ret = get_config(info, argp);
1323 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 case RCKP_SET_CONFIG:
Alan Cox47b01b32009-01-02 13:48:30 +00001325 ret = set_config(tty, info, argp);
Alan Coxbdf183a2008-04-30 00:53:21 -07001326 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001328 ret = get_ports(info, argp);
1329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001331 ret = reset_rm2(info, argp);
1332 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001334 ret = get_version(info, argp);
1335 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001337 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001339 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340}
1341
1342static void rp_send_xchar(struct tty_struct *tty, char ch)
1343{
Alan Coxc9f19e92009-01-02 13:47:26 +00001344 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 CHANNEL_t *cp;
1346
1347 if (rocket_paranoia_check(info, "rp_send_xchar"))
1348 return;
1349
1350 cp = &info->channel;
1351 if (sGetTxCnt(cp))
1352 sWriteTxPrioByte(cp, ch);
1353 else
1354 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1355}
1356
1357static void rp_throttle(struct tty_struct *tty)
1358{
Alan Coxc9f19e92009-01-02 13:47:26 +00001359 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361#ifdef ROCKET_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08001362 printk(KERN_INFO "throttle %s ....\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363#endif
1364
1365 if (rocket_paranoia_check(info, "rp_throttle"))
1366 return;
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (I_IXOFF(tty))
1369 rp_send_xchar(tty, STOP_CHAR(tty));
1370
1371 sClrRTS(&info->channel);
1372}
1373
1374static void rp_unthrottle(struct tty_struct *tty)
1375{
Alan Coxc9f19e92009-01-02 13:47:26 +00001376 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377#ifdef ROCKET_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08001378 printk(KERN_INFO "unthrottle %s ....\n", tty->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379#endif
1380
Julia Lawalle5f50fb2014-12-07 20:21:01 +01001381 if (rocket_paranoia_check(info, "rp_unthrottle"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return;
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 if (I_IXOFF(tty))
1385 rp_send_xchar(tty, START_CHAR(tty));
1386
1387 sSetRTS(&info->channel);
1388}
1389
1390/*
1391 * ------------------------------------------------------------
1392 * rp_stop() and rp_start()
1393 *
1394 * This routines are called before setting or resetting tty->stopped.
1395 * They enable or disable transmitter interrupts, as necessary.
1396 * ------------------------------------------------------------
1397 */
1398static void rp_stop(struct tty_struct *tty)
1399{
Alan Coxc9f19e92009-01-02 13:47:26 +00001400 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402#ifdef ROCKET_DEBUG_FLOW
1403 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1404 info->xmit_cnt, info->xmit_fifo_room);
1405#endif
1406
1407 if (rocket_paranoia_check(info, "rp_stop"))
1408 return;
1409
1410 if (sGetTxCnt(&info->channel))
1411 sDisTransmit(&info->channel);
1412}
1413
1414static void rp_start(struct tty_struct *tty)
1415{
Alan Coxc9f19e92009-01-02 13:47:26 +00001416 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418#ifdef ROCKET_DEBUG_FLOW
1419 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1420 info->xmit_cnt, info->xmit_fifo_room);
1421#endif
1422
1423 if (rocket_paranoia_check(info, "rp_stop"))
1424 return;
1425
1426 sEnTransmit(&info->channel);
1427 set_bit((info->aiop * 8) + info->chan,
1428 (void *) &xmit_flags[info->board]);
1429}
1430
1431/*
1432 * rp_wait_until_sent() --- wait until the transmitter is empty
1433 */
1434static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1435{
Alan Coxc9f19e92009-01-02 13:47:26 +00001436 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 CHANNEL_t *cp;
1438 unsigned long orig_jiffies;
1439 int check_time, exit_time;
1440 int txcnt;
1441
1442 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1443 return;
1444
1445 cp = &info->channel;
1446
1447 orig_jiffies = jiffies;
1448#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Julia Lawalle5f50fb2014-12-07 20:21:01 +01001449 printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001451 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452#endif
1453 while (1) {
1454 txcnt = sGetTxCnt(cp);
1455 if (!txcnt) {
1456 if (sGetChanStatusLo(cp) & TXSHRMT)
1457 break;
1458 check_time = (HZ / info->cps) / 5;
1459 } else {
1460 check_time = HZ * txcnt / info->cps;
1461 }
1462 if (timeout) {
1463 exit_time = orig_jiffies + timeout - jiffies;
1464 if (exit_time <= 0)
1465 break;
1466 if (exit_time < check_time)
1467 check_time = exit_time;
1468 }
1469 if (check_time == 0)
1470 check_time = 1;
1471#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001472 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1473 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474#endif
1475 msleep_interruptible(jiffies_to_msecs(check_time));
1476 if (signal_pending(current))
1477 break;
1478 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001479 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1481 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1482#endif
1483}
1484
1485/*
1486 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1487 */
1488static void rp_hangup(struct tty_struct *tty)
1489{
1490 CHANNEL_t *cp;
Alan Coxc9f19e92009-01-02 13:47:26 +00001491 struct r_port *info = tty->driver_data;
Alan Cox417b6e02010-06-01 22:52:45 +02001492 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
1494 if (rocket_paranoia_check(info, "rp_hangup"))
1495 return;
1496
1497#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001498 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499#endif
1500 rp_flush_buffer(tty);
Alan Cox417b6e02010-06-01 22:52:45 +02001501 spin_lock_irqsave(&info->port.lock, flags);
Alan Coxe60a1082008-07-16 21:56:18 +01001502 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 atomic_dec(&rp_num_ports_open);
1504 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
Alan Cox417b6e02010-06-01 22:52:45 +02001505 spin_unlock_irqrestore(&info->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Alan Coxfba85e02009-01-02 13:48:39 +00001507 tty_port_hangup(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
1509 cp = &info->channel;
1510 sDisRxFIFO(cp);
1511 sDisTransmit(cp);
1512 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1513 sDisCTSFlowCtl(cp);
1514 sDisTxSoftFlowCtl(cp);
1515 sClrTxXOFF(cp);
Peter Hurleyd41861c2016-04-09 17:53:25 -07001516 tty_port_set_initialized(&info->port, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Alan Coxe60a1082008-07-16 21:56:18 +01001518 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519}
1520
1521/*
1522 * Exception handler - write char routine. The RocketPort driver uses a
1523 * double-buffering strategy, with the twist that if the in-memory CPU
1524 * buffer is empty, and there's space in the transmit FIFO, the
1525 * writing routines will write directly to transmit FIFO.
1526 * Write buffer and counters protected by spinlocks
1527 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001528static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529{
Alan Coxc9f19e92009-01-02 13:47:26 +00001530 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 CHANNEL_t *cp;
1532 unsigned long flags;
1533
1534 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001535 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001537 /*
1538 * Grab the port write mutex, locking out other processes that try to
1539 * write to this port
1540 */
1541 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
1543#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001544 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545#endif
1546
1547 spin_lock_irqsave(&info->slock, flags);
1548 cp = &info->channel;
1549
Jiri Slabyee797062013-03-07 13:12:34 +01001550 if (!tty->stopped && info->xmit_fifo_room == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1552
Jiri Slabyee797062013-03-07 13:12:34 +01001553 if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 info->xmit_buf[info->xmit_head++] = ch;
1555 info->xmit_head &= XMIT_BUF_SIZE - 1;
1556 info->xmit_cnt++;
1557 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1558 } else {
1559 sOutB(sGetTxRxDataIO(cp), ch);
1560 info->xmit_fifo_room--;
1561 }
1562 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001563 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001564 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565}
1566
1567/*
1568 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001569 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 * this port at the same time. This other process could be running on the other CPU
1571 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1572 * Spinlocks protect the info xmit members.
1573 */
1574static int rp_write(struct tty_struct *tty,
1575 const unsigned char *buf, int count)
1576{
Alan Coxc9f19e92009-01-02 13:47:26 +00001577 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 CHANNEL_t *cp;
1579 const unsigned char *b;
1580 int c, retval = 0;
1581 unsigned long flags;
1582
1583 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1584 return 0;
1585
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001586 if (mutex_lock_interruptible(&info->write_mtx))
1587 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001590 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591#endif
1592 cp = &info->channel;
1593
Jiri Slabyee797062013-03-07 13:12:34 +01001594 if (!tty->stopped && info->xmit_fifo_room < count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1596
1597 /*
1598 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1599 * into FIFO. Use the write queue for temp storage.
1600 */
Jiri Slabyee797062013-03-07 13:12:34 +01001601 if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 c = min(count, info->xmit_fifo_room);
1603 b = buf;
1604
1605 /* Push data into FIFO, 2 bytes at a time */
1606 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1607
1608 /* If there is a byte remaining, write it */
1609 if (c & 1)
1610 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1611
1612 retval += c;
1613 buf += c;
1614 count -= c;
1615
1616 spin_lock_irqsave(&info->slock, flags);
1617 info->xmit_fifo_room -= c;
1618 spin_unlock_irqrestore(&info->slock, flags);
1619 }
1620
1621 /* If count is zero, we wrote it all and are done */
1622 if (!count)
1623 goto end;
1624
1625 /* Write remaining data into the port's xmit_buf */
1626 while (1) {
Alan Cox47b01b32009-01-02 13:48:30 +00001627 /* Hung up ? */
Peter Hurley807c8d812016-04-09 17:53:22 -07001628 if (!tty_port_active(&info->port))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001630 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1631 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 if (c <= 0)
1633 break;
1634
1635 b = buf;
1636 memcpy(info->xmit_buf + info->xmit_head, b, c);
1637
1638 spin_lock_irqsave(&info->slock, flags);
1639 info->xmit_head =
1640 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1641 info->xmit_cnt += c;
1642 spin_unlock_irqrestore(&info->slock, flags);
1643
1644 buf += c;
1645 count -= c;
1646 retval += c;
1647 }
1648
Jiri Slabyee797062013-03-07 13:12:34 +01001649 if ((retval > 0) && !tty->stopped)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1651
1652end:
1653 if (info->xmit_cnt < WAKEUP_CHARS) {
1654 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655#ifdef ROCKETPORT_HAVE_POLL_WAIT
1656 wake_up_interruptible(&tty->poll_wait);
1657#endif
1658 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001659 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 return retval;
1661}
1662
1663/*
1664 * Return the number of characters that can be sent. We estimate
1665 * only using the in-memory transmit buffer only, and ignore the
1666 * potential space in the transmit FIFO.
1667 */
1668static int rp_write_room(struct tty_struct *tty)
1669{
Alan Coxc9f19e92009-01-02 13:47:26 +00001670 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 int ret;
1672
1673 if (rocket_paranoia_check(info, "rp_write_room"))
1674 return 0;
1675
1676 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1677 if (ret < 0)
1678 ret = 0;
1679#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001680 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681#endif
1682 return ret;
1683}
1684
1685/*
1686 * Return the number of characters in the buffer. Again, this only
1687 * counts those characters in the in-memory transmit buffer.
1688 */
1689static int rp_chars_in_buffer(struct tty_struct *tty)
1690{
Alan Coxc9f19e92009-01-02 13:47:26 +00001691 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1694 return 0;
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001697 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698#endif
1699 return info->xmit_cnt;
1700}
1701
1702/*
1703 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1704 * r_port struct for the port. Note that spinlock are used to protect info members,
1705 * do not call this function if the spinlock is already held.
1706 */
1707static void rp_flush_buffer(struct tty_struct *tty)
1708{
Alan Coxc9f19e92009-01-02 13:47:26 +00001709 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 CHANNEL_t *cp;
1711 unsigned long flags;
1712
1713 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1714 return;
1715
1716 spin_lock_irqsave(&info->slock, flags);
1717 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1718 spin_unlock_irqrestore(&info->slock, flags);
1719
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720#ifdef ROCKETPORT_HAVE_POLL_WAIT
1721 wake_up_interruptible(&tty->poll_wait);
1722#endif
1723 tty_wakeup(tty);
1724
1725 cp = &info->channel;
1726 sFlushTxFIFO(cp);
1727}
1728
1729#ifdef CONFIG_PCI
1730
Jingoo Han311df742013-12-03 08:26:37 +09001731static const struct pci_device_id rocket_pci_ids[] = {
Kevin Cernekeeb9d42392013-01-16 20:28:39 -08001732 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },
1733 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },
1734 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) },
1735 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) },
1736 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) },
1737 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) },
1738 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) },
1739 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) },
1740 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) },
1741 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) },
1742 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) },
1743 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) },
1744 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) },
1745 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) },
1746 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) },
1747 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) },
1748 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) },
1749 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) },
1750 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) },
1751 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) },
1752 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) },
1753 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) },
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001754 { }
1755};
1756MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1757
Jiri Slaby416187c2013-04-25 15:36:48 +02001758/* Resets the speaker controller on RocketModem II and III devices */
1759static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
1760{
1761 ByteIO_t addr;
1762
1763 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
1764 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
1765 addr = CtlP->AiopIO[0] + 0x4F;
1766 sOutB(addr, 0);
1767 }
1768
1769 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
1770 if ((model == MODEL_UPCI_RM3_8PORT)
1771 || (model == MODEL_UPCI_RM3_4PORT)) {
1772 addr = CtlP->AiopIO[0] + 0x88;
1773 sOutB(addr, 0);
1774 }
1775}
1776
1777/***************************************************************************
1778Function: sPCIInitController
1779Purpose: Initialization of controller global registers and controller
1780 structure.
1781Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
1782 IRQNum,Frequency,PeriodicOnly)
1783 CONTROLLER_T *CtlP; Ptr to controller structure
1784 int CtlNum; Controller number
1785 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
1786 This list must be in the order the AIOPs will be found on the
1787 controller. Once an AIOP in the list is not found, it is
1788 assumed that there are no more AIOPs on the controller.
1789 int AiopIOListSize; Number of addresses in AiopIOList
1790 int IRQNum; Interrupt Request number. Can be any of the following:
1791 0: Disable global interrupts
1792 3: IRQ 3
1793 4: IRQ 4
1794 5: IRQ 5
1795 9: IRQ 9
1796 10: IRQ 10
1797 11: IRQ 11
1798 12: IRQ 12
1799 15: IRQ 15
1800 Byte_t Frequency: A flag identifying the frequency
1801 of the periodic interrupt, can be any one of the following:
1802 FREQ_DIS - periodic interrupt disabled
1803 FREQ_137HZ - 137 Hertz
1804 FREQ_69HZ - 69 Hertz
1805 FREQ_34HZ - 34 Hertz
1806 FREQ_17HZ - 17 Hertz
1807 FREQ_9HZ - 9 Hertz
1808 FREQ_4HZ - 4 Hertz
1809 If IRQNum is set to 0 the Frequency parameter is
1810 overidden, it is forced to a value of FREQ_DIS.
1811 int PeriodicOnly: 1 if all interrupts except the periodic
1812 interrupt are to be blocked.
1813 0 is both the periodic interrupt and
1814 other channel interrupts are allowed.
1815 If IRQNum is set to 0 the PeriodicOnly parameter is
1816 overidden, it is forced to a value of 0.
1817Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
1818 initialization failed.
1819
1820Comments:
1821 If periodic interrupts are to be disabled but AIOP interrupts
1822 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
1823
1824 If interrupts are to be completely disabled set IRQNum to 0.
1825
1826 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
1827 invalid combination.
1828
1829 This function performs initialization of global interrupt modes,
1830 but it does not actually enable global interrupts. To enable
1831 and disable global interrupts use functions sEnGlobalInt() and
1832 sDisGlobalInt(). Enabling of global interrupts is normally not
1833 done until all other initializations are complete.
1834
1835 Even if interrupts are globally enabled, they must also be
1836 individually enabled for each channel that is to generate
1837 interrupts.
1838
1839Warnings: No range checking on any of the parameters is done.
1840
1841 No context switches are allowed while executing this function.
1842
1843 After this function all AIOPs on the controller are disabled,
1844 they can be enabled with sEnAiop().
1845*/
1846static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
1847 ByteIO_t * AiopIOList, int AiopIOListSize,
1848 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
1849 int PeriodicOnly, int altChanRingIndicator,
1850 int UPCIRingInd)
1851{
1852 int i;
1853 ByteIO_t io;
1854
1855 CtlP->AltChanRingIndicator = altChanRingIndicator;
1856 CtlP->UPCIRingInd = UPCIRingInd;
1857 CtlP->CtlNum = CtlNum;
1858 CtlP->CtlID = CTLID_0001; /* controller release 1 */
1859 CtlP->BusType = isPCI; /* controller release 1 */
1860
1861 if (ConfigIO) {
1862 CtlP->isUPCI = 1;
1863 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
1864 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
1865 CtlP->AiopIntrBits = upci_aiop_intr_bits;
1866 } else {
1867 CtlP->isUPCI = 0;
1868 CtlP->PCIIO =
1869 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
1870 CtlP->AiopIntrBits = aiop_intr_bits;
1871 }
1872
1873 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
1874 /* Init AIOPs */
1875 CtlP->NumAiop = 0;
1876 for (i = 0; i < AiopIOListSize; i++) {
1877 io = AiopIOList[i];
1878 CtlP->AiopIO[i] = (WordIO_t) io;
1879 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
1880
1881 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
1882 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
1883 break; /* done looking for AIOPs */
1884
1885 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
1886 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
1887 sOutB(io + _INDX_DATA, sClockPrescale);
1888 CtlP->NumAiop++; /* bump count of AIOPs */
1889 }
1890
1891 if (CtlP->NumAiop == 0)
1892 return (-1);
1893 else
1894 return (CtlP->NumAiop);
1895}
1896
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897/*
1898 * Called when a PCI card is found. Retrieves and stores model information,
1899 * init's aiopic and serial port hardware.
1900 * Inputs: i is the board number (0-n)
1901 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001902static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
1904 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1905 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 CONTROLLER_t *ctlp;
1907
1908 int fast_clock = 0;
1909 int altChanRingIndicator = 0;
1910 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 WordIO_t ConfigIO = 0;
1912 ByteIO_t UPCIRingInd = 0;
1913
Kevin Cernekeeb9d42392013-01-16 20:28:39 -08001914 if (!dev || !pci_match_id(rocket_pci_ids, dev) ||
1915 pci_enable_device(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 return 0;
1917
1918 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1921 rocketModel[i].loadrm2 = 0;
1922 rocketModel[i].startingPortNumber = nextLineNumber;
1923
1924 /* Depending on the model, set up some config variables */
1925 switch (dev->device) {
1926 case PCI_DEVICE_ID_RP4QUAD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 max_num_aiops = 1;
1928 ports_per_aiop = 4;
1929 rocketModel[i].model = MODEL_RP4QUAD;
1930 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1931 rocketModel[i].numPorts = 4;
1932 break;
1933 case PCI_DEVICE_ID_RP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 max_num_aiops = 1;
1935 rocketModel[i].model = MODEL_RP8OCTA;
1936 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1937 rocketModel[i].numPorts = 8;
1938 break;
1939 case PCI_DEVICE_ID_URP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 max_num_aiops = 1;
1941 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1942 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1943 rocketModel[i].numPorts = 8;
1944 break;
1945 case PCI_DEVICE_ID_RP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 max_num_aiops = 1;
1947 rocketModel[i].model = MODEL_RP8INTF;
1948 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1949 rocketModel[i].numPorts = 8;
1950 break;
1951 case PCI_DEVICE_ID_URP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 max_num_aiops = 1;
1953 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1954 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1955 rocketModel[i].numPorts = 8;
1956 break;
1957 case PCI_DEVICE_ID_RP8J:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 max_num_aiops = 1;
1959 rocketModel[i].model = MODEL_RP8J;
1960 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1961 rocketModel[i].numPorts = 8;
1962 break;
1963 case PCI_DEVICE_ID_RP4J:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 max_num_aiops = 1;
1965 ports_per_aiop = 4;
1966 rocketModel[i].model = MODEL_RP4J;
1967 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1968 rocketModel[i].numPorts = 4;
1969 break;
1970 case PCI_DEVICE_ID_RP8SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 max_num_aiops = 1;
1972 rocketModel[i].model = MODEL_RP8SNI;
1973 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1974 rocketModel[i].numPorts = 8;
1975 break;
1976 case PCI_DEVICE_ID_RP16SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 max_num_aiops = 2;
1978 rocketModel[i].model = MODEL_RP16SNI;
1979 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1980 rocketModel[i].numPorts = 16;
1981 break;
1982 case PCI_DEVICE_ID_RP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 max_num_aiops = 2;
1984 rocketModel[i].model = MODEL_RP16INTF;
1985 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1986 rocketModel[i].numPorts = 16;
1987 break;
1988 case PCI_DEVICE_ID_URP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 max_num_aiops = 2;
1990 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1991 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1992 rocketModel[i].numPorts = 16;
1993 break;
1994 case PCI_DEVICE_ID_CRP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 max_num_aiops = 2;
1996 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1997 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
1998 rocketModel[i].numPorts = 16;
1999 break;
2000 case PCI_DEVICE_ID_RP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 max_num_aiops = 4;
2002 rocketModel[i].model = MODEL_RP32INTF;
2003 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
2004 rocketModel[i].numPorts = 32;
2005 break;
2006 case PCI_DEVICE_ID_URP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 max_num_aiops = 4;
2008 rocketModel[i].model = MODEL_UPCI_RP32INTF;
2009 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
2010 rocketModel[i].numPorts = 32;
2011 break;
2012 case PCI_DEVICE_ID_RPP4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 max_num_aiops = 1;
2014 ports_per_aiop = 4;
2015 altChanRingIndicator++;
2016 fast_clock++;
2017 rocketModel[i].model = MODEL_RPP4;
2018 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
2019 rocketModel[i].numPorts = 4;
2020 break;
2021 case PCI_DEVICE_ID_RPP8:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 max_num_aiops = 2;
2023 ports_per_aiop = 4;
2024 altChanRingIndicator++;
2025 fast_clock++;
2026 rocketModel[i].model = MODEL_RPP8;
2027 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
2028 rocketModel[i].numPorts = 8;
2029 break;
2030 case PCI_DEVICE_ID_RP2_232:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 max_num_aiops = 1;
2032 ports_per_aiop = 2;
2033 altChanRingIndicator++;
2034 fast_clock++;
2035 rocketModel[i].model = MODEL_RP2_232;
2036 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
2037 rocketModel[i].numPorts = 2;
2038 break;
2039 case PCI_DEVICE_ID_RP2_422:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 max_num_aiops = 1;
2041 ports_per_aiop = 2;
2042 altChanRingIndicator++;
2043 fast_clock++;
2044 rocketModel[i].model = MODEL_RP2_422;
2045 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
2046 rocketModel[i].numPorts = 2;
2047 break;
2048 case PCI_DEVICE_ID_RP6M:
2049
2050 max_num_aiops = 1;
2051 ports_per_aiop = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
Jiri Slaby57fedc72007-10-18 03:06:28 -07002053 /* If revision is 1, the rocketmodem flash must be loaded.
2054 * If it is 2 it is a "socketed" version. */
2055 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2057 rocketModel[i].loadrm2 = 1;
2058 } else {
2059 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2060 }
2061
2062 rocketModel[i].model = MODEL_RP6M;
2063 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
2064 rocketModel[i].numPorts = 6;
2065 break;
2066 case PCI_DEVICE_ID_RP4M:
2067 max_num_aiops = 1;
2068 ports_per_aiop = 4;
Jiri Slaby57fedc72007-10-18 03:06:28 -07002069 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2071 rocketModel[i].loadrm2 = 1;
2072 } else {
2073 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2074 }
2075
2076 rocketModel[i].model = MODEL_RP4M;
2077 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
2078 rocketModel[i].numPorts = 4;
2079 break;
2080 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 max_num_aiops = 0;
2082 break;
2083 }
2084
2085 /*
2086 * Check for UPCI boards.
2087 */
2088
2089 switch (dev->device) {
2090 case PCI_DEVICE_ID_URP32INTF:
2091 case PCI_DEVICE_ID_URP8INTF:
2092 case PCI_DEVICE_ID_URP16INTF:
2093 case PCI_DEVICE_ID_CRP16INTF:
2094 case PCI_DEVICE_ID_URP8OCTA:
2095 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2096 ConfigIO = pci_resource_start(dev, 1);
2097 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
2098 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2099
2100 /*
2101 * Check for octa or quad cable.
2102 */
2103 if (!
2104 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
2105 PCI_GPIO_CTRL_8PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 ports_per_aiop = 4;
2107 rocketModel[i].numPorts = 4;
2108 }
2109 }
2110 break;
2111 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 max_num_aiops = 1;
2113 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
2114 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
2115 rocketModel[i].numPorts = 8;
2116 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2117 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2118 ConfigIO = pci_resource_start(dev, 1);
2119 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2120 break;
2121 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 max_num_aiops = 1;
2123 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2124 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2125 rocketModel[i].numPorts = 4;
2126 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2127 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2128 ConfigIO = pci_resource_start(dev, 1);
2129 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2130 break;
2131 default:
2132 break;
2133 }
2134
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (fast_clock) {
2136 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2137 rp_baud_base[i] = 921600;
2138 } else {
2139 /*
2140 * If support_low_speed is set, use the slow clock
2141 * prescale, which supports 50 bps
2142 */
2143 if (support_low_speed) {
2144 /* mod 9 (divide by 10) prescale */
2145 sClockPrescale = 0x19;
2146 rp_baud_base[i] = 230400;
2147 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002148 /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 sClockPrescale = 0x14;
2150 rp_baud_base[i] = 460800;
2151 }
2152 }
2153
2154 for (aiop = 0; aiop < max_num_aiops; aiop++)
2155 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2156 ctlp = sCtlNumToCtlPtr(i);
2157 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2158 for (aiop = 0; aiop < max_num_aiops; aiop++)
2159 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2160
Jiri Slaby68562b72008-02-07 00:16:33 -08002161 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2162 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2163 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2164 rocketModel[i].startingPortNumber,
2165 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 if (num_aiops <= 0) {
2168 rcktpt_io_addr[i] = 0;
2169 return (0);
2170 }
2171 is_PCI[i] = 1;
2172
2173 /* Reset the AIOPIC, init the serial ports */
2174 for (aiop = 0; aiop < num_aiops; aiop++) {
2175 sResetAiopByNum(ctlp, aiop);
2176 num_chan = ports_per_aiop;
2177 for (chan = 0; chan < num_chan; chan++)
2178 init_r_port(i, aiop, chan, dev);
2179 }
2180
2181 /* Rocket modems must be reset */
2182 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2183 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2184 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2185 num_chan = ports_per_aiop;
2186 for (chan = 0; chan < num_chan; chan++)
2187 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002188 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 for (chan = 0; chan < num_chan; chan++)
2190 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002191 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 rmSpeakerReset(ctlp, rocketModel[i].model);
2193 }
2194 return (1);
2195}
2196
2197/*
2198 * Probes for PCI cards, inits them if found
2199 * Input: board_found = number of ISA boards already found, or the
2200 * starting board number
2201 * Returns: Number of PCI boards found
2202 */
2203static int __init init_PCI(int boards_found)
2204{
2205 struct pci_dev *dev = NULL;
2206 int count = 0;
2207
2208 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002209 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 if (register_PCI(count + boards_found, dev))
2211 count++;
2212 }
2213 return (count);
2214}
2215
2216#endif /* CONFIG_PCI */
2217
2218/*
2219 * Probes for ISA cards
2220 * Input: i = the board number to look for
2221 * Returns: 1 if board found, 0 else
2222 */
2223static int __init init_ISA(int i)
2224{
2225 int num_aiops, num_chan = 0, total_num_chan = 0;
2226 int aiop, chan;
2227 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2228 CONTROLLER_t *ctlp;
2229 char *type_string;
2230
2231 /* If io_addr is zero, no board configured */
2232 if (rcktpt_io_addr[i] == 0)
2233 return (0);
2234
2235 /* Reserve the IO region */
2236 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002237 printk(KERN_ERR "Unable to reserve IO region for configured "
2238 "ISA RocketPort at address 0x%lx, board not "
2239 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 rcktpt_io_addr[i] = 0;
2241 return (0);
2242 }
2243
2244 ctlp = sCtlNumToCtlPtr(i);
2245
2246 ctlp->boardType = rcktpt_type[i];
2247
2248 switch (rcktpt_type[i]) {
2249 case ROCKET_TYPE_PC104:
2250 type_string = "(PC104)";
2251 break;
2252 case ROCKET_TYPE_MODEM:
2253 type_string = "(RocketModem)";
2254 break;
2255 case ROCKET_TYPE_MODEMII:
2256 type_string = "(RocketModem II)";
2257 break;
2258 default:
2259 type_string = "";
2260 break;
2261 }
2262
2263 /*
2264 * If support_low_speed is set, use the slow clock prescale,
2265 * which supports 50 bps
2266 */
2267 if (support_low_speed) {
2268 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2269 rp_baud_base[i] = 230400;
2270 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002271 sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 rp_baud_base[i] = 460800;
2273 }
2274
2275 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2276 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2277
2278 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2279
2280 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2281 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2282 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2283 }
2284
2285 /* If something went wrong initing the AIOP's release the ISA IO memory */
2286 if (num_aiops <= 0) {
2287 release_region(rcktpt_io_addr[i], 64);
2288 rcktpt_io_addr[i] = 0;
2289 return (0);
2290 }
2291
2292 rocketModel[i].startingPortNumber = nextLineNumber;
2293
2294 for (aiop = 0; aiop < num_aiops; aiop++) {
2295 sResetAiopByNum(ctlp, aiop);
2296 sEnAiop(ctlp, aiop);
2297 num_chan = sGetAiopNumChan(ctlp, aiop);
2298 total_num_chan += num_chan;
2299 for (chan = 0; chan < num_chan; chan++)
2300 init_r_port(i, aiop, chan, NULL);
2301 }
2302 is_PCI[i] = 0;
2303 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2304 num_chan = sGetAiopNumChan(ctlp, 0);
2305 total_num_chan = num_chan;
2306 for (chan = 0; chan < num_chan; chan++)
2307 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002308 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 for (chan = 0; chan < num_chan; chan++)
2310 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002311 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2313 } else {
2314 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2315 }
2316 rocketModel[i].numPorts = total_num_chan;
2317 rocketModel[i].model = MODEL_ISA;
2318
2319 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2320 i, rcktpt_io_addr[i], num_aiops, type_string);
2321
2322 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2323 rocketModel[i].modelString,
2324 rocketModel[i].startingPortNumber,
2325 rocketModel[i].startingPortNumber +
2326 rocketModel[i].numPorts - 1);
2327
2328 return (1);
2329}
2330
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002331static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 .open = rp_open,
2333 .close = rp_close,
2334 .write = rp_write,
2335 .put_char = rp_put_char,
2336 .write_room = rp_write_room,
2337 .chars_in_buffer = rp_chars_in_buffer,
2338 .flush_buffer = rp_flush_buffer,
2339 .ioctl = rp_ioctl,
2340 .throttle = rp_throttle,
2341 .unthrottle = rp_unthrottle,
2342 .set_termios = rp_set_termios,
2343 .stop = rp_stop,
2344 .start = rp_start,
2345 .hangup = rp_hangup,
2346 .break_ctl = rp_break,
2347 .send_xchar = rp_send_xchar,
2348 .wait_until_sent = rp_wait_until_sent,
2349 .tiocmget = rp_tiocmget,
2350 .tiocmset = rp_tiocmset,
2351};
2352
Alan Cox31f35932009-01-02 13:45:05 +00002353static const struct tty_port_operations rocket_port_ops = {
2354 .carrier_raised = carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +01002355 .dtr_rts = dtr_rts,
Alan Cox31f35932009-01-02 13:45:05 +00002356};
2357
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358/*
2359 * The module "startup" routine; it's run when the module is loaded.
2360 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002361static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002363 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
2365 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2366 ROCKET_VERSION, ROCKET_DATE);
2367
2368 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2369 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002370 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2374 * zero, use the default controller IO address of board1 + 0x40.
2375 */
2376 if (board1) {
2377 if (controller == 0)
2378 controller = board1 + 0x40;
2379 } else {
2380 controller = 0; /* Used as a flag, meaning no ISA boards */
2381 }
2382
2383 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2384 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002385 printk(KERN_ERR "Unable to reserve IO region for first "
2386 "configured ISA RocketPort controller 0x%lx. "
2387 "Driver exiting\n", controller);
2388 ret = -EBUSY;
2389 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 }
2391
2392 /* Store ISA variable retrieved from command line or .conf file. */
2393 rcktpt_io_addr[0] = board1;
2394 rcktpt_io_addr[1] = board2;
2395 rcktpt_io_addr[2] = board3;
2396 rcktpt_io_addr[3] = board4;
2397
2398 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2399 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2400 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2401 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2402 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2403 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2404 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2405 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2406
2407 /*
2408 * Set up the tty driver structure and then register this
2409 * driver with the tty layer.
2410 */
2411
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002412 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 rocket_driver->name = "ttyR";
2414 rocket_driver->driver_name = "Comtrol RocketPort";
2415 rocket_driver->major = TTY_ROCKET_MAJOR;
2416 rocket_driver->minor_start = 0;
2417 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2418 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2419 rocket_driver->init_termios = tty_std_termios;
2420 rocket_driver->init_termios.c_cflag =
2421 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002422 rocket_driver->init_termios.c_ispeed = 9600;
2423 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002425 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426#endif
2427 tty_set_operations(rocket_driver, &rocket_ops);
2428
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002429 ret = tty_register_driver(rocket_driver);
2430 if (ret < 0) {
2431 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
Dan Carpenter713efa92010-10-27 15:34:18 -07002432 goto err_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 }
2434
2435#ifdef ROCKET_DEBUG_OPEN
2436 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2437#endif
2438
2439 /*
2440 * OK, let's probe each of the controllers looking for boards. Any boards found
2441 * will be initialized here.
2442 */
2443 isa_boards_found = 0;
2444 pci_boards_found = 0;
2445
2446 for (i = 0; i < NUM_BOARDS; i++) {
2447 if (init_ISA(i))
2448 isa_boards_found++;
2449 }
2450
2451#ifdef CONFIG_PCI
2452 if (isa_boards_found < NUM_BOARDS)
2453 pci_boards_found = init_PCI(isa_boards_found);
2454#endif
2455
2456 max_board = pci_boards_found + isa_boards_found;
2457
2458 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002459 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2460 ret = -ENXIO;
2461 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 }
2463
2464 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002465err_ttyu:
2466 tty_unregister_driver(rocket_driver);
Dan Carpenter713efa92010-10-27 15:34:18 -07002467err_controller:
2468 if (controller)
2469 release_region(controller, 4);
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002470err_tty:
2471 put_tty_driver(rocket_driver);
2472err:
2473 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474}
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
2477static void rp_cleanup_module(void)
2478{
2479 int retval;
2480 int i;
2481
2482 del_timer_sync(&rocket_timer);
2483
2484 retval = tty_unregister_driver(rocket_driver);
2485 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002486 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488
Jesper Juhl735d5662005-11-07 01:01:29 -08002489 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002490 if (rp_table[i]) {
2491 tty_unregister_device(rocket_driver, i);
Jiri Slaby191c5f12012-11-15 09:49:56 +01002492 tty_port_destroy(&rp_table[i]->port);
Jiri Slabyac6aec22007-10-18 03:06:26 -07002493 kfree(rp_table[i]);
2494 }
2495
2496 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
2498 for (i = 0; i < NUM_BOARDS; i++) {
2499 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2500 continue;
2501 release_region(rcktpt_io_addr[i], 64);
2502 }
2503 if (controller)
2504 release_region(controller, 4);
2505}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507/***************************************************************************
2508Function: sInitController
2509Purpose: Initialization of controller global registers and controller
2510 structure.
2511Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2512 IRQNum,Frequency,PeriodicOnly)
2513 CONTROLLER_T *CtlP; Ptr to controller structure
2514 int CtlNum; Controller number
2515 ByteIO_t MudbacIO; Mudbac base I/O address.
2516 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2517 This list must be in the order the AIOPs will be found on the
2518 controller. Once an AIOP in the list is not found, it is
2519 assumed that there are no more AIOPs on the controller.
2520 int AiopIOListSize; Number of addresses in AiopIOList
2521 int IRQNum; Interrupt Request number. Can be any of the following:
2522 0: Disable global interrupts
2523 3: IRQ 3
2524 4: IRQ 4
2525 5: IRQ 5
2526 9: IRQ 9
2527 10: IRQ 10
2528 11: IRQ 11
2529 12: IRQ 12
2530 15: IRQ 15
2531 Byte_t Frequency: A flag identifying the frequency
2532 of the periodic interrupt, can be any one of the following:
2533 FREQ_DIS - periodic interrupt disabled
2534 FREQ_137HZ - 137 Hertz
2535 FREQ_69HZ - 69 Hertz
2536 FREQ_34HZ - 34 Hertz
2537 FREQ_17HZ - 17 Hertz
2538 FREQ_9HZ - 9 Hertz
2539 FREQ_4HZ - 4 Hertz
2540 If IRQNum is set to 0 the Frequency parameter is
2541 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002542 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002544 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 other channel interrupts are allowed.
2546 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002547 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2549 initialization failed.
2550
2551Comments:
2552 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002553 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
2555 If interrupts are to be completely disabled set IRQNum to 0.
2556
Adrian Bunkf15313b2005-06-25 14:59:05 -07002557 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 invalid combination.
2559
2560 This function performs initialization of global interrupt modes,
2561 but it does not actually enable global interrupts. To enable
2562 and disable global interrupts use functions sEnGlobalInt() and
2563 sDisGlobalInt(). Enabling of global interrupts is normally not
2564 done until all other initializations are complete.
2565
2566 Even if interrupts are globally enabled, they must also be
2567 individually enabled for each channel that is to generate
2568 interrupts.
2569
2570Warnings: No range checking on any of the parameters is done.
2571
2572 No context switches are allowed while executing this function.
2573
2574 After this function all AIOPs on the controller are disabled,
2575 they can be enabled with sEnAiop().
2576*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002577static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2578 ByteIO_t * AiopIOList, int AiopIOListSize,
2579 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580{
2581 int i;
2582 ByteIO_t io;
2583 int done;
2584
2585 CtlP->AiopIntrBits = aiop_intr_bits;
2586 CtlP->AltChanRingIndicator = 0;
2587 CtlP->CtlNum = CtlNum;
2588 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2589 CtlP->BusType = isISA;
2590 CtlP->MBaseIO = MudbacIO;
2591 CtlP->MReg1IO = MudbacIO + 1;
2592 CtlP->MReg2IO = MudbacIO + 2;
2593 CtlP->MReg3IO = MudbacIO + 3;
2594#if 1
2595 CtlP->MReg2 = 0; /* interrupt disable */
2596 CtlP->MReg3 = 0; /* no periodic interrupts */
2597#else
2598 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2599 CtlP->MReg2 = 0; /* interrupt disable */
2600 CtlP->MReg3 = 0; /* no periodic interrupts */
2601 } else {
2602 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2603 CtlP->MReg3 = Frequency; /* set frequency */
2604 if (PeriodicOnly) { /* periodic interrupt only */
2605 CtlP->MReg3 |= PERIODIC_ONLY;
2606 }
2607 }
2608#endif
2609 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2610 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2611 sControllerEOI(CtlP); /* clear EOI if warm init */
2612 /* Init AIOPs */
2613 CtlP->NumAiop = 0;
2614 for (i = done = 0; i < AiopIOListSize; i++) {
2615 io = AiopIOList[i];
2616 CtlP->AiopIO[i] = (WordIO_t) io;
2617 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2618 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2619 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2620 if (done)
2621 continue;
2622 sEnAiop(CtlP, i); /* enable the AIOP */
2623 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2624 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2625 done = 1; /* done looking for AIOPs */
2626 else {
2627 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2628 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2629 sOutB(io + _INDX_DATA, sClockPrescale);
2630 CtlP->NumAiop++; /* bump count of AIOPs */
2631 }
2632 sDisAiop(CtlP, i); /* disable AIOP */
2633 }
2634
2635 if (CtlP->NumAiop == 0)
2636 return (-1);
2637 else
2638 return (CtlP->NumAiop);
2639}
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641/***************************************************************************
2642Function: sReadAiopID
2643Purpose: Read the AIOP idenfication number directly from an AIOP.
2644Call: sReadAiopID(io)
2645 ByteIO_t io: AIOP base I/O address
2646Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2647 is replace by an identifying number.
2648 Flag AIOPID_NULL if no valid AIOP is found
2649Warnings: No context switches are allowed while executing this function.
2650
2651*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002652static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
2654 Byte_t AiopID; /* ID byte from AIOP */
2655
2656 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2657 sOutB(io + _CMD_REG, 0x0);
2658 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2659 if (AiopID == 0x06)
2660 return (1);
2661 else /* AIOP does not exist */
2662 return (-1);
2663}
2664
2665/***************************************************************************
2666Function: sReadAiopNumChan
2667Purpose: Read the number of channels available in an AIOP directly from
2668 an AIOP.
2669Call: sReadAiopNumChan(io)
2670 WordIO_t io: AIOP base I/O address
2671Return: int: The number of channels available
2672Comments: The number of channels is determined by write/reads from identical
2673 offsets within the SRAM address spaces for channels 0 and 4.
2674 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2675 AIOP, otherwise it is an 8 channel.
2676Warnings: No context switches are allowed while executing this function.
2677*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002678static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679{
2680 Word_t x;
2681 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2682
2683 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002684 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2686 x = sInW(io + _INDX_DATA);
2687 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2688 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2689 return (8);
2690 else
2691 return (4);
2692}
2693
2694/***************************************************************************
2695Function: sInitChan
2696Purpose: Initialization of a channel and channel structure
2697Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2698 CONTROLLER_T *CtlP; Ptr to controller structure
2699 CHANNEL_T *ChP; Ptr to channel structure
2700 int AiopNum; AIOP number within controller
2701 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002702Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 number exceeds number of channels available in AIOP.
2704Comments: This function must be called before a channel can be used.
2705Warnings: No range checking on any of the parameters is done.
2706
2707 No context switches are allowed while executing this function.
2708*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002709static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2710 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711{
2712 int i;
2713 WordIO_t AiopIO;
2714 WordIO_t ChIOOff;
2715 Byte_t *ChR;
2716 Word_t ChOff;
2717 static Byte_t R[4];
2718 int brd9600;
2719
2720 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002721 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723 /* Channel, AIOP, and controller identifiers */
2724 ChP->CtlP = CtlP;
2725 ChP->ChanID = CtlP->AiopID[AiopNum];
2726 ChP->AiopNum = AiopNum;
2727 ChP->ChanNum = ChanNum;
2728
2729 /* Global direct addresses */
2730 AiopIO = CtlP->AiopIO[AiopNum];
2731 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2732 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2733 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2734 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2735 ChP->IndexData = AiopIO + _INDX_DATA;
2736
2737 /* Channel direct addresses */
2738 ChIOOff = AiopIO + ChP->ChanNum * 2;
2739 ChP->TxRxData = ChIOOff + _TD0;
2740 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2741 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2742 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2743
2744 /* Initialize the channel from the RData array */
2745 for (i = 0; i < RDATASIZE; i += 4) {
2746 R[0] = RData[i];
2747 R[1] = RData[i + 1] + 0x10 * ChanNum;
2748 R[2] = RData[i + 2];
2749 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002750 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 }
2752
2753 ChR = ChP->R;
2754 for (i = 0; i < RREGDATASIZE; i += 4) {
2755 ChR[i] = RRegData[i];
2756 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2757 ChR[i + 2] = RRegData[i + 2];
2758 ChR[i + 3] = RRegData[i + 3];
2759 }
2760
2761 /* Indexed registers */
2762 ChOff = (Word_t) ChanNum *0x1000;
2763
2764 if (sClockPrescale == 0x14)
2765 brd9600 = 47;
2766 else
2767 brd9600 = 23;
2768
2769 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2770 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2771 ChP->BaudDiv[2] = (Byte_t) brd9600;
2772 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002773 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2776 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2777 ChP->TxControl[2] = 0;
2778 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002779 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
2781 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2782 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2783 ChP->RxControl[2] = 0;
2784 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002785 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
2787 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2788 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2789 ChP->TxEnables[2] = 0;
2790 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002791 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2794 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2795 ChP->TxCompare[2] = 0;
2796 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002797 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
2799 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2800 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2801 ChP->TxReplace1[2] = 0;
2802 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002803 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2806 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2807 ChP->TxReplace2[2] = 0;
2808 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002809 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810
2811 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2812 ChP->TxFIFO = ChOff + _TX_FIFO;
2813
2814 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2815 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2816 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2817 sOutW(ChP->IndexData, 0);
2818 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2819 ChP->RxFIFO = ChOff + _RX_FIFO;
2820
2821 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2822 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2823 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2824 sOutW(ChP->IndexData, 0);
2825 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2826 sOutW(ChP->IndexData, 0);
2827 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2828 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2829 sOutB(ChP->IndexData, 0);
2830 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2831 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2832 sOutB(ChP->IndexData, 0);
2833 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2834 sEnRxProcessor(ChP); /* start the Rx processor */
2835
Adrian Bunkf15313b2005-06-25 14:59:05 -07002836 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837}
2838
2839/***************************************************************************
2840Function: sStopRxProcessor
2841Purpose: Stop the receive processor from processing a channel.
2842Call: sStopRxProcessor(ChP)
2843 CHANNEL_T *ChP; Ptr to channel structure
2844
2845Comments: The receive processor can be started again with sStartRxProcessor().
2846 This function causes the receive processor to skip over the
2847 stopped channel. It does not stop it from processing other channels.
2848
2849Warnings: No context switches are allowed while executing this function.
2850
2851 Do not leave the receive processor stopped for more than one
2852 character time.
2853
2854 After calling this function a delay of 4 uS is required to ensure
2855 that the receive processor is no longer processing this channel.
2856*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002857static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858{
2859 Byte_t R[4];
2860
2861 R[0] = ChP->R[0];
2862 R[1] = ChP->R[1];
2863 R[2] = 0x0a;
2864 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00002865 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866}
2867
2868/***************************************************************************
2869Function: sFlushRxFIFO
2870Purpose: Flush the Rx FIFO
2871Call: sFlushRxFIFO(ChP)
2872 CHANNEL_T *ChP; Ptr to channel structure
2873Return: void
2874Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2875 while it is being flushed the receive processor is stopped
2876 and the transmitter is disabled. After these operations a
2877 4 uS delay is done before clearing the pointers to allow
2878 the receive processor to stop. These items are handled inside
2879 this function.
2880Warnings: No context switches are allowed while executing this function.
2881*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002882static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
2884 int i;
2885 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002886 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
2889 return; /* don't need to flush */
2890
Adrian Bunkf15313b2005-06-25 14:59:05 -07002891 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002893 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 sDisRxFIFO(ChP); /* disable it */
2895 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
2896 sInB(ChP->IntChan); /* depends on bus i/o timing */
2897 }
2898 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
2899 Ch = (Byte_t) sGetChanNum(ChP);
2900 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
2901 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
2902 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2903 sOutW(ChP->IndexData, 0);
2904 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2905 sOutW(ChP->IndexData, 0);
2906 if (RxFIFOEnabled)
2907 sEnRxFIFO(ChP); /* enable Rx FIFO */
2908}
2909
2910/***************************************************************************
2911Function: sFlushTxFIFO
2912Purpose: Flush the Tx FIFO
2913Call: sFlushTxFIFO(ChP)
2914 CHANNEL_T *ChP; Ptr to channel structure
2915Return: void
2916Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2917 while it is being flushed the receive processor is stopped
2918 and the transmitter is disabled. After these operations a
2919 4 uS delay is done before clearing the pointers to allow
2920 the receive processor to stop. These items are handled inside
2921 this function.
2922Warnings: No context switches are allowed while executing this function.
2923*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002924static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
2926 int i;
2927 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002928 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
2931 return; /* don't need to flush */
2932
Adrian Bunkf15313b2005-06-25 14:59:05 -07002933 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07002935 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 sDisTransmit(ChP); /* disable transmitter */
2937 }
2938 sStopRxProcessor(ChP); /* stop Rx processor */
2939 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
2940 sInB(ChP->IntChan); /* depends on bus i/o timing */
2941 Ch = (Byte_t) sGetChanNum(ChP);
2942 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
2943 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
2944 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2945 sOutW(ChP->IndexData, 0);
2946 if (TxEnabled)
2947 sEnTransmit(ChP); /* enable transmitter */
2948 sStartRxProcessor(ChP); /* restart Rx processor */
2949}
2950
2951/***************************************************************************
2952Function: sWriteTxPrioByte
2953Purpose: Write a byte of priority transmit data to a channel
2954Call: sWriteTxPrioByte(ChP,Data)
2955 CHANNEL_T *ChP; Ptr to channel structure
2956 Byte_t Data; The transmit data byte
2957
2958Return: int: 1 if the bytes is successfully written, otherwise 0.
2959
2960Comments: The priority byte is transmitted before any data in the Tx FIFO.
2961
2962Warnings: No context switches are allowed while executing this function.
2963*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002964static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965{
2966 Byte_t DWBuf[4]; /* buffer for double word writes */
2967 Word_t *WordPtr; /* must be far because Win SS != DS */
2968 register DWordIO_t IndexAddr;
2969
2970 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
2971 IndexAddr = ChP->IndexAddr;
2972 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
2973 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
2974 return (0); /* nothing sent */
2975
2976 WordPtr = (Word_t *) (&DWBuf[0]);
2977 *WordPtr = ChP->TxPrioBuf; /* data byte address */
2978
2979 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00002980 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
2982 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
2983
2984 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
2985 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00002986 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 } else { /* write it to Tx FIFO */
2988
2989 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
2990 }
2991 return (1); /* 1 byte sent */
2992}
2993
2994/***************************************************************************
2995Function: sEnInterrupts
2996Purpose: Enable one or more interrupts for a channel
2997Call: sEnInterrupts(ChP,Flags)
2998 CHANNEL_T *ChP; Ptr to channel structure
2999 Word_t Flags: Interrupt enable flags, can be any combination
3000 of the following flags:
3001 TXINT_EN: Interrupt on Tx FIFO empty
3002 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3003 sSetRxTrigger())
3004 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3005 MCINT_EN: Interrupt on modem input change
3006 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3007 Interrupt Channel Register.
3008Return: void
3009Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3010 enabled. If an interrupt enable flag is not set in Flags, that
3011 interrupt will not be changed. Interrupts can be disabled with
3012 function sDisInterrupts().
3013
3014 This function sets the appropriate bit for the channel in the AIOP's
3015 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3016 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3017
3018 Interrupts must also be globally enabled before channel interrupts
3019 will be passed on to the host. This is done with function
3020 sEnGlobalInt().
3021
3022 In some cases it may be desirable to disable interrupts globally but
3023 enable channel interrupts. This would allow the global interrupt
3024 status register to be used to determine which AIOPs need service.
3025*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003026static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027{
3028 Byte_t Mask; /* Interrupt Mask Register */
3029
3030 ChP->RxControl[2] |=
3031 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3032
Al Viro457fb602008-03-19 16:27:48 +00003033 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
3035 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3036
Al Viro457fb602008-03-19 16:27:48 +00003037 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 if (Flags & CHANINT_EN) {
3040 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3041 sOutB(ChP->IntMask, Mask);
3042 }
3043}
3044
3045/***************************************************************************
3046Function: sDisInterrupts
3047Purpose: Disable one or more interrupts for a channel
3048Call: sDisInterrupts(ChP,Flags)
3049 CHANNEL_T *ChP; Ptr to channel structure
3050 Word_t Flags: Interrupt flags, can be any combination
3051 of the following flags:
3052 TXINT_EN: Interrupt on Tx FIFO empty
3053 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3054 sSetRxTrigger())
3055 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3056 MCINT_EN: Interrupt on modem input change
3057 CHANINT_EN: Disable channel interrupt signal to the
3058 AIOP's Interrupt Channel Register.
3059Return: void
3060Comments: If an interrupt flag is set in Flags, that interrupt will be
3061 disabled. If an interrupt flag is not set in Flags, that
3062 interrupt will not be changed. Interrupts can be enabled with
3063 function sEnInterrupts().
3064
3065 This function clears the appropriate bit for the channel in the AIOP's
3066 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3067 this channel's bit from being set in the AIOP's Interrupt Channel
3068 Register.
3069*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003070static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071{
3072 Byte_t Mask; /* Interrupt Mask Register */
3073
3074 ChP->RxControl[2] &=
3075 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003076 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003078 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
3080 if (Flags & CHANINT_EN) {
3081 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3082 sOutB(ChP->IntMask, Mask);
3083 }
3084}
3085
Adrian Bunkf15313b2005-06-25 14:59:05 -07003086static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087{
3088 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3089}
3090
3091/*
3092 * Not an official SSCI function, but how to reset RocketModems.
3093 * ISA bus version
3094 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003095static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096{
3097 ByteIO_t addr;
3098 Byte_t val;
3099
3100 addr = CtlP->AiopIO[0] + 0x400;
3101 val = sInB(CtlP->MReg3IO);
3102 /* if AIOP[1] is not enabled, enable it */
3103 if ((val & 2) == 0) {
3104 val = sInB(CtlP->MReg2IO);
3105 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3106 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3107 }
3108
3109 sEnAiop(CtlP, 1);
3110 if (!on)
3111 addr += 8;
3112 sOutB(addr + chan, 0); /* apply or remove reset */
3113 sDisAiop(CtlP, 1);
3114}
3115
3116/*
3117 * Not an official SSCI function, but how to reset RocketModems.
3118 * PCI bus version
3119 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003120static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121{
3122 ByteIO_t addr;
3123
3124 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3125 if (!on)
3126 addr += 8;
3127 sOutB(addr + chan, 0); /* apply or remove reset */
3128}
3129
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130/* Returns the line number given the controller (board), aiop and channel number */
3131static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3132{
3133 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3134}
3135
3136/*
3137 * Stores the line number associated with a given controller (board), aiop
3138 * and channel number.
3139 * Returns: The line number assigned
3140 */
3141static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3142{
3143 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3144 return (nextLineNumber - 1);
3145}