blob: 7a697055e4f6a3af0d5625712d21b6bbbce6ad10 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 Copyright (C) 1996 Digi International.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 For technical support please email digiLinux@dgii.com or
5 call Digi tech support at (612) 912-3456
6
Alan Coxf2cf8e22005-09-06 15:16:44 -07007 ** This driver is no longer supported by Digi **
8
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07009 Much of this design and code came from epca.c which was
10 copyright (C) 1994, 1995 Troy De Jongh, and subsquently
11 modified by David Nugent, Christoph Lameter, Mike McLagan.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070018 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070023 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070027/* See README.epca for change history --DAT*/
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/init.h>
33#include <linux/serial.h>
34#include <linux/delay.h>
35#include <linux/ctype.h>
36#include <linux/tty.h>
37#include <linux/tty_flip.h>
38#include <linux/slab.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
Alan Cox191260a2008-04-30 00:54:16 -070041#include <linux/uaccess.h>
42#include <linux/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070043#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/pci.h>
45#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include "digi1.h"
49#include "digiFep1.h"
50#include "epca.h"
51#include "epcaconfig.h"
52
Alan Coxf2cf8e22005-09-06 15:16:44 -070053#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070056#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58
59#define MAXCARDS 7
60#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
61
62#define PFX "epca: "
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static int nbdevs, num_cards, liloconfig;
65static int digi_poller_inhibited = 1 ;
66
67static int setup_error_code;
68static int invalid_lilo_config;
69
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070070/*
71 * The ISA boards do window flipping into the same spaces so its only sane with
Alan Coxd1c815e2009-01-02 13:47:58 +000072 * a single lock. It's still pretty efficient. This lock guards the hardware
73 * and the tty_port lock guards the kernel side stuff like use counts. Take
74 * this lock inside the port lock if you must take both.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070075 */
Ingo Molnar34af9462006-06-27 02:53:55 -070076static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070077
Alan Cox191260a2008-04-30 00:54:16 -070078/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
79 to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static struct board_info boards[MAXBOARDS];
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct tty_driver *pc_driver;
83static struct tty_driver *pc_info;
84
85/* ------------------ Begin Digi specific structures -------------------- */
86
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070087/*
88 * digi_channels represents an array of structures that keep track of each
89 * channel of the Digi product. Information such as transmit and receive
90 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
91 * here. This structure is NOT used to overlay the cards physical channel
92 * structure.
93 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static struct channel digi_channels[MAX_ALLOC];
95
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070096/*
97 * card_ptr is an array used to hold the address of the first channel structure
98 * of each card. This array will hold the addresses of various channels located
99 * in digi_channels.
100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static struct channel *card_ptr[MAXCARDS];
102
103static struct timer_list epca_timer;
104
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700105/*
106 * Begin generic memory functions. These functions will be alias (point at)
107 * more specific functions dependent on the board being configured.
108 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700109static void memwinon(struct board_info *b, unsigned int win);
110static void memwinoff(struct board_info *b, unsigned int win);
111static void globalwinon(struct channel *ch);
112static void rxwinon(struct channel *ch);
113static void txwinon(struct channel *ch);
114static void memoff(struct channel *ch);
115static void assertgwinon(struct channel *ch);
116static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118/* ---- Begin more 'specific' memory functions for cx_like products --- */
119
Alan Coxf2cf8e22005-09-06 15:16:44 -0700120static void pcxem_memwinon(struct board_info *b, unsigned int win);
121static void pcxem_memwinoff(struct board_info *b, unsigned int win);
122static void pcxem_globalwinon(struct channel *ch);
123static void pcxem_rxwinon(struct channel *ch);
124static void pcxem_txwinon(struct channel *ch);
125static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* ------ Begin more 'specific' memory functions for the pcxe ------- */
128
Alan Coxf2cf8e22005-09-06 15:16:44 -0700129static void pcxe_memwinon(struct board_info *b, unsigned int win);
130static void pcxe_memwinoff(struct board_info *b, unsigned int win);
131static void pcxe_globalwinon(struct channel *ch);
132static void pcxe_rxwinon(struct channel *ch);
133static void pcxe_txwinon(struct channel *ch);
134static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
137/* Note : pc64xe and pcxi share the same windowing routines */
138
Alan Coxf2cf8e22005-09-06 15:16:44 -0700139static void pcxi_memwinon(struct board_info *b, unsigned int win);
140static void pcxi_memwinoff(struct board_info *b, unsigned int win);
141static void pcxi_globalwinon(struct channel *ch);
142static void pcxi_rxwinon(struct channel *ch);
143static void pcxi_txwinon(struct channel *ch);
144static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146/* - Begin 'specific' do nothing memory functions needed for some cards - */
147
Alan Coxf2cf8e22005-09-06 15:16:44 -0700148static void dummy_memwinon(struct board_info *b, unsigned int win);
149static void dummy_memwinoff(struct board_info *b, unsigned int win);
150static void dummy_globalwinon(struct channel *ch);
151static void dummy_rxwinon(struct channel *ch);
152static void dummy_txwinon(struct channel *ch);
153static void dummy_memoff(struct channel *ch);
154static void dummy_assertgwinon(struct channel *ch);
155static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Alan Coxf2cf8e22005-09-06 15:16:44 -0700157static struct channel *verifyChannel(struct tty_struct *);
158static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static void epca_error(int, char *);
160static void pc_close(struct tty_struct *, struct file *);
Alan Coxd1c815e2009-01-02 13:47:58 +0000161static void shutdown(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int pc_write_room(struct tty_struct *);
164static int pc_chars_in_buffer(struct tty_struct *);
165static void pc_flush_buffer(struct tty_struct *);
166static void pc_flush_chars(struct tty_struct *);
167static int block_til_ready(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700168 struct channel *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169static int pc_open(struct tty_struct *, struct file *);
170static void post_fep_init(unsigned int crd);
171static void epcapoll(unsigned long);
172static void doevent(int);
173static void fepcmd(struct channel *, int, int, int, int, int);
174static unsigned termios2digi_h(struct channel *ch, unsigned);
175static unsigned termios2digi_i(struct channel *ch, unsigned);
176static unsigned termios2digi_c(struct channel *ch, unsigned);
177static void epcaparam(struct tty_struct *, struct channel *);
Alan Cox3969ffb2009-01-02 13:48:04 +0000178static void receive_data(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int pc_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700180 unsigned int, unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int info_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700182 unsigned int, unsigned long);
Alan Cox606d0992006-12-08 02:38:45 -0800183static void pc_set_termios(struct tty_struct *, struct ktermios *);
David Howellsc4028952006-11-22 14:57:56 +0000184static void do_softint(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static void pc_stop(struct tty_struct *);
186static void pc_start(struct tty_struct *);
Alan Cox191260a2008-04-30 00:54:16 -0700187static void pc_throttle(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static void pc_unthrottle(struct tty_struct *tty);
Alan Coxdcbf1282008-07-22 11:18:12 +0100189static int pc_send_break(struct tty_struct *tty, int msec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static int pc_write(struct tty_struct *, const unsigned char *, int);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700193static int pc_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194static int init_PCI(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700196/*
197 * Table of functions for each board to handle memory. Mantaining parallelism
198 * is a *very* good idea here. The idea is for the runtime code to blindly call
199 * these functions, not knowing/caring about the underlying hardware. This
200 * stuff should contain no conditionals; if more functionality is needed a
201 * different entry should be established. These calls are the interface calls
202 * and are the only functions that should be accessed. Anyone caught making
203 * direct calls deserves what they get.
204 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700205static void memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700207 b->memwinon(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
Alan Coxf2cf8e22005-09-06 15:16:44 -0700210static void memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700212 b->memwinoff(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Alan Coxf2cf8e22005-09-06 15:16:44 -0700215static void globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700217 ch->board->globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218}
219
Alan Coxf2cf8e22005-09-06 15:16:44 -0700220static void rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700222 ch->board->rxwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
Alan Coxf2cf8e22005-09-06 15:16:44 -0700225static void txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700227 ch->board->txwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228}
229
Alan Coxf2cf8e22005-09-06 15:16:44 -0700230static void memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700232 ch->board->memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233}
Alan Coxf2cf8e22005-09-06 15:16:44 -0700234static void assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700236 ch->board->assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237}
238
Alan Coxf2cf8e22005-09-06 15:16:44 -0700239static void assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700241 ch->board->assertmemoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242}
243
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700244/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700245static void pcxem_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246{
Alan Cox191260a2008-04-30 00:54:16 -0700247 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248}
249
Alan Coxf2cf8e22005-09-06 15:16:44 -0700250static void pcxem_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700252 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253}
254
Alan Coxf2cf8e22005-09-06 15:16:44 -0700255static void pcxem_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
Alan Cox191260a2008-04-30 00:54:16 -0700257 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
Alan Coxf2cf8e22005-09-06 15:16:44 -0700260static void pcxem_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
262 outb_p(ch->rxwin, (int)ch->board->port + 1);
263}
264
Alan Coxf2cf8e22005-09-06 15:16:44 -0700265static void pcxem_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266{
267 outb_p(ch->txwin, (int)ch->board->port + 1);
268}
269
Alan Coxf2cf8e22005-09-06 15:16:44 -0700270static void pcxem_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
272 outb_p(0, (int)ch->board->port + 1);
273}
274
275/* ----------------- Begin pcxe memory window stuff ------------------ */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700276static void pcxe_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700278 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Alan Coxf2cf8e22005-09-06 15:16:44 -0700281static void pcxe_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700283 outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700284 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285}
286
Alan Coxf2cf8e22005-09-06 15:16:44 -0700287static void pcxe_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700289 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290}
291
Alan Coxf2cf8e22005-09-06 15:16:44 -0700292static void pcxe_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700294 outb_p(ch->rxwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Alan Coxf2cf8e22005-09-06 15:16:44 -0700297static void pcxe_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700299 outb_p(ch->txwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300}
301
Alan Coxf2cf8e22005-09-06 15:16:44 -0700302static void pcxe_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
304 outb_p(0, (int)ch->board->port);
305 outb_p(0, (int)ch->board->port + 1);
306}
307
308/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700309static void pcxi_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700311 outb_p(inb(b->port) | FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
Alan Coxf2cf8e22005-09-06 15:16:44 -0700314static void pcxi_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700316 outb_p(inb(b->port) & ~FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318
Alan Coxf2cf8e22005-09-06 15:16:44 -0700319static void pcxi_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700321 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Alan Coxf2cf8e22005-09-06 15:16:44 -0700324static void pcxi_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700326 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Alan Coxf2cf8e22005-09-06 15:16:44 -0700329static void pcxi_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700331 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Alan Coxf2cf8e22005-09-06 15:16:44 -0700334static void pcxi_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700336 outb_p(0, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337}
338
Alan Coxf2cf8e22005-09-06 15:16:44 -0700339static void pcxi_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700341 epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342}
343
Alan Coxf2cf8e22005-09-06 15:16:44 -0700344static void pcxi_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700346 epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347}
348
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700349/*
350 * Not all of the cards need specific memory windowing routines. Some cards
351 * (Such as PCI) needs no windowing routines at all. We provide these do
352 * nothing routines so that the same code base can be used. The driver will
353 * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
354 * card. However, dependent on the card the routine may or may not do anything.
355 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700356static void dummy_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
358}
359
Alan Coxf2cf8e22005-09-06 15:16:44 -0700360static void dummy_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361{
362}
363
Alan Coxf2cf8e22005-09-06 15:16:44 -0700364static void dummy_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365{
366}
367
Alan Coxf2cf8e22005-09-06 15:16:44 -0700368static void dummy_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370}
371
Alan Coxf2cf8e22005-09-06 15:16:44 -0700372static void dummy_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
374}
375
Alan Coxf2cf8e22005-09-06 15:16:44 -0700376static void dummy_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377{
378}
379
Alan Coxf2cf8e22005-09-06 15:16:44 -0700380static void dummy_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381{
382}
383
Alan Coxf2cf8e22005-09-06 15:16:44 -0700384static void dummy_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
386}
387
Alan Coxf2cf8e22005-09-06 15:16:44 -0700388static struct channel *verifyChannel(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700389{
390 /*
391 * This routine basically provides a sanity check. It insures that the
392 * channel returned is within the proper range of addresses as well as
393 * properly initialized. If some bogus info gets passed in
394 * through tty->driver_data this should catch it.
395 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700396 if (tty) {
Alan Coxc9f19e92009-01-02 13:47:26 +0000397 struct channel *ch = tty->driver_data;
Alan Cox191260a2008-04-30 00:54:16 -0700398 if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (ch->magic == EPCA_MAGIC)
400 return ch;
401 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return NULL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700404}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
Alan Coxf2cf8e22005-09-06 15:16:44 -0700406static void pc_sched_event(struct channel *ch, int event)
407{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700408 /*
409 * We call this to schedule interrupt processing on some event. The
410 * kernel sees our request and calls the related routine in OUR driver.
411 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 ch->event |= 1 << event;
413 schedule_work(&ch->tqueue);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700414}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416static void epca_error(int line, char *msg)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700417{
Alan Cox191260a2008-04-30 00:54:16 -0700418 printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700419}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700421static void pc_close(struct tty_struct *tty, struct file *filp)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700422{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000424 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700426 /*
427 * verifyChannel returns the channel from the tty struct if it is
428 * valid. This serves as a sanity check.
429 */
Alan Cox191260a2008-04-30 00:54:16 -0700430 ch = verifyChannel(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000431 if (ch == NULL)
432 return;
433 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Alan Coxd1c815e2009-01-02 13:47:58 +0000435 spin_lock_irqsave(&port->lock, flags);
436 if (tty_hung_up_p(filp)) {
437 spin_unlock_irqrestore(&port->lock, flags);
438 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700439 }
Alan Coxd1c815e2009-01-02 13:47:58 +0000440 if (port->count-- > 1) {
441 /* Begin channel is open more than once */
442 /*
443 * Return without doing anything. Someone might still
444 * be using the channel.
445 */
446 spin_unlock_irqrestore(&port->lock, flags);
447 return;
448 }
449 /* Port open only once go ahead with shutdown & reset */
450 WARN_ON(port->count < 0);
451
452 /*
453 * Let the rest of the driver know the channel is being closed.
454 * This becomes important if an open is attempted before close
455 * is finished.
456 */
457 port->flags |= ASYNC_CLOSING;
458 tty->closing = 1;
459
460 spin_unlock_irqrestore(&port->lock, flags);
461
462 if (port->flags & ASYNC_INITIALIZED) {
463 /* Setup an event to indicate when the
464 transmit buffer empties */
465 setup_empty_event(tty, ch);
466 /* 30 seconds timeout */
467 tty_wait_until_sent(tty, 3000);
468 }
469 pc_flush_buffer(tty);
470 tty_ldisc_flush(tty);
471 shutdown(ch, tty);
472
473 spin_lock_irqsave(&port->lock, flags);
474 tty->closing = 0;
475 ch->event = 0;
Alan Cox3969ffb2009-01-02 13:48:04 +0000476 tty_port_tty_set(port, NULL);
Alan Coxd1c815e2009-01-02 13:47:58 +0000477 spin_unlock_irqrestore(&port->lock, flags);
478
479 if (port->blocked_open) {
480 if (ch->close_delay)
481 msleep_interruptible(jiffies_to_msecs(ch->close_delay));
482 wake_up_interruptible(&port->open_wait);
483 }
484 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
485 ASYNC_CLOSING);
486 wake_up_interruptible(&port->close_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700487}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Alan Coxd1c815e2009-01-02 13:47:58 +0000489static void shutdown(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700490{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +0100492 struct board_chan __iomem *bc;
Alan Coxd1c815e2009-01-02 13:47:58 +0000493 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Alan Coxd1c815e2009-01-02 13:47:58 +0000495 if (!(port->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return;
497
Alan Coxf2cf8e22005-09-06 15:16:44 -0700498 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Alan Coxf2cf8e22005-09-06 15:16:44 -0700500 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 bc = ch->brdchan;
502
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700503 /*
504 * In order for an event to be generated on the receipt of data the
505 * idata flag must be set. Since we are shutting down, this is not
506 * necessary clear this flag.
507 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700509 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700511 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700512 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
514 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 memoff(ch);
517
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700518 /*
519 * The channel has officialy been closed. The next time it is opened it
520 * will have to reinitialized. Set a flag to indicate this.
521 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 /* Prevent future Digi programmed interrupts from coming active */
Alan Coxd1c815e2009-01-02 13:47:58 +0000523 port->flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700524 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700525}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700528{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000530 struct tty_port *port;
531
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700532 /*
533 * verifyChannel returns the channel from the tty struct if it is
534 * valid. This serves as a sanity check.
535 */
Alan Cox191260a2008-04-30 00:54:16 -0700536 ch = verifyChannel(tty);
537 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 unsigned long flags;
Alan Coxd1c815e2009-01-02 13:47:58 +0000539 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Alan Cox978e5952008-04-30 00:53:59 -0700541 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 tty_ldisc_flush(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000543 shutdown(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Alan Coxd1c815e2009-01-02 13:47:58 +0000545 spin_lock_irqsave(&port->lock, flags);
546 port->tty = NULL;
547 ch->event = 0; /* FIXME: review locking of ch->event */
548 port->count = 0;
549 port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
550 spin_unlock_irqrestore(&port->lock, flags);
551 wake_up_interruptible(&port->open_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700552 }
553}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700555static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700556 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700557{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700558 unsigned int head, tail;
559 int dataLen;
560 int size;
561 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 struct channel *ch;
563 unsigned long flags;
564 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100565 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700567 /*
568 * pc_write is primarily called directly by the kernel routine
569 * tty_write (Though it can also be called by put_char) found in
570 * tty_io.c. pc_write is passed a line discipline buffer where the data
571 * to be written out is stored. The line discipline implementation
572 * itself is done at the kernel level and is not brought into the
573 * driver.
574 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700576 /*
577 * verifyChannel returns the channel from the tty struct if it is
578 * valid. This serves as a sanity check.
579 */
Alan Cox191260a2008-04-30 00:54:16 -0700580 ch = verifyChannel(tty);
581 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583
584 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 bc = ch->brdchan;
586 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Alan Coxf2cf8e22005-09-06 15:16:44 -0700589 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 globalwinon(ch);
591
Alan Coxf2cf8e22005-09-06 15:16:44 -0700592 head = readw(&bc->tin) & (size - 1);
593 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Alan Coxf2cf8e22005-09-06 15:16:44 -0700595 if (tail != readw(&bc->tout))
596 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 tail &= (size - 1);
598
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700599 if (head >= tail) {
600 /* head has not wrapped */
601 /*
602 * remain (much like dataLen above) represents the total amount
603 * of space available on the card for data. Here dataLen
604 * represents the space existing between the head pointer and
605 * the end of buffer. This is important because a memcpy cannot
606 * be told to automatically wrap around when it hits the buffer
607 * end.
608 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 dataLen = size - head;
610 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700611 } else {
612 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 remain = tail - head - 1;
614 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700615 }
616 /*
617 * Check the space on the card. If we have more data than space; reduce
618 * the amount of data to fit the space.
619 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700622 while (bytesAvailable > 0) {
623 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700625 /*
626 * If head is not wrapped, the below will make sure the first
627 * data copy fills to the end of card buffer.
628 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100630 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 buf += dataLen;
632 head += dataLen;
633 amountCopied += dataLen;
634 bytesAvailable -= dataLen;
635
Alan Coxf2cf8e22005-09-06 15:16:44 -0700636 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 head = 0;
638 dataLen = tail;
639 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 ch->statusflags |= TXBUSY;
642 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700643 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Alan Coxf2cf8e22005-09-06 15:16:44 -0700645 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700647 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
649 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700650 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700651 return amountCopied;
652}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700655{
Alan Cox191260a2008-04-30 00:54:16 -0700656 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 struct channel *ch;
658 unsigned long flags;
659 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100660 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700661 /*
662 * verifyChannel returns the channel from the tty struct if it is
663 * valid. This serves as a sanity check.
664 */
Alan Cox191260a2008-04-30 00:54:16 -0700665 ch = verifyChannel(tty);
666 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700667 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 globalwinon(ch);
669
670 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700671 head = readw(&bc->tin) & (ch->txbufsize - 1);
672 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Alan Coxf2cf8e22005-09-06 15:16:44 -0700674 if (tail != readw(&bc->tout))
675 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /* Wrap tail if necessary */
677 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700678 remain = tail - head - 1;
679 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 remain += ch->txbufsize;
681
Alan Coxf2cf8e22005-09-06 15:16:44 -0700682 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700684 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 }
686 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700687 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 /* Return how much room is left on card */
690 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700691}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700694{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 int chars;
696 unsigned int ctail, head, tail;
697 int remain;
698 unsigned long flags;
699 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100700 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700701 /*
702 * verifyChannel returns the channel from the tty struct if it is
703 * valid. This serves as a sanity check.
704 */
Alan Cox191260a2008-04-30 00:54:16 -0700705 ch = verifyChannel(tty);
706 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700707 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Alan Coxf2cf8e22005-09-06 15:16:44 -0700709 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 globalwinon(ch);
711
712 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700713 tail = readw(&bc->tout);
714 head = readw(&bc->tin);
715 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
Alan Cox191260a2008-04-30 00:54:16 -0700717 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
718 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700720 else { /* Begin if some space on the card has been used */
721 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700723 /*
724 * The logic here is basically opposite of the above
725 * pc_write_room here we are finding the amount of bytes in the
726 * buffer filled. Not the amount of bytes empty.
727 */
Alan Cox191260a2008-04-30 00:54:16 -0700728 remain = tail - head - 1;
729 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 remain += ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700732 /*
733 * Make it possible to wakeup anything waiting for output in
734 * tty_ioctl.c, etc.
735 *
736 * If not already set. Setup an event to indicate when the
737 * transmit buffer empties.
738 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700740 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700743 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700745 return chars;
746}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700749{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 unsigned int tail;
751 unsigned long flags;
752 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100753 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700754 /*
755 * verifyChannel returns the channel from the tty struct if it is
756 * valid. This serves as a sanity check.
757 */
Alan Cox191260a2008-04-30 00:54:16 -0700758 ch = verifyChannel(tty);
759 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return;
761
Alan Coxf2cf8e22005-09-06 15:16:44 -0700762 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700765 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700769 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700771}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
773static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700774{
775 struct channel *ch;
776 /*
777 * verifyChannel returns the channel from the tty struct if it is
778 * valid. This serves as a sanity check.
779 */
Alan Cox191260a2008-04-30 00:54:16 -0700780 ch = verifyChannel(tty);
781 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700783 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700784 /*
785 * If not already set and the transmitter is busy setup an
786 * event to indicate when the transmit empties.
787 */
Alan Cox191260a2008-04-30 00:54:16 -0700788 if ((ch->statusflags & TXBUSY) &&
789 !(ch->statusflags & EMPTYWAIT))
790 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700791 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700793}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700795static int block_til_ready(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700796 struct file *filp, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700797{
Alan Cox191260a2008-04-30 00:54:16 -0700798 DECLARE_WAITQUEUE(wait, current);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700799 int retval, do_clocal = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 unsigned long flags;
Alan Coxd1c815e2009-01-02 13:47:58 +0000801 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Alan Coxf2cf8e22005-09-06 15:16:44 -0700803 if (tty_hung_up_p(filp)) {
Alan Coxd1c815e2009-01-02 13:47:58 +0000804 if (port->flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 retval = -EAGAIN;
806 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700807 retval = -ERESTARTSYS;
808 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
810
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700811 /*
812 * If the device is in the middle of being closed, then block until
813 * it's done, and then try again.
814 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000815 if (port->flags & ASYNC_CLOSING) {
816 interruptible_sleep_on(&port->close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Alan Coxd1c815e2009-01-02 13:47:58 +0000818 if (port->flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return -EAGAIN;
820 else
821 return -ERESTARTSYS;
822 }
823
Alan Coxf2cf8e22005-09-06 15:16:44 -0700824 if (filp->f_flags & O_NONBLOCK) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700825 /*
826 * If non-blocking mode is set, then make the check up front
827 * and then exit.
828 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000829 port->flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return 0;
831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if (tty->termios->c_cflag & CLOCAL)
833 do_clocal = 1;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700834 /* Block waiting for the carrier detect and the line to become free */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 retval = 0;
Alan Coxd1c815e2009-01-02 13:47:58 +0000837 add_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Alan Coxd1c815e2009-01-02 13:47:58 +0000839 spin_lock_irqsave(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 /* We dec count so that pc_close will know when to free things */
841 if (!tty_hung_up_p(filp))
Alan Coxd1c815e2009-01-02 13:47:58 +0000842 port->count--;
843 port->blocked_open++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700844 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 if (tty_hung_up_p(filp) ||
Alan Coxd1c815e2009-01-02 13:47:58 +0000847 !(port->flags & ASYNC_INITIALIZED)) {
848 if (port->flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 retval = -EAGAIN;
850 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700851 retval = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 break;
853 }
Alan Coxd1c815e2009-01-02 13:47:58 +0000854 if (!(port->flags & ASYNC_CLOSING) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 (do_clocal || (ch->imodem & ch->dcd)))
856 break;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700857 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 retval = -ERESTARTSYS;
859 break;
860 }
Alan Coxd1c815e2009-01-02 13:47:58 +0000861 spin_unlock_irqrestore(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700862 /*
863 * Allow someone else to be scheduled. We will occasionally go
864 * through this loop until one of the above conditions change.
865 * The below schedule call will allow other processes to enter
866 * and prevent this loop from hogging the cpu.
867 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 schedule();
Alan Coxd1c815e2009-01-02 13:47:58 +0000869 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700872 __set_current_state(TASK_RUNNING);
Alan Coxd1c815e2009-01-02 13:47:58 +0000873 remove_wait_queue(&port->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (!tty_hung_up_p(filp))
Alan Coxd1c815e2009-01-02 13:47:58 +0000875 port->count++;
876 port->blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Alan Coxd1c815e2009-01-02 13:47:58 +0000878 spin_unlock_irqrestore(&port->lock, flags);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (retval)
881 return retval;
882
Alan Coxd1c815e2009-01-02 13:47:58 +0000883 port->flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700885}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
Alan Cox191260a2008-04-30 00:54:16 -0700887static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700888{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000890 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 unsigned long flags;
892 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100893 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700894 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700897 if (line < 0 || line >= nbdevs)
898 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 ch = &digi_channels[line];
Alan Coxd1c815e2009-01-02 13:47:58 +0000901 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 boardnum = ch->boardnum;
903
904 /* Check status of board configured in system. */
905
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700906 /*
907 * I check to see if the epca_setup routine detected an user error. It
908 * might be better to put this in pc_init, but for the moment it goes
909 * here.
910 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700911 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700913 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700915 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700917 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700919 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700921 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700923 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700925 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700927 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 tty->driver_data = NULL; /* Mark this device as 'down' */
929 return(-ENODEV);
930 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700931
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700932 bc = ch->brdchan;
933 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700935 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 }
937
Alan Coxd1c815e2009-01-02 13:47:58 +0000938 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700939 /*
940 * Every time a channel is opened, increment a counter. This is
941 * necessary because we do not wish to flush and shutdown the channel
942 * until the last app holding the channel open, closes it.
943 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000944 port->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700945 /*
946 * Set a kernel structures pointer to our local channel structure. This
947 * way we can get to it when passed only a tty struct.
948 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 tty->driver_data = ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000950 port->tty = tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700951 /*
952 * If this is the first time the channel has been opened, initialize
953 * the tty->termios struct otherwise let pc_close handle it.
954 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000955 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 globalwinon(ch);
957 ch->statusflags = 0;
958
959 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100960 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700962 /*
963 * Set receive head and tail ptrs to each other. This indicates no data
964 * available to read.
965 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700966 head = readw(&bc->rin);
967 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
969 /* Set the channels associated tty structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700971 /*
972 * The below routine generally sets up parity, baud, flow control
973 * issues, etc.... It effect both control flags and input flags.
974 */
Alan Cox191260a2008-04-30 00:54:16 -0700975 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000977 spin_unlock(&epca_lock);
978 port->flags |= ASYNC_INITIALIZED;
979 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 retval = block_til_ready(tty, filp, ch);
982 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700984 /*
985 * Set this again in case a hangup set it to zero while this open() was
986 * waiting for the line...
987 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000988 spin_lock_irqsave(&port->lock, flags);
989 port->tty = tty;
990 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700993 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000995 spin_unlock(&epca_lock);
996 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998}
999
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001000static int __init epca_module_init(void)
1001{
1002 return pc_init();
1003}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008static void __exit epca_module_exit(void)
1009{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 int count, crd;
1011 struct board_info *bd;
1012 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 del_timer_sync(&epca_timer);
1015
Alan Cox191260a2008-04-30 00:54:16 -07001016 if (tty_unregister_driver(pc_driver) ||
1017 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001018 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return;
1020 }
1021 put_tty_driver(pc_driver);
1022 put_tty_driver(pc_info);
1023
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001024 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001026 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
1028 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001029 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001030 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001031 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox3969ffb2009-01-02 13:48:04 +00001032 struct tty_struct *tty = tty_port_tty_get(&ch->port);
1033 if (tty) {
1034 tty_hangup(tty);
1035 tty_kref_put(tty);
1036 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001037 }
1038 }
1039 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040}
1041module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001043static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 .open = pc_open,
1045 .close = pc_close,
1046 .write = pc_write,
1047 .write_room = pc_write_room,
1048 .flush_buffer = pc_flush_buffer,
1049 .chars_in_buffer = pc_chars_in_buffer,
1050 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 .ioctl = pc_ioctl,
1052 .set_termios = pc_set_termios,
1053 .stop = pc_stop,
1054 .start = pc_start,
1055 .throttle = pc_throttle,
1056 .unthrottle = pc_unthrottle,
1057 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +01001058 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059};
1060
Alan Cox191260a2008-04-30 00:54:16 -07001061static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
1063 return 0;
1064}
1065
1066static struct tty_operations info_ops = {
1067 .open = info_open,
1068 .ioctl = info_ioctl,
1069};
1070
Alan Coxf2cf8e22005-09-06 15:16:44 -07001071static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001072{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 int crd;
1074 struct board_info *bd;
1075 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -07001076 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 int pci_boards_found, pci_count;
1079
1080 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 pc_driver = alloc_tty_driver(MAX_ALLOC);
1083 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -07001084 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -07001087 if (!pc_info)
1088 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001090 /*
1091 * If epca_setup has not been ran by LILO set num_cards to defaults;
1092 * copy board structure defined by digiConfig into drivers board
1093 * structure. Note : If LILO has ran epca_setup then epca_setup will
1094 * handle defining num_cards as well as copying the data into the board
1095 * structure.
1096 */
1097 if (!liloconfig) {
1098 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 nbdevs = NBDEVS;
1100 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001101 memcpy(&boards, &static_boards,
1102 sizeof(struct board_info) * NUMCARDS);
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001105 /*
1106 * Note : If lilo was used to configure the driver and the ignore
1107 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
1108 * will equal 0 at this point. This is okay; PCI cards will still be
1109 * picked up if detected.
1110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001112 /*
1113 * Set up interrupt, we will worry about memory allocation in
1114 * post_fep_init.
1115 */
Alan Cox191260a2008-04-30 00:54:16 -07001116 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001118 /*
1119 * NOTE : This code assumes that the number of ports found in the
1120 * boards array is correct. This could be wrong if the card in question
1121 * is PCI (And therefore has no ports entry in the boards structure.)
1122 * The rest of the information will be valid for PCI because the
1123 * beginning of pc_init scans for PCI and determines i/o and base
1124 * memory addresses. I am not sure if it is possible to read the number
1125 * of ports supported by the card prior to it being booted (Since that
1126 * is the state it is in when pc_init is run). Because it is not
1127 * possible to query the number of supported ports until after the card
1128 * has booted; we are required to calculate the card_ptrs as the card
1129 * is initialized (Inside post_fep_init). The negative thing about this
1130 * approach is that digiDload's call to GET_INFO will have a bad port
1131 * value. (Since this is called prior to post_fep_init.)
1132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001134 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 pci_boards_found += init_PCI();
1136 num_cards += pci_boards_found;
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001139 pc_driver->name = "ttyD";
1140 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 pc_driver->minor_start = 0;
1142 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1143 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1144 pc_driver->init_termios = tty_std_termios;
1145 pc_driver->init_termios.c_iflag = 0;
1146 pc_driver->init_termios.c_oflag = 0;
1147 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1148 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001149 pc_driver->init_termios.c_ispeed = 9600;
1150 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001151 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 tty_set_operations(pc_driver, &pc_ops);
1153
1154 pc_info->owner = THIS_MODULE;
1155 pc_info->name = "digi_ctl";
1156 pc_info->major = DIGIINFOMAJOR;
1157 pc_info->minor_start = 0;
1158 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1159 pc_info->subtype = SERIAL_TYPE_INFO;
1160 pc_info->init_termios = tty_std_termios;
1161 pc_info->init_termios.c_iflag = 0;
1162 pc_info->init_termios.c_oflag = 0;
1163 pc_info->init_termios.c_lflag = 0;
1164 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001165 pc_info->init_termios.c_ispeed = 9600;
1166 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 pc_info->flags = TTY_DRIVER_REAL_RAW;
1168 tty_set_operations(pc_info, &info_ops);
1169
1170
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001171 for (crd = 0; crd < num_cards; crd++) {
1172 /*
1173 * This is where the appropriate memory handlers for the
1174 * hardware is set. Everything at runtime blindly jumps through
1175 * these vectors.
1176 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 /* defined in epcaconfig.h */
1179 bd = &boards[crd];
1180
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001181 switch (bd->type) {
1182 case PCXEM:
1183 case EISAXEM:
1184 bd->memwinon = pcxem_memwinon;
1185 bd->memwinoff = pcxem_memwinoff;
1186 bd->globalwinon = pcxem_globalwinon;
1187 bd->txwinon = pcxem_txwinon;
1188 bd->rxwinon = pcxem_rxwinon;
1189 bd->memoff = pcxem_memoff;
1190 bd->assertgwinon = dummy_assertgwinon;
1191 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 break;
1193
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001194 case PCIXEM:
1195 case PCIXRJ:
1196 case PCIXR:
1197 bd->memwinon = dummy_memwinon;
1198 bd->memwinoff = dummy_memwinoff;
1199 bd->globalwinon = dummy_globalwinon;
1200 bd->txwinon = dummy_txwinon;
1201 bd->rxwinon = dummy_rxwinon;
1202 bd->memoff = dummy_memoff;
1203 bd->assertgwinon = dummy_assertgwinon;
1204 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 break;
1206
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001207 case PCXE:
1208 case PCXEVE:
1209 bd->memwinon = pcxe_memwinon;
1210 bd->memwinoff = pcxe_memwinoff;
1211 bd->globalwinon = pcxe_globalwinon;
1212 bd->txwinon = pcxe_txwinon;
1213 bd->rxwinon = pcxe_rxwinon;
1214 bd->memoff = pcxe_memoff;
1215 bd->assertgwinon = dummy_assertgwinon;
1216 bd->assertmemoff = dummy_assertmemoff;
1217 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001219 case PCXI:
1220 case PC64XE:
1221 bd->memwinon = pcxi_memwinon;
1222 bd->memwinoff = pcxi_memwinoff;
1223 bd->globalwinon = pcxi_globalwinon;
1224 bd->txwinon = pcxi_txwinon;
1225 bd->rxwinon = pcxi_rxwinon;
1226 bd->memoff = pcxi_memoff;
1227 bd->assertgwinon = pcxi_assertgwinon;
1228 bd->assertmemoff = pcxi_assertmemoff;
1229 break;
1230
1231 default:
1232 break;
1233 }
1234
1235 /*
1236 * Some cards need a memory segment to be defined for use in
1237 * transmit and receive windowing operations. These boards are
1238 * listed in the below switch. In the case of the XI the amount
1239 * of memory on the board is variable so the memory_seg is also
1240 * variable. This code determines what they segment should be.
1241 */
1242 switch (bd->type) {
1243 case PCXE:
1244 case PCXEVE:
1245 case PC64XE:
1246 bd->memory_seg = 0xf000;
1247 break;
1248
1249 case PCXI:
1250 board_id = inb((int)bd->port);
1251 if ((board_id & 0x1) == 0x1) {
1252 /* it's an XI card */
1253 /* Is it a 64K board */
1254 if ((board_id & 0x30) == 0)
1255 bd->memory_seg = 0xf000;
1256
1257 /* Is it a 128K board */
1258 if ((board_id & 0x30) == 0x10)
1259 bd->memory_seg = 0xe000;
1260
1261 /* Is is a 256K board */
1262 if ((board_id & 0x30) == 0x20)
1263 bd->memory_seg = 0xc000;
1264
1265 /* Is it a 512K board */
1266 if ((board_id & 0x30) == 0x30)
1267 bd->memory_seg = 0x8000;
1268 } else
Alan Cox191260a2008-04-30 00:54:16 -07001269 printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n", (int)bd->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001270 break;
1271 }
1272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Akinobu Mitadabad052006-10-17 00:10:28 -07001274 err = tty_register_driver(pc_driver);
1275 if (err) {
1276 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1277 goto out3;
1278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Akinobu Mitadabad052006-10-17 00:10:28 -07001280 err = tty_register_driver(pc_info);
1281 if (err) {
1282 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1283 goto out4;
1284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001286 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 init_timer(&epca_timer);
1288 epca_timer.function = epcapoll;
1289 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 return 0;
1291
Akinobu Mitadabad052006-10-17 00:10:28 -07001292out4:
1293 tty_unregister_driver(pc_driver);
1294out3:
1295 put_tty_driver(pc_info);
1296out2:
1297 put_tty_driver(pc_driver);
1298out1:
1299 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001300}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001303{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001305 void __iomem *memaddr;
1306 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001308 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001309 struct channel *ch;
1310 int shrinkmem = 0, lowwater;
1311
1312 /*
1313 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1314 * responsible for setting up all the card specific stuff.
1315 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 bd = &boards[crd];
1317
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001318 /*
1319 * If this is a PCI board, get the port info. Remember PCI cards do not
1320 * have entries into the epcaconfig.h file, so we can't get the number
1321 * of ports from it. Unfortunetly, this means that anyone doing a
1322 * DIGI_GETINFO before the board has booted will get an invalid number
1323 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1324 * DIGI_INIT has been called will return the proper values.
1325 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001326 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001327 /*
1328 * Below we use XEMPORTS as a memory offset regardless of which
1329 * PCI card it is. This is because all of the supported PCI
1330 * cards have the same memory offset for the channel data. This
1331 * will have to be changed if we ever develop a PCI/XE card.
1332 * NOTE : The FEP manual states that the port offset is 0xC22
1333 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1334 * cards; not for the XEM, or CX series. On the PCI cards the
1335 * number of ports is determined by reading a ID PROM located
1336 * in the box attached to the card. The card can then determine
1337 * the index the id to determine the number of ports available.
1338 * (FYI - The id should be located at 0x1ac (And may use up to
1339 * 4 bytes if the box in question is a XEM or CX)).
1340 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001341 /* PCI cards are already remapped at this point ISA are not */
1342 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001343 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001345 } else {
1346 /* Fix up the mappings for ISA/EISA etc */
1347 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001348 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 if (crd != 0)
1352 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1353 else
1354 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1355
1356 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1358
Alan Coxf2cf8e22005-09-06 15:16:44 -07001359 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001361 /*
1362 * The below assignment will set bc to point at the BEGINING of the
1363 * cards channel structures. For 1 card there will be between 8 and 64
1364 * of these structures.
1365 */
Al Virobc9a5152005-09-15 22:53:28 +01001366 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001368 /*
1369 * The below assignment will set gd to point at the BEGINING of global
1370 * memory address 0xc00. The first data in that global memory actually
1371 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1372 */
Al Virobc9a5152005-09-15 22:53:28 +01001373 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001375 /*
1376 * XEPORTS (address 0xc22) points at the number of channels the card
1377 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1378 */
Alan Cox191260a2008-04-30 00:54:16 -07001379 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1380 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 shrinkmem = 1;
1382 if (bd->type < PCIXEM)
1383 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001384 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 memwinon(bd, 0);
1386
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001387 /*
1388 * Remember ch is the main drivers channels structure, while bc is the
1389 * cards channel structure.
1390 */
1391 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001392 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001393 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Alan Cox9ae7b082008-10-13 10:32:09 +01001395 tty_port_init(&ch->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001396 ch->brdchan = bc;
1397 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001398 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001399 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Alan Coxf2cf8e22005-09-06 15:16:44 -07001401 spin_lock_irqsave(&epca_lock, flags);
1402 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001403 /*
1404 * Since some of the boards use different bitmaps for
1405 * their control signals we cannot hard code these
1406 * values and retain portability. We virtualize this
1407 * data here.
1408 */
1409 case EISAXEM:
1410 case PCXEM:
1411 case PCIXEM:
1412 case PCIXRJ:
1413 case PCIXR:
1414 ch->m_rts = 0x02;
1415 ch->m_dcd = 0x80;
1416 ch->m_dsr = 0x20;
1417 ch->m_cts = 0x10;
1418 ch->m_ri = 0x40;
1419 ch->m_dtr = 0x01;
1420 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001422 case PCXE:
1423 case PCXEVE:
1424 case PCXI:
1425 case PC64XE:
1426 ch->m_rts = 0x02;
1427 ch->m_dcd = 0x08;
1428 ch->m_dsr = 0x10;
1429 ch->m_cts = 0x20;
1430 ch->m_ri = 0x40;
1431 ch->m_dtr = 0x80;
1432 break;
1433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Alan Coxf2cf8e22005-09-06 15:16:44 -07001435 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 ch->dsr = ch->m_dcd;
1437 ch->dcd = ch->m_dsr;
1438 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001439 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 ch->dcd = ch->m_dcd;
1441 ch->dsr = ch->m_dsr;
1442 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 ch->boardnum = crd;
1445 ch->channelnum = i;
1446 ch->magic = EPCA_MAGIC;
Alan Cox3969ffb2009-01-02 13:48:04 +00001447 tty_port_tty_set(&ch->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Alan Coxf2cf8e22005-09-06 15:16:44 -07001449 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1451 shrinkmem = 0;
1452 }
1453
Al Virobc9a5152005-09-15 22:53:28 +01001454 tseg = readw(&bc->tseg);
1455 rseg = readw(&bc->rseg);
1456
Alan Coxf2cf8e22005-09-06 15:16:44 -07001457 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001458 case PCIXEM:
1459 case PCIXRJ:
1460 case PCIXR:
1461 /* Cover all the 2MEG cards */
1462 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1463 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1464 ch->txwin = FEPWIN | (tseg >> 11);
1465 ch->rxwin = FEPWIN | (rseg >> 11);
1466 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001468 case PCXEM:
1469 case EISAXEM:
1470 /* Cover all the 32K windowed cards */
1471 /* Mask equal to window size - 1 */
1472 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1473 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1474 ch->txwin = FEPWIN | (tseg >> 11);
1475 ch->rxwin = FEPWIN | (rseg >> 11);
1476 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001478 case PCXEVE:
1479 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001480 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1481 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001482 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001483 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1484 & 0x1fff);
1485 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001486 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001488 case PCXI:
1489 case PC64XE:
1490 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1491 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1492 ch->txwin = ch->rxwin = 0;
1493 break;
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
1496 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001497 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001500 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001501
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1503
1504 /* Set transmitter low water mark */
1505 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1506
1507 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1509
1510 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1512
Alan Coxf2cf8e22005-09-06 15:16:44 -07001513 writew(100, &bc->edelay);
1514 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001515
Alan Coxf2cf8e22005-09-06 15:16:44 -07001516 ch->startc = readb(&bc->startc);
1517 ch->stopc = readb(&bc->stopc);
1518 ch->startca = readb(&bc->startca);
1519 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001520
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 ch->fepcflag = 0;
1522 ch->fepiflag = 0;
1523 ch->fepoflag = 0;
1524 ch->fepstartc = 0;
1525 ch->fepstopc = 0;
1526 ch->fepstartca = 0;
1527 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001528
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 ch->close_delay = 50;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001530
1531 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001534 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001535 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1536 VERSION, board_desc[bd->type], (long)bd->port,
1537 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001539}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
1541static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001542{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 unsigned long flags;
1544 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001545 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 struct channel *ch;
1547 struct board_info *bd;
1548
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001549 /*
1550 * This routine is called upon every timer interrupt. Even though the
1551 * Digi series cards are capable of generating interrupts this method
1552 * of non-looping polling is more efficient. This routine checks for
1553 * card generated events (Such as receive data, are transmit buffer
1554 * empty) and acts on those events.
1555 */
1556 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 bd = &boards[crd];
1558 ch = card_ptr[crd];
1559
1560 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001561 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001563 /*
1564 * assertmemoff is not needed here; indeed it is an empty
1565 * subroutine. It is being kept because future boards may need
1566 * this as well as some legacy boards.
1567 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001568 spin_lock_irqsave(&epca_lock, flags);
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 assertmemoff(ch);
1571
1572 globalwinon(ch);
1573
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001574 /*
1575 * In this case head and tail actually refer to the event queue
1576 * not the transmit or receive queue.
1577 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001578 head = readw(&ch->mailbox->ein);
1579 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001581 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (head != tail)
1583 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 memoff(ch);
1585
Alan Coxf2cf8e22005-09-06 15:16:44 -07001586 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001589}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001592{
Al Virobc9a5152005-09-15 22:53:28 +01001593 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 struct channel *ch, *chan0;
1595 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001596 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001597 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001598 unsigned int tail, head;
1599 int event, channel;
1600 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001602 /*
1603 * This subroutine is called by epcapoll when an event is detected
1604 * in the event queue. This routine responds to those events.
1605 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 bd = &boards[crd];
1607
1608 chan0 = card_ptr[crd];
1609 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001611 while ((tail = readw(&chan0->mailbox->eout)) !=
1612 (head = readw(&chan0->mailbox->ein))) {
1613 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001615 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001617 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001619 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001620 /*
1621 * The two assignments below get the current modem status
1622 * (mstat) and the previous modem status (lstat). These are
1623 * useful becuase an event could signal a change in modem
1624 * signals itself.
1625 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001626 mstat = readb(eventbuf + 2);
1627 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001630 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 if (channel >= bd->numports)
1632 ch = chan0;
1633 bc = ch->brdchan;
1634 goto next;
1635 }
1636
Alan Cox191260a2008-04-30 00:54:16 -07001637 bc = ch->brdchan;
1638 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 goto next;
1640
Alan Cox3969ffb2009-01-02 13:48:04 +00001641 tty = tty_port_tty_get(&ch->port);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001642 if (event & DATA_IND) { /* Begin DATA_IND */
Alan Cox3969ffb2009-01-02 13:48:04 +00001643 receive_data(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 } /* End DATA_IND */
1646 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001647 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 ch->imodem = mstat;
Alan Cox52d41732008-07-16 21:55:02 +01001650 if (ch->port.flags & ASYNC_CHECK_CD) {
Alan Cox191260a2008-04-30 00:54:16 -07001651 /* We are now receiving dcd */
1652 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001653 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001654 else /* No dcd; hangup */
1655 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001657 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001658 if (tty) {
1659 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001661 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001662 tty_schedule_flip(tty);
1663 } else if (event & LOWTX_IND) {
1664 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 ch->statusflags &= ~LOWWAIT;
1666 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001667 }
1668 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001669 /* This event is generated by
1670 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001672 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 ch->statusflags &= ~EMPTYWAIT;
1674 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001675 }
1676 }
Alan Cox3969ffb2009-01-02 13:48:04 +00001677 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001678 }
Alan Cox191260a2008-04-30 00:54:16 -07001679next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001681 BUG_ON(!bc);
1682 writew(1, &bc->idata);
1683 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001686}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001689 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001690{
Al Virobc9a5152005-09-15 22:53:28 +01001691 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 unsigned int head, cmdTail, cmdStart, cmdMax;
1693 long count;
1694 int n;
1695
1696 /* This is the routine in which commands may be passed to the card. */
1697
1698 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001702 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001704 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001705 /*
1706 * We do the addition below because we do not want a max pointer
1707 * relative to cmdStart. We want a max pointer that points at the
1708 * physical end of the command queue.
1709 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001710 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 memaddr = ch->board->re_map_membase;
1712
Alan Coxf2cf8e22005-09-06 15:16:44 -07001713 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001714 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1715 __LINE__, cmd, head);
1716 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1717 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 return;
1719 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001720 if (bytecmd) {
1721 writeb(cmd, memaddr + head + cmdStart + 0);
1722 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001724 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001726 writeb(byte2, memaddr + head + cmdStart + 3);
1727 } else {
1728 writeb(cmd, memaddr + head + cmdStart + 0);
1729 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1730 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001733 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 count = FEPTIMEOUT;
1735
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001736 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001738 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1740 return;
1741 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001742 head = readw(&ch->mailbox->cin);
1743 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001745 /*
1746 * Basically this will break when the FEP acknowledges the
1747 * command by incrementing cmdTail (Making it equal to head).
1748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001750 break;
1751 }
1752}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001754/*
1755 * Digi products use fields in their channels structures that are very similar
1756 * to the c_cflag and c_iflag fields typically found in UNIX termios
1757 * structures. The below three routines allow mappings between these hardware
1758 * "flags" and their respective Linux flags.
1759 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001761{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 unsigned res = 0;
1763
Alan Coxf2cf8e22005-09-06 15:16:44 -07001764 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1766 res |= ((ch->m_cts) | (ch->m_rts));
1767 }
1768
1769 if (ch->digiext.digi_flags & RTSPACE)
1770 res |= ch->m_rts;
1771
1772 if (ch->digiext.digi_flags & DTRPACE)
1773 res |= ch->m_dtr;
1774
1775 if (ch->digiext.digi_flags & CTSPACE)
1776 res |= ch->m_cts;
1777
1778 if (ch->digiext.digi_flags & DSRPACE)
1779 res |= ch->dsr;
1780
1781 if (ch->digiext.digi_flags & DCDPACE)
1782 res |= ch->dcd;
1783
1784 if (res & (ch->m_rts))
1785 ch->digiext.digi_flags |= RTSPACE;
1786
1787 if (res & (ch->m_cts))
1788 ch->digiext.digi_flags |= CTSPACE;
1789
1790 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001791}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001794{
1795 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001796 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 if (ch->digiext.digi_flags & DIGI_AIXON)
1798 res |= IAIXON;
1799 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001800}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001803{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001805 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001806 ch->digiext.digi_flags |= DIGI_FAST;
1807 /*
1808 * HUPCL bit is used by FEP to indicate fast baud table is to
1809 * be used.
1810 */
1811 res |= FEP_HUPCL;
1812 } else
1813 ch->digiext.digi_flags &= ~DIGI_FAST;
1814 /*
1815 * CBAUD has bit position 0x1000 set these days to indicate Linux
1816 * baud rate remap. Digi hardware can't handle the bit assignment.
1817 * (We use a different bit assignment for high speed.). Clear this
1818 * bit out.
1819 */
1820 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1821 /*
1822 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001823 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001824 * this is identical to the Linux implementation. However; Digi
1825 * supports one rate (76800) that Linux doesn't. This means that the
1826 * c_cflag entry that would normally mean 76800 for Digi actually means
1827 * 115200 under Linux. Without the below mapping, a stty 115200 would
1828 * only drive the board at 76800. Since the rate 230400 is also found
1829 * after 76800, the same problem afflicts us when we choose a rate of
1830 * 230400. Without the below modificiation stty 230400 would actually
1831 * give us 115200.
1832 *
1833 * There are two additional differences. The Linux value for CLOCAL
1834 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1835 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1836 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1837 * checked for a screened out prior to termios2digi_c returning. Since
1838 * CLOCAL isn't used by the board this can be ignored as long as the
1839 * returned value is used only by Digi hardware.
1840 */
1841 if (cflag & CBAUDEX) {
1842 /*
1843 * The below code is trying to guarantee that only baud rates
1844 * 115200 and 230400 are remapped. We use exclusive or because
1845 * the various baud rates share common bit positions and
1846 * therefore can't be tested for easily.
1847 */
1848 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001853}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
Alan Coxf2cf8e22005-09-06 15:16:44 -07001855/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001857{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001859 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001860 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 unsigned mval, hflow, cflag, iflag;
1862
1863 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001864 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001868 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1869 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001870 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001871 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001873 /*
1874 * Flush current transmit buffer by setting cmdTail pointer
1875 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1876 * buffer is empty.
1877 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1879 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001880 } else { /* Begin CBAUD not detected */
1881 /*
1882 * c_cflags have changed but that change had nothing to do with
1883 * BAUD. Propagate the change to the card.
1884 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001886 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 ch->fepcflag = cflag;
1888 /* Set baud rate, char size, stop bits, parity */
1889 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1890 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001891 /*
1892 * If the user has not forced CLOCAL and if the device is not a
1893 * CALLOUT device (Which is always CLOCAL) we set flags such
1894 * that the driver will wait on carrier detect.
1895 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 if (ts->c_cflag & CLOCAL)
Alan Cox52d41732008-07-16 21:55:02 +01001897 ch->port.flags &= ~ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 else
Alan Cox52d41732008-07-16 21:55:02 +01001899 ch->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001904 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001906 /*
1907 * Command sets channels iflag structure on the board. Such
1908 * things as input soft flow control, handling of parity
1909 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001910 *
1911 * break handling, parity handling, input stripping,
1912 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001913 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1915 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001916 /*
1917 * Set the board mint value for this channel. This will cause hardware
1918 * events to be generated each time the DCD signal (Described in mint)
1919 * changes.
1920 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001921 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1923 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001924 writeb(0, &bc->mint);
1925 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001927 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001929 /*
1930 * Hard flow control has been selected but the board is not
1931 * using it. Activate hard flow control now.
1932 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 mval ^= ch->modemfake & (mval ^ ch->modem);
1936
Alan Coxf2cf8e22005-09-06 15:16:44 -07001937 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001939 /*
1940 * The below command sets the DTR and RTS mstat structure. If
1941 * hard flow control is NOT active these changes will drive the
1942 * output of the actual DTR and RTS lines. If hard flow control
1943 * is active, the changes will be saved in the mstat structure
1944 * and only asserted when hard flow control is turned off.
1945 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
1947 /* First reset DTR & RTS; then set them */
1948 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1949 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001951 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 ch->fepstartc = ch->startc;
1953 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001954 /*
1955 * The XON / XOFF characters have changed; propagate these
1956 * changes to the card.
1957 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1959 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001960 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 ch->fepstartca = ch->startca;
1962 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001963 /*
1964 * Similar to the above, this time the auxilarly XON / XOFF
1965 * characters have changed; propagate these changes to the card.
1966 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1968 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001969}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
Alan Coxf2cf8e22005-09-06 15:16:44 -07001971/* Caller holds lock */
Alan Cox3969ffb2009-01-02 13:48:04 +00001972static void receive_data(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001973{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001975 struct ktermios *ts = NULL;
Al Virobc9a5152005-09-15 22:53:28 +01001976 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001977 int dataToRead, wrapgap, bytesAvailable;
1978 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001981 /*
1982 * This routine is called by doint when a receive data event has taken
1983 * place.
1984 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 if (ch->statusflags & RXSTOPPED)
1987 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 if (tty)
1989 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001991 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 wrapmask = ch->rxbufsize - 1;
1993
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001994 /*
1995 * Get the head and tail pointers to the receiver queue. Wrap the head
1996 * pointer if it has reached the end of the buffer.
1997 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001998 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002000 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 if (bytesAvailable == 0)
2004 return;
2005
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002006 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07002007 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01002008 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 return;
2010 }
2011
Alan Cox33f0f882006-01-09 20:54:13 -08002012 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 return;
2014
Alan Coxf2cf8e22005-09-06 15:16:44 -07002015 if (readb(&bc->orun)) {
2016 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07002017 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
2018 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08002019 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07002022 while (bytesAvailable > 0) {
2023 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002025 /*
2026 * Even if head has wrapped around only report the amount of
2027 * data to be equal to the size - tail. Remember memcpy can't
2028 * automaticly wrap around the receive buffer.
2029 */
Alan Cox191260a2008-04-30 00:54:16 -07002030 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
2031 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002032 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08002033 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 if (dataToRead == 0)
2035 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002036 /*
2037 * Move data read from our card into the line disciplines
2038 * buffer for translation if necessary.
2039 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002040 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 tail = (tail + dataToRead) & wrapmask;
2042 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002045 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 /* Must be called with global data */
Alan Cox3969ffb2009-01-02 13:48:04 +00002047 tty_schedule_flip(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002048}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002050static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 unsigned int cmd, unsigned long arg)
2052{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002053 switch (cmd) {
2054 case DIGI_GETINFO:
2055 {
2056 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 int brd;
2058
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002059 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07002060 return -EFAULT;
2061 if (brd < 0 || brd >= num_cards || num_cards == 0)
2062 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
2064 memset(&di, 0, sizeof(di));
2065
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002066 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 di.status = boards[brd].status;
2068 di.type = boards[brd].type ;
2069 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002070 /* Legacy fixups - just move along nothing to see */
2071 di.port = (unsigned char *)boards[brd].port ;
2072 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002074 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return -EFAULT;
2076 break;
2077
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002080 case DIGI_POLLER:
2081 {
2082 int brd = arg & 0xff000000 >> 16;
2083 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Alan Coxf2cf8e22005-09-06 15:16:44 -07002085 if (brd < 0 || brd >= num_cards) {
2086 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002087 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002089 digi_poller_inhibited = state;
2090 break;
2091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002093 case DIGI_INIT:
2094 {
2095 /*
2096 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02002097 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002098 * responsible for setting the card to its initial
2099 * state and setting the drivers control fields to the
2100 * sutianle settings for the card in question.
2101 */
2102 int crd;
2103 for (crd = 0; crd < num_cards; crd++)
2104 post_fep_init(crd);
2105 break;
2106 }
2107 default:
2108 return -ENOTTY;
2109 }
2110 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
2113static int pc_tiocmget(struct tty_struct *tty, struct file *file)
2114{
Alan Coxc9f19e92009-01-02 13:47:26 +00002115 struct channel *ch = tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01002116 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 unsigned int mstat, mflag = 0;
2118 unsigned long flags;
2119
2120 if (ch)
2121 bc = ch->brdchan;
2122 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002123 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
Alan Coxf2cf8e22005-09-06 15:16:44 -07002125 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002127 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002129 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
2131 if (mstat & ch->m_dtr)
2132 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 if (mstat & ch->m_rts)
2134 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (mstat & ch->m_cts)
2136 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 if (mstat & ch->dsr)
2138 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 if (mstat & ch->m_ri)
2140 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if (mstat & ch->dcd)
2142 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return mflag;
2144}
2145
2146static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2147 unsigned int set, unsigned int clear)
2148{
Alan Coxc9f19e92009-01-02 13:47:26 +00002149 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 unsigned long flags;
2151
Alan Coxf2cf8e22005-09-06 15:16:44 -07002152 if (!ch)
2153 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Alan Coxf2cf8e22005-09-06 15:16:44 -07002155 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002157 * I think this modemfake stuff is broken. It doesn't correctly reflect
2158 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2159 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 */
2161 if (set & TIOCM_RTS) {
2162 ch->modemfake |= ch->m_rts;
2163 ch->modem |= ch->m_rts;
2164 }
2165 if (set & TIOCM_DTR) {
2166 ch->modemfake |= ch->m_dtr;
2167 ch->modem |= ch->m_dtr;
2168 }
2169 if (clear & TIOCM_RTS) {
2170 ch->modemfake |= ch->m_rts;
2171 ch->modem &= ~ch->m_rts;
2172 }
2173 if (clear & TIOCM_DTR) {
2174 ch->modemfake |= ch->m_dtr;
2175 ch->modem &= ~ch->m_dtr;
2176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002178 /*
2179 * The below routine generally sets up parity, baud, flow control
2180 * issues, etc.... It effect both control flags and input flags.
2181 */
Alan Cox191260a2008-04-30 00:54:16 -07002182 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002184 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 return 0;
2186}
2187
Alan Cox191260a2008-04-30 00:54:16 -07002188static int pc_ioctl(struct tty_struct *tty, struct file *file,
2189 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002190{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 unsigned long flags;
2193 unsigned int mflag, mstat;
2194 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002195 struct board_chan __iomem *bc;
Alan Coxc9f19e92009-01-02 13:47:26 +00002196 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002198
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if (ch)
2200 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002201 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002202 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002203 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002204 case TIOCMODG:
2205 mflag = pc_tiocmget(tty, file);
2206 if (put_user(mflag, (unsigned long __user *)argp))
2207 return -EFAULT;
2208 break;
2209 case TIOCMODS:
2210 if (get_user(mstat, (unsigned __user *)argp))
2211 return -EFAULT;
2212 return pc_tiocmset(tty, file, mstat, ~mstat);
2213 case TIOCSDTR:
2214 spin_lock_irqsave(&epca_lock, flags);
2215 ch->omodem |= ch->m_dtr;
2216 globalwinon(ch);
2217 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2218 memoff(ch);
2219 spin_unlock_irqrestore(&epca_lock, flags);
2220 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002222 case TIOCCDTR:
2223 spin_lock_irqsave(&epca_lock, flags);
2224 ch->omodem &= ~ch->m_dtr;
2225 globalwinon(ch);
2226 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2227 memoff(ch);
2228 spin_unlock_irqrestore(&epca_lock, flags);
2229 break;
2230 case DIGI_GETA:
2231 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2232 return -EFAULT;
2233 break;
2234 case DIGI_SETAW:
2235 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002236 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002237 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002238 /* Setup an event to indicate when the transmit
2239 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002240 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002241 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002242 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002243 tty_wait_until_sent(tty, 0);
2244 } else {
2245 /* ldisc lock already held in ioctl */
Alan Coxa352def2008-07-16 21:53:12 +01002246 if (tty->ldisc.ops->flush_buffer)
2247 tty->ldisc.ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002248 }
Alan Cox37925e02008-04-30 00:53:17 -07002249 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002250 /* Fall Thru */
2251 case DIGI_SETA:
2252 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2253 return -EFAULT;
2254
2255 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2256 ch->dcd = ch->m_dsr;
2257 ch->dsr = ch->m_dcd;
2258 } else {
2259 ch->dcd = ch->m_dcd;
2260 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002262
2263 spin_lock_irqsave(&epca_lock, flags);
2264 globalwinon(ch);
2265
2266 /*
2267 * The below routine generally sets up parity, baud, flow
2268 * control issues, etc.... It effect both control flags and
2269 * input flags.
2270 */
Alan Cox191260a2008-04-30 00:54:16 -07002271 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002272 memoff(ch);
2273 spin_unlock_irqrestore(&epca_lock, flags);
2274 break;
2275
2276 case DIGI_GETFLOW:
2277 case DIGI_GETAFLOW:
2278 spin_lock_irqsave(&epca_lock, flags);
2279 globalwinon(ch);
2280 if (cmd == DIGI_GETFLOW) {
2281 dflow.startc = readb(&bc->startc);
2282 dflow.stopc = readb(&bc->stopc);
2283 } else {
2284 dflow.startc = readb(&bc->startca);
2285 dflow.stopc = readb(&bc->stopca);
2286 }
2287 memoff(ch);
2288 spin_unlock_irqrestore(&epca_lock, flags);
2289
2290 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2291 return -EFAULT;
2292 break;
2293
2294 case DIGI_SETAFLOW:
2295 case DIGI_SETFLOW:
2296 if (cmd == DIGI_SETFLOW) {
2297 startc = ch->startc;
2298 stopc = ch->stopc;
2299 } else {
2300 startc = ch->startca;
2301 stopc = ch->stopca;
2302 }
2303
2304 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2305 return -EFAULT;
2306
Alan Cox191260a2008-04-30 00:54:16 -07002307 if (dflow.startc != startc || dflow.stopc != stopc) {
2308 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002309 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 globalwinon(ch);
2311
Alan Coxf2cf8e22005-09-06 15:16:44 -07002312 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002313 ch->fepstartc = ch->startc = dflow.startc;
2314 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002315 fepcmd(ch, SONOFFC, ch->fepstartc,
2316 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002317 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002318 ch->fepstartca = ch->startca = dflow.startc;
2319 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002320 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2321 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 }
2323
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002324 if (ch->statusflags & TXSTOPPED)
2325 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002327 memoff(ch);
2328 spin_unlock_irqrestore(&epca_lock, flags);
2329 } /* End if setflow toggled */
2330 break;
2331 default:
2332 return -ENOIOCTLCMD;
2333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002335}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Alan Cox606d0992006-12-08 02:38:45 -08002337static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002338{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 struct channel *ch;
2340 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002341 /*
2342 * verifyChannel returns the channel from the tty struct if it is
2343 * valid. This serves as a sanity check.
2344 */
Alan Cox191260a2008-04-30 00:54:16 -07002345 ch = verifyChannel(tty);
2346
2347 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002348 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 globalwinon(ch);
2350 epcaparam(tty, ch);
2351 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002352 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
2354 if ((old_termios->c_cflag & CRTSCTS) &&
2355 ((tty->termios->c_cflag & CRTSCTS) == 0))
2356 tty->hw_stopped = 0;
2357
2358 if (!(old_termios->c_cflag & CLOCAL) &&
2359 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002360 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002363}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
David Howellsc4028952006-11-22 14:57:56 +00002365static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002366{
David Howellsc4028952006-11-22 14:57:56 +00002367 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002369 if (ch && ch->magic == EPCA_MAGIC) {
Alan Cox3969ffb2009-01-02 13:48:04 +00002370 struct tty_struct *tty = tty_port_tty_get(&ch->port);;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Alan Coxf2cf8e22005-09-06 15:16:44 -07002372 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002373 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002374 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002375 wake_up_interruptible(&ch->port.open_wait);
2376 ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002379 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002380 }
2381}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002383/*
2384 * pc_stop and pc_start provide software flow control to the routine and the
2385 * pc_ioctl routine.
2386 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002388{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 struct channel *ch;
2390 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002391 /*
2392 * verifyChannel returns the channel from the tty struct if it is
2393 * valid. This serves as a sanity check.
2394 */
Alan Cox191260a2008-04-30 00:54:16 -07002395 ch = verifyChannel(tty);
2396 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002397 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002398 if ((ch->statusflags & TXSTOPPED) == 0) {
2399 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 ch->statusflags |= TXSTOPPED;
2404 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002406 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002407 }
2408}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002411{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002413 /*
2414 * verifyChannel returns the channel from the tty struct if it is
2415 * valid. This serves as a sanity check.
2416 */
Alan Cox191260a2008-04-30 00:54:16 -07002417 ch = verifyChannel(tty);
2418 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002420 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002421 /* Just in case output was resumed because of a change
2422 in Digi-flow */
2423 if (ch->statusflags & TXSTOPPED) {
2424 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002425 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 globalwinon(ch);
2427 bc = ch->brdchan;
2428 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002429 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 ch->statusflags &= ~TXSTOPPED;
2433 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002435 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002436 }
2437}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002439/*
2440 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2441 * resume) the receipt of data into the kernels receive buffers. The exact
2442 * occurrence of this depends on the size of the kernels receive buffer and
2443 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2444 * more details.
2445 */
2446static void pc_throttle(struct tty_struct *tty)
2447{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 struct channel *ch;
2449 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002450 /*
2451 * verifyChannel returns the channel from the tty struct if it is
2452 * valid. This serves as a sanity check.
2453 */
Alan Cox191260a2008-04-30 00:54:16 -07002454 ch = verifyChannel(tty);
2455 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002456 spin_lock_irqsave(&epca_lock, flags);
2457 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 globalwinon(ch);
2459 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 ch->statusflags |= RXSTOPPED;
2461 memoff(ch);
2462 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002463 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002464 }
2465}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
2467static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002468{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 struct channel *ch;
2470 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002471 /*
2472 * verifyChannel returns the channel from the tty struct if it is
2473 * valid. This serves as a sanity check.
2474 */
Alan Cox191260a2008-04-30 00:54:16 -07002475 ch = verifyChannel(tty);
2476 if (ch != NULL) {
2477 /* Just in case output was resumed because of a change
2478 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002479 spin_lock_irqsave(&epca_lock, flags);
2480 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 ch->statusflags &= ~RXSTOPPED;
2484 memoff(ch);
2485 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002486 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002487 }
2488}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Alan Coxdcbf1282008-07-22 11:18:12 +01002490static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002491{
Alan Coxc9f19e92009-01-02 13:47:26 +00002492 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 unsigned long flags;
2494
Alan Coxdcbf1282008-07-22 11:18:12 +01002495 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002496 msec = 0xFFFF;
2497 else if (msec > 0xFFFE)
2498 msec = 0xFFFE;
2499 else if (msec < 1)
2500 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002501
Alan Coxf2cf8e22005-09-06 15:16:44 -07002502 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002504 /*
2505 * Maybe I should send an infinite break here, schedule() for msec
2506 * amount of time, and then stop the break. This way, the user can't
2507 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2508 * an ioctl()) more than once in msec amount of time.
2509 * Try this for now...
2510 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2512 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002513 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002514 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002515}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
Alan Coxf2cf8e22005-09-06 15:16:44 -07002517/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002519{
Al Virobc9a5152005-09-15 22:53:28 +01002520 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 globalwinon(ch);
2523 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002524 /*
2525 * When set the iempty flag request a event to be generated when the
2526 * transmit buffer is empty (If there is no BREAK in progress).
2527 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002528 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002530}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
David Howells88e88242008-07-22 11:20:45 +01002532#ifndef MODULE
2533static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002534{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 struct board_info board;
2536 int index, loop, last;
2537 char *temp, *t2;
2538 unsigned len;
2539
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002540 /*
2541 * If this routine looks a little strange it is because it is only
2542 * called if a LILO append command is given to boot the kernel with
2543 * parameters. In this way, we can provide the user a method of
2544 * changing his board configuration without rebuilding the kernel.
2545 */
2546 if (!liloconfig)
2547 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 memset(&board, 0, sizeof(board));
2550
2551 /* Assume the data is int first, later we can change it */
2552 /* I think that array position 0 of ints holds the number of args */
2553 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002554 switch (index) { /* Begin parse switch */
2555 case 1:
2556 board.status = ints[index];
2557 /*
2558 * We check for 2 (As opposed to 1; because 2 is a flag
2559 * instructing the driver to ignore epcaconfig.) For
2560 * this reason we check for 2.
2561 */
Alan Cox191260a2008-04-30 00:54:16 -07002562 if (board.status == 2) {
2563 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002564 nbdevs = 0;
2565 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002567 } /* End ignore epcaconfig as well as lilo cmd line */
2568
2569 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002570 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2571 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002572 invalid_lilo_config = 1;
2573 setup_error_code |= INVALID_BOARD_STATUS;
2574 return;
2575 }
2576 last = index;
2577 break;
2578 case 2:
2579 board.type = ints[index];
2580 if (board.type >= PCIXEM) {
2581 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2582 invalid_lilo_config = 1;
2583 setup_error_code |= INVALID_BOARD_TYPE;
2584 return;
2585 }
2586 last = index;
2587 break;
2588 case 3:
2589 board.altpin = ints[index];
2590 if (board.altpin > 1) {
2591 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2592 invalid_lilo_config = 1;
2593 setup_error_code |= INVALID_ALTPIN;
2594 return;
2595 }
2596 last = index;
2597 break;
2598
2599 case 4:
2600 board.numports = ints[index];
2601 if (board.numports < 2 || board.numports > 256) {
2602 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2603 invalid_lilo_config = 1;
2604 setup_error_code |= INVALID_NUM_PORTS;
2605 return;
2606 }
2607 nbdevs += board.numports;
2608 last = index;
2609 break;
2610
2611 case 5:
2612 board.port = ints[index];
2613 if (ints[index] <= 0) {
2614 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2615 invalid_lilo_config = 1;
2616 setup_error_code |= INVALID_PORT_BASE;
2617 return;
2618 }
2619 last = index;
2620 break;
2621
2622 case 6:
2623 board.membase = ints[index];
2624 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002625 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2626 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002627 invalid_lilo_config = 1;
2628 setup_error_code |= INVALID_MEM_BASE;
2629 return;
2630 }
2631 last = index;
2632 break;
2633
2634 default:
2635 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2636 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
2638 } /* End parse switch */
2639
Alan Coxf2cf8e22005-09-06 15:16:44 -07002640 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 /* find the next comma or terminator */
2642 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* While string is not null, and a comma hasn't been found */
2644 while (*temp && (*temp != ','))
2645 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if (!*temp)
2647 temp = NULL;
2648 else
2649 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 /* Set index to the number of args + 1 */
2651 index = last + 1;
2652
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002653 switch (index) {
2654 case 1:
2655 len = strlen(str);
2656 if (strncmp("Disable", str, len) == 0)
2657 board.status = 0;
2658 else if (strncmp("Enable", str, len) == 0)
2659 board.status = 1;
2660 else {
2661 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2662 invalid_lilo_config = 1;
2663 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002665 }
2666 last = index;
2667 break;
2668
2669 case 2:
2670 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2671 if (strcmp(board_desc[loop], str) == 0)
2672 break;
2673 /*
2674 * If the index incremented above refers to a
2675 * legitamate board type set it here.
2676 */
2677 if (index < EPCA_NUM_TYPES)
2678 board.type = loop;
2679 else {
2680 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2681 invalid_lilo_config = 1;
2682 setup_error_code |= INVALID_BOARD_TYPE;
2683 return;
2684 }
2685 last = index;
2686 break;
2687
2688 case 3:
2689 len = strlen(str);
2690 if (strncmp("Disable", str, len) == 0)
2691 board.altpin = 0;
2692 else if (strncmp("Enable", str, len) == 0)
2693 board.altpin = 1;
2694 else {
2695 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2696 invalid_lilo_config = 1;
2697 setup_error_code |= INVALID_ALTPIN;
2698 return;
2699 }
2700 last = index;
2701 break;
2702
2703 case 4:
2704 t2 = str;
2705 while (isdigit(*t2))
2706 t2++;
2707
2708 if (*t2) {
2709 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2710 invalid_lilo_config = 1;
2711 setup_error_code |= INVALID_NUM_PORTS;
2712 return;
2713 }
2714
2715 /*
2716 * There is not a man page for simple_strtoul but the
2717 * code can be found in vsprintf.c. The first argument
2718 * is the string to translate (To an unsigned long
2719 * obviously), the second argument can be the address
2720 * of any character variable or a NULL. If a variable
2721 * is given, the end pointer of the string will be
2722 * stored in that variable; if a NULL is given the end
2723 * pointer will not be returned. The last argument is
2724 * the base to use. If a 0 is indicated, the routine
2725 * will attempt to determine the proper base by looking
2726 * at the values prefix (A '0' for octal, a 'x' for
2727 * hex, etc ... If a value is given it will use that
2728 * value as the base.
2729 */
2730 board.numports = simple_strtoul(str, NULL, 0);
2731 nbdevs += board.numports;
2732 last = index;
2733 break;
2734
2735 case 5:
2736 t2 = str;
2737 while (isxdigit(*t2))
2738 t2++;
2739
2740 if (*t2) {
2741 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2742 invalid_lilo_config = 1;
2743 setup_error_code |= INVALID_PORT_BASE;
2744 return;
2745 }
2746
2747 board.port = simple_strtoul(str, NULL, 16);
2748 last = index;
2749 break;
2750
2751 case 6:
2752 t2 = str;
2753 while (isxdigit(*t2))
2754 t2++;
2755
2756 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002757 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002758 invalid_lilo_config = 1;
2759 setup_error_code |= INVALID_MEM_BASE;
2760 return;
2761 }
2762 board.membase = simple_strtoul(str, NULL, 16);
2763 last = index;
2764 break;
2765 default:
2766 printk(KERN_ERR "epca: Too many string parms\n");
2767 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 }
2769 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 } /* End while there is a string arg */
2771
Alan Coxf2cf8e22005-09-06 15:16:44 -07002772 if (last < 6) {
2773 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return;
2775 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002776
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002779 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002781 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2782 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002785}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
David Howells88e88242008-07-22 11:20:45 +01002787static int __init epca_real_setup(char *str)
2788{
2789 int ints[11];
2790
2791 epca_setup(get_options(str, 11, ints), ints);
2792 return 1;
2793}
2794
2795__setup("digiepca", epca_real_setup);
2796#endif
2797
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798enum epic_board_types {
2799 brd_xr = 0,
2800 brd_xem,
2801 brd_cx,
2802 brd_xrj,
2803};
2804
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805/* indexed directly by epic_board_types enum */
2806static struct {
2807 unsigned char board_type;
2808 unsigned bar_idx; /* PCI base address region */
2809} epca_info_tbl[] = {
2810 { PCIXR, 0, },
2811 { PCIXEM, 0, },
2812 { PCICX, 0, },
2813 { PCIXRJ, 2, },
2814};
2815
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002816static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 const struct pci_device_id *ent)
2818{
2819 static int board_num = -1;
2820 int board_idx, info_idx = ent->driver_data;
2821 unsigned long addr;
2822
2823 if (pci_enable_device(pdev))
2824 return -EIO;
2825
2826 board_num++;
2827 board_idx = board_num + num_cards;
2828 if (board_idx >= MAXBOARDS)
2829 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002830
Alan Cox191260a2008-04-30 00:54:16 -07002831 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002833 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 epca_info_tbl[info_idx].bar_idx);
2835 goto err_out;
2836 }
2837
2838 boards[board_idx].status = ENABLED;
2839 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2840 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002841 boards[board_idx].port = addr + PCI_IO_OFFSET;
2842 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
Alan Cox191260a2008-04-30 00:54:16 -07002844 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2845 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 0x200000, addr + PCI_IO_OFFSET);
2847 goto err_out;
2848 }
2849
Alan Cox191260a2008-04-30 00:54:16 -07002850 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2851 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002853 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 0x200000, addr + PCI_IO_OFFSET);
2855 goto err_out_free_pciio;
2856 }
2857
Alan Cox191260a2008-04-30 00:54:16 -07002858 if (!request_mem_region(addr, 0x200000, "epca")) {
2859 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 0x200000, addr);
2861 goto err_out_free_iounmap;
2862 }
2863
Alan Cox191260a2008-04-30 00:54:16 -07002864 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002866 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 0x200000, addr + PCI_IO_OFFSET);
2868 goto err_out_free_memregion;
2869 }
2870
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002871 /*
2872 * I don't know what the below does, but the hardware guys say its
2873 * required on everything except PLX (In this case XRJ).
2874 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002876 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 pci_write_config_byte(pdev, 0x46, 0);
2878 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002879
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 return 0;
2881
2882err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002883 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002885 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002887 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888err_out:
2889 return -ENODEV;
2890}
2891
2892
2893static struct pci_device_id epca_pci_tbl[] = {
2894 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2895 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2896 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2897 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2898 { 0, }
2899};
2900
2901MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2902
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002903static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002904{
Alan Cox191260a2008-04-30 00:54:16 -07002905 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 epca_driver.name = "epca";
2907 epca_driver.id_table = epca_pci_tbl;
2908 epca_driver.probe = epca_init_one;
2909
2910 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002911}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913MODULE_LICENSE("GPL");