blob: ca6fcdcca56ea8c21b75cb288cddaf978fa7f153 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * RocketPort device driver for Linux
3 *
4 * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000.
5 *
6 * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * Kernel Synchronization:
25 *
26 * This driver has 2 kernel control paths - exception handlers (calls into the driver
27 * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts
28 * are not used.
29 *
30 * Critical data:
31 * - rp_table[], accessed through passed "info" pointers, is a global (static) array of
32 * serial port state information and the xmit_buf circular buffer. Protected by
33 * a per port spinlock.
34 * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there
35 * is data to be transmitted. Protected by atomic bit operations.
36 * - rp_num_ports, int indicating number of open ports, protected by atomic operations.
37 *
38 * rp_write() and rp_write_char() functions use a per port semaphore to protect against
39 * simultaneous access to the same port by more than one process.
40 */
41
42/****** Defines ******/
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define ROCKET_PARANOIA_CHECK
44#define ROCKET_DISABLE_SIMUSAGE
45
46#undef ROCKET_SOFT_FLOW
47#undef ROCKET_DEBUG_OPEN
48#undef ROCKET_DEBUG_INTR
49#undef ROCKET_DEBUG_WRITE
50#undef ROCKET_DEBUG_FLOW
51#undef ROCKET_DEBUG_THROTTLE
52#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
53#undef ROCKET_DEBUG_RECEIVE
54#undef ROCKET_DEBUG_HANGUP
55#undef REV_PCI_ORDER
56#undef ROCKET_DEBUG_IO
57
58#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */
59
60/****** Kernel includes ******/
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <linux/module.h>
63#include <linux/errno.h>
64#include <linux/major.h>
65#include <linux/kernel.h>
66#include <linux/signal.h>
67#include <linux/slab.h>
68#include <linux/mm.h>
69#include <linux/sched.h>
70#include <linux/timer.h>
71#include <linux/interrupt.h>
72#include <linux/tty.h>
73#include <linux/tty_driver.h>
74#include <linux/tty_flip.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010075#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/string.h>
77#include <linux/fcntl.h>
78#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070079#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include <linux/ioport.h>
81#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070082#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/wait.h>
84#include <linux/pci.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010085#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070086#include <asm/atomic.h>
Al Viro457fb602008-03-19 16:27:48 +000087#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/bitops.h>
89#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/init.h>
91
92/****** RocketPort includes ******/
93
94#include "rocket_int.h"
95#include "rocket.h"
96
97#define ROCKET_VERSION "2.09"
98#define ROCKET_DATE "12-June-2003"
99
100/****** RocketPort Local Variables ******/
101
Jiri Slaby40565f12007-02-12 00:52:31 -0800102static void rp_do_poll(unsigned long dummy);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static struct tty_driver *rocket_driver;
105
106static struct rocket_version driver_version = {
107 ROCKET_VERSION, ROCKET_DATE
108};
109
110static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
111static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
112 /* eg. Bit 0 indicates port 0 has xmit data, ... */
113static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800114static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
117static unsigned long board2;
118static unsigned long board3;
119static unsigned long board4;
120static unsigned long controller;
121static int support_low_speed;
122static unsigned long modem1;
123static unsigned long modem2;
124static unsigned long modem3;
125static unsigned long modem4;
126static unsigned long pc104_1[8];
127static unsigned long pc104_2[8];
128static unsigned long pc104_3[8];
129static unsigned long pc104_4[8];
130static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
131
132static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
133static unsigned long rcktpt_io_addr[NUM_BOARDS];
134static int rcktpt_type[NUM_BOARDS];
135static int is_PCI[NUM_BOARDS];
136static rocketModel_t rocketModel[NUM_BOARDS];
137static int max_board;
Alan Cox31f35932009-01-02 13:45:05 +0000138static const struct tty_port_operations rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140/*
141 * The following arrays define the interrupt bits corresponding to each AIOP.
142 * These bits are different between the ISA and regular PCI boards and the
143 * Universal PCI boards.
144 */
145
146static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
147 AIOP_INTR_BIT_0,
148 AIOP_INTR_BIT_1,
149 AIOP_INTR_BIT_2,
150 AIOP_INTR_BIT_3
151};
152
153static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
154 UPCI_AIOP_INTR_BIT_0,
155 UPCI_AIOP_INTR_BIT_1,
156 UPCI_AIOP_INTR_BIT_2,
157 UPCI_AIOP_INTR_BIT_3
158};
159
Adrian Bunkf15313b2005-06-25 14:59:05 -0700160static Byte_t RData[RDATASIZE] = {
161 0x00, 0x09, 0xf6, 0x82,
162 0x02, 0x09, 0x86, 0xfb,
163 0x04, 0x09, 0x00, 0x0a,
164 0x06, 0x09, 0x01, 0x0a,
165 0x08, 0x09, 0x8a, 0x13,
166 0x0a, 0x09, 0xc5, 0x11,
167 0x0c, 0x09, 0x86, 0x85,
168 0x0e, 0x09, 0x20, 0x0a,
169 0x10, 0x09, 0x21, 0x0a,
170 0x12, 0x09, 0x41, 0xff,
171 0x14, 0x09, 0x82, 0x00,
172 0x16, 0x09, 0x82, 0x7b,
173 0x18, 0x09, 0x8a, 0x7d,
174 0x1a, 0x09, 0x88, 0x81,
175 0x1c, 0x09, 0x86, 0x7a,
176 0x1e, 0x09, 0x84, 0x81,
177 0x20, 0x09, 0x82, 0x7c,
178 0x22, 0x09, 0x0a, 0x0a
179};
180
181static Byte_t RRegData[RREGDATASIZE] = {
182 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
183 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
184 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
185 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
186 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
187 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
188 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
189 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
190 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
191 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
192 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
193 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
194 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
195};
196
197static CONTROLLER_T sController[CTL_SIZE] = {
198 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
199 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
200 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
201 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
202 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
203 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
204 {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
205 {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
206};
207
208static Byte_t sBitMapClrTbl[8] = {
209 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
210};
211
212static Byte_t sBitMapSetTbl[8] = {
213 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
214};
215
216static int sClockPrescale = 0x14;
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218/*
219 * Line number is the ttySIx number (x), the Minor number. We
220 * assign them sequentially, starting at zero. The following
221 * array keeps track of the line number assigned to a given board/aiop/channel.
222 */
223static unsigned char lineNumbers[MAX_RP_PORTS];
224static unsigned long nextLineNumber;
225
226/***** RocketPort Static Prototypes *********/
227static int __init init_ISA(int i);
228static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
229static void rp_flush_buffer(struct tty_struct *tty);
230static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
231static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
232static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
233static void rp_start(struct tty_struct *tty);
Adrian Bunkf15313b2005-06-25 14:59:05 -0700234static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
235 int ChanNum);
236static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
237static void sFlushRxFIFO(CHANNEL_T * ChP);
238static void sFlushTxFIFO(CHANNEL_T * ChP);
239static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
240static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
241static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
242static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
243static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
244static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
245 ByteIO_t * AiopIOList, int AiopIOListSize,
246 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
247 int PeriodicOnly, int altChanRingIndicator,
248 int UPCIRingInd);
249static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
250 ByteIO_t * AiopIOList, int AiopIOListSize,
251 int IRQNum, Byte_t Frequency, int PeriodicOnly);
252static int sReadAiopID(ByteIO_t io);
253static int sReadAiopNumChan(WordIO_t io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255MODULE_AUTHOR("Theodore Ts'o");
256MODULE_DESCRIPTION("Comtrol RocketPort driver");
257module_param(board1, ulong, 0);
258MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
259module_param(board2, ulong, 0);
260MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
261module_param(board3, ulong, 0);
262MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
263module_param(board4, ulong, 0);
264MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
265module_param(controller, ulong, 0);
266MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
267module_param(support_low_speed, bool, 0);
268MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud");
269module_param(modem1, ulong, 0);
270MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem");
271module_param(modem2, ulong, 0);
272MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem");
273module_param(modem3, ulong, 0);
274MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem");
275module_param(modem4, ulong, 0);
276MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem");
277module_param_array(pc104_1, ulong, NULL, 0);
278MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,...");
279module_param_array(pc104_2, ulong, NULL, 0);
280MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,...");
281module_param_array(pc104_3, ulong, NULL, 0);
282MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,...");
283module_param_array(pc104_4, ulong, NULL, 0);
284MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,...");
285
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -0800286static int rp_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287static void rp_cleanup_module(void);
288
289module_init(rp_init);
290module_exit(rp_cleanup_module);
291
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293MODULE_LICENSE("Dual BSD/GPL");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295/*************************************************************************/
296/* Module code starts here */
297
298static inline int rocket_paranoia_check(struct r_port *info,
299 const char *routine)
300{
301#ifdef ROCKET_PARANOIA_CHECK
302 if (!info)
303 return 1;
304 if (info->magic != RPORT_MAGIC) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800305 printk(KERN_WARNING "Warning: bad magic number for rocketport "
306 "struct in %s\n", routine);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return 1;
308 }
309#endif
310 return 0;
311}
312
313
314/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals
315 * that receive data is present on a serial port. Pulls data from FIFO, moves it into the
316 * tty layer.
317 */
318static void rp_do_receive(struct r_port *info,
319 struct tty_struct *tty,
320 CHANNEL_t * cp, unsigned int ChanStatus)
321{
322 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700323 int ToRecv, wRecv, space;
324 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800328 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700330 if (ToRecv == 0)
331 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /*
334 * if status indicates there are errored characters in the
335 * FIFO, then enter status mode (a word in FIFO holds
336 * character and status).
337 */
338 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
339 if (!(ChanStatus & STATMODE)) {
340#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800341 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342#endif
343 ChanStatus |= STATMODE;
344 sEnRxStatusMode(cp);
345 }
346 }
347
348 /*
349 * if we previously entered status mode, then read down the
350 * FIFO one word at a time, pulling apart the character and
351 * the status. Update error counters depending on status
352 */
353 if (ChanStatus & STATMODE) {
354#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800355 printk(KERN_INFO "Ignore %x, read %x...\n",
356 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#endif
358 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700359 char flag;
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 CharNStat = sInW(sGetTxRxDataIO(cp));
362#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800363 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364#endif
365 if (CharNStat & STMBREAKH)
366 CharNStat &= ~(STMFRAMEH | STMPARITYH);
367 if (CharNStat & info->ignore_status_mask) {
368 ToRecv--;
369 continue;
370 }
371 CharNStat &= info->read_status_mask;
372 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700373 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700375 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700377 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700379 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700381 flag = TTY_NORMAL;
382 tty_insert_flip_char(tty, CharNStat & 0xff, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 ToRecv--;
384 }
385
386 /*
387 * after we've emptied the FIFO in status mode, turn
388 * status mode back off
389 */
390 if (sGetRxCnt(cp) == 0) {
391#ifdef ROCKET_DEBUG_RECEIVE
392 printk(KERN_INFO "Status mode off.\n");
393#endif
394 sDisRxStatusMode(cp);
395 }
396 } else {
397 /*
398 * we aren't in status mode, so read down the FIFO two
399 * characters at time by doing repeated word IO
400 * transfer.
401 */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700402 space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
403 if (space < ToRecv) {
404#ifdef ROCKET_DEBUG_RECEIVE
405 printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
406#endif
407 if (space <= 0)
408 return;
409 ToRecv = space;
410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 wRecv = ToRecv >> 1;
412 if (wRecv)
413 sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
414 if (ToRecv & 1)
415 cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 }
417 /* Push the data up to the tty layer */
Paul Fulghumcc44a812006-06-25 05:49:12 -0700418 tty_flip_buffer_push(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420
421/*
422 * Serial port transmit data function. Called from the timer polling loop as a
423 * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready
424 * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is
425 * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks.
426 */
427static void rp_do_transmit(struct r_port *info)
428{
429 int c;
430 CHANNEL_t *cp = &info->channel;
431 struct tty_struct *tty;
432 unsigned long flags;
433
434#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800435 printk(KERN_DEBUG "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436#endif
437 if (!info)
438 return;
Alan Coxe60a1082008-07-16 21:56:18 +0100439 if (!info->port.tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800440 printk(KERN_WARNING "rp: WARNING %s called with "
Alan Coxe60a1082008-07-16 21:56:18 +0100441 "info->port.tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
443 return;
444 }
445
446 spin_lock_irqsave(&info->slock, flags);
Alan Coxe60a1082008-07-16 21:56:18 +0100447 tty = info->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
449
450 /* Loop sending data to FIFO until done or FIFO full */
451 while (1) {
452 if (tty->stopped || tty->hw_stopped)
453 break;
Harvey Harrison709107f2008-04-30 00:53:51 -0700454 c = min(info->xmit_fifo_room, info->xmit_cnt);
455 c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (c <= 0 || info->xmit_fifo_room <= 0)
457 break;
458 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
459 if (c & 1)
460 sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]);
461 info->xmit_tail += c;
462 info->xmit_tail &= XMIT_BUF_SIZE - 1;
463 info->xmit_cnt -= c;
464 info->xmit_fifo_room -= c;
465#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800466 printk(KERN_INFO "tx %d chars...\n", c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467#endif
468 }
469
470 if (info->xmit_cnt == 0)
471 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
472
473 if (info->xmit_cnt < WAKEUP_CHARS) {
474 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475#ifdef ROCKETPORT_HAVE_POLL_WAIT
476 wake_up_interruptible(&tty->poll_wait);
477#endif
478 }
479
480 spin_unlock_irqrestore(&info->slock, flags);
481
482#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800483 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 info->xmit_tail, info->xmit_fifo_room);
485#endif
486}
487
488/*
489 * Called when a serial port signals it has read data in it's RX FIFO.
490 * It checks what interrupts are pending and services them, including
491 * receiving serial data.
492 */
493static void rp_handle_port(struct r_port *info)
494{
495 CHANNEL_t *cp;
496 struct tty_struct *tty;
497 unsigned int IntMask, ChanStatus;
498
499 if (!info)
500 return;
501
Alan Cox21bed702009-01-02 13:48:23 +0000502 if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800503 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
504 "info->flags & NOT_INIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return;
506 }
Alan Coxe60a1082008-07-16 21:56:18 +0100507 if (!info->port.tty) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800508 printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
Alan Coxe60a1082008-07-16 21:56:18 +0100509 "info->port.tty==NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 return;
511 }
512 cp = &info->channel;
Alan Coxe60a1082008-07-16 21:56:18 +0100513 tty = info->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 IntMask = sGetChanIntID(cp) & info->intmask;
516#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800517 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518#endif
519 ChanStatus = sGetChanStatus(cp);
520 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
521 rp_do_receive(info, tty, cp, ChanStatus);
522 }
523 if (IntMask & DELTA_CD) { /* CD change */
524#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800525 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 (ChanStatus & CD_ACT) ? "on" : "off");
527#endif
528 if (!(ChanStatus & CD_ACT) && info->cd_status) {
529#ifdef ROCKET_DEBUG_HANGUP
530 printk(KERN_INFO "CD drop, calling hangup.\n");
531#endif
532 tty_hangup(tty);
533 }
534 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100535 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
537#ifdef ROCKET_DEBUG_INTR
538 if (IntMask & DELTA_CTS) { /* CTS change */
539 printk(KERN_INFO "CTS change...\n");
540 }
541 if (IntMask & DELTA_DSR) { /* DSR change */
542 printk(KERN_INFO "DSR change...\n");
543 }
544#endif
545}
546
547/*
548 * The top level polling routine. Repeats every 1/100 HZ (10ms).
549 */
550static void rp_do_poll(unsigned long dummy)
551{
552 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700553 int ctrl, aiop, ch, line;
554 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 unsigned int CtlMask;
556 unsigned char AiopMask;
557 Word_t bit;
558
559 /* Walk through all the boards (ctrl's) */
560 for (ctrl = 0; ctrl < max_board; ctrl++) {
561 if (rcktpt_io_addr[ctrl] <= 0)
562 continue;
563
564 /* Get a ptr to the board's control struct */
565 ctlp = sCtlNumToCtlPtr(ctrl);
566
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200567 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_PCI
569 if (ctlp->BusType == isPCI)
570 CtlMask = sPCIGetControllerIntStatus(ctlp);
571 else
572#endif
573 CtlMask = sGetControllerIntStatus(ctlp);
574
575 /* Check if any AIOP read bits are set */
576 for (aiop = 0; CtlMask; aiop++) {
577 bit = ctlp->AiopIntrBits[aiop];
578 if (CtlMask & bit) {
579 CtlMask &= ~bit;
580 AiopMask = sGetAiopIntStatus(ctlp, aiop);
581
582 /* Check if any port read bits are set */
583 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
584 if (AiopMask & 1) {
585
586 /* Get the line number (/dev/ttyRx number). */
587 /* Read the data from the port. */
588 line = GetLineNumber(ctrl, aiop, ch);
589 rp_handle_port(rp_table[line]);
590 }
591 }
592 }
593 }
594
595 xmitmask = xmit_flags[ctrl];
596
597 /*
598 * xmit_flags contains bit-significant flags, indicating there is data
599 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
600 * 1, ... (32 total possible). The variable i has the aiop and ch
601 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
602 */
603 if (xmitmask) {
604 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
605 if (xmitmask & (1 << i)) {
606 aiop = (i & 0x18) >> 3;
607 ch = i & 0x07;
608 line = GetLineNumber(ctrl, aiop, ch);
609 rp_do_transmit(rp_table[line]);
610 }
611 }
612 }
613 }
614
615 /*
616 * Reset the timer so we get called at the next clock tick (10ms).
617 */
618 if (atomic_read(&rp_num_ports_open))
619 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
620}
621
622/*
623 * Initializes the r_port structure for a port, as well as enabling the port on
624 * the board.
625 * Inputs: board, aiop, chan numbers
626 */
627static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
628{
629 unsigned rocketMode;
630 struct r_port *info;
631 int line;
632 CONTROLLER_T *ctlp;
633
634 /* Get the next available line number */
635 line = SetLineNumber(board, aiop, chan);
636
637 ctlp = sCtlNumToCtlPtr(board);
638
639 /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700640 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800642 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
643 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return;
645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 info->magic = RPORT_MAGIC;
648 info->line = line;
649 info->ctlp = ctlp;
650 info->board = board;
651 info->aiop = aiop;
652 info->chan = chan;
Alan Cox31f35932009-01-02 13:45:05 +0000653 tty_port_init(&info->port);
654 info->port.ops = &rocket_port_ops;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700655 init_completion(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 info->flags &= ~ROCKET_MODE_MASK;
657 switch (pc104[board][line]) {
658 case 422:
659 info->flags |= ROCKET_MODE_RS422;
660 break;
661 case 485:
662 info->flags |= ROCKET_MODE_RS485;
663 break;
664 case 232:
665 default:
666 info->flags |= ROCKET_MODE_RS232;
667 break;
668 }
669
670 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
671 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800672 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
673 board, aiop, chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 kfree(info);
675 return;
676 }
677
678 rocketMode = info->flags & ROCKET_MODE_MASK;
679
680 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
681 sEnRTSToggle(&info->channel);
682 else
683 sDisRTSToggle(&info->channel);
684
685 if (ctlp->boardType == ROCKET_TYPE_PC104) {
686 switch (rocketMode) {
687 case ROCKET_MODE_RS485:
688 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
689 break;
690 case ROCKET_MODE_RS422:
691 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
692 break;
693 case ROCKET_MODE_RS232:
694 default:
695 if (info->flags & ROCKET_RTS_TOGGLE)
696 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
697 else
698 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
699 break;
700 }
701 }
702 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700703 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 rp_table[line] = info;
Jiri Slabyac6aec22007-10-18 03:06:26 -0700705 tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
706 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707}
708
709/*
710 * Configures a rocketport port according to its termio settings. Called from
711 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
712 */
713static void configure_r_port(struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800714 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 unsigned cflag;
717 unsigned long flags;
718 unsigned rocketMode;
719 int bits, baud, divisor;
720 CHANNEL_t *cp;
Alan Coxe60a1082008-07-16 21:56:18 +0100721 struct ktermios *t = info->port.tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800724 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /* Byte size and parity */
727 if ((cflag & CSIZE) == CS8) {
728 sSetData8(cp);
729 bits = 10;
730 } else {
731 sSetData7(cp);
732 bits = 9;
733 }
734 if (cflag & CSTOPB) {
735 sSetStop2(cp);
736 bits++;
737 } else {
738 sSetStop1(cp);
739 }
740
741 if (cflag & PARENB) {
742 sEnParity(cp);
743 bits++;
744 if (cflag & PARODD) {
745 sSetOddParity(cp);
746 } else {
747 sSetEvenParity(cp);
748 }
749 } else {
750 sDisParity(cp);
751 }
752
753 /* baud rate */
Alan Coxe60a1082008-07-16 21:56:18 +0100754 baud = tty_get_baud_rate(info->port.tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (!baud)
756 baud = 9600;
757 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
758 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800759 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (!baud)
761 baud = 9600;
762 divisor = (rp_baud_base[info->board] / baud) - 1;
763 }
764 if (divisor >= 8192 || divisor < 0) {
765 baud = 9600;
766 divisor = (rp_baud_base[info->board] / baud) - 1;
767 }
768 info->cps = baud / bits;
769 sSetBaud(cp, divisor);
770
Alan Cox6df35262008-02-08 04:18:45 -0800771 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Coxe60a1082008-07-16 21:56:18 +0100772 tty_encode_baud_rate(info->port.tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800773
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (cflag & CRTSCTS) {
775 info->intmask |= DELTA_CTS;
776 sEnCTSFlowCtl(cp);
777 } else {
778 info->intmask &= ~DELTA_CTS;
779 sDisCTSFlowCtl(cp);
780 }
781 if (cflag & CLOCAL) {
782 info->intmask &= ~DELTA_CD;
783 } else {
784 spin_lock_irqsave(&info->slock, flags);
785 if (sGetChanStatus(cp) & CD_ACT)
786 info->cd_status = 1;
787 else
788 info->cd_status = 0;
789 info->intmask |= DELTA_CD;
790 spin_unlock_irqrestore(&info->slock, flags);
791 }
792
793 /*
794 * Handle software flow control in the board
795 */
796#ifdef ROCKET_SOFT_FLOW
Alan Coxe60a1082008-07-16 21:56:18 +0100797 if (I_IXON(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 sEnTxSoftFlowCtl(cp);
Alan Coxe60a1082008-07-16 21:56:18 +0100799 if (I_IXANY(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 sEnIXANY(cp);
801 } else {
802 sDisIXANY(cp);
803 }
Alan Coxe60a1082008-07-16 21:56:18 +0100804 sSetTxXONChar(cp, START_CHAR(info->port.tty));
805 sSetTxXOFFChar(cp, STOP_CHAR(info->port.tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 } else {
807 sDisTxSoftFlowCtl(cp);
808 sDisIXANY(cp);
809 sClrTxXOFF(cp);
810 }
811#endif
812
813 /*
814 * Set up ignore/read mask words
815 */
816 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Coxe60a1082008-07-16 21:56:18 +0100817 if (I_INPCK(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Coxe60a1082008-07-16 21:56:18 +0100819 if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 info->read_status_mask |= STMBREAKH;
821
822 /*
823 * Characters to ignore
824 */
825 info->ignore_status_mask = 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100826 if (I_IGNPAR(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Coxe60a1082008-07-16 21:56:18 +0100828 if (I_IGNBRK(info->port.tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 info->ignore_status_mask |= STMBREAKH;
830 /*
831 * If we're ignoring parity and break indicators,
832 * ignore overruns too. (For real raw support).
833 */
Alan Coxe60a1082008-07-16 21:56:18 +0100834 if (I_IGNPAR(info->port.tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 info->ignore_status_mask |= STMRCVROVRH;
836 }
837
838 rocketMode = info->flags & ROCKET_MODE_MASK;
839
840 if ((info->flags & ROCKET_RTS_TOGGLE)
841 || (rocketMode == ROCKET_MODE_RS485))
842 sEnRTSToggle(cp);
843 else
844 sDisRTSToggle(cp);
845
846 sSetRTS(&info->channel);
847
848 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
849 switch (rocketMode) {
850 case ROCKET_MODE_RS485:
851 sSetInterfaceMode(cp, InterfaceModeRS485);
852 break;
853 case ROCKET_MODE_RS422:
854 sSetInterfaceMode(cp, InterfaceModeRS422);
855 break;
856 case ROCKET_MODE_RS232:
857 default:
858 if (info->flags & ROCKET_RTS_TOGGLE)
859 sSetInterfaceMode(cp, InterfaceModeRS232T);
860 else
861 sSetInterfaceMode(cp, InterfaceModeRS232);
862 break;
863 }
864 }
865}
866
Alan Cox31f35932009-01-02 13:45:05 +0000867static int carrier_raised(struct tty_port *port)
868{
869 struct r_port *info = container_of(port, struct r_port, port);
870 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
871}
872
Alan Cox5d951fb2009-01-02 13:45:19 +0000873static void raise_dtr_rts(struct tty_port *port)
874{
875 struct r_port *info = container_of(port, struct r_port, port);
876 sSetDTR(&info->channel);
877 sSetRTS(&info->channel);
878}
879
Alan Coxe60a1082008-07-16 21:56:18 +0100880/* info->port.count is considered critical, protected by spinlocks. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881static int block_til_ready(struct tty_struct *tty, struct file *filp,
882 struct r_port *info)
883{
884 DECLARE_WAITQUEUE(wait, current);
Alan Cox31f35932009-01-02 13:45:05 +0000885 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 int retval;
887 int do_clocal = 0, extra_count = 0;
888 unsigned long flags;
889
890 /*
891 * If the device is in the middle of being closed, then block
892 * until it's done, and then try again.
893 */
894 if (tty_hung_up_p(filp))
Alan Cox21bed702009-01-02 13:48:23 +0000895 return ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Alan Coxa1299092009-01-02 13:45:44 +0000896 if (info->flags & ASYNC_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700897 if (wait_for_completion_interruptible(&info->close_wait))
898 return -ERESTARTSYS;
Alan Cox21bed702009-01-02 13:48:23 +0000899 return ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
901
902 /*
903 * If non-blocking mode is set, or the port is not enabled,
904 * then make the check up front and then exit.
905 */
906 if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
Alan Cox21bed702009-01-02 13:48:23 +0000907 info->port.flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return 0;
909 }
910 if (tty->termios->c_cflag & CLOCAL)
911 do_clocal = 1;
912
913 /*
914 * Block waiting for the carrier detect and the line to become free. While we are in
Alan Cox31f35932009-01-02 13:45:05 +0000915 * this loop, port->count is dropped by one, so that rp_close() knows when to free things.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 * We restore it upon exit, either normal or abnormal.
917 */
918 retval = 0;
Alan Cox31f35932009-01-02 13:45:05 +0000919 add_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920#ifdef ROCKET_DEBUG_OPEN
Alan Cox31f35932009-01-02 13:45:05 +0000921 printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, port->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922#endif
Alan Coxc1314a42009-01-02 13:48:17 +0000923 spin_lock_irqsave(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
925#ifdef ROCKET_DISABLE_SIMUSAGE
Alan Cox21bed702009-01-02 13:48:23 +0000926 info->port.flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927#else
928 if (!tty_hung_up_p(filp)) {
929 extra_count = 1;
Alan Cox31f35932009-01-02 13:45:05 +0000930 port->count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 }
932#endif
Alan Cox31f35932009-01-02 13:45:05 +0000933 port->blocked_open++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Alan Coxc1314a42009-01-02 13:48:17 +0000935 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 while (1) {
Alan Cox5d951fb2009-01-02 13:45:19 +0000938 if (tty->termios->c_cflag & CBAUD)
939 tty_port_raise_dtr_rts(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 set_current_state(TASK_INTERRUPTIBLE);
Alan Cox21bed702009-01-02 13:48:23 +0000941 if (tty_hung_up_p(filp) || !(info->port.flags & ASYNC_INITIALIZED)) {
942 if (info->port.flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 retval = -EAGAIN;
944 else
945 retval = -ERESTARTSYS;
946 break;
947 }
Alan Cox21bed702009-01-02 13:48:23 +0000948 if (!(info->port.flags & ASYNC_CLOSING) &&
Alan Cox31f35932009-01-02 13:45:05 +0000949 (do_clocal || tty_port_carrier_raised(port)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
951 if (signal_pending(current)) {
952 retval = -ERESTARTSYS;
953 break;
954 }
955#ifdef ROCKET_DEBUG_OPEN
956 printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",
Alan Cox21bed702009-01-02 13:48:23 +0000957 info->line, port->count, info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958#endif
959 schedule(); /* Don't hold spinlock here, will hang PC */
960 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700961 __set_current_state(TASK_RUNNING);
Alan Cox31f35932009-01-02 13:45:05 +0000962 remove_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Alan Coxc1314a42009-01-02 13:48:17 +0000964 spin_lock_irqsave(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 if (extra_count)
Alan Cox31f35932009-01-02 13:45:05 +0000967 port->count++;
968 port->blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
Alan Coxc1314a42009-01-02 13:48:17 +0000970 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972#ifdef ROCKET_DEBUG_OPEN
973 printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",
Alan Cox31f35932009-01-02 13:45:05 +0000974 info->line, port->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975#endif
976 if (retval)
977 return retval;
Alan Cox21bed702009-01-02 13:48:23 +0000978 info->port.flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return 0;
980}
981
982/*
983 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
984 * port's r_port struct. Initializes the port hardware.
985 */
986static int rp_open(struct tty_struct *tty, struct file *filp)
987{
988 struct r_port *info;
989 int line = 0, retval;
990 CHANNEL_t *cp;
991 unsigned long page;
992
Jiri Slabyf6de0c92008-02-07 00:16:33 -0800993 line = tty->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))
995 return -ENXIO;
996
997 page = __get_free_page(GFP_KERNEL);
998 if (!page)
999 return -ENOMEM;
1000
Alan Cox21bed702009-01-02 13:48:23 +00001001 if (info->port.flags & ASYNC_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001002 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001004 if (retval)
1005 return retval;
Alan Cox21bed702009-01-02 13:48:23 +00001006 return ((info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008
1009 /*
1010 * We must not sleep from here until the port is marked fully in use.
1011 */
1012 if (info->xmit_buf)
1013 free_page(page);
1014 else
1015 info->xmit_buf = (unsigned char *) page;
1016
1017 tty->driver_data = info;
Alan Coxe60a1082008-07-16 21:56:18 +01001018 info->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Alan Coxe60a1082008-07-16 21:56:18 +01001020 if (info->port.count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 atomic_inc(&rp_num_ports_open);
1022
1023#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001024 printk(KERN_INFO "rocket mod++ = %d...\n",
1025 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026#endif
1027 }
1028#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001029 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030#endif
1031
1032 /*
1033 * Info->count is now 1; so it's safe to sleep now.
1034 */
Alan Cox21bed702009-01-02 13:48:23 +00001035 if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 cp = &info->channel;
1037 sSetRxTrigger(cp, TRIG_1);
1038 if (sGetChanStatus(cp) & CD_ACT)
1039 info->cd_status = 1;
1040 else
1041 info->cd_status = 0;
1042 sDisRxStatusMode(cp);
1043 sFlushRxFIFO(cp);
1044 sFlushTxFIFO(cp);
1045
1046 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1047 sSetRxTrigger(cp, TRIG_1);
1048
1049 sGetChanStatus(cp);
1050 sDisRxStatusMode(cp);
1051 sClrTxXOFF(cp);
1052
1053 sDisCTSFlowCtl(cp);
1054 sDisTxSoftFlowCtl(cp);
1055
1056 sEnRxFIFO(cp);
1057 sEnTransmit(cp);
1058
Alan Cox21bed702009-01-02 13:48:23 +00001059 info->port.flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
1061 /*
1062 * Set up the tty->alt_speed kludge
1063 */
1064 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Coxe60a1082008-07-16 21:56:18 +01001065 info->port.tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001067 info->port.tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001069 info->port.tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Coxe60a1082008-07-16 21:56:18 +01001071 info->port.tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 configure_r_port(info, NULL);
1074 if (tty->termios->c_cflag & CBAUD) {
1075 sSetDTR(cp);
1076 sSetRTS(cp);
1077 }
1078 }
1079 /* Starts (or resets) the maint polling loop */
1080 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
1081
1082 retval = block_til_ready(tty, filp, info);
1083 if (retval) {
1084#ifdef ROCKET_DEBUG_OPEN
1085 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
1086#endif
1087 return retval;
1088 }
1089 return 0;
1090}
1091
1092/*
Alan Coxe60a1082008-07-16 21:56:18 +01001093 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 */
1095static void rp_close(struct tty_struct *tty, struct file *filp)
1096{
Alan Coxc9f19e92009-01-02 13:47:26 +00001097 struct r_port *info = tty->driver_data;
Alan Coxc1314a42009-01-02 13:48:17 +00001098 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 unsigned long flags;
1100 int timeout;
1101 CHANNEL_t *cp;
1102
1103 if (rocket_paranoia_check(info, "rp_close"))
1104 return;
1105
1106#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001107 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108#endif
1109
1110 if (tty_hung_up_p(filp))
1111 return;
Alan Coxc1314a42009-01-02 13:48:17 +00001112 spin_lock_irqsave(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Alan Coxc1314a42009-01-02 13:48:17 +00001114 if (tty->count == 1 && port->count != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 /*
1116 * Uh, oh. tty->count is 1, which means that the tty
1117 * structure will be freed. Info->count should always
1118 * be one in these conditions. If it's greater than
1119 * one, we've got real problems, since it means the
1120 * serial port won't be shutdown.
1121 */
Jiri Slaby68562b72008-02-07 00:16:33 -08001122 printk(KERN_WARNING "rp_close: bad serial port count; "
Alan Coxe60a1082008-07-16 21:56:18 +01001123 "tty->count is 1, info->port.count is %d\n", info->port.count);
Alan Coxc1314a42009-01-02 13:48:17 +00001124 port->count = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
Alan Coxc1314a42009-01-02 13:48:17 +00001126 if (--port->count < 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -08001127 printk(KERN_WARNING "rp_close: bad serial port count for "
Alan Coxe60a1082008-07-16 21:56:18 +01001128 "ttyR%d: %d\n", info->line, info->port.count);
Alan Coxc1314a42009-01-02 13:48:17 +00001129 port->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
Alan Coxc1314a42009-01-02 13:48:17 +00001131 if (port->count) {
1132 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return;
1134 }
Alan Cox21bed702009-01-02 13:48:23 +00001135 info->port.flags |= ASYNC_CLOSING;
Alan Coxc1314a42009-01-02 13:48:17 +00001136 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 cp = &info->channel;
1139
1140 /*
1141 * Notify the line discpline to only process XON/XOFF characters
1142 */
1143 tty->closing = 1;
1144
1145 /*
1146 * If transmission was throttled by the application request,
1147 * just flush the xmit buffer.
1148 */
1149 if (tty->flow_stopped)
1150 rp_flush_buffer(tty);
1151
1152 /*
1153 * Wait for the transmit buffer to clear
1154 */
Alan Coxa1299092009-01-02 13:45:44 +00001155 if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
Alan Coxc1314a42009-01-02 13:48:17 +00001156 tty_wait_until_sent(tty, port->closing_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 /*
1158 * Before we drop DTR, make sure the UART transmitter
1159 * has completely drained; this is especially
1160 * important if there is a transmit FIFO!
1161 */
1162 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1163 if (timeout == 0)
1164 timeout = 1;
1165 rp_wait_until_sent(tty, timeout);
1166 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1167
1168 sDisTransmit(cp);
1169 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1170 sDisCTSFlowCtl(cp);
1171 sDisTxSoftFlowCtl(cp);
1172 sClrTxXOFF(cp);
1173 sFlushRxFIFO(cp);
1174 sFlushTxFIFO(cp);
1175 sClrRTS(cp);
1176 if (C_HUPCL(tty))
1177 sClrDTR(cp);
1178
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001179 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 tty_ldisc_flush(tty);
1182
1183 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1184
Alan Coxc1314a42009-01-02 13:48:17 +00001185 if (port->blocked_open) {
1186 if (port->close_delay) {
1187 msleep_interruptible(jiffies_to_msecs(port->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
Alan Coxc1314a42009-01-02 13:48:17 +00001189 wake_up_interruptible(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 } else {
1191 if (info->xmit_buf) {
1192 free_page((unsigned long) info->xmit_buf);
1193 info->xmit_buf = NULL;
1194 }
1195 }
Alan Cox21bed702009-01-02 13:48:23 +00001196 info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 tty->closing = 0;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001198 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 atomic_dec(&rp_num_ports_open);
1200
1201#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001202 printk(KERN_INFO "rocket mod-- = %d...\n",
1203 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1205#endif
1206
1207}
1208
1209static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001210 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211{
Alan Coxc9f19e92009-01-02 13:47:26 +00001212 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 CHANNEL_t *cp;
1214 unsigned cflag;
1215
1216 if (rocket_paranoia_check(info, "rp_set_termios"))
1217 return;
1218
1219 cflag = tty->termios->c_cflag;
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 /*
1222 * This driver doesn't support CS5 or CS6
1223 */
1224 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
1225 tty->termios->c_cflag =
1226 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001227 /* Or CMSPAR */
1228 tty->termios->c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 configure_r_port(info, old_termios);
1231
1232 cp = &info->channel;
1233
1234 /* Handle transition to B0 status */
1235 if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
1236 sClrDTR(cp);
1237 sClrRTS(cp);
1238 }
1239
1240 /* Handle transition away from B0 status */
1241 if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
1242 if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
1243 sSetRTS(cp);
1244 sSetDTR(cp);
1245 }
1246
1247 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
1248 tty->hw_stopped = 0;
1249 rp_start(tty);
1250 }
1251}
1252
Alan Cox9e989662008-07-22 11:18:03 +01001253static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
Alan Coxc9f19e92009-01-02 13:47:26 +00001255 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 unsigned long flags;
1257
1258 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001259 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 spin_lock_irqsave(&info->slock, flags);
1262 if (break_state == -1)
1263 sSendBreak(&info->channel);
1264 else
1265 sClrBreak(&info->channel);
1266 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001267 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268}
1269
1270/*
1271 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1272 * the UPCI boards was added, it was decided to make this a function because
1273 * the macro was getting too complicated. All cases except the first one
1274 * (UPCIRingInd) are taken directly from the original macro.
1275 */
1276static int sGetChanRI(CHANNEL_T * ChP)
1277{
1278 CONTROLLER_t *CtlP = ChP->CtlP;
1279 int ChanNum = ChP->ChanNum;
1280 int RingInd = 0;
1281
1282 if (CtlP->UPCIRingInd)
1283 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1284 else if (CtlP->AltChanRingIndicator)
1285 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1286 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1287 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1288
1289 return RingInd;
1290}
1291
1292/********************************************************************************************/
1293/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1294
1295/*
1296 * Returns the state of the serial modem control lines. These next 2 functions
1297 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1298 */
1299static int rp_tiocmget(struct tty_struct *tty, struct file *file)
1300{
Alan Coxc9f19e92009-01-02 13:47:26 +00001301 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 unsigned int control, result, ChanStatus;
1303
1304 ChanStatus = sGetChanStatusLo(&info->channel);
1305 control = info->channel.TxControl[3];
1306 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1307 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1308 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1309 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1310 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1311 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1312
1313 return result;
1314}
1315
1316/*
1317 * Sets the modem control lines
1318 */
1319static int rp_tiocmset(struct tty_struct *tty, struct file *file,
1320 unsigned int set, unsigned int clear)
1321{
Alan Coxc9f19e92009-01-02 13:47:26 +00001322 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324 if (set & TIOCM_RTS)
1325 info->channel.TxControl[3] |= SET_RTS;
1326 if (set & TIOCM_DTR)
1327 info->channel.TxControl[3] |= SET_DTR;
1328 if (clear & TIOCM_RTS)
1329 info->channel.TxControl[3] &= ~SET_RTS;
1330 if (clear & TIOCM_DTR)
1331 info->channel.TxControl[3] &= ~SET_DTR;
1332
Al Viro457fb602008-03-19 16:27:48 +00001333 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 return 0;
1335}
1336
1337static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1338{
1339 struct rocket_config tmp;
1340
1341 if (!retinfo)
1342 return -EFAULT;
1343 memset(&tmp, 0, sizeof (tmp));
1344 tmp.line = info->line;
1345 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001346 tmp.close_delay = info->port.close_delay;
1347 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
1349
1350 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1351 return -EFAULT;
1352 return 0;
1353}
1354
1355static int set_config(struct r_port *info, struct rocket_config __user *new_info)
1356{
1357 struct rocket_config new_serial;
1358
1359 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1360 return -EFAULT;
1361
1362 if (!capable(CAP_SYS_ADMIN))
1363 {
1364 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))
1365 return -EPERM;
1366 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
1367 configure_r_port(info, NULL);
1368 return 0;
1369 }
1370
1371 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001372 info->port.close_delay = new_serial.close_delay;
1373 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Coxe60a1082008-07-16 21:56:18 +01001376 info->port.tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001378 info->port.tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Coxe60a1082008-07-16 21:56:18 +01001380 info->port.tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Coxe60a1082008-07-16 21:56:18 +01001382 info->port.tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 configure_r_port(info, NULL);
1385 return 0;
1386}
1387
1388/*
1389 * This function fills in a rocket_ports struct with information
1390 * about what boards/ports are in the system. This info is passed
1391 * to user space. See setrocket.c where the info is used to create
1392 * the /dev/ttyRx ports.
1393 */
1394static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1395{
1396 struct rocket_ports tmp;
1397 int board;
1398
1399 if (!retports)
1400 return -EFAULT;
1401 memset(&tmp, 0, sizeof (tmp));
1402 tmp.tty_major = rocket_driver->major;
1403
1404 for (board = 0; board < 4; board++) {
1405 tmp.rocketModel[board].model = rocketModel[board].model;
1406 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1407 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1408 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1409 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1410 }
1411 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1412 return -EFAULT;
1413 return 0;
1414}
1415
1416static int reset_rm2(struct r_port *info, void __user *arg)
1417{
1418 int reset;
1419
Alan Cox4129a6452008-02-08 04:18:45 -08001420 if (!capable(CAP_SYS_ADMIN))
1421 return -EPERM;
1422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 if (copy_from_user(&reset, arg, sizeof (int)))
1424 return -EFAULT;
1425 if (reset)
1426 reset = 1;
1427
1428 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1429 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1430 return -EINVAL;
1431
1432 if (info->ctlp->BusType == isISA)
1433 sModemReset(info->ctlp, info->chan, reset);
1434 else
1435 sPCIModemReset(info->ctlp, info->chan, reset);
1436
1437 return 0;
1438}
1439
1440static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1441{
1442 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1443 return -EFAULT;
1444 return 0;
1445}
1446
1447/* IOCTL call handler into the driver */
1448static int rp_ioctl(struct tty_struct *tty, struct file *file,
1449 unsigned int cmd, unsigned long arg)
1450{
Alan Coxc9f19e92009-01-02 13:47:26 +00001451 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001453 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1456 return -ENXIO;
1457
Alan Coxbdf183a2008-04-30 00:53:21 -07001458 lock_kernel();
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 switch (cmd) {
1461 case RCKP_GET_STRUCT:
1462 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001463 ret = -EFAULT;
1464 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001466 ret = get_config(info, argp);
1467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 case RCKP_SET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001469 ret = set_config(info, argp);
1470 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001472 ret = get_ports(info, argp);
1473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001475 ret = reset_rm2(info, argp);
1476 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001478 ret = get_version(info, argp);
1479 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001481 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001483 unlock_kernel();
1484 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485}
1486
1487static void rp_send_xchar(struct tty_struct *tty, char ch)
1488{
Alan Coxc9f19e92009-01-02 13:47:26 +00001489 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 CHANNEL_t *cp;
1491
1492 if (rocket_paranoia_check(info, "rp_send_xchar"))
1493 return;
1494
1495 cp = &info->channel;
1496 if (sGetTxCnt(cp))
1497 sWriteTxPrioByte(cp, ch);
1498 else
1499 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1500}
1501
1502static void rp_throttle(struct tty_struct *tty)
1503{
Alan Coxc9f19e92009-01-02 13:47:26 +00001504 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 CHANNEL_t *cp;
1506
1507#ifdef ROCKET_DEBUG_THROTTLE
1508 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1509 tty->ldisc.chars_in_buffer(tty));
1510#endif
1511
1512 if (rocket_paranoia_check(info, "rp_throttle"))
1513 return;
1514
1515 cp = &info->channel;
1516 if (I_IXOFF(tty))
1517 rp_send_xchar(tty, STOP_CHAR(tty));
1518
1519 sClrRTS(&info->channel);
1520}
1521
1522static void rp_unthrottle(struct tty_struct *tty)
1523{
Alan Coxc9f19e92009-01-02 13:47:26 +00001524 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 CHANNEL_t *cp;
1526#ifdef ROCKET_DEBUG_THROTTLE
1527 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1528 tty->ldisc.chars_in_buffer(tty));
1529#endif
1530
1531 if (rocket_paranoia_check(info, "rp_throttle"))
1532 return;
1533
1534 cp = &info->channel;
1535 if (I_IXOFF(tty))
1536 rp_send_xchar(tty, START_CHAR(tty));
1537
1538 sSetRTS(&info->channel);
1539}
1540
1541/*
1542 * ------------------------------------------------------------
1543 * rp_stop() and rp_start()
1544 *
1545 * This routines are called before setting or resetting tty->stopped.
1546 * They enable or disable transmitter interrupts, as necessary.
1547 * ------------------------------------------------------------
1548 */
1549static void rp_stop(struct tty_struct *tty)
1550{
Alan Coxc9f19e92009-01-02 13:47:26 +00001551 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553#ifdef ROCKET_DEBUG_FLOW
1554 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1555 info->xmit_cnt, info->xmit_fifo_room);
1556#endif
1557
1558 if (rocket_paranoia_check(info, "rp_stop"))
1559 return;
1560
1561 if (sGetTxCnt(&info->channel))
1562 sDisTransmit(&info->channel);
1563}
1564
1565static void rp_start(struct tty_struct *tty)
1566{
Alan Coxc9f19e92009-01-02 13:47:26 +00001567 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
1569#ifdef ROCKET_DEBUG_FLOW
1570 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1571 info->xmit_cnt, info->xmit_fifo_room);
1572#endif
1573
1574 if (rocket_paranoia_check(info, "rp_stop"))
1575 return;
1576
1577 sEnTransmit(&info->channel);
1578 set_bit((info->aiop * 8) + info->chan,
1579 (void *) &xmit_flags[info->board]);
1580}
1581
1582/*
1583 * rp_wait_until_sent() --- wait until the transmitter is empty
1584 */
1585static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1586{
Alan Coxc9f19e92009-01-02 13:47:26 +00001587 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 CHANNEL_t *cp;
1589 unsigned long orig_jiffies;
1590 int check_time, exit_time;
1591 int txcnt;
1592
1593 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1594 return;
1595
1596 cp = &info->channel;
1597
1598 orig_jiffies = jiffies;
1599#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001600 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001602 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603#endif
Alan Cox978e5952008-04-30 00:53:59 -07001604 lock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 while (1) {
1606 txcnt = sGetTxCnt(cp);
1607 if (!txcnt) {
1608 if (sGetChanStatusLo(cp) & TXSHRMT)
1609 break;
1610 check_time = (HZ / info->cps) / 5;
1611 } else {
1612 check_time = HZ * txcnt / info->cps;
1613 }
1614 if (timeout) {
1615 exit_time = orig_jiffies + timeout - jiffies;
1616 if (exit_time <= 0)
1617 break;
1618 if (exit_time < check_time)
1619 check_time = exit_time;
1620 }
1621 if (check_time == 0)
1622 check_time = 1;
1623#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001624 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1625 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626#endif
1627 msleep_interruptible(jiffies_to_msecs(check_time));
1628 if (signal_pending(current))
1629 break;
1630 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001631 __set_current_state(TASK_RUNNING);
Alan Cox978e5952008-04-30 00:53:59 -07001632 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1634 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1635#endif
1636}
1637
1638/*
1639 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1640 */
1641static void rp_hangup(struct tty_struct *tty)
1642{
1643 CHANNEL_t *cp;
Alan Coxc9f19e92009-01-02 13:47:26 +00001644 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 if (rocket_paranoia_check(info, "rp_hangup"))
1647 return;
1648
1649#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001650 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651#endif
1652 rp_flush_buffer(tty);
Alan Cox21bed702009-01-02 13:48:23 +00001653 if (info->port.flags & ASYNC_CLOSING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 return;
Alan Coxe60a1082008-07-16 21:56:18 +01001655 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 atomic_dec(&rp_num_ports_open);
1657 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1658
Alan Coxe60a1082008-07-16 21:56:18 +01001659 info->port.count = 0;
Alan Cox21bed702009-01-02 13:48:23 +00001660 info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
Alan Coxe60a1082008-07-16 21:56:18 +01001661 info->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 cp = &info->channel;
1664 sDisRxFIFO(cp);
1665 sDisTransmit(cp);
1666 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1667 sDisCTSFlowCtl(cp);
1668 sDisTxSoftFlowCtl(cp);
1669 sClrTxXOFF(cp);
Alan Cox21bed702009-01-02 13:48:23 +00001670 info->port.flags &= ~ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Alan Coxe60a1082008-07-16 21:56:18 +01001672 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673}
1674
1675/*
1676 * Exception handler - write char routine. The RocketPort driver uses a
1677 * double-buffering strategy, with the twist that if the in-memory CPU
1678 * buffer is empty, and there's space in the transmit FIFO, the
1679 * writing routines will write directly to transmit FIFO.
1680 * Write buffer and counters protected by spinlocks
1681 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001682static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683{
Alan Coxc9f19e92009-01-02 13:47:26 +00001684 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 CHANNEL_t *cp;
1686 unsigned long flags;
1687
1688 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001689 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001691 /*
1692 * Grab the port write mutex, locking out other processes that try to
1693 * write to this port
1694 */
1695 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001698 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699#endif
1700
1701 spin_lock_irqsave(&info->slock, flags);
1702 cp = &info->channel;
1703
1704 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1705 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1706
1707 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1708 info->xmit_buf[info->xmit_head++] = ch;
1709 info->xmit_head &= XMIT_BUF_SIZE - 1;
1710 info->xmit_cnt++;
1711 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1712 } else {
1713 sOutB(sGetTxRxDataIO(cp), ch);
1714 info->xmit_fifo_room--;
1715 }
1716 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001717 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001718 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719}
1720
1721/*
1722 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001723 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 * this port at the same time. This other process could be running on the other CPU
1725 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1726 * Spinlocks protect the info xmit members.
1727 */
1728static int rp_write(struct tty_struct *tty,
1729 const unsigned char *buf, int count)
1730{
Alan Coxc9f19e92009-01-02 13:47:26 +00001731 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 CHANNEL_t *cp;
1733 const unsigned char *b;
1734 int c, retval = 0;
1735 unsigned long flags;
1736
1737 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1738 return 0;
1739
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001740 if (mutex_lock_interruptible(&info->write_mtx))
1741 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001744 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745#endif
1746 cp = &info->channel;
1747
1748 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1749 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1750
1751 /*
1752 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1753 * into FIFO. Use the write queue for temp storage.
1754 */
1755 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1756 c = min(count, info->xmit_fifo_room);
1757 b = buf;
1758
1759 /* Push data into FIFO, 2 bytes at a time */
1760 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1761
1762 /* If there is a byte remaining, write it */
1763 if (c & 1)
1764 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1765
1766 retval += c;
1767 buf += c;
1768 count -= c;
1769
1770 spin_lock_irqsave(&info->slock, flags);
1771 info->xmit_fifo_room -= c;
1772 spin_unlock_irqrestore(&info->slock, flags);
1773 }
1774
1775 /* If count is zero, we wrote it all and are done */
1776 if (!count)
1777 goto end;
1778
1779 /* Write remaining data into the port's xmit_buf */
1780 while (1) {
Alan Coxe60a1082008-07-16 21:56:18 +01001781 if (!info->port.tty) /* Seemingly obligatory check... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001783 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1784 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 if (c <= 0)
1786 break;
1787
1788 b = buf;
1789 memcpy(info->xmit_buf + info->xmit_head, b, c);
1790
1791 spin_lock_irqsave(&info->slock, flags);
1792 info->xmit_head =
1793 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1794 info->xmit_cnt += c;
1795 spin_unlock_irqrestore(&info->slock, flags);
1796
1797 buf += c;
1798 count -= c;
1799 retval += c;
1800 }
1801
1802 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1803 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1804
1805end:
1806 if (info->xmit_cnt < WAKEUP_CHARS) {
1807 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808#ifdef ROCKETPORT_HAVE_POLL_WAIT
1809 wake_up_interruptible(&tty->poll_wait);
1810#endif
1811 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001812 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 return retval;
1814}
1815
1816/*
1817 * Return the number of characters that can be sent. We estimate
1818 * only using the in-memory transmit buffer only, and ignore the
1819 * potential space in the transmit FIFO.
1820 */
1821static int rp_write_room(struct tty_struct *tty)
1822{
Alan Coxc9f19e92009-01-02 13:47:26 +00001823 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 int ret;
1825
1826 if (rocket_paranoia_check(info, "rp_write_room"))
1827 return 0;
1828
1829 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1830 if (ret < 0)
1831 ret = 0;
1832#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001833 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834#endif
1835 return ret;
1836}
1837
1838/*
1839 * Return the number of characters in the buffer. Again, this only
1840 * counts those characters in the in-memory transmit buffer.
1841 */
1842static int rp_chars_in_buffer(struct tty_struct *tty)
1843{
Alan Coxc9f19e92009-01-02 13:47:26 +00001844 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 CHANNEL_t *cp;
1846
1847 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1848 return 0;
1849
1850 cp = &info->channel;
1851
1852#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001853 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854#endif
1855 return info->xmit_cnt;
1856}
1857
1858/*
1859 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1860 * r_port struct for the port. Note that spinlock are used to protect info members,
1861 * do not call this function if the spinlock is already held.
1862 */
1863static void rp_flush_buffer(struct tty_struct *tty)
1864{
Alan Coxc9f19e92009-01-02 13:47:26 +00001865 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 CHANNEL_t *cp;
1867 unsigned long flags;
1868
1869 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1870 return;
1871
1872 spin_lock_irqsave(&info->slock, flags);
1873 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1874 spin_unlock_irqrestore(&info->slock, flags);
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876#ifdef ROCKETPORT_HAVE_POLL_WAIT
1877 wake_up_interruptible(&tty->poll_wait);
1878#endif
1879 tty_wakeup(tty);
1880
1881 cp = &info->channel;
1882 sFlushTxFIFO(cp);
1883}
1884
1885#ifdef CONFIG_PCI
1886
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001887static struct pci_device_id __devinitdata rocket_pci_ids[] = {
1888 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
1889 { }
1890};
1891MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1892
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893/*
1894 * Called when a PCI card is found. Retrieves and stores model information,
1895 * init's aiopic and serial port hardware.
1896 * Inputs: i is the board number (0-n)
1897 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001898static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899{
1900 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1901 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1902 char *str, *board_type;
1903 CONTROLLER_t *ctlp;
1904
1905 int fast_clock = 0;
1906 int altChanRingIndicator = 0;
1907 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 WordIO_t ConfigIO = 0;
1909 ByteIO_t UPCIRingInd = 0;
1910
1911 if (!dev || pci_enable_device(dev))
1912 return 0;
1913
1914 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1917 rocketModel[i].loadrm2 = 0;
1918 rocketModel[i].startingPortNumber = nextLineNumber;
1919
1920 /* Depending on the model, set up some config variables */
1921 switch (dev->device) {
1922 case PCI_DEVICE_ID_RP4QUAD:
1923 str = "Quadcable";
1924 max_num_aiops = 1;
1925 ports_per_aiop = 4;
1926 rocketModel[i].model = MODEL_RP4QUAD;
1927 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1928 rocketModel[i].numPorts = 4;
1929 break;
1930 case PCI_DEVICE_ID_RP8OCTA:
1931 str = "Octacable";
1932 max_num_aiops = 1;
1933 rocketModel[i].model = MODEL_RP8OCTA;
1934 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1935 rocketModel[i].numPorts = 8;
1936 break;
1937 case PCI_DEVICE_ID_URP8OCTA:
1938 str = "Octacable";
1939 max_num_aiops = 1;
1940 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1941 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1942 rocketModel[i].numPorts = 8;
1943 break;
1944 case PCI_DEVICE_ID_RP8INTF:
1945 str = "8";
1946 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:
1952 str = "8";
1953 max_num_aiops = 1;
1954 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1955 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1956 rocketModel[i].numPorts = 8;
1957 break;
1958 case PCI_DEVICE_ID_RP8J:
1959 str = "8J";
1960 max_num_aiops = 1;
1961 rocketModel[i].model = MODEL_RP8J;
1962 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1963 rocketModel[i].numPorts = 8;
1964 break;
1965 case PCI_DEVICE_ID_RP4J:
1966 str = "4J";
1967 max_num_aiops = 1;
1968 ports_per_aiop = 4;
1969 rocketModel[i].model = MODEL_RP4J;
1970 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1971 rocketModel[i].numPorts = 4;
1972 break;
1973 case PCI_DEVICE_ID_RP8SNI:
1974 str = "8 (DB78 Custom)";
1975 max_num_aiops = 1;
1976 rocketModel[i].model = MODEL_RP8SNI;
1977 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1978 rocketModel[i].numPorts = 8;
1979 break;
1980 case PCI_DEVICE_ID_RP16SNI:
1981 str = "16 (DB78 Custom)";
1982 max_num_aiops = 2;
1983 rocketModel[i].model = MODEL_RP16SNI;
1984 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1985 rocketModel[i].numPorts = 16;
1986 break;
1987 case PCI_DEVICE_ID_RP16INTF:
1988 str = "16";
1989 max_num_aiops = 2;
1990 rocketModel[i].model = MODEL_RP16INTF;
1991 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1992 rocketModel[i].numPorts = 16;
1993 break;
1994 case PCI_DEVICE_ID_URP16INTF:
1995 str = "16";
1996 max_num_aiops = 2;
1997 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1998 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1999 rocketModel[i].numPorts = 16;
2000 break;
2001 case PCI_DEVICE_ID_CRP16INTF:
2002 str = "16";
2003 max_num_aiops = 2;
2004 rocketModel[i].model = MODEL_CPCI_RP16INTF;
2005 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
2006 rocketModel[i].numPorts = 16;
2007 break;
2008 case PCI_DEVICE_ID_RP32INTF:
2009 str = "32";
2010 max_num_aiops = 4;
2011 rocketModel[i].model = MODEL_RP32INTF;
2012 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
2013 rocketModel[i].numPorts = 32;
2014 break;
2015 case PCI_DEVICE_ID_URP32INTF:
2016 str = "32";
2017 max_num_aiops = 4;
2018 rocketModel[i].model = MODEL_UPCI_RP32INTF;
2019 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
2020 rocketModel[i].numPorts = 32;
2021 break;
2022 case PCI_DEVICE_ID_RPP4:
2023 str = "Plus Quadcable";
2024 max_num_aiops = 1;
2025 ports_per_aiop = 4;
2026 altChanRingIndicator++;
2027 fast_clock++;
2028 rocketModel[i].model = MODEL_RPP4;
2029 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
2030 rocketModel[i].numPorts = 4;
2031 break;
2032 case PCI_DEVICE_ID_RPP8:
2033 str = "Plus Octacable";
2034 max_num_aiops = 2;
2035 ports_per_aiop = 4;
2036 altChanRingIndicator++;
2037 fast_clock++;
2038 rocketModel[i].model = MODEL_RPP8;
2039 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
2040 rocketModel[i].numPorts = 8;
2041 break;
2042 case PCI_DEVICE_ID_RP2_232:
2043 str = "Plus 2 (RS-232)";
2044 max_num_aiops = 1;
2045 ports_per_aiop = 2;
2046 altChanRingIndicator++;
2047 fast_clock++;
2048 rocketModel[i].model = MODEL_RP2_232;
2049 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
2050 rocketModel[i].numPorts = 2;
2051 break;
2052 case PCI_DEVICE_ID_RP2_422:
2053 str = "Plus 2 (RS-422)";
2054 max_num_aiops = 1;
2055 ports_per_aiop = 2;
2056 altChanRingIndicator++;
2057 fast_clock++;
2058 rocketModel[i].model = MODEL_RP2_422;
2059 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
2060 rocketModel[i].numPorts = 2;
2061 break;
2062 case PCI_DEVICE_ID_RP6M:
2063
2064 max_num_aiops = 1;
2065 ports_per_aiop = 6;
2066 str = "6-port";
2067
Jiri Slaby57fedc72007-10-18 03:06:28 -07002068 /* If revision is 1, the rocketmodem flash must be loaded.
2069 * If it is 2 it is a "socketed" version. */
2070 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2072 rocketModel[i].loadrm2 = 1;
2073 } else {
2074 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2075 }
2076
2077 rocketModel[i].model = MODEL_RP6M;
2078 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
2079 rocketModel[i].numPorts = 6;
2080 break;
2081 case PCI_DEVICE_ID_RP4M:
2082 max_num_aiops = 1;
2083 ports_per_aiop = 4;
2084 str = "4-port";
Jiri Slaby57fedc72007-10-18 03:06:28 -07002085 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
2087 rocketModel[i].loadrm2 = 1;
2088 } else {
2089 rcktpt_type[i] = ROCKET_TYPE_MODEM;
2090 }
2091
2092 rocketModel[i].model = MODEL_RP4M;
2093 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
2094 rocketModel[i].numPorts = 4;
2095 break;
2096 default:
2097 str = "(unknown/unsupported)";
2098 max_num_aiops = 0;
2099 break;
2100 }
2101
2102 /*
2103 * Check for UPCI boards.
2104 */
2105
2106 switch (dev->device) {
2107 case PCI_DEVICE_ID_URP32INTF:
2108 case PCI_DEVICE_ID_URP8INTF:
2109 case PCI_DEVICE_ID_URP16INTF:
2110 case PCI_DEVICE_ID_CRP16INTF:
2111 case PCI_DEVICE_ID_URP8OCTA:
2112 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2113 ConfigIO = pci_resource_start(dev, 1);
2114 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
2115 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2116
2117 /*
2118 * Check for octa or quad cable.
2119 */
2120 if (!
2121 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
2122 PCI_GPIO_CTRL_8PORT)) {
2123 str = "Quadcable";
2124 ports_per_aiop = 4;
2125 rocketModel[i].numPorts = 4;
2126 }
2127 }
2128 break;
2129 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
2130 str = "8 ports";
2131 max_num_aiops = 1;
2132 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
2133 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
2134 rocketModel[i].numPorts = 8;
2135 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2136 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2137 ConfigIO = pci_resource_start(dev, 1);
2138 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2139 break;
2140 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
2141 str = "4 ports";
2142 max_num_aiops = 1;
2143 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2144 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2145 rocketModel[i].numPorts = 4;
2146 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2147 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2148 ConfigIO = pci_resource_start(dev, 1);
2149 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2150 break;
2151 default:
2152 break;
2153 }
2154
2155 switch (rcktpt_type[i]) {
2156 case ROCKET_TYPE_MODEM:
2157 board_type = "RocketModem";
2158 break;
2159 case ROCKET_TYPE_MODEMII:
2160 board_type = "RocketModem II";
2161 break;
2162 case ROCKET_TYPE_MODEMIII:
2163 board_type = "RocketModem III";
2164 break;
2165 default:
2166 board_type = "RocketPort";
2167 break;
2168 }
2169
2170 if (fast_clock) {
2171 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2172 rp_baud_base[i] = 921600;
2173 } else {
2174 /*
2175 * If support_low_speed is set, use the slow clock
2176 * prescale, which supports 50 bps
2177 */
2178 if (support_low_speed) {
2179 /* mod 9 (divide by 10) prescale */
2180 sClockPrescale = 0x19;
2181 rp_baud_base[i] = 230400;
2182 } else {
2183 /* mod 4 (devide by 5) prescale */
2184 sClockPrescale = 0x14;
2185 rp_baud_base[i] = 460800;
2186 }
2187 }
2188
2189 for (aiop = 0; aiop < max_num_aiops; aiop++)
2190 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2191 ctlp = sCtlNumToCtlPtr(i);
2192 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2193 for (aiop = 0; aiop < max_num_aiops; aiop++)
2194 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2195
Jiri Slaby68562b72008-02-07 00:16:33 -08002196 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2197 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2198 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2199 rocketModel[i].startingPortNumber,
2200 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 if (num_aiops <= 0) {
2203 rcktpt_io_addr[i] = 0;
2204 return (0);
2205 }
2206 is_PCI[i] = 1;
2207
2208 /* Reset the AIOPIC, init the serial ports */
2209 for (aiop = 0; aiop < num_aiops; aiop++) {
2210 sResetAiopByNum(ctlp, aiop);
2211 num_chan = ports_per_aiop;
2212 for (chan = 0; chan < num_chan; chan++)
2213 init_r_port(i, aiop, chan, dev);
2214 }
2215
2216 /* Rocket modems must be reset */
2217 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2218 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2219 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2220 num_chan = ports_per_aiop;
2221 for (chan = 0; chan < num_chan; chan++)
2222 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002223 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 for (chan = 0; chan < num_chan; chan++)
2225 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002226 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 rmSpeakerReset(ctlp, rocketModel[i].model);
2228 }
2229 return (1);
2230}
2231
2232/*
2233 * Probes for PCI cards, inits them if found
2234 * Input: board_found = number of ISA boards already found, or the
2235 * starting board number
2236 * Returns: Number of PCI boards found
2237 */
2238static int __init init_PCI(int boards_found)
2239{
2240 struct pci_dev *dev = NULL;
2241 int count = 0;
2242
2243 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002244 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 if (register_PCI(count + boards_found, dev))
2246 count++;
2247 }
2248 return (count);
2249}
2250
2251#endif /* CONFIG_PCI */
2252
2253/*
2254 * Probes for ISA cards
2255 * Input: i = the board number to look for
2256 * Returns: 1 if board found, 0 else
2257 */
2258static int __init init_ISA(int i)
2259{
2260 int num_aiops, num_chan = 0, total_num_chan = 0;
2261 int aiop, chan;
2262 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2263 CONTROLLER_t *ctlp;
2264 char *type_string;
2265
2266 /* If io_addr is zero, no board configured */
2267 if (rcktpt_io_addr[i] == 0)
2268 return (0);
2269
2270 /* Reserve the IO region */
2271 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002272 printk(KERN_ERR "Unable to reserve IO region for configured "
2273 "ISA RocketPort at address 0x%lx, board not "
2274 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 rcktpt_io_addr[i] = 0;
2276 return (0);
2277 }
2278
2279 ctlp = sCtlNumToCtlPtr(i);
2280
2281 ctlp->boardType = rcktpt_type[i];
2282
2283 switch (rcktpt_type[i]) {
2284 case ROCKET_TYPE_PC104:
2285 type_string = "(PC104)";
2286 break;
2287 case ROCKET_TYPE_MODEM:
2288 type_string = "(RocketModem)";
2289 break;
2290 case ROCKET_TYPE_MODEMII:
2291 type_string = "(RocketModem II)";
2292 break;
2293 default:
2294 type_string = "";
2295 break;
2296 }
2297
2298 /*
2299 * If support_low_speed is set, use the slow clock prescale,
2300 * which supports 50 bps
2301 */
2302 if (support_low_speed) {
2303 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2304 rp_baud_base[i] = 230400;
2305 } else {
2306 sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */
2307 rp_baud_base[i] = 460800;
2308 }
2309
2310 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2311 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2312
2313 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2314
2315 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2316 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2317 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2318 }
2319
2320 /* If something went wrong initing the AIOP's release the ISA IO memory */
2321 if (num_aiops <= 0) {
2322 release_region(rcktpt_io_addr[i], 64);
2323 rcktpt_io_addr[i] = 0;
2324 return (0);
2325 }
2326
2327 rocketModel[i].startingPortNumber = nextLineNumber;
2328
2329 for (aiop = 0; aiop < num_aiops; aiop++) {
2330 sResetAiopByNum(ctlp, aiop);
2331 sEnAiop(ctlp, aiop);
2332 num_chan = sGetAiopNumChan(ctlp, aiop);
2333 total_num_chan += num_chan;
2334 for (chan = 0; chan < num_chan; chan++)
2335 init_r_port(i, aiop, chan, NULL);
2336 }
2337 is_PCI[i] = 0;
2338 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2339 num_chan = sGetAiopNumChan(ctlp, 0);
2340 total_num_chan = num_chan;
2341 for (chan = 0; chan < num_chan; chan++)
2342 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002343 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 for (chan = 0; chan < num_chan; chan++)
2345 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002346 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2348 } else {
2349 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2350 }
2351 rocketModel[i].numPorts = total_num_chan;
2352 rocketModel[i].model = MODEL_ISA;
2353
2354 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2355 i, rcktpt_io_addr[i], num_aiops, type_string);
2356
2357 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2358 rocketModel[i].modelString,
2359 rocketModel[i].startingPortNumber,
2360 rocketModel[i].startingPortNumber +
2361 rocketModel[i].numPorts - 1);
2362
2363 return (1);
2364}
2365
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002366static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 .open = rp_open,
2368 .close = rp_close,
2369 .write = rp_write,
2370 .put_char = rp_put_char,
2371 .write_room = rp_write_room,
2372 .chars_in_buffer = rp_chars_in_buffer,
2373 .flush_buffer = rp_flush_buffer,
2374 .ioctl = rp_ioctl,
2375 .throttle = rp_throttle,
2376 .unthrottle = rp_unthrottle,
2377 .set_termios = rp_set_termios,
2378 .stop = rp_stop,
2379 .start = rp_start,
2380 .hangup = rp_hangup,
2381 .break_ctl = rp_break,
2382 .send_xchar = rp_send_xchar,
2383 .wait_until_sent = rp_wait_until_sent,
2384 .tiocmget = rp_tiocmget,
2385 .tiocmset = rp_tiocmset,
2386};
2387
Alan Cox31f35932009-01-02 13:45:05 +00002388static const struct tty_port_operations rocket_port_ops = {
2389 .carrier_raised = carrier_raised,
Alan Cox5d951fb2009-01-02 13:45:19 +00002390 .raise_dtr_rts = raise_dtr_rts,
Alan Cox31f35932009-01-02 13:45:05 +00002391};
2392
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393/*
2394 * The module "startup" routine; it's run when the module is loaded.
2395 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002396static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002398 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
2400 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2401 ROCKET_VERSION, ROCKET_DATE);
2402
2403 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2404 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002405 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2409 * zero, use the default controller IO address of board1 + 0x40.
2410 */
2411 if (board1) {
2412 if (controller == 0)
2413 controller = board1 + 0x40;
2414 } else {
2415 controller = 0; /* Used as a flag, meaning no ISA boards */
2416 }
2417
2418 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2419 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002420 printk(KERN_ERR "Unable to reserve IO region for first "
2421 "configured ISA RocketPort controller 0x%lx. "
2422 "Driver exiting\n", controller);
2423 ret = -EBUSY;
2424 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 }
2426
2427 /* Store ISA variable retrieved from command line or .conf file. */
2428 rcktpt_io_addr[0] = board1;
2429 rcktpt_io_addr[1] = board2;
2430 rcktpt_io_addr[2] = board3;
2431 rcktpt_io_addr[3] = board4;
2432
2433 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2434 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2435 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2436 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2437 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2438 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2439 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2440 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2441
2442 /*
2443 * Set up the tty driver structure and then register this
2444 * driver with the tty layer.
2445 */
2446
2447 rocket_driver->owner = THIS_MODULE;
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002448 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 rocket_driver->name = "ttyR";
2450 rocket_driver->driver_name = "Comtrol RocketPort";
2451 rocket_driver->major = TTY_ROCKET_MAJOR;
2452 rocket_driver->minor_start = 0;
2453 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2454 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2455 rocket_driver->init_termios = tty_std_termios;
2456 rocket_driver->init_termios.c_cflag =
2457 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002458 rocket_driver->init_termios.c_ispeed = 9600;
2459 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002461 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462#endif
2463 tty_set_operations(rocket_driver, &rocket_ops);
2464
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002465 ret = tty_register_driver(rocket_driver);
2466 if (ret < 0) {
2467 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
2468 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470
2471#ifdef ROCKET_DEBUG_OPEN
2472 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2473#endif
2474
2475 /*
2476 * OK, let's probe each of the controllers looking for boards. Any boards found
2477 * will be initialized here.
2478 */
2479 isa_boards_found = 0;
2480 pci_boards_found = 0;
2481
2482 for (i = 0; i < NUM_BOARDS; i++) {
2483 if (init_ISA(i))
2484 isa_boards_found++;
2485 }
2486
2487#ifdef CONFIG_PCI
2488 if (isa_boards_found < NUM_BOARDS)
2489 pci_boards_found = init_PCI(isa_boards_found);
2490#endif
2491
2492 max_board = pci_boards_found + isa_boards_found;
2493
2494 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002495 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2496 ret = -ENXIO;
2497 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 }
2499
2500 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002501err_ttyu:
2502 tty_unregister_driver(rocket_driver);
2503err_tty:
2504 put_tty_driver(rocket_driver);
2505err:
2506 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507}
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
2510static void rp_cleanup_module(void)
2511{
2512 int retval;
2513 int i;
2514
2515 del_timer_sync(&rocket_timer);
2516
2517 retval = tty_unregister_driver(rocket_driver);
2518 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002519 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Jesper Juhl735d5662005-11-07 01:01:29 -08002522 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002523 if (rp_table[i]) {
2524 tty_unregister_device(rocket_driver, i);
2525 kfree(rp_table[i]);
2526 }
2527
2528 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 for (i = 0; i < NUM_BOARDS; i++) {
2531 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2532 continue;
2533 release_region(rcktpt_io_addr[i], 64);
2534 }
2535 if (controller)
2536 release_region(controller, 4);
2537}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539/***************************************************************************
2540Function: sInitController
2541Purpose: Initialization of controller global registers and controller
2542 structure.
2543Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2544 IRQNum,Frequency,PeriodicOnly)
2545 CONTROLLER_T *CtlP; Ptr to controller structure
2546 int CtlNum; Controller number
2547 ByteIO_t MudbacIO; Mudbac base I/O address.
2548 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2549 This list must be in the order the AIOPs will be found on the
2550 controller. Once an AIOP in the list is not found, it is
2551 assumed that there are no more AIOPs on the controller.
2552 int AiopIOListSize; Number of addresses in AiopIOList
2553 int IRQNum; Interrupt Request number. Can be any of the following:
2554 0: Disable global interrupts
2555 3: IRQ 3
2556 4: IRQ 4
2557 5: IRQ 5
2558 9: IRQ 9
2559 10: IRQ 10
2560 11: IRQ 11
2561 12: IRQ 12
2562 15: IRQ 15
2563 Byte_t Frequency: A flag identifying the frequency
2564 of the periodic interrupt, can be any one of the following:
2565 FREQ_DIS - periodic interrupt disabled
2566 FREQ_137HZ - 137 Hertz
2567 FREQ_69HZ - 69 Hertz
2568 FREQ_34HZ - 34 Hertz
2569 FREQ_17HZ - 17 Hertz
2570 FREQ_9HZ - 9 Hertz
2571 FREQ_4HZ - 4 Hertz
2572 If IRQNum is set to 0 the Frequency parameter is
2573 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002574 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002576 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 other channel interrupts are allowed.
2578 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002579 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2581 initialization failed.
2582
2583Comments:
2584 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002585 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 If interrupts are to be completely disabled set IRQNum to 0.
2588
Adrian Bunkf15313b2005-06-25 14:59:05 -07002589 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 invalid combination.
2591
2592 This function performs initialization of global interrupt modes,
2593 but it does not actually enable global interrupts. To enable
2594 and disable global interrupts use functions sEnGlobalInt() and
2595 sDisGlobalInt(). Enabling of global interrupts is normally not
2596 done until all other initializations are complete.
2597
2598 Even if interrupts are globally enabled, they must also be
2599 individually enabled for each channel that is to generate
2600 interrupts.
2601
2602Warnings: No range checking on any of the parameters is done.
2603
2604 No context switches are allowed while executing this function.
2605
2606 After this function all AIOPs on the controller are disabled,
2607 they can be enabled with sEnAiop().
2608*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002609static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2610 ByteIO_t * AiopIOList, int AiopIOListSize,
2611 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612{
2613 int i;
2614 ByteIO_t io;
2615 int done;
2616
2617 CtlP->AiopIntrBits = aiop_intr_bits;
2618 CtlP->AltChanRingIndicator = 0;
2619 CtlP->CtlNum = CtlNum;
2620 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2621 CtlP->BusType = isISA;
2622 CtlP->MBaseIO = MudbacIO;
2623 CtlP->MReg1IO = MudbacIO + 1;
2624 CtlP->MReg2IO = MudbacIO + 2;
2625 CtlP->MReg3IO = MudbacIO + 3;
2626#if 1
2627 CtlP->MReg2 = 0; /* interrupt disable */
2628 CtlP->MReg3 = 0; /* no periodic interrupts */
2629#else
2630 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2631 CtlP->MReg2 = 0; /* interrupt disable */
2632 CtlP->MReg3 = 0; /* no periodic interrupts */
2633 } else {
2634 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2635 CtlP->MReg3 = Frequency; /* set frequency */
2636 if (PeriodicOnly) { /* periodic interrupt only */
2637 CtlP->MReg3 |= PERIODIC_ONLY;
2638 }
2639 }
2640#endif
2641 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2642 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2643 sControllerEOI(CtlP); /* clear EOI if warm init */
2644 /* Init AIOPs */
2645 CtlP->NumAiop = 0;
2646 for (i = done = 0; i < AiopIOListSize; i++) {
2647 io = AiopIOList[i];
2648 CtlP->AiopIO[i] = (WordIO_t) io;
2649 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2650 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2651 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2652 if (done)
2653 continue;
2654 sEnAiop(CtlP, i); /* enable the AIOP */
2655 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2656 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2657 done = 1; /* done looking for AIOPs */
2658 else {
2659 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2660 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2661 sOutB(io + _INDX_DATA, sClockPrescale);
2662 CtlP->NumAiop++; /* bump count of AIOPs */
2663 }
2664 sDisAiop(CtlP, i); /* disable AIOP */
2665 }
2666
2667 if (CtlP->NumAiop == 0)
2668 return (-1);
2669 else
2670 return (CtlP->NumAiop);
2671}
2672
2673/***************************************************************************
2674Function: sPCIInitController
2675Purpose: Initialization of controller global registers and controller
2676 structure.
2677Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2678 IRQNum,Frequency,PeriodicOnly)
2679 CONTROLLER_T *CtlP; Ptr to controller structure
2680 int CtlNum; Controller number
2681 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2682 This list must be in the order the AIOPs will be found on the
2683 controller. Once an AIOP in the list is not found, it is
2684 assumed that there are no more AIOPs on the controller.
2685 int AiopIOListSize; Number of addresses in AiopIOList
2686 int IRQNum; Interrupt Request number. Can be any of the following:
2687 0: Disable global interrupts
2688 3: IRQ 3
2689 4: IRQ 4
2690 5: IRQ 5
2691 9: IRQ 9
2692 10: IRQ 10
2693 11: IRQ 11
2694 12: IRQ 12
2695 15: IRQ 15
2696 Byte_t Frequency: A flag identifying the frequency
2697 of the periodic interrupt, can be any one of the following:
2698 FREQ_DIS - periodic interrupt disabled
2699 FREQ_137HZ - 137 Hertz
2700 FREQ_69HZ - 69 Hertz
2701 FREQ_34HZ - 34 Hertz
2702 FREQ_17HZ - 17 Hertz
2703 FREQ_9HZ - 9 Hertz
2704 FREQ_4HZ - 4 Hertz
2705 If IRQNum is set to 0 the Frequency parameter is
2706 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002707 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002709 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 other channel interrupts are allowed.
2711 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002712 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2714 initialization failed.
2715
2716Comments:
2717 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002718 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
2720 If interrupts are to be completely disabled set IRQNum to 0.
2721
Adrian Bunkf15313b2005-06-25 14:59:05 -07002722 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 invalid combination.
2724
2725 This function performs initialization of global interrupt modes,
2726 but it does not actually enable global interrupts. To enable
2727 and disable global interrupts use functions sEnGlobalInt() and
2728 sDisGlobalInt(). Enabling of global interrupts is normally not
2729 done until all other initializations are complete.
2730
2731 Even if interrupts are globally enabled, they must also be
2732 individually enabled for each channel that is to generate
2733 interrupts.
2734
2735Warnings: No range checking on any of the parameters is done.
2736
2737 No context switches are allowed while executing this function.
2738
2739 After this function all AIOPs on the controller are disabled,
2740 they can be enabled with sEnAiop().
2741*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002742static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2743 ByteIO_t * AiopIOList, int AiopIOListSize,
2744 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2745 int PeriodicOnly, int altChanRingIndicator,
2746 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747{
2748 int i;
2749 ByteIO_t io;
2750
2751 CtlP->AltChanRingIndicator = altChanRingIndicator;
2752 CtlP->UPCIRingInd = UPCIRingInd;
2753 CtlP->CtlNum = CtlNum;
2754 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2755 CtlP->BusType = isPCI; /* controller release 1 */
2756
2757 if (ConfigIO) {
2758 CtlP->isUPCI = 1;
2759 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2760 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2761 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2762 } else {
2763 CtlP->isUPCI = 0;
2764 CtlP->PCIIO =
2765 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2766 CtlP->AiopIntrBits = aiop_intr_bits;
2767 }
2768
2769 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2770 /* Init AIOPs */
2771 CtlP->NumAiop = 0;
2772 for (i = 0; i < AiopIOListSize; i++) {
2773 io = AiopIOList[i];
2774 CtlP->AiopIO[i] = (WordIO_t) io;
2775 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2776
2777 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2778 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2779 break; /* done looking for AIOPs */
2780
2781 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2782 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2783 sOutB(io + _INDX_DATA, sClockPrescale);
2784 CtlP->NumAiop++; /* bump count of AIOPs */
2785 }
2786
2787 if (CtlP->NumAiop == 0)
2788 return (-1);
2789 else
2790 return (CtlP->NumAiop);
2791}
2792
2793/***************************************************************************
2794Function: sReadAiopID
2795Purpose: Read the AIOP idenfication number directly from an AIOP.
2796Call: sReadAiopID(io)
2797 ByteIO_t io: AIOP base I/O address
2798Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2799 is replace by an identifying number.
2800 Flag AIOPID_NULL if no valid AIOP is found
2801Warnings: No context switches are allowed while executing this function.
2802
2803*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002804static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
2806 Byte_t AiopID; /* ID byte from AIOP */
2807
2808 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2809 sOutB(io + _CMD_REG, 0x0);
2810 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2811 if (AiopID == 0x06)
2812 return (1);
2813 else /* AIOP does not exist */
2814 return (-1);
2815}
2816
2817/***************************************************************************
2818Function: sReadAiopNumChan
2819Purpose: Read the number of channels available in an AIOP directly from
2820 an AIOP.
2821Call: sReadAiopNumChan(io)
2822 WordIO_t io: AIOP base I/O address
2823Return: int: The number of channels available
2824Comments: The number of channels is determined by write/reads from identical
2825 offsets within the SRAM address spaces for channels 0 and 4.
2826 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2827 AIOP, otherwise it is an 8 channel.
2828Warnings: No context switches are allowed while executing this function.
2829*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002830static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831{
2832 Word_t x;
2833 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2834
2835 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002836 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2838 x = sInW(io + _INDX_DATA);
2839 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2840 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2841 return (8);
2842 else
2843 return (4);
2844}
2845
2846/***************************************************************************
2847Function: sInitChan
2848Purpose: Initialization of a channel and channel structure
2849Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2850 CONTROLLER_T *CtlP; Ptr to controller structure
2851 CHANNEL_T *ChP; Ptr to channel structure
2852 int AiopNum; AIOP number within controller
2853 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002854Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 number exceeds number of channels available in AIOP.
2856Comments: This function must be called before a channel can be used.
2857Warnings: No range checking on any of the parameters is done.
2858
2859 No context switches are allowed while executing this function.
2860*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002861static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2862 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863{
2864 int i;
2865 WordIO_t AiopIO;
2866 WordIO_t ChIOOff;
2867 Byte_t *ChR;
2868 Word_t ChOff;
2869 static Byte_t R[4];
2870 int brd9600;
2871
2872 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002873 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875 /* Channel, AIOP, and controller identifiers */
2876 ChP->CtlP = CtlP;
2877 ChP->ChanID = CtlP->AiopID[AiopNum];
2878 ChP->AiopNum = AiopNum;
2879 ChP->ChanNum = ChanNum;
2880
2881 /* Global direct addresses */
2882 AiopIO = CtlP->AiopIO[AiopNum];
2883 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2884 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2885 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2886 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2887 ChP->IndexData = AiopIO + _INDX_DATA;
2888
2889 /* Channel direct addresses */
2890 ChIOOff = AiopIO + ChP->ChanNum * 2;
2891 ChP->TxRxData = ChIOOff + _TD0;
2892 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2893 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2894 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2895
2896 /* Initialize the channel from the RData array */
2897 for (i = 0; i < RDATASIZE; i += 4) {
2898 R[0] = RData[i];
2899 R[1] = RData[i + 1] + 0x10 * ChanNum;
2900 R[2] = RData[i + 2];
2901 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002902 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 }
2904
2905 ChR = ChP->R;
2906 for (i = 0; i < RREGDATASIZE; i += 4) {
2907 ChR[i] = RRegData[i];
2908 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2909 ChR[i + 2] = RRegData[i + 2];
2910 ChR[i + 3] = RRegData[i + 3];
2911 }
2912
2913 /* Indexed registers */
2914 ChOff = (Word_t) ChanNum *0x1000;
2915
2916 if (sClockPrescale == 0x14)
2917 brd9600 = 47;
2918 else
2919 brd9600 = 23;
2920
2921 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2922 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2923 ChP->BaudDiv[2] = (Byte_t) brd9600;
2924 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002925 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2928 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2929 ChP->TxControl[2] = 0;
2930 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002931 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932
2933 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2934 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2935 ChP->RxControl[2] = 0;
2936 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002937 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
2939 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2940 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2941 ChP->TxEnables[2] = 0;
2942 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002943 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
2945 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2946 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2947 ChP->TxCompare[2] = 0;
2948 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002949 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2952 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2953 ChP->TxReplace1[2] = 0;
2954 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002955 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
2957 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2958 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2959 ChP->TxReplace2[2] = 0;
2960 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002961 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2964 ChP->TxFIFO = ChOff + _TX_FIFO;
2965
2966 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2967 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2968 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2969 sOutW(ChP->IndexData, 0);
2970 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2971 ChP->RxFIFO = ChOff + _RX_FIFO;
2972
2973 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2974 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2975 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2976 sOutW(ChP->IndexData, 0);
2977 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2978 sOutW(ChP->IndexData, 0);
2979 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2980 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2981 sOutB(ChP->IndexData, 0);
2982 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2983 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2984 sOutB(ChP->IndexData, 0);
2985 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2986 sEnRxProcessor(ChP); /* start the Rx processor */
2987
Adrian Bunkf15313b2005-06-25 14:59:05 -07002988 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989}
2990
2991/***************************************************************************
2992Function: sStopRxProcessor
2993Purpose: Stop the receive processor from processing a channel.
2994Call: sStopRxProcessor(ChP)
2995 CHANNEL_T *ChP; Ptr to channel structure
2996
2997Comments: The receive processor can be started again with sStartRxProcessor().
2998 This function causes the receive processor to skip over the
2999 stopped channel. It does not stop it from processing other channels.
3000
3001Warnings: No context switches are allowed while executing this function.
3002
3003 Do not leave the receive processor stopped for more than one
3004 character time.
3005
3006 After calling this function a delay of 4 uS is required to ensure
3007 that the receive processor is no longer processing this channel.
3008*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003009static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010{
3011 Byte_t R[4];
3012
3013 R[0] = ChP->R[0];
3014 R[1] = ChP->R[1];
3015 R[2] = 0x0a;
3016 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00003017 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018}
3019
3020/***************************************************************************
3021Function: sFlushRxFIFO
3022Purpose: Flush the Rx FIFO
3023Call: sFlushRxFIFO(ChP)
3024 CHANNEL_T *ChP; Ptr to channel structure
3025Return: void
3026Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
3027 while it is being flushed the receive processor is stopped
3028 and the transmitter is disabled. After these operations a
3029 4 uS delay is done before clearing the pointers to allow
3030 the receive processor to stop. These items are handled inside
3031 this function.
3032Warnings: No context switches are allowed while executing this function.
3033*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003034static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035{
3036 int i;
3037 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003038 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
3040 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
3041 return; /* don't need to flush */
3042
Adrian Bunkf15313b2005-06-25 14:59:05 -07003043 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003045 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 sDisRxFIFO(ChP); /* disable it */
3047 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
3048 sInB(ChP->IntChan); /* depends on bus i/o timing */
3049 }
3050 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
3051 Ch = (Byte_t) sGetChanNum(ChP);
3052 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
3053 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
3054 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
3055 sOutW(ChP->IndexData, 0);
3056 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
3057 sOutW(ChP->IndexData, 0);
3058 if (RxFIFOEnabled)
3059 sEnRxFIFO(ChP); /* enable Rx FIFO */
3060}
3061
3062/***************************************************************************
3063Function: sFlushTxFIFO
3064Purpose: Flush the Tx FIFO
3065Call: sFlushTxFIFO(ChP)
3066 CHANNEL_T *ChP; Ptr to channel structure
3067Return: void
3068Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
3069 while it is being flushed the receive processor is stopped
3070 and the transmitter is disabled. After these operations a
3071 4 uS delay is done before clearing the pointers to allow
3072 the receive processor to stop. These items are handled inside
3073 this function.
3074Warnings: No context switches are allowed while executing this function.
3075*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003076static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077{
3078 int i;
3079 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003080 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081
3082 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
3083 return; /* don't need to flush */
3084
Adrian Bunkf15313b2005-06-25 14:59:05 -07003085 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07003087 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 sDisTransmit(ChP); /* disable transmitter */
3089 }
3090 sStopRxProcessor(ChP); /* stop Rx processor */
3091 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
3092 sInB(ChP->IntChan); /* depends on bus i/o timing */
3093 Ch = (Byte_t) sGetChanNum(ChP);
3094 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
3095 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
3096 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
3097 sOutW(ChP->IndexData, 0);
3098 if (TxEnabled)
3099 sEnTransmit(ChP); /* enable transmitter */
3100 sStartRxProcessor(ChP); /* restart Rx processor */
3101}
3102
3103/***************************************************************************
3104Function: sWriteTxPrioByte
3105Purpose: Write a byte of priority transmit data to a channel
3106Call: sWriteTxPrioByte(ChP,Data)
3107 CHANNEL_T *ChP; Ptr to channel structure
3108 Byte_t Data; The transmit data byte
3109
3110Return: int: 1 if the bytes is successfully written, otherwise 0.
3111
3112Comments: The priority byte is transmitted before any data in the Tx FIFO.
3113
3114Warnings: No context switches are allowed while executing this function.
3115*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003116static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117{
3118 Byte_t DWBuf[4]; /* buffer for double word writes */
3119 Word_t *WordPtr; /* must be far because Win SS != DS */
3120 register DWordIO_t IndexAddr;
3121
3122 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
3123 IndexAddr = ChP->IndexAddr;
3124 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
3125 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
3126 return (0); /* nothing sent */
3127
3128 WordPtr = (Word_t *) (&DWBuf[0]);
3129 *WordPtr = ChP->TxPrioBuf; /* data byte address */
3130
3131 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00003132 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
3134 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
3135
3136 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
3137 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00003138 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 } else { /* write it to Tx FIFO */
3140
3141 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
3142 }
3143 return (1); /* 1 byte sent */
3144}
3145
3146/***************************************************************************
3147Function: sEnInterrupts
3148Purpose: Enable one or more interrupts for a channel
3149Call: sEnInterrupts(ChP,Flags)
3150 CHANNEL_T *ChP; Ptr to channel structure
3151 Word_t Flags: Interrupt enable flags, can be any combination
3152 of the following flags:
3153 TXINT_EN: Interrupt on Tx FIFO empty
3154 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3155 sSetRxTrigger())
3156 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3157 MCINT_EN: Interrupt on modem input change
3158 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3159 Interrupt Channel Register.
3160Return: void
3161Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3162 enabled. If an interrupt enable flag is not set in Flags, that
3163 interrupt will not be changed. Interrupts can be disabled with
3164 function sDisInterrupts().
3165
3166 This function sets the appropriate bit for the channel in the AIOP's
3167 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3168 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3169
3170 Interrupts must also be globally enabled before channel interrupts
3171 will be passed on to the host. This is done with function
3172 sEnGlobalInt().
3173
3174 In some cases it may be desirable to disable interrupts globally but
3175 enable channel interrupts. This would allow the global interrupt
3176 status register to be used to determine which AIOPs need service.
3177*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003178static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179{
3180 Byte_t Mask; /* Interrupt Mask Register */
3181
3182 ChP->RxControl[2] |=
3183 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3184
Al Viro457fb602008-03-19 16:27:48 +00003185 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
3187 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3188
Al Viro457fb602008-03-19 16:27:48 +00003189 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191 if (Flags & CHANINT_EN) {
3192 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3193 sOutB(ChP->IntMask, Mask);
3194 }
3195}
3196
3197/***************************************************************************
3198Function: sDisInterrupts
3199Purpose: Disable one or more interrupts for a channel
3200Call: sDisInterrupts(ChP,Flags)
3201 CHANNEL_T *ChP; Ptr to channel structure
3202 Word_t Flags: Interrupt flags, can be any combination
3203 of the following flags:
3204 TXINT_EN: Interrupt on Tx FIFO empty
3205 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3206 sSetRxTrigger())
3207 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3208 MCINT_EN: Interrupt on modem input change
3209 CHANINT_EN: Disable channel interrupt signal to the
3210 AIOP's Interrupt Channel Register.
3211Return: void
3212Comments: If an interrupt flag is set in Flags, that interrupt will be
3213 disabled. If an interrupt flag is not set in Flags, that
3214 interrupt will not be changed. Interrupts can be enabled with
3215 function sEnInterrupts().
3216
3217 This function clears the appropriate bit for the channel in the AIOP's
3218 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3219 this channel's bit from being set in the AIOP's Interrupt Channel
3220 Register.
3221*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003222static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223{
3224 Byte_t Mask; /* Interrupt Mask Register */
3225
3226 ChP->RxControl[2] &=
3227 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003228 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003230 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 if (Flags & CHANINT_EN) {
3233 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3234 sOutB(ChP->IntMask, Mask);
3235 }
3236}
3237
Adrian Bunkf15313b2005-06-25 14:59:05 -07003238static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239{
3240 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3241}
3242
3243/*
3244 * Not an official SSCI function, but how to reset RocketModems.
3245 * ISA bus version
3246 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003247static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248{
3249 ByteIO_t addr;
3250 Byte_t val;
3251
3252 addr = CtlP->AiopIO[0] + 0x400;
3253 val = sInB(CtlP->MReg3IO);
3254 /* if AIOP[1] is not enabled, enable it */
3255 if ((val & 2) == 0) {
3256 val = sInB(CtlP->MReg2IO);
3257 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3258 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3259 }
3260
3261 sEnAiop(CtlP, 1);
3262 if (!on)
3263 addr += 8;
3264 sOutB(addr + chan, 0); /* apply or remove reset */
3265 sDisAiop(CtlP, 1);
3266}
3267
3268/*
3269 * Not an official SSCI function, but how to reset RocketModems.
3270 * PCI bus version
3271 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003272static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273{
3274 ByteIO_t addr;
3275
3276 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3277 if (!on)
3278 addr += 8;
3279 sOutB(addr + chan, 0); /* apply or remove reset */
3280}
3281
3282/* Resets the speaker controller on RocketModem II and III devices */
3283static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3284{
3285 ByteIO_t addr;
3286
3287 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3288 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3289 addr = CtlP->AiopIO[0] + 0x4F;
3290 sOutB(addr, 0);
3291 }
3292
3293 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3294 if ((model == MODEL_UPCI_RM3_8PORT)
3295 || (model == MODEL_UPCI_RM3_4PORT)) {
3296 addr = CtlP->AiopIO[0] + 0x88;
3297 sOutB(addr, 0);
3298 }
3299}
3300
3301/* Returns the line number given the controller (board), aiop and channel number */
3302static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3303{
3304 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3305}
3306
3307/*
3308 * Stores the line number associated with a given controller (board), aiop
3309 * and channel number.
3310 * Returns: The line number assigned
3311 */
3312static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3313{
3314 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3315 return (nextLineNumber - 1);
3316}