blob: bbffd7a431e97d0d17b8c37e0d492586f1f00745 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * RocketPort device driver for Linux
3 *
4 * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000.
5 *
6 * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * Kernel Synchronization:
25 *
26 * This driver has 2 kernel control paths - exception handlers (calls into the driver
27 * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts
28 * are not used.
29 *
30 * Critical data:
31 * - rp_table[], accessed through passed "info" pointers, is a global (static) array of
32 * serial port state information and the xmit_buf circular buffer. Protected by
33 * a per port spinlock.
34 * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there
35 * is data to be transmitted. Protected by atomic bit operations.
36 * - rp_num_ports, int indicating number of open ports, protected by atomic operations.
37 *
38 * rp_write() and rp_write_char() functions use a per port semaphore to protect against
39 * simultaneous access to the same port by more than one process.
40 */
41
42/****** Defines ******/
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#define ROCKET_PARANOIA_CHECK
44#define ROCKET_DISABLE_SIMUSAGE
45
46#undef ROCKET_SOFT_FLOW
47#undef ROCKET_DEBUG_OPEN
48#undef ROCKET_DEBUG_INTR
49#undef ROCKET_DEBUG_WRITE
50#undef ROCKET_DEBUG_FLOW
51#undef ROCKET_DEBUG_THROTTLE
52#undef ROCKET_DEBUG_WAIT_UNTIL_SENT
53#undef ROCKET_DEBUG_RECEIVE
54#undef ROCKET_DEBUG_HANGUP
55#undef REV_PCI_ORDER
56#undef ROCKET_DEBUG_IO
57
Cong Ding37c44b52013-01-12 05:42:07 +010058#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/****** Kernel includes ******/
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <linux/module.h>
63#include <linux/errno.h>
64#include <linux/major.h>
65#include <linux/kernel.h>
66#include <linux/signal.h>
67#include <linux/slab.h>
68#include <linux/mm.h>
69#include <linux/sched.h>
70#include <linux/timer.h>
71#include <linux/interrupt.h>
72#include <linux/tty.h>
73#include <linux/tty_driver.h>
74#include <linux/tty_flip.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010075#include <linux/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#include <linux/string.h>
77#include <linux/fcntl.h>
78#include <linux/ptrace.h>
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -070079#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#include <linux/ioport.h>
81#include <linux/delay.h>
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -070082#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/wait.h>
84#include <linux/pci.h>
Alan Cox44b7d1b2008-07-16 21:57:18 +010085#include <linux/uaccess.h>
Arun Sharma600634972011-07-26 16:09:06 -070086#include <linux/atomic.h>
Al Viro457fb602008-03-19 16:27:48 +000087#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070088#include <linux/bitops.h>
89#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070090#include <linux/init.h>
91
92/****** RocketPort includes ******/
93
94#include "rocket_int.h"
95#include "rocket.h"
96
97#define ROCKET_VERSION "2.09"
98#define ROCKET_DATE "12-June-2003"
99
100/****** RocketPort Local Variables ******/
101
Jiri Slaby40565f12007-02-12 00:52:31 -0800102static void rp_do_poll(unsigned long dummy);
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static struct tty_driver *rocket_driver;
105
106static struct rocket_version driver_version = {
107 ROCKET_VERSION, ROCKET_DATE
108};
109
110static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */
111static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */
112 /* eg. Bit 0 indicates port 0 has xmit data, ... */
113static atomic_t rp_num_ports_open; /* Number of serial ports open */
Jiri Slaby40565f12007-02-12 00:52:31 -0800114static DEFINE_TIMER(rocket_timer, rp_do_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */
117static unsigned long board2;
118static unsigned long board3;
119static unsigned long board4;
120static unsigned long controller;
Rusty Russell90ab5ee2012-01-13 09:32:20 +1030121static bool support_low_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122static unsigned long modem1;
123static unsigned long modem2;
124static unsigned long modem3;
125static unsigned long modem4;
126static unsigned long pc104_1[8];
127static unsigned long pc104_2[8];
128static unsigned long pc104_3[8];
129static unsigned long pc104_4[8];
130static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 };
131
132static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */
133static unsigned long rcktpt_io_addr[NUM_BOARDS];
134static int rcktpt_type[NUM_BOARDS];
135static int is_PCI[NUM_BOARDS];
136static rocketModel_t rocketModel[NUM_BOARDS];
137static int max_board;
Alan Cox31f35932009-01-02 13:45:05 +0000138static const struct tty_port_operations rocket_port_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140/*
141 * The following arrays define the interrupt bits corresponding to each AIOP.
142 * These bits are different between the ISA and regular PCI boards and the
143 * Universal PCI boards.
144 */
145
146static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
147 AIOP_INTR_BIT_0,
148 AIOP_INTR_BIT_1,
149 AIOP_INTR_BIT_2,
150 AIOP_INTR_BIT_3
151};
152
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 */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100318static void rp_do_receive(struct r_port *info, CHANNEL_t *cp,
319 unsigned int ChanStatus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 unsigned int CharNStat;
Paul Fulghumcc44a812006-06-25 05:49:12 -0700322 int ToRecv, wRecv, space;
323 unsigned char *cbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 ToRecv = sGetRxCnt(cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800327 printk(KERN_INFO "rp_do_receive(%d)...\n", ToRecv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328#endif
Paul Fulghumcc44a812006-06-25 05:49:12 -0700329 if (ToRecv == 0)
330 return;
Alan Cox33f0f882006-01-09 20:54:13 -0800331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /*
333 * if status indicates there are errored characters in the
334 * FIFO, then enter status mode (a word in FIFO holds
335 * character and status).
336 */
337 if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
338 if (!(ChanStatus & STATMODE)) {
339#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800340 printk(KERN_INFO "Entering STATMODE...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341#endif
342 ChanStatus |= STATMODE;
343 sEnRxStatusMode(cp);
344 }
345 }
346
347 /*
348 * if we previously entered status mode, then read down the
349 * FIFO one word at a time, pulling apart the character and
350 * the status. Update error counters depending on status
351 */
352 if (ChanStatus & STATMODE) {
353#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800354 printk(KERN_INFO "Ignore %x, read %x...\n",
355 info->ignore_status_mask, info->read_status_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#endif
357 while (ToRecv) {
Paul Fulghumcc44a812006-06-25 05:49:12 -0700358 char flag;
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 CharNStat = sInW(sGetTxRxDataIO(cp));
361#ifdef ROCKET_DEBUG_RECEIVE
Jiri Slaby68562b72008-02-07 00:16:33 -0800362 printk(KERN_INFO "%x...\n", CharNStat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363#endif
364 if (CharNStat & STMBREAKH)
365 CharNStat &= ~(STMFRAMEH | STMPARITYH);
366 if (CharNStat & info->ignore_status_mask) {
367 ToRecv--;
368 continue;
369 }
370 CharNStat &= info->read_status_mask;
371 if (CharNStat & STMBREAKH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700372 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 else if (CharNStat & STMPARITYH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700374 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 else if (CharNStat & STMFRAMEH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700376 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 else if (CharNStat & STMRCVROVRH)
Paul Fulghumcc44a812006-06-25 05:49:12 -0700378 flag = TTY_OVERRUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 else
Paul Fulghumcc44a812006-06-25 05:49:12 -0700380 flag = TTY_NORMAL;
Jiri Slaby92a19f92013-01-03 15:53:03 +0100381 tty_insert_flip_char(&info->port, CharNStat & 0xff,
382 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 */
Jiri Slaby2f693352013-01-03 15:53:02 +0100402 space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv);
Paul Fulghumcc44a812006-06-25 05:49:12 -0700403 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 */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100418 tty_flip_buffer_push(&info->port);
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 Cox47b01b32009-01-02 13:48:30 +0000439 tty = tty_port_tty_get(&info->port);
440
441 if (tty == NULL) {
442 printk(KERN_WARNING "rp: WARNING %s called with tty==NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
444 return;
445 }
446
447 spin_lock_irqsave(&info->slock, flags);
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);
Alan Cox47b01b32009-01-02 13:48:30 +0000481 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800484 printk(KERN_DEBUG "(%d,%d,%d,%d)...\n", info->xmit_cnt, info->xmit_head,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 info->xmit_tail, info->xmit_fifo_room);
486#endif
487}
488
489/*
490 * Called when a serial port signals it has read data in it's RX FIFO.
491 * It checks what interrupts are pending and services them, including
492 * receiving serial data.
493 */
494static void rp_handle_port(struct r_port *info)
495{
496 CHANNEL_t *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 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 }
Jiri Slaby2e124b42013-01-03 15:53:06 +0100507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 IntMask = sGetChanIntID(cp) & info->intmask;
511#ifdef ROCKET_DEBUG_INTR
Jiri Slaby68562b72008-02-07 00:16:33 -0800512 printk(KERN_INFO "rp_interrupt %02x...\n", IntMask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513#endif
514 ChanStatus = sGetChanStatus(cp);
515 if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
Jiri Slaby2e124b42013-01-03 15:53:06 +0100516 rp_do_receive(info, cp, ChanStatus);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 }
518 if (IntMask & DELTA_CD) { /* CD change */
519#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -0800520 printk(KERN_INFO "ttyR%d CD now %s...\n", info->line,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 (ChanStatus & CD_ACT) ? "on" : "off");
522#endif
523 if (!(ChanStatus & CD_ACT) && info->cd_status) {
524#ifdef ROCKET_DEBUG_HANGUP
525 printk(KERN_INFO "CD drop, calling hangup.\n");
526#endif
Jiri Slabyaa27a092013-03-07 13:12:30 +0100527 tty_port_tty_hangup(&info->port, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 }
529 info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
Alan Coxe60a1082008-07-16 21:56:18 +0100530 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 }
532#ifdef ROCKET_DEBUG_INTR
533 if (IntMask & DELTA_CTS) { /* CTS change */
534 printk(KERN_INFO "CTS change...\n");
535 }
536 if (IntMask & DELTA_DSR) { /* DSR change */
537 printk(KERN_INFO "DSR change...\n");
538 }
539#endif
540}
541
542/*
543 * The top level polling routine. Repeats every 1/100 HZ (10ms).
544 */
545static void rp_do_poll(unsigned long dummy)
546{
547 CONTROLLER_t *ctlp;
Jiri Slaby6c0286b2007-10-18 03:06:29 -0700548 int ctrl, aiop, ch, line;
549 unsigned int xmitmask, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 unsigned int CtlMask;
551 unsigned char AiopMask;
552 Word_t bit;
553
554 /* Walk through all the boards (ctrl's) */
555 for (ctrl = 0; ctrl < max_board; ctrl++) {
556 if (rcktpt_io_addr[ctrl] <= 0)
557 continue;
558
559 /* Get a ptr to the board's control struct */
560 ctlp = sCtlNumToCtlPtr(ctrl);
561
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +0200562 /* Get the interrupt status from the board */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563#ifdef CONFIG_PCI
564 if (ctlp->BusType == isPCI)
565 CtlMask = sPCIGetControllerIntStatus(ctlp);
566 else
567#endif
568 CtlMask = sGetControllerIntStatus(ctlp);
569
570 /* Check if any AIOP read bits are set */
571 for (aiop = 0; CtlMask; aiop++) {
572 bit = ctlp->AiopIntrBits[aiop];
573 if (CtlMask & bit) {
574 CtlMask &= ~bit;
575 AiopMask = sGetAiopIntStatus(ctlp, aiop);
576
577 /* Check if any port read bits are set */
578 for (ch = 0; AiopMask; AiopMask >>= 1, ch++) {
579 if (AiopMask & 1) {
580
581 /* Get the line number (/dev/ttyRx number). */
582 /* Read the data from the port. */
583 line = GetLineNumber(ctrl, aiop, ch);
584 rp_handle_port(rp_table[line]);
585 }
586 }
587 }
588 }
589
590 xmitmask = xmit_flags[ctrl];
591
592 /*
593 * xmit_flags contains bit-significant flags, indicating there is data
594 * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port
595 * 1, ... (32 total possible). The variable i has the aiop and ch
596 * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).
597 */
598 if (xmitmask) {
599 for (i = 0; i < rocketModel[ctrl].numPorts; i++) {
600 if (xmitmask & (1 << i)) {
601 aiop = (i & 0x18) >> 3;
602 ch = i & 0x07;
603 line = GetLineNumber(ctrl, aiop, ch);
604 rp_do_transmit(rp_table[line]);
605 }
606 }
607 }
608 }
609
610 /*
611 * Reset the timer so we get called at the next clock tick (10ms).
612 */
613 if (atomic_read(&rp_num_ports_open))
614 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
615}
616
617/*
618 * Initializes the r_port structure for a port, as well as enabling the port on
619 * the board.
620 * Inputs: board, aiop, chan numbers
621 */
622static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
623{
624 unsigned rocketMode;
625 struct r_port *info;
626 int line;
627 CONTROLLER_T *ctlp;
628
629 /* Get the next available line number */
630 line = SetLineNumber(board, aiop, chan);
631
632 ctlp = sCtlNumToCtlPtr(board);
633
634 /* 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 -0700635 info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (!info) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800637 printk(KERN_ERR "Couldn't allocate info struct for line #%d\n",
638 line);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return;
640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 info->magic = RPORT_MAGIC;
643 info->line = line;
644 info->ctlp = ctlp;
645 info->board = board;
646 info->aiop = aiop;
647 info->chan = chan;
Alan Cox31f35932009-01-02 13:45:05 +0000648 tty_port_init(&info->port);
649 info->port.ops = &rocket_port_ops;
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700650 init_completion(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 info->flags &= ~ROCKET_MODE_MASK;
652 switch (pc104[board][line]) {
653 case 422:
654 info->flags |= ROCKET_MODE_RS422;
655 break;
656 case 485:
657 info->flags |= ROCKET_MODE_RS485;
658 break;
659 case 232:
660 default:
661 info->flags |= ROCKET_MODE_RS232;
662 break;
663 }
664
665 info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;
666 if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {
Jiri Slaby68562b72008-02-07 00:16:33 -0800667 printk(KERN_ERR "RocketPort sInitChan(%d, %d, %d) failed!\n",
668 board, aiop, chan);
Jiri Slaby191c5f12012-11-15 09:49:56 +0100669 tty_port_destroy(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 kfree(info);
671 return;
672 }
673
674 rocketMode = info->flags & ROCKET_MODE_MASK;
675
676 if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))
677 sEnRTSToggle(&info->channel);
678 else
679 sDisRTSToggle(&info->channel);
680
681 if (ctlp->boardType == ROCKET_TYPE_PC104) {
682 switch (rocketMode) {
683 case ROCKET_MODE_RS485:
684 sSetInterfaceMode(&info->channel, InterfaceModeRS485);
685 break;
686 case ROCKET_MODE_RS422:
687 sSetInterfaceMode(&info->channel, InterfaceModeRS422);
688 break;
689 case ROCKET_MODE_RS232:
690 default:
691 if (info->flags & ROCKET_RTS_TOGGLE)
692 sSetInterfaceMode(&info->channel, InterfaceModeRS232T);
693 else
694 sSetInterfaceMode(&info->channel, InterfaceModeRS232);
695 break;
696 }
697 }
698 spin_lock_init(&info->slock);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -0700699 mutex_init(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 rp_table[line] = info;
Jiri Slaby734cc172012-08-07 21:47:47 +0200701 tty_port_register_device(&info->port, rocket_driver, line,
702 pci_dev ? &pci_dev->dev : NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703}
704
705/*
706 * Configures a rocketport port according to its termio settings. Called from
707 * user mode into the driver (exception handler). *info CD manipulation is spinlock protected.
708 */
Alan Cox47b01b32009-01-02 13:48:30 +0000709static void configure_r_port(struct tty_struct *tty, struct r_port *info,
Alan Cox606d0992006-12-08 02:38:45 -0800710 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712 unsigned cflag;
713 unsigned long flags;
714 unsigned rocketMode;
715 int bits, baud, divisor;
716 CHANNEL_t *cp;
Alan Coxadc8d742012-07-14 15:31:47 +0100717 struct ktermios *t = &tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 cp = &info->channel;
Alan Cox6df35262008-02-08 04:18:45 -0800720 cflag = t->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 /* Byte size and parity */
723 if ((cflag & CSIZE) == CS8) {
724 sSetData8(cp);
725 bits = 10;
726 } else {
727 sSetData7(cp);
728 bits = 9;
729 }
730 if (cflag & CSTOPB) {
731 sSetStop2(cp);
732 bits++;
733 } else {
734 sSetStop1(cp);
735 }
736
737 if (cflag & PARENB) {
738 sEnParity(cp);
739 bits++;
740 if (cflag & PARODD) {
741 sSetOddParity(cp);
742 } else {
743 sSetEvenParity(cp);
744 }
745 } else {
746 sDisParity(cp);
747 }
748
749 /* baud rate */
Alan Cox47b01b32009-01-02 13:48:30 +0000750 baud = tty_get_baud_rate(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (!baud)
752 baud = 9600;
753 divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;
754 if ((divisor >= 8192 || divisor < 0) && old_termios) {
Alan Cox6df35262008-02-08 04:18:45 -0800755 baud = tty_termios_baud_rate(old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (!baud)
757 baud = 9600;
758 divisor = (rp_baud_base[info->board] / baud) - 1;
759 }
760 if (divisor >= 8192 || divisor < 0) {
761 baud = 9600;
762 divisor = (rp_baud_base[info->board] / baud) - 1;
763 }
764 info->cps = baud / bits;
765 sSetBaud(cp, divisor);
766
Alan Cox6df35262008-02-08 04:18:45 -0800767 /* FIXME: Should really back compute a baud rate from the divisor */
Alan Cox47b01b32009-01-02 13:48:30 +0000768 tty_encode_baud_rate(tty, baud, baud);
Alan Cox6df35262008-02-08 04:18:45 -0800769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (cflag & CRTSCTS) {
771 info->intmask |= DELTA_CTS;
772 sEnCTSFlowCtl(cp);
773 } else {
774 info->intmask &= ~DELTA_CTS;
775 sDisCTSFlowCtl(cp);
776 }
777 if (cflag & CLOCAL) {
778 info->intmask &= ~DELTA_CD;
779 } else {
780 spin_lock_irqsave(&info->slock, flags);
781 if (sGetChanStatus(cp) & CD_ACT)
782 info->cd_status = 1;
783 else
784 info->cd_status = 0;
785 info->intmask |= DELTA_CD;
786 spin_unlock_irqrestore(&info->slock, flags);
787 }
788
789 /*
790 * Handle software flow control in the board
791 */
792#ifdef ROCKET_SOFT_FLOW
Alan Cox47b01b32009-01-02 13:48:30 +0000793 if (I_IXON(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 sEnTxSoftFlowCtl(cp);
Alan Cox47b01b32009-01-02 13:48:30 +0000795 if (I_IXANY(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 sEnIXANY(cp);
797 } else {
798 sDisIXANY(cp);
799 }
Alan Cox47b01b32009-01-02 13:48:30 +0000800 sSetTxXONChar(cp, START_CHAR(tty));
801 sSetTxXOFFChar(cp, STOP_CHAR(tty));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 } else {
803 sDisTxSoftFlowCtl(cp);
804 sDisIXANY(cp);
805 sClrTxXOFF(cp);
806 }
807#endif
808
809 /*
810 * Set up ignore/read mask words
811 */
812 info->read_status_mask = STMRCVROVRH | 0xFF;
Alan Cox47b01b32009-01-02 13:48:30 +0000813 if (I_INPCK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 info->read_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000815 if (I_BRKINT(tty) || I_PARMRK(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 info->read_status_mask |= STMBREAKH;
817
818 /*
819 * Characters to ignore
820 */
821 info->ignore_status_mask = 0;
Alan Cox47b01b32009-01-02 13:48:30 +0000822 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 info->ignore_status_mask |= STMFRAMEH | STMPARITYH;
Alan Cox47b01b32009-01-02 13:48:30 +0000824 if (I_IGNBRK(tty)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 info->ignore_status_mask |= STMBREAKH;
826 /*
827 * If we're ignoring parity and break indicators,
828 * ignore overruns too. (For real raw support).
829 */
Alan Cox47b01b32009-01-02 13:48:30 +0000830 if (I_IGNPAR(tty))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 info->ignore_status_mask |= STMRCVROVRH;
832 }
833
834 rocketMode = info->flags & ROCKET_MODE_MASK;
835
836 if ((info->flags & ROCKET_RTS_TOGGLE)
837 || (rocketMode == ROCKET_MODE_RS485))
838 sEnRTSToggle(cp);
839 else
840 sDisRTSToggle(cp);
841
842 sSetRTS(&info->channel);
843
844 if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {
845 switch (rocketMode) {
846 case ROCKET_MODE_RS485:
847 sSetInterfaceMode(cp, InterfaceModeRS485);
848 break;
849 case ROCKET_MODE_RS422:
850 sSetInterfaceMode(cp, InterfaceModeRS422);
851 break;
852 case ROCKET_MODE_RS232:
853 default:
854 if (info->flags & ROCKET_RTS_TOGGLE)
855 sSetInterfaceMode(cp, InterfaceModeRS232T);
856 else
857 sSetInterfaceMode(cp, InterfaceModeRS232);
858 break;
859 }
860 }
861}
862
Alan Cox31f35932009-01-02 13:45:05 +0000863static int carrier_raised(struct tty_port *port)
864{
865 struct r_port *info = container_of(port, struct r_port, port);
866 return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
867}
868
Alan Coxfcc8ac12009-06-11 12:24:17 +0100869static void dtr_rts(struct tty_port *port, int on)
Alan Cox5d951fb2009-01-02 13:45:19 +0000870{
871 struct r_port *info = container_of(port, struct r_port, port);
Alan Coxfcc8ac12009-06-11 12:24:17 +0100872 if (on) {
873 sSetDTR(&info->channel);
874 sSetRTS(&info->channel);
875 } else {
876 sClrDTR(&info->channel);
877 sClrRTS(&info->channel);
878 }
Alan Cox5d951fb2009-01-02 13:45:19 +0000879}
880
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881/*
882 * Exception handler that opens a serial port. Creates xmit_buf storage, fills in
883 * port's r_port struct. Initializes the port hardware.
884 */
885static int rp_open(struct tty_struct *tty, struct file *filp)
886{
887 struct r_port *info;
Alan Coxfba85e02009-01-02 13:48:39 +0000888 struct tty_port *port;
Jiri Slaby410235f2012-03-05 14:52:01 +0100889 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 CHANNEL_t *cp;
891 unsigned long page;
892
Jiri Slaby410235f2012-03-05 14:52:01 +0100893 info = rp_table[tty->index];
894 if (info == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 return -ENXIO;
Alan Coxfba85e02009-01-02 13:48:39 +0000896 port = &info->port;
897
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 page = __get_free_page(GFP_KERNEL);
899 if (!page)
900 return -ENOMEM;
901
Alan Coxfba85e02009-01-02 13:48:39 +0000902 if (port->flags & ASYNC_CLOSING) {
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700903 retval = wait_for_completion_interruptible(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 free_page(page);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -0700905 if (retval)
906 return retval;
Alan Coxfba85e02009-01-02 13:48:39 +0000907 return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
909
910 /*
911 * We must not sleep from here until the port is marked fully in use.
912 */
913 if (info->xmit_buf)
914 free_page(page);
915 else
916 info->xmit_buf = (unsigned char *) page;
917
918 tty->driver_data = info;
Alan Coxfba85e02009-01-02 13:48:39 +0000919 tty_port_tty_set(port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Alan Coxfba85e02009-01-02 13:48:39 +0000921 if (port->count++ == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 atomic_inc(&rp_num_ports_open);
923
924#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -0800925 printk(KERN_INFO "rocket mod++ = %d...\n",
926 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927#endif
928 }
929#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +0100930 printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931#endif
932
933 /*
934 * Info->count is now 1; so it's safe to sleep now.
935 */
Jiri Slabya391ad02009-06-11 12:40:17 +0100936 if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 cp = &info->channel;
938 sSetRxTrigger(cp, TRIG_1);
939 if (sGetChanStatus(cp) & CD_ACT)
940 info->cd_status = 1;
941 else
942 info->cd_status = 0;
943 sDisRxStatusMode(cp);
944 sFlushRxFIFO(cp);
945 sFlushTxFIFO(cp);
946
947 sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
948 sSetRxTrigger(cp, TRIG_1);
949
950 sGetChanStatus(cp);
951 sDisRxStatusMode(cp);
952 sClrTxXOFF(cp);
953
954 sDisCTSFlowCtl(cp);
955 sDisTxSoftFlowCtl(cp);
956
957 sEnRxFIFO(cp);
958 sEnTransmit(cp);
959
Jiri Slabya391ad02009-06-11 12:40:17 +0100960 set_bit(ASYNCB_INITIALIZED, &info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
962 /*
963 * Set up the tty->alt_speed kludge
964 */
965 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +0000966 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000968 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +0000970 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +0000972 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Alan Cox47b01b32009-01-02 13:48:30 +0000974 configure_r_port(tty, info, NULL);
Alan Coxadc8d742012-07-14 15:31:47 +0100975 if (tty->termios.c_cflag & CBAUD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 sSetDTR(cp);
977 sSetRTS(cp);
978 }
979 }
980 /* Starts (or resets) the maint polling loop */
981 mod_timer(&rocket_timer, jiffies + POLL_PERIOD);
982
Alan Coxfba85e02009-01-02 13:48:39 +0000983 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 if (retval) {
985#ifdef ROCKET_DEBUG_OPEN
986 printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);
987#endif
988 return retval;
989 }
990 return 0;
991}
992
993/*
Alan Coxe60a1082008-07-16 21:56:18 +0100994 * Exception handler that closes a serial port. info->port.count is considered critical.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 */
996static void rp_close(struct tty_struct *tty, struct file *filp)
997{
Alan Coxc9f19e92009-01-02 13:47:26 +0000998 struct r_port *info = tty->driver_data;
Alan Coxc1314a42009-01-02 13:48:17 +0000999 struct tty_port *port = &info->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 int timeout;
1001 CHANNEL_t *cp;
1002
1003 if (rocket_paranoia_check(info, "rp_close"))
1004 return;
1005
1006#ifdef ROCKET_DEBUG_OPEN
Alan Coxe60a1082008-07-16 21:56:18 +01001007 printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008#endif
1009
Alan Coxfba85e02009-01-02 13:48:39 +00001010 if (tty_port_close_start(port, tty, filp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Alan Cox417b6e02010-06-01 22:52:45 +02001013 mutex_lock(&port->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 cp = &info->channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 /*
1016 * Before we drop DTR, make sure the UART transmitter
1017 * has completely drained; this is especially
1018 * important if there is a transmit FIFO!
1019 */
1020 timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;
1021 if (timeout == 0)
1022 timeout = 1;
1023 rp_wait_until_sent(tty, timeout);
1024 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1025
1026 sDisTransmit(cp);
1027 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1028 sDisCTSFlowCtl(cp);
1029 sDisTxSoftFlowCtl(cp);
1030 sClrTxXOFF(cp);
1031 sFlushRxFIFO(cp);
1032 sFlushTxFIFO(cp);
1033 sClrRTS(cp);
1034 if (C_HUPCL(tty))
1035 sClrDTR(cp);
1036
Jiri Slabyf6de0c92008-02-07 00:16:33 -08001037 rp_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 tty_ldisc_flush(tty);
1040
1041 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1042
Alan Coxfba85e02009-01-02 13:48:39 +00001043 /* We can't yet use tty_port_close_end as the buffer handling in this
1044 driver is a bit different to the usual */
1045
Alan Coxc1314a42009-01-02 13:48:17 +00001046 if (port->blocked_open) {
1047 if (port->close_delay) {
1048 msleep_interruptible(jiffies_to_msecs(port->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 }
Alan Coxc1314a42009-01-02 13:48:17 +00001050 wake_up_interruptible(&port->open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 } else {
1052 if (info->xmit_buf) {
1053 free_page((unsigned long) info->xmit_buf);
1054 info->xmit_buf = NULL;
1055 }
1056 }
Alan Cox417b6e02010-06-01 22:52:45 +02001057 spin_lock_irq(&port->lock);
Alan Cox21bed702009-01-02 13:48:23 +00001058 info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 tty->closing = 0;
Alan Cox417b6e02010-06-01 22:52:45 +02001060 spin_unlock_irq(&port->lock);
1061 mutex_unlock(&port->mutex);
Alan Coxfba85e02009-01-02 13:48:39 +00001062 tty_port_tty_set(port, NULL);
Alan Cox417b6e02010-06-01 22:52:45 +02001063
Alan Coxfba85e02009-01-02 13:48:39 +00001064 wake_up_interruptible(&port->close_wait);
Jiri Slaby8cf5a8c2007-10-18 03:06:25 -07001065 complete_all(&info->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 atomic_dec(&rp_num_ports_open);
1067
1068#ifdef ROCKET_DEBUG_OPEN
Jiri Slaby68562b72008-02-07 00:16:33 -08001069 printk(KERN_INFO "rocket mod-- = %d...\n",
1070 atomic_read(&rp_num_ports_open));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);
1072#endif
1073
1074}
1075
1076static void rp_set_termios(struct tty_struct *tty,
Alan Cox606d0992006-12-08 02:38:45 -08001077 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
Alan Coxc9f19e92009-01-02 13:47:26 +00001079 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 CHANNEL_t *cp;
1081 unsigned cflag;
1082
1083 if (rocket_paranoia_check(info, "rp_set_termios"))
1084 return;
1085
Alan Coxadc8d742012-07-14 15:31:47 +01001086 cflag = tty->termios.c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 /*
1089 * This driver doesn't support CS5 or CS6
1090 */
1091 if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
Alan Coxadc8d742012-07-14 15:31:47 +01001092 tty->termios.c_cflag =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
Alan Cox6df35262008-02-08 04:18:45 -08001094 /* Or CMSPAR */
Alan Coxadc8d742012-07-14 15:31:47 +01001095 tty->termios.c_cflag &= ~CMSPAR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Alan Cox47b01b32009-01-02 13:48:30 +00001097 configure_r_port(tty, info, old_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 cp = &info->channel;
1100
1101 /* Handle transition to B0 status */
Alan Coxadc8d742012-07-14 15:31:47 +01001102 if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 sClrDTR(cp);
1104 sClrRTS(cp);
1105 }
1106
1107 /* Handle transition away from B0 status */
Alan Coxadc8d742012-07-14 15:31:47 +01001108 if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
1109 if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 sSetRTS(cp);
1111 sSetDTR(cp);
1112 }
1113
Alan Coxadc8d742012-07-14 15:31:47 +01001114 if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 tty->hw_stopped = 0;
1116 rp_start(tty);
1117 }
1118}
1119
Alan Cox9e989662008-07-22 11:18:03 +01001120static int rp_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121{
Alan Coxc9f19e92009-01-02 13:47:26 +00001122 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 unsigned long flags;
1124
1125 if (rocket_paranoia_check(info, "rp_break"))
Alan Cox9e989662008-07-22 11:18:03 +01001126 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 spin_lock_irqsave(&info->slock, flags);
1129 if (break_state == -1)
1130 sSendBreak(&info->channel);
1131 else
1132 sClrBreak(&info->channel);
1133 spin_unlock_irqrestore(&info->slock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01001134 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
1137/*
1138 * sGetChanRI used to be a macro in rocket_int.h. When the functionality for
1139 * the UPCI boards was added, it was decided to make this a function because
1140 * the macro was getting too complicated. All cases except the first one
1141 * (UPCIRingInd) are taken directly from the original macro.
1142 */
1143static int sGetChanRI(CHANNEL_T * ChP)
1144{
1145 CONTROLLER_t *CtlP = ChP->CtlP;
1146 int ChanNum = ChP->ChanNum;
1147 int RingInd = 0;
1148
1149 if (CtlP->UPCIRingInd)
1150 RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);
1151 else if (CtlP->AltChanRingIndicator)
1152 RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;
1153 else if (CtlP->boardType == ROCKET_TYPE_PC104)
1154 RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);
1155
1156 return RingInd;
1157}
1158
1159/********************************************************************************************/
1160/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */
1161
1162/*
1163 * Returns the state of the serial modem control lines. These next 2 functions
1164 * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs.
1165 */
Alan Cox60b33c12011-02-14 16:26:14 +00001166static int rp_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Alan Coxc9f19e92009-01-02 13:47:26 +00001168 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 unsigned int control, result, ChanStatus;
1170
1171 ChanStatus = sGetChanStatusLo(&info->channel);
1172 control = info->channel.TxControl[3];
1173 result = ((control & SET_RTS) ? TIOCM_RTS : 0) |
1174 ((control & SET_DTR) ? TIOCM_DTR : 0) |
1175 ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |
1176 (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |
1177 ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |
1178 ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);
1179
1180 return result;
1181}
1182
1183/*
1184 * Sets the modem control lines
1185 */
Alan Cox20b9d172011-02-14 16:26:50 +00001186static int rp_tiocmset(struct tty_struct *tty,
1187 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
Alan Coxc9f19e92009-01-02 13:47:26 +00001189 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190
1191 if (set & TIOCM_RTS)
1192 info->channel.TxControl[3] |= SET_RTS;
1193 if (set & TIOCM_DTR)
1194 info->channel.TxControl[3] |= SET_DTR;
1195 if (clear & TIOCM_RTS)
1196 info->channel.TxControl[3] &= ~SET_RTS;
1197 if (clear & TIOCM_DTR)
1198 info->channel.TxControl[3] &= ~SET_DTR;
1199
Al Viro457fb602008-03-19 16:27:48 +00001200 out32(info->channel.IndexAddr, info->channel.TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return 0;
1202}
1203
1204static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
1205{
1206 struct rocket_config tmp;
1207
1208 if (!retinfo)
1209 return -EFAULT;
1210 memset(&tmp, 0, sizeof (tmp));
Alan Cox417b6e02010-06-01 22:52:45 +02001211 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 tmp.line = info->line;
1213 tmp.flags = info->flags;
Alan Cox44b7d1b2008-07-16 21:57:18 +01001214 tmp.close_delay = info->port.close_delay;
1215 tmp.closing_wait = info->port.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];
Alan Cox417b6e02010-06-01 22:52:45 +02001217 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))
1220 return -EFAULT;
1221 return 0;
1222}
1223
Alan Cox47b01b32009-01-02 13:48:30 +00001224static int set_config(struct tty_struct *tty, struct r_port *info,
1225 struct rocket_config __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
1227 struct rocket_config new_serial;
1228
1229 if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))
1230 return -EFAULT;
1231
Alan Cox417b6e02010-06-01 22:52:45 +02001232 mutex_lock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if (!capable(CAP_SYS_ADMIN))
1234 {
Alan Cox417b6e02010-06-01 22:52:45 +02001235 if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) {
1236 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 return -EPERM;
Alan Cox417b6e02010-06-01 22:52:45 +02001238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
Alan Cox47b01b32009-01-02 13:48:30 +00001240 configure_r_port(tty, info, NULL);
Dan Carpenter49bf7ea2010-08-11 20:00:09 +02001241 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return 0;
1243 }
1244
1245 info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
Alan Cox44b7d1b2008-07-16 21:57:18 +01001246 info->port.close_delay = new_serial.close_delay;
1247 info->port.closing_wait = new_serial.closing_wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
Alan Cox47b01b32009-01-02 13:48:30 +00001250 tty->alt_speed = 57600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001252 tty->alt_speed = 115200;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
Alan Cox47b01b32009-01-02 13:48:30 +00001254 tty->alt_speed = 230400;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
Alan Cox47b01b32009-01-02 13:48:30 +00001256 tty->alt_speed = 460800;
Alan Cox417b6e02010-06-01 22:52:45 +02001257 mutex_unlock(&info->port.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Alan Cox47b01b32009-01-02 13:48:30 +00001259 configure_r_port(tty, info, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 return 0;
1261}
1262
1263/*
1264 * This function fills in a rocket_ports struct with information
1265 * about what boards/ports are in the system. This info is passed
1266 * to user space. See setrocket.c where the info is used to create
1267 * the /dev/ttyRx ports.
1268 */
1269static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
1270{
1271 struct rocket_ports tmp;
1272 int board;
1273
1274 if (!retports)
1275 return -EFAULT;
1276 memset(&tmp, 0, sizeof (tmp));
1277 tmp.tty_major = rocket_driver->major;
1278
1279 for (board = 0; board < 4; board++) {
1280 tmp.rocketModel[board].model = rocketModel[board].model;
1281 strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);
1282 tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;
1283 tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;
1284 tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;
1285 }
1286 if (copy_to_user(retports, &tmp, sizeof (*retports)))
1287 return -EFAULT;
1288 return 0;
1289}
1290
1291static int reset_rm2(struct r_port *info, void __user *arg)
1292{
1293 int reset;
1294
Alan Cox4129a6452008-02-08 04:18:45 -08001295 if (!capable(CAP_SYS_ADMIN))
1296 return -EPERM;
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (copy_from_user(&reset, arg, sizeof (int)))
1299 return -EFAULT;
1300 if (reset)
1301 reset = 1;
1302
1303 if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&
1304 rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)
1305 return -EINVAL;
1306
1307 if (info->ctlp->BusType == isISA)
1308 sModemReset(info->ctlp, info->chan, reset);
1309 else
1310 sPCIModemReset(info->ctlp, info->chan, reset);
1311
1312 return 0;
1313}
1314
1315static int get_version(struct r_port *info, struct rocket_version __user *retvers)
1316{
1317 if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))
1318 return -EFAULT;
1319 return 0;
1320}
1321
1322/* IOCTL call handler into the driver */
Alan Cox6caa76b2011-02-14 16:27:22 +00001323static int rp_ioctl(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 unsigned int cmd, unsigned long arg)
1325{
Alan Coxc9f19e92009-01-02 13:47:26 +00001326 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 void __user *argp = (void __user *)arg;
Alan Coxbdf183a2008-04-30 00:53:21 -07001328 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
1331 return -ENXIO;
1332
1333 switch (cmd) {
1334 case RCKP_GET_STRUCT:
1335 if (copy_to_user(argp, info, sizeof (struct r_port)))
Alan Coxbdf183a2008-04-30 00:53:21 -07001336 ret = -EFAULT;
1337 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 case RCKP_GET_CONFIG:
Alan Coxbdf183a2008-04-30 00:53:21 -07001339 ret = get_config(info, argp);
1340 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 case RCKP_SET_CONFIG:
Alan Cox47b01b32009-01-02 13:48:30 +00001342 ret = set_config(tty, info, argp);
Alan Coxbdf183a2008-04-30 00:53:21 -07001343 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 case RCKP_GET_PORTS:
Alan Coxbdf183a2008-04-30 00:53:21 -07001345 ret = get_ports(info, argp);
1346 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 case RCKP_RESET_RM2:
Alan Coxbdf183a2008-04-30 00:53:21 -07001348 ret = reset_rm2(info, argp);
1349 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 case RCKP_GET_VERSION:
Alan Coxbdf183a2008-04-30 00:53:21 -07001351 ret = get_version(info, argp);
1352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 default:
Alan Coxbdf183a2008-04-30 00:53:21 -07001354 ret = -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
Alan Coxbdf183a2008-04-30 00:53:21 -07001356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
1358
1359static void rp_send_xchar(struct tty_struct *tty, char ch)
1360{
Alan Coxc9f19e92009-01-02 13:47:26 +00001361 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 CHANNEL_t *cp;
1363
1364 if (rocket_paranoia_check(info, "rp_send_xchar"))
1365 return;
1366
1367 cp = &info->channel;
1368 if (sGetTxCnt(cp))
1369 sWriteTxPrioByte(cp, ch);
1370 else
1371 sWriteTxByte(sGetTxRxDataIO(cp), ch);
1372}
1373
1374static void rp_throttle(struct tty_struct *tty)
1375{
Alan Coxc9f19e92009-01-02 13:47:26 +00001376 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378#ifdef ROCKET_DEBUG_THROTTLE
1379 printk(KERN_INFO "throttle %s: %d....\n", tty->name,
1380 tty->ldisc.chars_in_buffer(tty));
1381#endif
1382
1383 if (rocket_paranoia_check(info, "rp_throttle"))
1384 return;
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (I_IXOFF(tty))
1387 rp_send_xchar(tty, STOP_CHAR(tty));
1388
1389 sClrRTS(&info->channel);
1390}
1391
1392static void rp_unthrottle(struct tty_struct *tty)
1393{
Alan Coxc9f19e92009-01-02 13:47:26 +00001394 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395#ifdef ROCKET_DEBUG_THROTTLE
1396 printk(KERN_INFO "unthrottle %s: %d....\n", tty->name,
1397 tty->ldisc.chars_in_buffer(tty));
1398#endif
1399
1400 if (rocket_paranoia_check(info, "rp_throttle"))
1401 return;
1402
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (I_IXOFF(tty))
1404 rp_send_xchar(tty, START_CHAR(tty));
1405
1406 sSetRTS(&info->channel);
1407}
1408
1409/*
1410 * ------------------------------------------------------------
1411 * rp_stop() and rp_start()
1412 *
1413 * This routines are called before setting or resetting tty->stopped.
1414 * They enable or disable transmitter interrupts, as necessary.
1415 * ------------------------------------------------------------
1416 */
1417static void rp_stop(struct tty_struct *tty)
1418{
Alan Coxc9f19e92009-01-02 13:47:26 +00001419 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421#ifdef ROCKET_DEBUG_FLOW
1422 printk(KERN_INFO "stop %s: %d %d....\n", tty->name,
1423 info->xmit_cnt, info->xmit_fifo_room);
1424#endif
1425
1426 if (rocket_paranoia_check(info, "rp_stop"))
1427 return;
1428
1429 if (sGetTxCnt(&info->channel))
1430 sDisTransmit(&info->channel);
1431}
1432
1433static void rp_start(struct tty_struct *tty)
1434{
Alan Coxc9f19e92009-01-02 13:47:26 +00001435 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437#ifdef ROCKET_DEBUG_FLOW
1438 printk(KERN_INFO "start %s: %d %d....\n", tty->name,
1439 info->xmit_cnt, info->xmit_fifo_room);
1440#endif
1441
1442 if (rocket_paranoia_check(info, "rp_stop"))
1443 return;
1444
1445 sEnTransmit(&info->channel);
1446 set_bit((info->aiop * 8) + info->chan,
1447 (void *) &xmit_flags[info->board]);
1448}
1449
1450/*
1451 * rp_wait_until_sent() --- wait until the transmitter is empty
1452 */
1453static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
1454{
Alan Coxc9f19e92009-01-02 13:47:26 +00001455 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 CHANNEL_t *cp;
1457 unsigned long orig_jiffies;
1458 int check_time, exit_time;
1459 int txcnt;
1460
1461 if (rocket_paranoia_check(info, "rp_wait_until_sent"))
1462 return;
1463
1464 cp = &info->channel;
1465
1466 orig_jiffies = jiffies;
1467#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001468 printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 jiffies);
Jiri Slaby68562b72008-02-07 00:16:33 -08001470 printk(KERN_INFO "cps=%d...\n", info->cps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471#endif
1472 while (1) {
1473 txcnt = sGetTxCnt(cp);
1474 if (!txcnt) {
1475 if (sGetChanStatusLo(cp) & TXSHRMT)
1476 break;
1477 check_time = (HZ / info->cps) / 5;
1478 } else {
1479 check_time = HZ * txcnt / info->cps;
1480 }
1481 if (timeout) {
1482 exit_time = orig_jiffies + timeout - jiffies;
1483 if (exit_time <= 0)
1484 break;
1485 if (exit_time < check_time)
1486 check_time = exit_time;
1487 }
1488 if (check_time == 0)
1489 check_time = 1;
1490#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
Jiri Slaby68562b72008-02-07 00:16:33 -08001491 printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...\n", txcnt,
1492 jiffies, check_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493#endif
1494 msleep_interruptible(jiffies_to_msecs(check_time));
1495 if (signal_pending(current))
1496 break;
1497 }
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -07001498 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
1500 printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
1501#endif
1502}
1503
1504/*
1505 * rp_hangup() --- called by tty_hangup() when a hangup is signaled.
1506 */
1507static void rp_hangup(struct tty_struct *tty)
1508{
1509 CHANNEL_t *cp;
Alan Coxc9f19e92009-01-02 13:47:26 +00001510 struct r_port *info = tty->driver_data;
Alan Cox417b6e02010-06-01 22:52:45 +02001511 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
1513 if (rocket_paranoia_check(info, "rp_hangup"))
1514 return;
1515
1516#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP))
Jiri Slaby68562b72008-02-07 00:16:33 -08001517 printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518#endif
1519 rp_flush_buffer(tty);
Alan Cox417b6e02010-06-01 22:52:45 +02001520 spin_lock_irqsave(&info->port.lock, flags);
1521 if (info->port.flags & ASYNC_CLOSING) {
1522 spin_unlock_irqrestore(&info->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return;
Alan Cox417b6e02010-06-01 22:52:45 +02001524 }
Alan Coxe60a1082008-07-16 21:56:18 +01001525 if (info->port.count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 atomic_dec(&rp_num_ports_open);
1527 clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
Alan Cox417b6e02010-06-01 22:52:45 +02001528 spin_unlock_irqrestore(&info->port.lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Alan Coxfba85e02009-01-02 13:48:39 +00001530 tty_port_hangup(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 cp = &info->channel;
1533 sDisRxFIFO(cp);
1534 sDisTransmit(cp);
1535 sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));
1536 sDisCTSFlowCtl(cp);
1537 sDisTxSoftFlowCtl(cp);
1538 sClrTxXOFF(cp);
Alan Cox417b6e02010-06-01 22:52:45 +02001539 clear_bit(ASYNCB_INITIALIZED, &info->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Alan Coxe60a1082008-07-16 21:56:18 +01001541 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542}
1543
1544/*
1545 * Exception handler - write char routine. The RocketPort driver uses a
1546 * double-buffering strategy, with the twist that if the in-memory CPU
1547 * buffer is empty, and there's space in the transmit FIFO, the
1548 * writing routines will write directly to transmit FIFO.
1549 * Write buffer and counters protected by spinlocks
1550 */
Alan Coxbbbbb962008-04-30 00:54:05 -07001551static int rp_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
Alan Coxc9f19e92009-01-02 13:47:26 +00001553 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 CHANNEL_t *cp;
1555 unsigned long flags;
1556
1557 if (rocket_paranoia_check(info, "rp_put_char"))
Alan Coxbbbbb962008-04-30 00:54:05 -07001558 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001560 /*
1561 * Grab the port write mutex, locking out other processes that try to
1562 * write to this port
1563 */
1564 mutex_lock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001567 printk(KERN_INFO "rp_put_char %c...\n", ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568#endif
1569
1570 spin_lock_irqsave(&info->slock, flags);
1571 cp = &info->channel;
1572
1573 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
1574 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1575
1576 if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
1577 info->xmit_buf[info->xmit_head++] = ch;
1578 info->xmit_head &= XMIT_BUF_SIZE - 1;
1579 info->xmit_cnt++;
1580 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1581 } else {
1582 sOutB(sGetTxRxDataIO(cp), ch);
1583 info->xmit_fifo_room--;
1584 }
1585 spin_unlock_irqrestore(&info->slock, flags);
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001586 mutex_unlock(&info->write_mtx);
Alan Coxbbbbb962008-04-30 00:54:05 -07001587 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588}
1589
1590/*
1591 * Exception handler - write routine, called when user app writes to the device.
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001592 * A per port write mutex is used to protect from another process writing to
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 * this port at the same time. This other process could be running on the other CPU
1594 * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
1595 * Spinlocks protect the info xmit members.
1596 */
1597static int rp_write(struct tty_struct *tty,
1598 const unsigned char *buf, int count)
1599{
Alan Coxc9f19e92009-01-02 13:47:26 +00001600 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 CHANNEL_t *cp;
1602 const unsigned char *b;
1603 int c, retval = 0;
1604 unsigned long flags;
1605
1606 if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
1607 return 0;
1608
Satyam Sharma1e3e8d92007-07-15 23:40:07 -07001609 if (mutex_lock_interruptible(&info->write_mtx))
1610 return -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
1612#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001613 printk(KERN_INFO "rp_write %d chars...\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614#endif
1615 cp = &info->channel;
1616
1617 if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
1618 info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1619
1620 /*
1621 * If the write queue for the port is empty, and there is FIFO space, stuff bytes
1622 * into FIFO. Use the write queue for temp storage.
1623 */
1624 if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
1625 c = min(count, info->xmit_fifo_room);
1626 b = buf;
1627
1628 /* Push data into FIFO, 2 bytes at a time */
1629 sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2);
1630
1631 /* If there is a byte remaining, write it */
1632 if (c & 1)
1633 sOutB(sGetTxRxDataIO(cp), b[c - 1]);
1634
1635 retval += c;
1636 buf += c;
1637 count -= c;
1638
1639 spin_lock_irqsave(&info->slock, flags);
1640 info->xmit_fifo_room -= c;
1641 spin_unlock_irqrestore(&info->slock, flags);
1642 }
1643
1644 /* If count is zero, we wrote it all and are done */
1645 if (!count)
1646 goto end;
1647
1648 /* Write remaining data into the port's xmit_buf */
1649 while (1) {
Alan Cox47b01b32009-01-02 13:48:30 +00001650 /* Hung up ? */
Jiri Slabya391ad02009-06-11 12:40:17 +01001651 if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 goto end;
Harvey Harrison709107f2008-04-30 00:53:51 -07001653 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
1654 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (c <= 0)
1656 break;
1657
1658 b = buf;
1659 memcpy(info->xmit_buf + info->xmit_head, b, c);
1660
1661 spin_lock_irqsave(&info->slock, flags);
1662 info->xmit_head =
1663 (info->xmit_head + c) & (XMIT_BUF_SIZE - 1);
1664 info->xmit_cnt += c;
1665 spin_unlock_irqrestore(&info->slock, flags);
1666
1667 buf += c;
1668 count -= c;
1669 retval += c;
1670 }
1671
1672 if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
1673 set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
1674
1675end:
1676 if (info->xmit_cnt < WAKEUP_CHARS) {
1677 tty_wakeup(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678#ifdef ROCKETPORT_HAVE_POLL_WAIT
1679 wake_up_interruptible(&tty->poll_wait);
1680#endif
1681 }
Matthias Kaehlcke69f545e2007-05-08 00:32:00 -07001682 mutex_unlock(&info->write_mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 return retval;
1684}
1685
1686/*
1687 * Return the number of characters that can be sent. We estimate
1688 * only using the in-memory transmit buffer only, and ignore the
1689 * potential space in the transmit FIFO.
1690 */
1691static int rp_write_room(struct tty_struct *tty)
1692{
Alan Coxc9f19e92009-01-02 13:47:26 +00001693 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 int ret;
1695
1696 if (rocket_paranoia_check(info, "rp_write_room"))
1697 return 0;
1698
1699 ret = XMIT_BUF_SIZE - info->xmit_cnt - 1;
1700 if (ret < 0)
1701 ret = 0;
1702#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001703 printk(KERN_INFO "rp_write_room returns %d...\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704#endif
1705 return ret;
1706}
1707
1708/*
1709 * Return the number of characters in the buffer. Again, this only
1710 * counts those characters in the in-memory transmit buffer.
1711 */
1712static int rp_chars_in_buffer(struct tty_struct *tty)
1713{
Alan Coxc9f19e92009-01-02 13:47:26 +00001714 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
1716 if (rocket_paranoia_check(info, "rp_chars_in_buffer"))
1717 return 0;
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719#ifdef ROCKET_DEBUG_WRITE
Jiri Slaby68562b72008-02-07 00:16:33 -08001720 printk(KERN_INFO "rp_chars_in_buffer returns %d...\n", info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721#endif
1722 return info->xmit_cnt;
1723}
1724
1725/*
1726 * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the
1727 * r_port struct for the port. Note that spinlock are used to protect info members,
1728 * do not call this function if the spinlock is already held.
1729 */
1730static void rp_flush_buffer(struct tty_struct *tty)
1731{
Alan Coxc9f19e92009-01-02 13:47:26 +00001732 struct r_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 CHANNEL_t *cp;
1734 unsigned long flags;
1735
1736 if (rocket_paranoia_check(info, "rp_flush_buffer"))
1737 return;
1738
1739 spin_lock_irqsave(&info->slock, flags);
1740 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1741 spin_unlock_irqrestore(&info->slock, flags);
1742
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743#ifdef ROCKETPORT_HAVE_POLL_WAIT
1744 wake_up_interruptible(&tty->poll_wait);
1745#endif
1746 tty_wakeup(tty);
1747
1748 cp = &info->channel;
1749 sFlushTxFIFO(cp);
1750}
1751
1752#ifdef CONFIG_PCI
1753
Kevin Cernekeeb9d42392013-01-16 20:28:39 -08001754static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
1755 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },
1756 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },
1757 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) },
1758 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) },
1759 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) },
1760 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) },
1761 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) },
1762 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) },
1763 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) },
1764 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) },
1765 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) },
1766 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) },
1767 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) },
1768 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) },
1769 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) },
1770 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) },
1771 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) },
1772 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) },
1773 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) },
1774 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) },
1775 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) },
1776 { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) },
Jiri Slaby8d5916d2007-05-08 00:27:05 -07001777 { }
1778};
1779MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781/*
1782 * Called when a PCI card is found. Retrieves and stores model information,
1783 * init's aiopic and serial port hardware.
1784 * Inputs: i is the board number (0-n)
1785 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07001786static __init int register_PCI(int i, struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787{
1788 int num_aiops, aiop, max_num_aiops, num_chan, chan;
1789 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 CONTROLLER_t *ctlp;
1791
1792 int fast_clock = 0;
1793 int altChanRingIndicator = 0;
1794 int ports_per_aiop = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 WordIO_t ConfigIO = 0;
1796 ByteIO_t UPCIRingInd = 0;
1797
Kevin Cernekeeb9d42392013-01-16 20:28:39 -08001798 if (!dev || !pci_match_id(rocket_pci_ids, dev) ||
1799 pci_enable_device(dev))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 return 0;
1801
1802 rcktpt_io_addr[i] = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 rcktpt_type[i] = ROCKET_TYPE_NORMAL;
1805 rocketModel[i].loadrm2 = 0;
1806 rocketModel[i].startingPortNumber = nextLineNumber;
1807
1808 /* Depending on the model, set up some config variables */
1809 switch (dev->device) {
1810 case PCI_DEVICE_ID_RP4QUAD:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 max_num_aiops = 1;
1812 ports_per_aiop = 4;
1813 rocketModel[i].model = MODEL_RP4QUAD;
1814 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable");
1815 rocketModel[i].numPorts = 4;
1816 break;
1817 case PCI_DEVICE_ID_RP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 max_num_aiops = 1;
1819 rocketModel[i].model = MODEL_RP8OCTA;
1820 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable");
1821 rocketModel[i].numPorts = 8;
1822 break;
1823 case PCI_DEVICE_ID_URP8OCTA:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 max_num_aiops = 1;
1825 rocketModel[i].model = MODEL_UPCI_RP8OCTA;
1826 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable");
1827 rocketModel[i].numPorts = 8;
1828 break;
1829 case PCI_DEVICE_ID_RP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 max_num_aiops = 1;
1831 rocketModel[i].model = MODEL_RP8INTF;
1832 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F");
1833 rocketModel[i].numPorts = 8;
1834 break;
1835 case PCI_DEVICE_ID_URP8INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 max_num_aiops = 1;
1837 rocketModel[i].model = MODEL_UPCI_RP8INTF;
1838 strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F");
1839 rocketModel[i].numPorts = 8;
1840 break;
1841 case PCI_DEVICE_ID_RP8J:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 max_num_aiops = 1;
1843 rocketModel[i].model = MODEL_RP8J;
1844 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors");
1845 rocketModel[i].numPorts = 8;
1846 break;
1847 case PCI_DEVICE_ID_RP4J:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 max_num_aiops = 1;
1849 ports_per_aiop = 4;
1850 rocketModel[i].model = MODEL_RP4J;
1851 strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors");
1852 rocketModel[i].numPorts = 4;
1853 break;
1854 case PCI_DEVICE_ID_RP8SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 max_num_aiops = 1;
1856 rocketModel[i].model = MODEL_RP8SNI;
1857 strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78");
1858 rocketModel[i].numPorts = 8;
1859 break;
1860 case PCI_DEVICE_ID_RP16SNI:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 max_num_aiops = 2;
1862 rocketModel[i].model = MODEL_RP16SNI;
1863 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78");
1864 rocketModel[i].numPorts = 16;
1865 break;
1866 case PCI_DEVICE_ID_RP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 max_num_aiops = 2;
1868 rocketModel[i].model = MODEL_RP16INTF;
1869 strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F");
1870 rocketModel[i].numPorts = 16;
1871 break;
1872 case PCI_DEVICE_ID_URP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 max_num_aiops = 2;
1874 rocketModel[i].model = MODEL_UPCI_RP16INTF;
1875 strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F");
1876 rocketModel[i].numPorts = 16;
1877 break;
1878 case PCI_DEVICE_ID_CRP16INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 max_num_aiops = 2;
1880 rocketModel[i].model = MODEL_CPCI_RP16INTF;
1881 strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F");
1882 rocketModel[i].numPorts = 16;
1883 break;
1884 case PCI_DEVICE_ID_RP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 max_num_aiops = 4;
1886 rocketModel[i].model = MODEL_RP32INTF;
1887 strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F");
1888 rocketModel[i].numPorts = 32;
1889 break;
1890 case PCI_DEVICE_ID_URP32INTF:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 max_num_aiops = 4;
1892 rocketModel[i].model = MODEL_UPCI_RP32INTF;
1893 strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F");
1894 rocketModel[i].numPorts = 32;
1895 break;
1896 case PCI_DEVICE_ID_RPP4:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 max_num_aiops = 1;
1898 ports_per_aiop = 4;
1899 altChanRingIndicator++;
1900 fast_clock++;
1901 rocketModel[i].model = MODEL_RPP4;
1902 strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port");
1903 rocketModel[i].numPorts = 4;
1904 break;
1905 case PCI_DEVICE_ID_RPP8:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 max_num_aiops = 2;
1907 ports_per_aiop = 4;
1908 altChanRingIndicator++;
1909 fast_clock++;
1910 rocketModel[i].model = MODEL_RPP8;
1911 strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port");
1912 rocketModel[i].numPorts = 8;
1913 break;
1914 case PCI_DEVICE_ID_RP2_232:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 max_num_aiops = 1;
1916 ports_per_aiop = 2;
1917 altChanRingIndicator++;
1918 fast_clock++;
1919 rocketModel[i].model = MODEL_RP2_232;
1920 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232");
1921 rocketModel[i].numPorts = 2;
1922 break;
1923 case PCI_DEVICE_ID_RP2_422:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 max_num_aiops = 1;
1925 ports_per_aiop = 2;
1926 altChanRingIndicator++;
1927 fast_clock++;
1928 rocketModel[i].model = MODEL_RP2_422;
1929 strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422");
1930 rocketModel[i].numPorts = 2;
1931 break;
1932 case PCI_DEVICE_ID_RP6M:
1933
1934 max_num_aiops = 1;
1935 ports_per_aiop = 6;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
Jiri Slaby57fedc72007-10-18 03:06:28 -07001937 /* If revision is 1, the rocketmodem flash must be loaded.
1938 * If it is 2 it is a "socketed" version. */
1939 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
1941 rocketModel[i].loadrm2 = 1;
1942 } else {
1943 rcktpt_type[i] = ROCKET_TYPE_MODEM;
1944 }
1945
1946 rocketModel[i].model = MODEL_RP6M;
1947 strcpy(rocketModel[i].modelString, "RocketModem 6 port");
1948 rocketModel[i].numPorts = 6;
1949 break;
1950 case PCI_DEVICE_ID_RP4M:
1951 max_num_aiops = 1;
1952 ports_per_aiop = 4;
Jiri Slaby57fedc72007-10-18 03:06:28 -07001953 if (dev->revision == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 rcktpt_type[i] = ROCKET_TYPE_MODEMII;
1955 rocketModel[i].loadrm2 = 1;
1956 } else {
1957 rcktpt_type[i] = ROCKET_TYPE_MODEM;
1958 }
1959
1960 rocketModel[i].model = MODEL_RP4M;
1961 strcpy(rocketModel[i].modelString, "RocketModem 4 port");
1962 rocketModel[i].numPorts = 4;
1963 break;
1964 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 max_num_aiops = 0;
1966 break;
1967 }
1968
1969 /*
1970 * Check for UPCI boards.
1971 */
1972
1973 switch (dev->device) {
1974 case PCI_DEVICE_ID_URP32INTF:
1975 case PCI_DEVICE_ID_URP8INTF:
1976 case PCI_DEVICE_ID_URP16INTF:
1977 case PCI_DEVICE_ID_CRP16INTF:
1978 case PCI_DEVICE_ID_URP8OCTA:
1979 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
1980 ConfigIO = pci_resource_start(dev, 1);
1981 if (dev->device == PCI_DEVICE_ID_URP8OCTA) {
1982 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
1983
1984 /*
1985 * Check for octa or quad cable.
1986 */
1987 if (!
1988 (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) &
1989 PCI_GPIO_CTRL_8PORT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 ports_per_aiop = 4;
1991 rocketModel[i].numPorts = 4;
1992 }
1993 }
1994 break;
1995 case PCI_DEVICE_ID_UPCI_RM3_8PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 max_num_aiops = 1;
1997 rocketModel[i].model = MODEL_UPCI_RM3_8PORT;
1998 strcpy(rocketModel[i].modelString, "RocketModem III 8 port");
1999 rocketModel[i].numPorts = 8;
2000 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2001 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2002 ConfigIO = pci_resource_start(dev, 1);
2003 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2004 break;
2005 case PCI_DEVICE_ID_UPCI_RM3_4PORT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 max_num_aiops = 1;
2007 rocketModel[i].model = MODEL_UPCI_RM3_4PORT;
2008 strcpy(rocketModel[i].modelString, "RocketModem III 4 port");
2009 rocketModel[i].numPorts = 4;
2010 rcktpt_io_addr[i] = pci_resource_start(dev, 2);
2011 UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND;
2012 ConfigIO = pci_resource_start(dev, 1);
2013 rcktpt_type[i] = ROCKET_TYPE_MODEMIII;
2014 break;
2015 default:
2016 break;
2017 }
2018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 if (fast_clock) {
2020 sClockPrescale = 0x12; /* mod 2 (divide by 3) */
2021 rp_baud_base[i] = 921600;
2022 } else {
2023 /*
2024 * If support_low_speed is set, use the slow clock
2025 * prescale, which supports 50 bps
2026 */
2027 if (support_low_speed) {
2028 /* mod 9 (divide by 10) prescale */
2029 sClockPrescale = 0x19;
2030 rp_baud_base[i] = 230400;
2031 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002032 /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 sClockPrescale = 0x14;
2034 rp_baud_base[i] = 460800;
2035 }
2036 }
2037
2038 for (aiop = 0; aiop < max_num_aiops; aiop++)
2039 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40);
2040 ctlp = sCtlNumToCtlPtr(i);
2041 num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd);
2042 for (aiop = 0; aiop < max_num_aiops; aiop++)
2043 ctlp->AiopNumChan[aiop] = ports_per_aiop;
2044
Jiri Slaby68562b72008-02-07 00:16:33 -08002045 dev_info(&dev->dev, "comtrol PCI controller #%d found at "
2046 "address %04lx, %d AIOP(s) (%s), creating ttyR%d - %ld\n",
2047 i, rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString,
2048 rocketModel[i].startingPortNumber,
2049 rocketModel[i].startingPortNumber + rocketModel[i].numPorts-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
2051 if (num_aiops <= 0) {
2052 rcktpt_io_addr[i] = 0;
2053 return (0);
2054 }
2055 is_PCI[i] = 1;
2056
2057 /* Reset the AIOPIC, init the serial ports */
2058 for (aiop = 0; aiop < num_aiops; aiop++) {
2059 sResetAiopByNum(ctlp, aiop);
2060 num_chan = ports_per_aiop;
2061 for (chan = 0; chan < num_chan; chan++)
2062 init_r_port(i, aiop, chan, dev);
2063 }
2064
2065 /* Rocket modems must be reset */
2066 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) ||
2067 (rcktpt_type[i] == ROCKET_TYPE_MODEMII) ||
2068 (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) {
2069 num_chan = ports_per_aiop;
2070 for (chan = 0; chan < num_chan; chan++)
2071 sPCIModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002072 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 for (chan = 0; chan < num_chan; chan++)
2074 sPCIModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002075 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 rmSpeakerReset(ctlp, rocketModel[i].model);
2077 }
2078 return (1);
2079}
2080
2081/*
2082 * Probes for PCI cards, inits them if found
2083 * Input: board_found = number of ISA boards already found, or the
2084 * starting board number
2085 * Returns: Number of PCI boards found
2086 */
2087static int __init init_PCI(int boards_found)
2088{
2089 struct pci_dev *dev = NULL;
2090 int count = 0;
2091
2092 /* Work through the PCI device list, pulling out ours */
Alan Cox606d0992006-12-08 02:38:45 -08002093 while ((dev = pci_get_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 if (register_PCI(count + boards_found, dev))
2095 count++;
2096 }
2097 return (count);
2098}
2099
2100#endif /* CONFIG_PCI */
2101
2102/*
2103 * Probes for ISA cards
2104 * Input: i = the board number to look for
2105 * Returns: 1 if board found, 0 else
2106 */
2107static int __init init_ISA(int i)
2108{
2109 int num_aiops, num_chan = 0, total_num_chan = 0;
2110 int aiop, chan;
2111 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
2112 CONTROLLER_t *ctlp;
2113 char *type_string;
2114
2115 /* If io_addr is zero, no board configured */
2116 if (rcktpt_io_addr[i] == 0)
2117 return (0);
2118
2119 /* Reserve the IO region */
2120 if (!request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort")) {
Jiri Slaby68562b72008-02-07 00:16:33 -08002121 printk(KERN_ERR "Unable to reserve IO region for configured "
2122 "ISA RocketPort at address 0x%lx, board not "
2123 "installed...\n", rcktpt_io_addr[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 rcktpt_io_addr[i] = 0;
2125 return (0);
2126 }
2127
2128 ctlp = sCtlNumToCtlPtr(i);
2129
2130 ctlp->boardType = rcktpt_type[i];
2131
2132 switch (rcktpt_type[i]) {
2133 case ROCKET_TYPE_PC104:
2134 type_string = "(PC104)";
2135 break;
2136 case ROCKET_TYPE_MODEM:
2137 type_string = "(RocketModem)";
2138 break;
2139 case ROCKET_TYPE_MODEMII:
2140 type_string = "(RocketModem II)";
2141 break;
2142 default:
2143 type_string = "";
2144 break;
2145 }
2146
2147 /*
2148 * If support_low_speed is set, use the slow clock prescale,
2149 * which supports 50 bps
2150 */
2151 if (support_low_speed) {
2152 sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */
2153 rp_baud_base[i] = 230400;
2154 } else {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002155 sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 rp_baud_base[i] = 460800;
2157 }
2158
2159 for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
2160 aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400);
2161
2162 num_aiops = sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0);
2163
2164 if (ctlp->boardType == ROCKET_TYPE_PC104) {
2165 sEnAiop(ctlp, 2); /* only one AIOPIC, but these */
2166 sEnAiop(ctlp, 3); /* CSels used for other stuff */
2167 }
2168
2169 /* If something went wrong initing the AIOP's release the ISA IO memory */
2170 if (num_aiops <= 0) {
2171 release_region(rcktpt_io_addr[i], 64);
2172 rcktpt_io_addr[i] = 0;
2173 return (0);
2174 }
2175
2176 rocketModel[i].startingPortNumber = nextLineNumber;
2177
2178 for (aiop = 0; aiop < num_aiops; aiop++) {
2179 sResetAiopByNum(ctlp, aiop);
2180 sEnAiop(ctlp, aiop);
2181 num_chan = sGetAiopNumChan(ctlp, aiop);
2182 total_num_chan += num_chan;
2183 for (chan = 0; chan < num_chan; chan++)
2184 init_r_port(i, aiop, chan, NULL);
2185 }
2186 is_PCI[i] = 0;
2187 if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) {
2188 num_chan = sGetAiopNumChan(ctlp, 0);
2189 total_num_chan = num_chan;
2190 for (chan = 0; chan < num_chan; chan++)
2191 sModemReset(ctlp, chan, 1);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002192 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 for (chan = 0; chan < num_chan; chan++)
2194 sModemReset(ctlp, chan, 0);
Jiri Slaby48a67f52008-02-07 00:16:32 -08002195 msleep(500);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 strcpy(rocketModel[i].modelString, "RocketModem ISA");
2197 } else {
2198 strcpy(rocketModel[i].modelString, "RocketPort ISA");
2199 }
2200 rocketModel[i].numPorts = total_num_chan;
2201 rocketModel[i].model = MODEL_ISA;
2202
2203 printk(KERN_INFO "RocketPort ISA card #%d found at 0x%lx - %d AIOPs %s\n",
2204 i, rcktpt_io_addr[i], num_aiops, type_string);
2205
2206 printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n",
2207 rocketModel[i].modelString,
2208 rocketModel[i].startingPortNumber,
2209 rocketModel[i].startingPortNumber +
2210 rocketModel[i].numPorts - 1);
2211
2212 return (1);
2213}
2214
Jeff Dikeb68e31d2006-10-02 02:17:18 -07002215static const struct tty_operations rocket_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 .open = rp_open,
2217 .close = rp_close,
2218 .write = rp_write,
2219 .put_char = rp_put_char,
2220 .write_room = rp_write_room,
2221 .chars_in_buffer = rp_chars_in_buffer,
2222 .flush_buffer = rp_flush_buffer,
2223 .ioctl = rp_ioctl,
2224 .throttle = rp_throttle,
2225 .unthrottle = rp_unthrottle,
2226 .set_termios = rp_set_termios,
2227 .stop = rp_stop,
2228 .start = rp_start,
2229 .hangup = rp_hangup,
2230 .break_ctl = rp_break,
2231 .send_xchar = rp_send_xchar,
2232 .wait_until_sent = rp_wait_until_sent,
2233 .tiocmget = rp_tiocmget,
2234 .tiocmset = rp_tiocmset,
2235};
2236
Alan Cox31f35932009-01-02 13:45:05 +00002237static const struct tty_port_operations rocket_port_ops = {
2238 .carrier_raised = carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +01002239 .dtr_rts = dtr_rts,
Alan Cox31f35932009-01-02 13:45:05 +00002240};
2241
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242/*
2243 * The module "startup" routine; it's run when the module is loaded.
2244 */
Bjorn Helgaasd269cdd2005-10-30 15:03:14 -08002245static int __init rp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246{
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002247 int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
2249 printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
2250 ROCKET_VERSION, ROCKET_DATE);
2251
2252 rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
2253 if (!rocket_driver)
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002254 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
2256 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 * If board 1 is non-zero, there is at least one ISA configured. If controller is
2258 * zero, use the default controller IO address of board1 + 0x40.
2259 */
2260 if (board1) {
2261 if (controller == 0)
2262 controller = board1 + 0x40;
2263 } else {
2264 controller = 0; /* Used as a flag, meaning no ISA boards */
2265 }
2266
2267 /* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
2268 if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002269 printk(KERN_ERR "Unable to reserve IO region for first "
2270 "configured ISA RocketPort controller 0x%lx. "
2271 "Driver exiting\n", controller);
2272 ret = -EBUSY;
2273 goto err_tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 }
2275
2276 /* Store ISA variable retrieved from command line or .conf file. */
2277 rcktpt_io_addr[0] = board1;
2278 rcktpt_io_addr[1] = board2;
2279 rcktpt_io_addr[2] = board3;
2280 rcktpt_io_addr[3] = board4;
2281
2282 rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2283 rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0];
2284 rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2285 rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1];
2286 rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2287 rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2];
2288 rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL;
2289 rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3];
2290
2291 /*
2292 * Set up the tty driver structure and then register this
2293 * driver with the tty layer.
2294 */
2295
Greg Kroah-Hartman331b8312005-06-20 21:15:16 -07002296 rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 rocket_driver->name = "ttyR";
2298 rocket_driver->driver_name = "Comtrol RocketPort";
2299 rocket_driver->major = TTY_ROCKET_MAJOR;
2300 rocket_driver->minor_start = 0;
2301 rocket_driver->type = TTY_DRIVER_TYPE_SERIAL;
2302 rocket_driver->subtype = SERIAL_TYPE_NORMAL;
2303 rocket_driver->init_termios = tty_std_termios;
2304 rocket_driver->init_termios.c_cflag =
2305 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Alan Cox606d0992006-12-08 02:38:45 -08002306 rocket_driver->init_termios.c_ispeed = 9600;
2307 rocket_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308#ifdef ROCKET_SOFT_FLOW
Jiri Slabyac6aec22007-10-18 03:06:26 -07002309 rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310#endif
2311 tty_set_operations(rocket_driver, &rocket_ops);
2312
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002313 ret = tty_register_driver(rocket_driver);
2314 if (ret < 0) {
2315 printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
Dan Carpenter713efa92010-10-27 15:34:18 -07002316 goto err_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 }
2318
2319#ifdef ROCKET_DEBUG_OPEN
2320 printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major);
2321#endif
2322
2323 /*
2324 * OK, let's probe each of the controllers looking for boards. Any boards found
2325 * will be initialized here.
2326 */
2327 isa_boards_found = 0;
2328 pci_boards_found = 0;
2329
2330 for (i = 0; i < NUM_BOARDS; i++) {
2331 if (init_ISA(i))
2332 isa_boards_found++;
2333 }
2334
2335#ifdef CONFIG_PCI
2336 if (isa_boards_found < NUM_BOARDS)
2337 pci_boards_found = init_PCI(isa_boards_found);
2338#endif
2339
2340 max_board = pci_boards_found + isa_boards_found;
2341
2342 if (max_board == 0) {
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002343 printk(KERN_ERR "No rocketport ports found; unloading driver\n");
2344 ret = -ENXIO;
2345 goto err_ttyu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
2347
2348 return 0;
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002349err_ttyu:
2350 tty_unregister_driver(rocket_driver);
Dan Carpenter713efa92010-10-27 15:34:18 -07002351err_controller:
2352 if (controller)
2353 release_region(controller, 4);
Jiri Slaby4384a3f2007-10-18 03:06:28 -07002354err_tty:
2355 put_tty_driver(rocket_driver);
2356err:
2357 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358}
2359
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361static void rp_cleanup_module(void)
2362{
2363 int retval;
2364 int i;
2365
2366 del_timer_sync(&rocket_timer);
2367
2368 retval = tty_unregister_driver(rocket_driver);
2369 if (retval)
Jiri Slaby68562b72008-02-07 00:16:33 -08002370 printk(KERN_ERR "Error %d while trying to unregister "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 "rocketport driver\n", -retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Jesper Juhl735d5662005-11-07 01:01:29 -08002373 for (i = 0; i < MAX_RP_PORTS; i++)
Jiri Slabyac6aec22007-10-18 03:06:26 -07002374 if (rp_table[i]) {
2375 tty_unregister_device(rocket_driver, i);
Jiri Slaby191c5f12012-11-15 09:49:56 +01002376 tty_port_destroy(&rp_table[i]->port);
Jiri Slabyac6aec22007-10-18 03:06:26 -07002377 kfree(rp_table[i]);
2378 }
2379
2380 put_tty_driver(rocket_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
2382 for (i = 0; i < NUM_BOARDS; i++) {
2383 if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
2384 continue;
2385 release_region(rcktpt_io_addr[i], 64);
2386 }
2387 if (controller)
2388 release_region(controller, 4);
2389}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391/***************************************************************************
2392Function: sInitController
2393Purpose: Initialization of controller global registers and controller
2394 structure.
2395Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
2396 IRQNum,Frequency,PeriodicOnly)
2397 CONTROLLER_T *CtlP; Ptr to controller structure
2398 int CtlNum; Controller number
2399 ByteIO_t MudbacIO; Mudbac base I/O address.
2400 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2401 This list must be in the order the AIOPs will be found on the
2402 controller. Once an AIOP in the list is not found, it is
2403 assumed that there are no more AIOPs on the controller.
2404 int AiopIOListSize; Number of addresses in AiopIOList
2405 int IRQNum; Interrupt Request number. Can be any of the following:
2406 0: Disable global interrupts
2407 3: IRQ 3
2408 4: IRQ 4
2409 5: IRQ 5
2410 9: IRQ 9
2411 10: IRQ 10
2412 11: IRQ 11
2413 12: IRQ 12
2414 15: IRQ 15
2415 Byte_t Frequency: A flag identifying the frequency
2416 of the periodic interrupt, can be any one of the following:
2417 FREQ_DIS - periodic interrupt disabled
2418 FREQ_137HZ - 137 Hertz
2419 FREQ_69HZ - 69 Hertz
2420 FREQ_34HZ - 34 Hertz
2421 FREQ_17HZ - 17 Hertz
2422 FREQ_9HZ - 9 Hertz
2423 FREQ_4HZ - 4 Hertz
2424 If IRQNum is set to 0 the Frequency parameter is
2425 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002426 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002428 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 other channel interrupts are allowed.
2430 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002431 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2433 initialization failed.
2434
2435Comments:
2436 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002437 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 If interrupts are to be completely disabled set IRQNum to 0.
2440
Adrian Bunkf15313b2005-06-25 14:59:05 -07002441 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 invalid combination.
2443
2444 This function performs initialization of global interrupt modes,
2445 but it does not actually enable global interrupts. To enable
2446 and disable global interrupts use functions sEnGlobalInt() and
2447 sDisGlobalInt(). Enabling of global interrupts is normally not
2448 done until all other initializations are complete.
2449
2450 Even if interrupts are globally enabled, they must also be
2451 individually enabled for each channel that is to generate
2452 interrupts.
2453
2454Warnings: No range checking on any of the parameters is done.
2455
2456 No context switches are allowed while executing this function.
2457
2458 After this function all AIOPs on the controller are disabled,
2459 they can be enabled with sEnAiop().
2460*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002461static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
2462 ByteIO_t * AiopIOList, int AiopIOListSize,
2463 int IRQNum, Byte_t Frequency, int PeriodicOnly)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464{
2465 int i;
2466 ByteIO_t io;
2467 int done;
2468
2469 CtlP->AiopIntrBits = aiop_intr_bits;
2470 CtlP->AltChanRingIndicator = 0;
2471 CtlP->CtlNum = CtlNum;
2472 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2473 CtlP->BusType = isISA;
2474 CtlP->MBaseIO = MudbacIO;
2475 CtlP->MReg1IO = MudbacIO + 1;
2476 CtlP->MReg2IO = MudbacIO + 2;
2477 CtlP->MReg3IO = MudbacIO + 3;
2478#if 1
2479 CtlP->MReg2 = 0; /* interrupt disable */
2480 CtlP->MReg3 = 0; /* no periodic interrupts */
2481#else
2482 if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */
2483 CtlP->MReg2 = 0; /* interrupt disable */
2484 CtlP->MReg3 = 0; /* no periodic interrupts */
2485 } else {
2486 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
2487 CtlP->MReg3 = Frequency; /* set frequency */
2488 if (PeriodicOnly) { /* periodic interrupt only */
2489 CtlP->MReg3 |= PERIODIC_ONLY;
2490 }
2491 }
2492#endif
2493 sOutB(CtlP->MReg2IO, CtlP->MReg2);
2494 sOutB(CtlP->MReg3IO, CtlP->MReg3);
2495 sControllerEOI(CtlP); /* clear EOI if warm init */
2496 /* Init AIOPs */
2497 CtlP->NumAiop = 0;
2498 for (i = done = 0; i < AiopIOListSize; i++) {
2499 io = AiopIOList[i];
2500 CtlP->AiopIO[i] = (WordIO_t) io;
2501 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2502 sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */
2503 sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */
2504 if (done)
2505 continue;
2506 sEnAiop(CtlP, i); /* enable the AIOP */
2507 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2508 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2509 done = 1; /* done looking for AIOPs */
2510 else {
2511 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2512 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2513 sOutB(io + _INDX_DATA, sClockPrescale);
2514 CtlP->NumAiop++; /* bump count of AIOPs */
2515 }
2516 sDisAiop(CtlP, i); /* disable AIOP */
2517 }
2518
2519 if (CtlP->NumAiop == 0)
2520 return (-1);
2521 else
2522 return (CtlP->NumAiop);
2523}
2524
2525/***************************************************************************
2526Function: sPCIInitController
2527Purpose: Initialization of controller global registers and controller
2528 structure.
2529Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
2530 IRQNum,Frequency,PeriodicOnly)
2531 CONTROLLER_T *CtlP; Ptr to controller structure
2532 int CtlNum; Controller number
2533 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
2534 This list must be in the order the AIOPs will be found on the
2535 controller. Once an AIOP in the list is not found, it is
2536 assumed that there are no more AIOPs on the controller.
2537 int AiopIOListSize; Number of addresses in AiopIOList
2538 int IRQNum; Interrupt Request number. Can be any of the following:
2539 0: Disable global interrupts
2540 3: IRQ 3
2541 4: IRQ 4
2542 5: IRQ 5
2543 9: IRQ 9
2544 10: IRQ 10
2545 11: IRQ 11
2546 12: IRQ 12
2547 15: IRQ 15
2548 Byte_t Frequency: A flag identifying the frequency
2549 of the periodic interrupt, can be any one of the following:
2550 FREQ_DIS - periodic interrupt disabled
2551 FREQ_137HZ - 137 Hertz
2552 FREQ_69HZ - 69 Hertz
2553 FREQ_34HZ - 34 Hertz
2554 FREQ_17HZ - 17 Hertz
2555 FREQ_9HZ - 9 Hertz
2556 FREQ_4HZ - 4 Hertz
2557 If IRQNum is set to 0 the Frequency parameter is
2558 overidden, it is forced to a value of FREQ_DIS.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002559 int PeriodicOnly: 1 if all interrupts except the periodic
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 interrupt are to be blocked.
Adrian Bunkf15313b2005-06-25 14:59:05 -07002561 0 is both the periodic interrupt and
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 other channel interrupts are allowed.
2563 If IRQNum is set to 0 the PeriodicOnly parameter is
Adrian Bunkf15313b2005-06-25 14:59:05 -07002564 overidden, it is forced to a value of 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
2566 initialization failed.
2567
2568Comments:
2569 If periodic interrupts are to be disabled but AIOP interrupts
Adrian Bunkf15313b2005-06-25 14:59:05 -07002570 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
2572 If interrupts are to be completely disabled set IRQNum to 0.
2573
Adrian Bunkf15313b2005-06-25 14:59:05 -07002574 Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 invalid combination.
2576
2577 This function performs initialization of global interrupt modes,
2578 but it does not actually enable global interrupts. To enable
2579 and disable global interrupts use functions sEnGlobalInt() and
2580 sDisGlobalInt(). Enabling of global interrupts is normally not
2581 done until all other initializations are complete.
2582
2583 Even if interrupts are globally enabled, they must also be
2584 individually enabled for each channel that is to generate
2585 interrupts.
2586
2587Warnings: No range checking on any of the parameters is done.
2588
2589 No context switches are allowed while executing this function.
2590
2591 After this function all AIOPs on the controller are disabled,
2592 they can be enabled with sEnAiop().
2593*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002594static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
2595 ByteIO_t * AiopIOList, int AiopIOListSize,
2596 WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
2597 int PeriodicOnly, int altChanRingIndicator,
2598 int UPCIRingInd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599{
2600 int i;
2601 ByteIO_t io;
2602
2603 CtlP->AltChanRingIndicator = altChanRingIndicator;
2604 CtlP->UPCIRingInd = UPCIRingInd;
2605 CtlP->CtlNum = CtlNum;
2606 CtlP->CtlID = CTLID_0001; /* controller release 1 */
2607 CtlP->BusType = isPCI; /* controller release 1 */
2608
2609 if (ConfigIO) {
2610 CtlP->isUPCI = 1;
2611 CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
2612 CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
2613 CtlP->AiopIntrBits = upci_aiop_intr_bits;
2614 } else {
2615 CtlP->isUPCI = 0;
2616 CtlP->PCIIO =
2617 (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
2618 CtlP->AiopIntrBits = aiop_intr_bits;
2619 }
2620
2621 sPCIControllerEOI(CtlP); /* clear EOI if warm init */
2622 /* Init AIOPs */
2623 CtlP->NumAiop = 0;
2624 for (i = 0; i < AiopIOListSize; i++) {
2625 io = AiopIOList[i];
2626 CtlP->AiopIO[i] = (WordIO_t) io;
2627 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
2628
2629 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
2630 if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
2631 break; /* done looking for AIOPs */
2632
2633 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
2634 sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
2635 sOutB(io + _INDX_DATA, sClockPrescale);
2636 CtlP->NumAiop++; /* bump count of AIOPs */
2637 }
2638
2639 if (CtlP->NumAiop == 0)
2640 return (-1);
2641 else
2642 return (CtlP->NumAiop);
2643}
2644
2645/***************************************************************************
2646Function: sReadAiopID
2647Purpose: Read the AIOP idenfication number directly from an AIOP.
2648Call: sReadAiopID(io)
2649 ByteIO_t io: AIOP base I/O address
2650Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
2651 is replace by an identifying number.
2652 Flag AIOPID_NULL if no valid AIOP is found
2653Warnings: No context switches are allowed while executing this function.
2654
2655*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002656static int sReadAiopID(ByteIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657{
2658 Byte_t AiopID; /* ID byte from AIOP */
2659
2660 sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */
2661 sOutB(io + _CMD_REG, 0x0);
2662 AiopID = sInW(io + _CHN_STAT0) & 0x07;
2663 if (AiopID == 0x06)
2664 return (1);
2665 else /* AIOP does not exist */
2666 return (-1);
2667}
2668
2669/***************************************************************************
2670Function: sReadAiopNumChan
2671Purpose: Read the number of channels available in an AIOP directly from
2672 an AIOP.
2673Call: sReadAiopNumChan(io)
2674 WordIO_t io: AIOP base I/O address
2675Return: int: The number of channels available
2676Comments: The number of channels is determined by write/reads from identical
2677 offsets within the SRAM address spaces for channels 0 and 4.
2678 If the channel 4 space is mirrored to channel 0 it is a 4 channel
2679 AIOP, otherwise it is an 8 channel.
2680Warnings: No context switches are allowed while executing this function.
2681*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002682static int sReadAiopNumChan(WordIO_t io)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683{
2684 Word_t x;
2685 static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
2686
2687 /* write to chan 0 SRAM */
Al Viro457fb602008-03-19 16:27:48 +00002688 out32((DWordIO_t) io + _INDX_ADDR, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */
2690 x = sInW(io + _INDX_DATA);
2691 sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */
2692 if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
2693 return (8);
2694 else
2695 return (4);
2696}
2697
2698/***************************************************************************
2699Function: sInitChan
2700Purpose: Initialization of a channel and channel structure
2701Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
2702 CONTROLLER_T *CtlP; Ptr to controller structure
2703 CHANNEL_T *ChP; Ptr to channel structure
2704 int AiopNum; AIOP number within controller
2705 int ChanNum; Channel number within AIOP
Adrian Bunkf15313b2005-06-25 14:59:05 -07002706Return: int: 1 if initialization succeeded, 0 if it fails because channel
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 number exceeds number of channels available in AIOP.
2708Comments: This function must be called before a channel can be used.
2709Warnings: No range checking on any of the parameters is done.
2710
2711 No context switches are allowed while executing this function.
2712*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002713static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
2714 int ChanNum)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715{
2716 int i;
2717 WordIO_t AiopIO;
2718 WordIO_t ChIOOff;
2719 Byte_t *ChR;
2720 Word_t ChOff;
2721 static Byte_t R[4];
2722 int brd9600;
2723
2724 if (ChanNum >= CtlP->AiopNumChan[AiopNum])
Adrian Bunkf15313b2005-06-25 14:59:05 -07002725 return 0; /* exceeds num chans in AIOP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726
2727 /* Channel, AIOP, and controller identifiers */
2728 ChP->CtlP = CtlP;
2729 ChP->ChanID = CtlP->AiopID[AiopNum];
2730 ChP->AiopNum = AiopNum;
2731 ChP->ChanNum = ChanNum;
2732
2733 /* Global direct addresses */
2734 AiopIO = CtlP->AiopIO[AiopNum];
2735 ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG;
2736 ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN;
2737 ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK;
2738 ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR;
2739 ChP->IndexData = AiopIO + _INDX_DATA;
2740
2741 /* Channel direct addresses */
2742 ChIOOff = AiopIO + ChP->ChanNum * 2;
2743 ChP->TxRxData = ChIOOff + _TD0;
2744 ChP->ChanStat = ChIOOff + _CHN_STAT0;
2745 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
2746 ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0;
2747
2748 /* Initialize the channel from the RData array */
2749 for (i = 0; i < RDATASIZE; i += 4) {
2750 R[0] = RData[i];
2751 R[1] = RData[i + 1] + 0x10 * ChanNum;
2752 R[2] = RData[i + 2];
2753 R[3] = RData[i + 3];
Al Viro457fb602008-03-19 16:27:48 +00002754 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 }
2756
2757 ChR = ChP->R;
2758 for (i = 0; i < RREGDATASIZE; i += 4) {
2759 ChR[i] = RRegData[i];
2760 ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum;
2761 ChR[i + 2] = RRegData[i + 2];
2762 ChR[i + 3] = RRegData[i + 3];
2763 }
2764
2765 /* Indexed registers */
2766 ChOff = (Word_t) ChanNum *0x1000;
2767
2768 if (sClockPrescale == 0x14)
2769 brd9600 = 47;
2770 else
2771 brd9600 = 23;
2772
2773 ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD);
2774 ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8);
2775 ChP->BaudDiv[2] = (Byte_t) brd9600;
2776 ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8);
Al Viro457fb602008-03-19 16:27:48 +00002777 out32(ChP->IndexAddr, ChP->BaudDiv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
2779 ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL);
2780 ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8);
2781 ChP->TxControl[2] = 0;
2782 ChP->TxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002783 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
2785 ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL);
2786 ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8);
2787 ChP->RxControl[2] = 0;
2788 ChP->RxControl[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002789 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790
2791 ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS);
2792 ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8);
2793 ChP->TxEnables[2] = 0;
2794 ChP->TxEnables[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002795 out32(ChP->IndexAddr, ChP->TxEnables);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797 ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1);
2798 ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8);
2799 ChP->TxCompare[2] = 0;
2800 ChP->TxCompare[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002801 out32(ChP->IndexAddr, ChP->TxCompare);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
2803 ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1);
2804 ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8);
2805 ChP->TxReplace1[2] = 0;
2806 ChP->TxReplace1[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002807 out32(ChP->IndexAddr, ChP->TxReplace1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2);
2810 ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8);
2811 ChP->TxReplace2[2] = 0;
2812 ChP->TxReplace2[3] = 0;
Al Viro457fb602008-03-19 16:27:48 +00002813 out32(ChP->IndexAddr, ChP->TxReplace2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
2815 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
2816 ChP->TxFIFO = ChOff + _TX_FIFO;
2817
2818 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
2819 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */
2820 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2821 sOutW(ChP->IndexData, 0);
2822 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
2823 ChP->RxFIFO = ChOff + _RX_FIFO;
2824
2825 sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
2826 sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */
2827 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2828 sOutW(ChP->IndexData, 0);
2829 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2830 sOutW(ChP->IndexData, 0);
2831 ChP->TxPrioCnt = ChOff + _TXP_CNT;
2832 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt);
2833 sOutB(ChP->IndexData, 0);
2834 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
2835 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr);
2836 sOutB(ChP->IndexData, 0);
2837 ChP->TxPrioBuf = ChOff + _TXP_BUF;
2838 sEnRxProcessor(ChP); /* start the Rx processor */
2839
Adrian Bunkf15313b2005-06-25 14:59:05 -07002840 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841}
2842
2843/***************************************************************************
2844Function: sStopRxProcessor
2845Purpose: Stop the receive processor from processing a channel.
2846Call: sStopRxProcessor(ChP)
2847 CHANNEL_T *ChP; Ptr to channel structure
2848
2849Comments: The receive processor can be started again with sStartRxProcessor().
2850 This function causes the receive processor to skip over the
2851 stopped channel. It does not stop it from processing other channels.
2852
2853Warnings: No context switches are allowed while executing this function.
2854
2855 Do not leave the receive processor stopped for more than one
2856 character time.
2857
2858 After calling this function a delay of 4 uS is required to ensure
2859 that the receive processor is no longer processing this channel.
2860*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002861static void sStopRxProcessor(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 Byte_t R[4];
2864
2865 R[0] = ChP->R[0];
2866 R[1] = ChP->R[1];
2867 R[2] = 0x0a;
2868 R[3] = ChP->R[3];
Al Viro457fb602008-03-19 16:27:48 +00002869 out32(ChP->IndexAddr, R);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870}
2871
2872/***************************************************************************
2873Function: sFlushRxFIFO
2874Purpose: Flush the Rx FIFO
2875Call: sFlushRxFIFO(ChP)
2876 CHANNEL_T *ChP; Ptr to channel structure
2877Return: void
2878Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2879 while it is being flushed the receive processor is stopped
2880 and the transmitter is disabled. After these operations a
2881 4 uS delay is done before clearing the pointers to allow
2882 the receive processor to stop. These items are handled inside
2883 this function.
2884Warnings: No context switches are allowed while executing this function.
2885*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002886static void sFlushRxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887{
2888 int i;
2889 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002890 int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
2892 if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
2893 return; /* don't need to flush */
2894
Adrian Bunkf15313b2005-06-25 14:59:05 -07002895 RxFIFOEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002897 RxFIFOEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 sDisRxFIFO(ChP); /* disable it */
2899 for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
2900 sInB(ChP->IntChan); /* depends on bus i/o timing */
2901 }
2902 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
2903 Ch = (Byte_t) sGetChanNum(ChP);
2904 sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */
2905 sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */
2906 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */
2907 sOutW(ChP->IndexData, 0);
2908 sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
2909 sOutW(ChP->IndexData, 0);
2910 if (RxFIFOEnabled)
2911 sEnRxFIFO(ChP); /* enable Rx FIFO */
2912}
2913
2914/***************************************************************************
2915Function: sFlushTxFIFO
2916Purpose: Flush the Tx FIFO
2917Call: sFlushTxFIFO(ChP)
2918 CHANNEL_T *ChP; Ptr to channel structure
2919Return: void
2920Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
2921 while it is being flushed the receive processor is stopped
2922 and the transmitter is disabled. After these operations a
2923 4 uS delay is done before clearing the pointers to allow
2924 the receive processor to stop. These items are handled inside
2925 this function.
2926Warnings: No context switches are allowed while executing this function.
2927*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002928static void sFlushTxFIFO(CHANNEL_T * ChP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929{
2930 int i;
2931 Byte_t Ch; /* channel number within AIOP */
Adrian Bunkf15313b2005-06-25 14:59:05 -07002932 int TxEnabled; /* 1 if transmitter enabled */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
2934 if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
2935 return; /* don't need to flush */
2936
Adrian Bunkf15313b2005-06-25 14:59:05 -07002937 TxEnabled = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 if (ChP->TxControl[3] & TX_ENABLE) {
Adrian Bunkf15313b2005-06-25 14:59:05 -07002939 TxEnabled = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 sDisTransmit(ChP); /* disable transmitter */
2941 }
2942 sStopRxProcessor(ChP); /* stop Rx processor */
2943 for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */
2944 sInB(ChP->IntChan); /* depends on bus i/o timing */
2945 Ch = (Byte_t) sGetChanNum(ChP);
2946 sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */
2947 sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */
2948 sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
2949 sOutW(ChP->IndexData, 0);
2950 if (TxEnabled)
2951 sEnTransmit(ChP); /* enable transmitter */
2952 sStartRxProcessor(ChP); /* restart Rx processor */
2953}
2954
2955/***************************************************************************
2956Function: sWriteTxPrioByte
2957Purpose: Write a byte of priority transmit data to a channel
2958Call: sWriteTxPrioByte(ChP,Data)
2959 CHANNEL_T *ChP; Ptr to channel structure
2960 Byte_t Data; The transmit data byte
2961
2962Return: int: 1 if the bytes is successfully written, otherwise 0.
2963
2964Comments: The priority byte is transmitted before any data in the Tx FIFO.
2965
2966Warnings: No context switches are allowed while executing this function.
2967*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07002968static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969{
2970 Byte_t DWBuf[4]; /* buffer for double word writes */
2971 Word_t *WordPtr; /* must be far because Win SS != DS */
2972 register DWordIO_t IndexAddr;
2973
2974 if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */
2975 IndexAddr = ChP->IndexAddr;
2976 sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */
2977 if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */
2978 return (0); /* nothing sent */
2979
2980 WordPtr = (Word_t *) (&DWBuf[0]);
2981 *WordPtr = ChP->TxPrioBuf; /* data byte address */
2982
2983 DWBuf[2] = Data; /* data byte value */
Al Viro457fb602008-03-19 16:27:48 +00002984 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
2986 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
2987
2988 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
2989 DWBuf[3] = 0; /* priority buffer pointer */
Al Viro457fb602008-03-19 16:27:48 +00002990 out32(IndexAddr, DWBuf); /* write it out */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 } else { /* write it to Tx FIFO */
2992
2993 sWriteTxByte(sGetTxRxDataIO(ChP), Data);
2994 }
2995 return (1); /* 1 byte sent */
2996}
2997
2998/***************************************************************************
2999Function: sEnInterrupts
3000Purpose: Enable one or more interrupts for a channel
3001Call: sEnInterrupts(ChP,Flags)
3002 CHANNEL_T *ChP; Ptr to channel structure
3003 Word_t Flags: Interrupt enable flags, can be any combination
3004 of the following flags:
3005 TXINT_EN: Interrupt on Tx FIFO empty
3006 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3007 sSetRxTrigger())
3008 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3009 MCINT_EN: Interrupt on modem input change
3010 CHANINT_EN: Allow channel interrupt signal to the AIOP's
3011 Interrupt Channel Register.
3012Return: void
3013Comments: If an interrupt enable flag is set in Flags, that interrupt will be
3014 enabled. If an interrupt enable flag is not set in Flags, that
3015 interrupt will not be changed. Interrupts can be disabled with
3016 function sDisInterrupts().
3017
3018 This function sets the appropriate bit for the channel in the AIOP's
3019 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
3020 this channel's bit to be set in the AIOP's Interrupt Channel Register.
3021
3022 Interrupts must also be globally enabled before channel interrupts
3023 will be passed on to the host. This is done with function
3024 sEnGlobalInt().
3025
3026 In some cases it may be desirable to disable interrupts globally but
3027 enable channel interrupts. This would allow the global interrupt
3028 status register to be used to determine which AIOPs need service.
3029*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003030static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031{
3032 Byte_t Mask; /* Interrupt Mask Register */
3033
3034 ChP->RxControl[2] |=
3035 ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
3036
Al Viro457fb602008-03-19 16:27:48 +00003037 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN);
3040
Al Viro457fb602008-03-19 16:27:48 +00003041 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
3043 if (Flags & CHANINT_EN) {
3044 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
3045 sOutB(ChP->IntMask, Mask);
3046 }
3047}
3048
3049/***************************************************************************
3050Function: sDisInterrupts
3051Purpose: Disable one or more interrupts for a channel
3052Call: sDisInterrupts(ChP,Flags)
3053 CHANNEL_T *ChP; Ptr to channel structure
3054 Word_t Flags: Interrupt flags, can be any combination
3055 of the following flags:
3056 TXINT_EN: Interrupt on Tx FIFO empty
3057 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
3058 sSetRxTrigger())
3059 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
3060 MCINT_EN: Interrupt on modem input change
3061 CHANINT_EN: Disable channel interrupt signal to the
3062 AIOP's Interrupt Channel Register.
3063Return: void
3064Comments: If an interrupt flag is set in Flags, that interrupt will be
3065 disabled. If an interrupt flag is not set in Flags, that
3066 interrupt will not be changed. Interrupts can be enabled with
3067 function sEnInterrupts().
3068
3069 This function clears the appropriate bit for the channel in the AIOP's
3070 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
3071 this channel's bit from being set in the AIOP's Interrupt Channel
3072 Register.
3073*/
Adrian Bunkf15313b2005-06-25 14:59:05 -07003074static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075{
3076 Byte_t Mask; /* Interrupt Mask Register */
3077
3078 ChP->RxControl[2] &=
3079 ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
Al Viro457fb602008-03-19 16:27:48 +00003080 out32(ChP->IndexAddr, ChP->RxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN);
Al Viro457fb602008-03-19 16:27:48 +00003082 out32(ChP->IndexAddr, ChP->TxControl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
3084 if (Flags & CHANINT_EN) {
3085 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
3086 sOutB(ChP->IntMask, Mask);
3087 }
3088}
3089
Adrian Bunkf15313b2005-06-25 14:59:05 -07003090static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091{
3092 sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
3093}
3094
3095/*
3096 * Not an official SSCI function, but how to reset RocketModems.
3097 * ISA bus version
3098 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003099static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100{
3101 ByteIO_t addr;
3102 Byte_t val;
3103
3104 addr = CtlP->AiopIO[0] + 0x400;
3105 val = sInB(CtlP->MReg3IO);
3106 /* if AIOP[1] is not enabled, enable it */
3107 if ((val & 2) == 0) {
3108 val = sInB(CtlP->MReg2IO);
3109 sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03));
3110 sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6));
3111 }
3112
3113 sEnAiop(CtlP, 1);
3114 if (!on)
3115 addr += 8;
3116 sOutB(addr + chan, 0); /* apply or remove reset */
3117 sDisAiop(CtlP, 1);
3118}
3119
3120/*
3121 * Not an official SSCI function, but how to reset RocketModems.
3122 * PCI bus version
3123 */
Adrian Bunkf15313b2005-06-25 14:59:05 -07003124static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125{
3126 ByteIO_t addr;
3127
3128 addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */
3129 if (!on)
3130 addr += 8;
3131 sOutB(addr + chan, 0); /* apply or remove reset */
3132}
3133
3134/* Resets the speaker controller on RocketModem II and III devices */
3135static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
3136{
3137 ByteIO_t addr;
3138
3139 /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
3140 if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
3141 addr = CtlP->AiopIO[0] + 0x4F;
3142 sOutB(addr, 0);
3143 }
3144
3145 /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
3146 if ((model == MODEL_UPCI_RM3_8PORT)
3147 || (model == MODEL_UPCI_RM3_4PORT)) {
3148 addr = CtlP->AiopIO[0] + 0x88;
3149 sOutB(addr, 0);
3150 }
3151}
3152
3153/* Returns the line number given the controller (board), aiop and channel number */
3154static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
3155{
3156 return lineNumbers[(ctrl << 5) | (aiop << 3) | ch];
3157}
3158
3159/*
3160 * Stores the line number associated with a given controller (board), aiop
3161 * and channel number.
3162 * Returns: The line number assigned
3163 */
3164static unsigned char SetLineNumber(int ctrl, int aiop, int ch)
3165{
3166 lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++;
3167 return (nextLineNumber - 1);
3168}