blob: 71225d1af9ee6eb65ab9a95806438c7460f800d2 [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 Cox6ed1dba2009-01-02 13:48:11 +0000435 if (tty_port_close_start(port, tty, filp) == 0)
Alan Coxd1c815e2009-01-02 13:47:58 +0000436 return;
Alan Coxd1c815e2009-01-02 13:47:58 +0000437
Alan Coxd1c815e2009-01-02 13:47:58 +0000438 pc_flush_buffer(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000439 shutdown(ch, tty);
440
Alan Cox6ed1dba2009-01-02 13:48:11 +0000441 tty_port_close_end(port, tty);
442 ch->event = 0; /* FIXME: review ch->event locking */
Alan Cox3969ffb2009-01-02 13:48:04 +0000443 tty_port_tty_set(port, NULL);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700444}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Alan Coxd1c815e2009-01-02 13:47:58 +0000446static void shutdown(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700447{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +0100449 struct board_chan __iomem *bc;
Alan Coxd1c815e2009-01-02 13:47:58 +0000450 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451
Alan Coxd1c815e2009-01-02 13:47:58 +0000452 if (!(port->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return;
454
Alan Coxf2cf8e22005-09-06 15:16:44 -0700455 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Alan Coxf2cf8e22005-09-06 15:16:44 -0700457 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 bc = ch->brdchan;
459
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700460 /*
461 * In order for an event to be generated on the receipt of data the
462 * idata flag must be set. Since we are shutting down, this is not
463 * necessary clear this flag.
464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700466 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700468 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700469 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
471 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 memoff(ch);
474
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700475 /*
476 * The channel has officialy been closed. The next time it is opened it
477 * will have to reinitialized. Set a flag to indicate this.
478 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 /* Prevent future Digi programmed interrupts from coming active */
Alan Coxd1c815e2009-01-02 13:47:58 +0000480 port->flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700481 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700482}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700485{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000487
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700488 /*
489 * verifyChannel returns the channel from the tty struct if it is
490 * valid. This serves as a sanity check.
491 */
Alan Cox191260a2008-04-30 00:54:16 -0700492 ch = verifyChannel(tty);
493 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 unsigned long flags;
495
Alan Cox978e5952008-04-30 00:53:59 -0700496 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 tty_ldisc_flush(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000498 shutdown(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Alan Coxd1c815e2009-01-02 13:47:58 +0000500 ch->event = 0; /* FIXME: review locking of ch->event */
Alan Cox6ed1dba2009-01-02 13:48:11 +0000501 tty_port_hangup(&ch->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700502 }
503}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700505static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700506 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700507{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700508 unsigned int head, tail;
509 int dataLen;
510 int size;
511 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 struct channel *ch;
513 unsigned long flags;
514 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100515 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700517 /*
518 * pc_write is primarily called directly by the kernel routine
519 * tty_write (Though it can also be called by put_char) found in
520 * tty_io.c. pc_write is passed a line discipline buffer where the data
521 * to be written out is stored. The line discipline implementation
522 * itself is done at the kernel level and is not brought into the
523 * driver.
524 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700526 /*
527 * verifyChannel returns the channel from the tty struct if it is
528 * valid. This serves as a sanity check.
529 */
Alan Cox191260a2008-04-30 00:54:16 -0700530 ch = verifyChannel(tty);
531 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return 0;
533
534 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 bc = ch->brdchan;
536 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Alan Coxf2cf8e22005-09-06 15:16:44 -0700539 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 globalwinon(ch);
541
Alan Coxf2cf8e22005-09-06 15:16:44 -0700542 head = readw(&bc->tin) & (size - 1);
543 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Alan Coxf2cf8e22005-09-06 15:16:44 -0700545 if (tail != readw(&bc->tout))
546 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 tail &= (size - 1);
548
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700549 if (head >= tail) {
550 /* head has not wrapped */
551 /*
552 * remain (much like dataLen above) represents the total amount
553 * of space available on the card for data. Here dataLen
554 * represents the space existing between the head pointer and
555 * the end of buffer. This is important because a memcpy cannot
556 * be told to automatically wrap around when it hits the buffer
557 * end.
558 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 dataLen = size - head;
560 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700561 } else {
562 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 remain = tail - head - 1;
564 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700565 }
566 /*
567 * Check the space on the card. If we have more data than space; reduce
568 * the amount of data to fit the space.
569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700572 while (bytesAvailable > 0) {
573 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700575 /*
576 * If head is not wrapped, the below will make sure the first
577 * data copy fills to the end of card buffer.
578 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100580 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 buf += dataLen;
582 head += dataLen;
583 amountCopied += dataLen;
584 bytesAvailable -= dataLen;
585
Alan Coxf2cf8e22005-09-06 15:16:44 -0700586 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 head = 0;
588 dataLen = tail;
589 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 ch->statusflags |= TXBUSY;
592 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700593 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Alan Coxf2cf8e22005-09-06 15:16:44 -0700595 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700597 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
599 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700600 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700601 return amountCopied;
602}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700605{
Alan Cox191260a2008-04-30 00:54:16 -0700606 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 struct channel *ch;
608 unsigned long flags;
609 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100610 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700611 /*
612 * verifyChannel returns the channel from the tty struct if it is
613 * valid. This serves as a sanity check.
614 */
Alan Cox191260a2008-04-30 00:54:16 -0700615 ch = verifyChannel(tty);
616 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700617 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 globalwinon(ch);
619
620 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700621 head = readw(&bc->tin) & (ch->txbufsize - 1);
622 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Alan Coxf2cf8e22005-09-06 15:16:44 -0700624 if (tail != readw(&bc->tout))
625 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 /* Wrap tail if necessary */
627 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700628 remain = tail - head - 1;
629 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 remain += ch->txbufsize;
631
Alan Coxf2cf8e22005-09-06 15:16:44 -0700632 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700634 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700637 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 /* Return how much room is left on card */
640 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700641}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700644{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 int chars;
646 unsigned int ctail, head, tail;
647 int remain;
648 unsigned long flags;
649 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100650 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700651 /*
652 * verifyChannel returns the channel from the tty struct if it is
653 * valid. This serves as a sanity check.
654 */
Alan Cox191260a2008-04-30 00:54:16 -0700655 ch = verifyChannel(tty);
656 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700657 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Alan Coxf2cf8e22005-09-06 15:16:44 -0700659 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 globalwinon(ch);
661
662 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700663 tail = readw(&bc->tout);
664 head = readw(&bc->tin);
665 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Alan Cox191260a2008-04-30 00:54:16 -0700667 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
668 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700670 else { /* Begin if some space on the card has been used */
671 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700673 /*
674 * The logic here is basically opposite of the above
675 * pc_write_room here we are finding the amount of bytes in the
676 * buffer filled. Not the amount of bytes empty.
677 */
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700682 /*
683 * Make it possible to wakeup anything waiting for output in
684 * tty_ioctl.c, etc.
685 *
686 * If not already set. Setup an event to indicate when the
687 * transmit buffer empties.
688 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700690 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700693 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700695 return chars;
696}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700699{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 unsigned int tail;
701 unsigned long flags;
702 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100703 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700704 /*
705 * verifyChannel returns the channel from the tty struct if it is
706 * valid. This serves as a sanity check.
707 */
Alan Cox191260a2008-04-30 00:54:16 -0700708 ch = verifyChannel(tty);
709 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return;
711
Alan Coxf2cf8e22005-09-06 15:16:44 -0700712 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700715 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700719 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700721}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700724{
725 struct channel *ch;
726 /*
727 * verifyChannel returns the channel from the tty struct if it is
728 * valid. This serves as a sanity check.
729 */
Alan Cox191260a2008-04-30 00:54:16 -0700730 ch = verifyChannel(tty);
731 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700733 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700734 /*
735 * If not already set and the transmitter is busy setup an
736 * event to indicate when the transmit empties.
737 */
Alan Cox191260a2008-04-30 00:54:16 -0700738 if ((ch->statusflags & TXBUSY) &&
739 !(ch->statusflags & EMPTYWAIT))
740 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700741 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700743}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Alan Cox6ed1dba2009-01-02 13:48:11 +0000745static int epca_carrier_raised(struct tty_port *port)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700746{
Alan Cox6ed1dba2009-01-02 13:48:11 +0000747 struct channel *ch = container_of(port, struct channel, port);
748 if (ch->imodem & ch->dcd)
749 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700751}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Alan Cox6ed1dba2009-01-02 13:48:11 +0000753static void epca_raise_dtr_rts(struct tty_port *port0
754{
755}
756
Alan Cox191260a2008-04-30 00:54:16 -0700757static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000760 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 unsigned long flags;
762 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100763 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700764 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700767 if (line < 0 || line >= nbdevs)
768 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
770 ch = &digi_channels[line];
Alan Coxd1c815e2009-01-02 13:47:58 +0000771 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 boardnum = ch->boardnum;
773
774 /* Check status of board configured in system. */
775
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700776 /*
777 * I check to see if the epca_setup routine detected an user error. It
778 * might be better to put this in pc_init, but for the moment it goes
779 * here.
780 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700781 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700783 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700785 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700787 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700789 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700791 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700793 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700795 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700797 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 tty->driver_data = NULL; /* Mark this device as 'down' */
799 return(-ENODEV);
800 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700801
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700802 bc = ch->brdchan;
803 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700805 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
807
Alan Coxd1c815e2009-01-02 13:47:58 +0000808 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700809 /*
810 * Every time a channel is opened, increment a counter. This is
811 * necessary because we do not wish to flush and shutdown the channel
812 * until the last app holding the channel open, closes it.
813 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000814 port->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700815 /*
816 * Set a kernel structures pointer to our local channel structure. This
817 * way we can get to it when passed only a tty struct.
818 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 tty->driver_data = ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000820 port->tty = tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700821 /*
822 * If this is the first time the channel has been opened, initialize
823 * the tty->termios struct otherwise let pc_close handle it.
824 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000825 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 globalwinon(ch);
827 ch->statusflags = 0;
828
829 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100830 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700832 /*
833 * Set receive head and tail ptrs to each other. This indicates no data
834 * available to read.
835 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700836 head = readw(&bc->rin);
837 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
839 /* Set the channels associated tty structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700841 /*
842 * The below routine generally sets up parity, baud, flow control
843 * issues, etc.... It effect both control flags and input flags.
844 */
Alan Cox191260a2008-04-30 00:54:16 -0700845 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000847 spin_unlock(&epca_lock);
848 port->flags |= ASYNC_INITIALIZED;
849 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Alan Cox6ed1dba2009-01-02 13:48:11 +0000851 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700854 /*
855 * Set this again in case a hangup set it to zero while this open() was
856 * waiting for the line...
857 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000858 spin_lock_irqsave(&port->lock, flags);
859 port->tty = tty;
860 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700863 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000865 spin_unlock(&epca_lock);
866 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868}
869
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700870static int __init epca_module_init(void)
871{
872 return pc_init();
873}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878static void __exit epca_module_exit(void)
879{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 int count, crd;
881 struct board_info *bd;
882 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 del_timer_sync(&epca_timer);
885
Alan Cox191260a2008-04-30 00:54:16 -0700886 if (tty_unregister_driver(pc_driver) ||
887 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700888 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 return;
890 }
891 put_tty_driver(pc_driver);
892 put_tty_driver(pc_info);
893
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700894 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700896 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
898 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700899 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700900 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700901 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox3969ffb2009-01-02 13:48:04 +0000902 struct tty_struct *tty = tty_port_tty_get(&ch->port);
903 if (tty) {
904 tty_hangup(tty);
905 tty_kref_put(tty);
906 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700907 }
908 }
909 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910}
911module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700913static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 .open = pc_open,
915 .close = pc_close,
916 .write = pc_write,
917 .write_room = pc_write_room,
918 .flush_buffer = pc_flush_buffer,
919 .chars_in_buffer = pc_chars_in_buffer,
920 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 .ioctl = pc_ioctl,
922 .set_termios = pc_set_termios,
923 .stop = pc_stop,
924 .start = pc_start,
925 .throttle = pc_throttle,
926 .unthrottle = pc_unthrottle,
927 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +0100928 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929};
930
Alan Cox6ed1dba2009-01-02 13:48:11 +0000931static const struct tty_port_operations epca_port_ops = {
932 .carrier_raised = epca_carrier_raised,
933 .raise_dtr_rts = epca_raise_dtr_rts,
934};
935
Alan Cox191260a2008-04-30 00:54:16 -0700936static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 return 0;
939}
940
941static struct tty_operations info_ops = {
942 .open = info_open,
943 .ioctl = info_ioctl,
944};
945
Alan Coxf2cf8e22005-09-06 15:16:44 -0700946static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700947{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 int crd;
949 struct board_info *bd;
950 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -0700951 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 int pci_boards_found, pci_count;
954
955 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 pc_driver = alloc_tty_driver(MAX_ALLOC);
958 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -0700959 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
961 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -0700962 if (!pc_info)
963 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700965 /*
966 * If epca_setup has not been ran by LILO set num_cards to defaults;
967 * copy board structure defined by digiConfig into drivers board
968 * structure. Note : If LILO has ran epca_setup then epca_setup will
969 * handle defining num_cards as well as copying the data into the board
970 * structure.
971 */
972 if (!liloconfig) {
973 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 nbdevs = NBDEVS;
975 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700976 memcpy(&boards, &static_boards,
977 sizeof(struct board_info) * NUMCARDS);
978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700980 /*
981 * Note : If lilo was used to configure the driver and the ignore
982 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
983 * will equal 0 at this point. This is okay; PCI cards will still be
984 * picked up if detected.
985 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700987 /*
988 * Set up interrupt, we will worry about memory allocation in
989 * post_fep_init.
990 */
Alan Cox191260a2008-04-30 00:54:16 -0700991 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700993 /*
994 * NOTE : This code assumes that the number of ports found in the
995 * boards array is correct. This could be wrong if the card in question
996 * is PCI (And therefore has no ports entry in the boards structure.)
997 * The rest of the information will be valid for PCI because the
998 * beginning of pc_init scans for PCI and determines i/o and base
999 * memory addresses. I am not sure if it is possible to read the number
1000 * of ports supported by the card prior to it being booted (Since that
1001 * is the state it is in when pc_init is run). Because it is not
1002 * possible to query the number of supported ports until after the card
1003 * has booted; we are required to calculate the card_ptrs as the card
1004 * is initialized (Inside post_fep_init). The negative thing about this
1005 * approach is that digiDload's call to GET_INFO will have a bad port
1006 * value. (Since this is called prior to post_fep_init.)
1007 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001009 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 pci_boards_found += init_PCI();
1011 num_cards += pci_boards_found;
1012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001014 pc_driver->name = "ttyD";
1015 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 pc_driver->minor_start = 0;
1017 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1018 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1019 pc_driver->init_termios = tty_std_termios;
1020 pc_driver->init_termios.c_iflag = 0;
1021 pc_driver->init_termios.c_oflag = 0;
1022 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1023 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001024 pc_driver->init_termios.c_ispeed = 9600;
1025 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001026 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 tty_set_operations(pc_driver, &pc_ops);
1028
1029 pc_info->owner = THIS_MODULE;
1030 pc_info->name = "digi_ctl";
1031 pc_info->major = DIGIINFOMAJOR;
1032 pc_info->minor_start = 0;
1033 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1034 pc_info->subtype = SERIAL_TYPE_INFO;
1035 pc_info->init_termios = tty_std_termios;
1036 pc_info->init_termios.c_iflag = 0;
1037 pc_info->init_termios.c_oflag = 0;
1038 pc_info->init_termios.c_lflag = 0;
1039 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001040 pc_info->init_termios.c_ispeed = 9600;
1041 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 pc_info->flags = TTY_DRIVER_REAL_RAW;
1043 tty_set_operations(pc_info, &info_ops);
1044
1045
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001046 for (crd = 0; crd < num_cards; crd++) {
1047 /*
1048 * This is where the appropriate memory handlers for the
1049 * hardware is set. Everything at runtime blindly jumps through
1050 * these vectors.
1051 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 /* defined in epcaconfig.h */
1054 bd = &boards[crd];
1055
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001056 switch (bd->type) {
1057 case PCXEM:
1058 case EISAXEM:
1059 bd->memwinon = pcxem_memwinon;
1060 bd->memwinoff = pcxem_memwinoff;
1061 bd->globalwinon = pcxem_globalwinon;
1062 bd->txwinon = pcxem_txwinon;
1063 bd->rxwinon = pcxem_rxwinon;
1064 bd->memoff = pcxem_memoff;
1065 bd->assertgwinon = dummy_assertgwinon;
1066 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 break;
1068
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001069 case PCIXEM:
1070 case PCIXRJ:
1071 case PCIXR:
1072 bd->memwinon = dummy_memwinon;
1073 bd->memwinoff = dummy_memwinoff;
1074 bd->globalwinon = dummy_globalwinon;
1075 bd->txwinon = dummy_txwinon;
1076 bd->rxwinon = dummy_rxwinon;
1077 bd->memoff = dummy_memoff;
1078 bd->assertgwinon = dummy_assertgwinon;
1079 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 break;
1081
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001082 case PCXE:
1083 case PCXEVE:
1084 bd->memwinon = pcxe_memwinon;
1085 bd->memwinoff = pcxe_memwinoff;
1086 bd->globalwinon = pcxe_globalwinon;
1087 bd->txwinon = pcxe_txwinon;
1088 bd->rxwinon = pcxe_rxwinon;
1089 bd->memoff = pcxe_memoff;
1090 bd->assertgwinon = dummy_assertgwinon;
1091 bd->assertmemoff = dummy_assertmemoff;
1092 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001094 case PCXI:
1095 case PC64XE:
1096 bd->memwinon = pcxi_memwinon;
1097 bd->memwinoff = pcxi_memwinoff;
1098 bd->globalwinon = pcxi_globalwinon;
1099 bd->txwinon = pcxi_txwinon;
1100 bd->rxwinon = pcxi_rxwinon;
1101 bd->memoff = pcxi_memoff;
1102 bd->assertgwinon = pcxi_assertgwinon;
1103 bd->assertmemoff = pcxi_assertmemoff;
1104 break;
1105
1106 default:
1107 break;
1108 }
1109
1110 /*
1111 * Some cards need a memory segment to be defined for use in
1112 * transmit and receive windowing operations. These boards are
1113 * listed in the below switch. In the case of the XI the amount
1114 * of memory on the board is variable so the memory_seg is also
1115 * variable. This code determines what they segment should be.
1116 */
1117 switch (bd->type) {
1118 case PCXE:
1119 case PCXEVE:
1120 case PC64XE:
1121 bd->memory_seg = 0xf000;
1122 break;
1123
1124 case PCXI:
1125 board_id = inb((int)bd->port);
1126 if ((board_id & 0x1) == 0x1) {
1127 /* it's an XI card */
1128 /* Is it a 64K board */
1129 if ((board_id & 0x30) == 0)
1130 bd->memory_seg = 0xf000;
1131
1132 /* Is it a 128K board */
1133 if ((board_id & 0x30) == 0x10)
1134 bd->memory_seg = 0xe000;
1135
1136 /* Is is a 256K board */
1137 if ((board_id & 0x30) == 0x20)
1138 bd->memory_seg = 0xc000;
1139
1140 /* Is it a 512K board */
1141 if ((board_id & 0x30) == 0x30)
1142 bd->memory_seg = 0x8000;
1143 } else
Alan Cox191260a2008-04-30 00:54:16 -07001144 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 -07001145 break;
1146 }
1147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Akinobu Mitadabad052006-10-17 00:10:28 -07001149 err = tty_register_driver(pc_driver);
1150 if (err) {
1151 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1152 goto out3;
1153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Akinobu Mitadabad052006-10-17 00:10:28 -07001155 err = tty_register_driver(pc_info);
1156 if (err) {
1157 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1158 goto out4;
1159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001161 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 init_timer(&epca_timer);
1163 epca_timer.function = epcapoll;
1164 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return 0;
1166
Akinobu Mitadabad052006-10-17 00:10:28 -07001167out4:
1168 tty_unregister_driver(pc_driver);
1169out3:
1170 put_tty_driver(pc_info);
1171out2:
1172 put_tty_driver(pc_driver);
1173out1:
1174 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001175}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001178{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001180 void __iomem *memaddr;
1181 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001183 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001184 struct channel *ch;
1185 int shrinkmem = 0, lowwater;
1186
1187 /*
1188 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1189 * responsible for setting up all the card specific stuff.
1190 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 bd = &boards[crd];
1192
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001193 /*
1194 * If this is a PCI board, get the port info. Remember PCI cards do not
1195 * have entries into the epcaconfig.h file, so we can't get the number
1196 * of ports from it. Unfortunetly, this means that anyone doing a
1197 * DIGI_GETINFO before the board has booted will get an invalid number
1198 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1199 * DIGI_INIT has been called will return the proper values.
1200 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001201 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001202 /*
1203 * Below we use XEMPORTS as a memory offset regardless of which
1204 * PCI card it is. This is because all of the supported PCI
1205 * cards have the same memory offset for the channel data. This
1206 * will have to be changed if we ever develop a PCI/XE card.
1207 * NOTE : The FEP manual states that the port offset is 0xC22
1208 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1209 * cards; not for the XEM, or CX series. On the PCI cards the
1210 * number of ports is determined by reading a ID PROM located
1211 * in the box attached to the card. The card can then determine
1212 * the index the id to determine the number of ports available.
1213 * (FYI - The id should be located at 0x1ac (And may use up to
1214 * 4 bytes if the box in question is a XEM or CX)).
1215 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001216 /* PCI cards are already remapped at this point ISA are not */
1217 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001218 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001220 } else {
1221 /* Fix up the mappings for ISA/EISA etc */
1222 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001223 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 if (crd != 0)
1227 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1228 else
1229 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1230
1231 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1233
Alan Coxf2cf8e22005-09-06 15:16:44 -07001234 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001236 /*
1237 * The below assignment will set bc to point at the BEGINING of the
1238 * cards channel structures. For 1 card there will be between 8 and 64
1239 * of these structures.
1240 */
Al Virobc9a5152005-09-15 22:53:28 +01001241 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001243 /*
1244 * The below assignment will set gd to point at the BEGINING of global
1245 * memory address 0xc00. The first data in that global memory actually
1246 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1247 */
Al Virobc9a5152005-09-15 22:53:28 +01001248 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001250 /*
1251 * XEPORTS (address 0xc22) points at the number of channels the card
1252 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1253 */
Alan Cox191260a2008-04-30 00:54:16 -07001254 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1255 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 shrinkmem = 1;
1257 if (bd->type < PCIXEM)
1258 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001259 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 memwinon(bd, 0);
1261
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001262 /*
1263 * Remember ch is the main drivers channels structure, while bc is the
1264 * cards channel structure.
1265 */
1266 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001267 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001268 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
Alan Cox9ae7b082008-10-13 10:32:09 +01001270 tty_port_init(&ch->port);
Alan Cox6ed1dba2009-01-02 13:48:11 +00001271 ch->port.ops - &epca_port_ops;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001272 ch->brdchan = bc;
1273 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001274 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001275 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Alan Coxf2cf8e22005-09-06 15:16:44 -07001277 spin_lock_irqsave(&epca_lock, flags);
1278 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001279 /*
1280 * Since some of the boards use different bitmaps for
1281 * their control signals we cannot hard code these
1282 * values and retain portability. We virtualize this
1283 * data here.
1284 */
1285 case EISAXEM:
1286 case PCXEM:
1287 case PCIXEM:
1288 case PCIXRJ:
1289 case PCIXR:
1290 ch->m_rts = 0x02;
1291 ch->m_dcd = 0x80;
1292 ch->m_dsr = 0x20;
1293 ch->m_cts = 0x10;
1294 ch->m_ri = 0x40;
1295 ch->m_dtr = 0x01;
1296 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001298 case PCXE:
1299 case PCXEVE:
1300 case PCXI:
1301 case PC64XE:
1302 ch->m_rts = 0x02;
1303 ch->m_dcd = 0x08;
1304 ch->m_dsr = 0x10;
1305 ch->m_cts = 0x20;
1306 ch->m_ri = 0x40;
1307 ch->m_dtr = 0x80;
1308 break;
1309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Alan Coxf2cf8e22005-09-06 15:16:44 -07001311 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 ch->dsr = ch->m_dcd;
1313 ch->dcd = ch->m_dsr;
1314 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001315 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 ch->dcd = ch->m_dcd;
1317 ch->dsr = ch->m_dsr;
1318 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001319
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 ch->boardnum = crd;
1321 ch->channelnum = i;
1322 ch->magic = EPCA_MAGIC;
Alan Cox3969ffb2009-01-02 13:48:04 +00001323 tty_port_tty_set(&ch->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Alan Coxf2cf8e22005-09-06 15:16:44 -07001325 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1327 shrinkmem = 0;
1328 }
1329
Al Virobc9a5152005-09-15 22:53:28 +01001330 tseg = readw(&bc->tseg);
1331 rseg = readw(&bc->rseg);
1332
Alan Coxf2cf8e22005-09-06 15:16:44 -07001333 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001334 case PCIXEM:
1335 case PCIXRJ:
1336 case PCIXR:
1337 /* Cover all the 2MEG cards */
1338 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1339 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1340 ch->txwin = FEPWIN | (tseg >> 11);
1341 ch->rxwin = FEPWIN | (rseg >> 11);
1342 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001344 case PCXEM:
1345 case EISAXEM:
1346 /* Cover all the 32K windowed cards */
1347 /* Mask equal to window size - 1 */
1348 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1349 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1350 ch->txwin = FEPWIN | (tseg >> 11);
1351 ch->rxwin = FEPWIN | (rseg >> 11);
1352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001354 case PCXEVE:
1355 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001356 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1357 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001358 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001359 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1360 & 0x1fff);
1361 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001362 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001364 case PCXI:
1365 case PC64XE:
1366 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1367 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1368 ch->txwin = ch->rxwin = 0;
1369 break;
1370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001373 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001376 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1379
1380 /* Set transmitter low water mark */
1381 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1382
1383 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1385
1386 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1388
Alan Coxf2cf8e22005-09-06 15:16:44 -07001389 writew(100, &bc->edelay);
1390 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001391
Alan Coxf2cf8e22005-09-06 15:16:44 -07001392 ch->startc = readb(&bc->startc);
1393 ch->stopc = readb(&bc->stopc);
1394 ch->startca = readb(&bc->startca);
1395 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 ch->fepcflag = 0;
1398 ch->fepiflag = 0;
1399 ch->fepoflag = 0;
1400 ch->fepstartc = 0;
1401 ch->fepstopc = 0;
1402 ch->fepstartca = 0;
1403 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001404
Alan Cox6ed1dba2009-01-02 13:48:11 +00001405 ch->port.close_delay = 50;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001406
1407 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001410 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001411 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1412 VERSION, board_desc[bd->type], (long)bd->port,
1413 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001415}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001418{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 unsigned long flags;
1420 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001421 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 struct channel *ch;
1423 struct board_info *bd;
1424
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001425 /*
1426 * This routine is called upon every timer interrupt. Even though the
1427 * Digi series cards are capable of generating interrupts this method
1428 * of non-looping polling is more efficient. This routine checks for
1429 * card generated events (Such as receive data, are transmit buffer
1430 * empty) and acts on those events.
1431 */
1432 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 bd = &boards[crd];
1434 ch = card_ptr[crd];
1435
1436 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001437 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001439 /*
1440 * assertmemoff is not needed here; indeed it is an empty
1441 * subroutine. It is being kept because future boards may need
1442 * this as well as some legacy boards.
1443 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001444 spin_lock_irqsave(&epca_lock, flags);
1445
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 assertmemoff(ch);
1447
1448 globalwinon(ch);
1449
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001450 /*
1451 * In this case head and tail actually refer to the event queue
1452 * not the transmit or receive queue.
1453 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001454 head = readw(&ch->mailbox->ein);
1455 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001457 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if (head != tail)
1459 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 memoff(ch);
1461
Alan Coxf2cf8e22005-09-06 15:16:44 -07001462 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001465}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
1467static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001468{
Al Virobc9a5152005-09-15 22:53:28 +01001469 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 struct channel *ch, *chan0;
1471 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001472 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001473 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001474 unsigned int tail, head;
1475 int event, channel;
1476 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001478 /*
1479 * This subroutine is called by epcapoll when an event is detected
1480 * in the event queue. This routine responds to those events.
1481 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 bd = &boards[crd];
1483
1484 chan0 = card_ptr[crd];
1485 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001487 while ((tail = readw(&chan0->mailbox->eout)) !=
1488 (head = readw(&chan0->mailbox->ein))) {
1489 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001491 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001493 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001495 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001496 /*
1497 * The two assignments below get the current modem status
1498 * (mstat) and the previous modem status (lstat). These are
1499 * useful becuase an event could signal a change in modem
1500 * signals itself.
1501 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001502 mstat = readb(eventbuf + 2);
1503 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001506 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (channel >= bd->numports)
1508 ch = chan0;
1509 bc = ch->brdchan;
1510 goto next;
1511 }
1512
Alan Cox191260a2008-04-30 00:54:16 -07001513 bc = ch->brdchan;
1514 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 goto next;
1516
Alan Cox3969ffb2009-01-02 13:48:04 +00001517 tty = tty_port_tty_get(&ch->port);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001518 if (event & DATA_IND) { /* Begin DATA_IND */
Alan Cox3969ffb2009-01-02 13:48:04 +00001519 receive_data(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 } /* End DATA_IND */
1522 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001523 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 ch->imodem = mstat;
Alan Cox6ed1dba2009-01-02 13:48:11 +00001526 if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
Alan Cox191260a2008-04-30 00:54:16 -07001527 /* We are now receiving dcd */
1528 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001529 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001530 else /* No dcd; hangup */
1531 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001533 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001534 if (tty) {
1535 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001537 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001538 tty_schedule_flip(tty);
1539 } else if (event & LOWTX_IND) {
1540 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 ch->statusflags &= ~LOWWAIT;
1542 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001543 }
1544 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001545 /* This event is generated by
1546 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001548 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 ch->statusflags &= ~EMPTYWAIT;
1550 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001551 }
1552 }
Alan Cox3969ffb2009-01-02 13:48:04 +00001553 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001554 }
Alan Cox191260a2008-04-30 00:54:16 -07001555next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001557 BUG_ON(!bc);
1558 writew(1, &bc->idata);
1559 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001562}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
1564static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001565 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001566{
Al Virobc9a5152005-09-15 22:53:28 +01001567 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 unsigned int head, cmdTail, cmdStart, cmdMax;
1569 long count;
1570 int n;
1571
1572 /* This is the routine in which commands may be passed to the card. */
1573
1574 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001578 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001580 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001581 /*
1582 * We do the addition below because we do not want a max pointer
1583 * relative to cmdStart. We want a max pointer that points at the
1584 * physical end of the command queue.
1585 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001586 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 memaddr = ch->board->re_map_membase;
1588
Alan Coxf2cf8e22005-09-06 15:16:44 -07001589 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001590 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1591 __LINE__, cmd, head);
1592 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1593 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 return;
1595 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001596 if (bytecmd) {
1597 writeb(cmd, memaddr + head + cmdStart + 0);
1598 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001600 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001602 writeb(byte2, memaddr + head + cmdStart + 3);
1603 } else {
1604 writeb(cmd, memaddr + head + cmdStart + 0);
1605 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1606 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001609 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 count = FEPTIMEOUT;
1611
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001612 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001614 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1616 return;
1617 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001618 head = readw(&ch->mailbox->cin);
1619 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001621 /*
1622 * Basically this will break when the FEP acknowledges the
1623 * command by incrementing cmdTail (Making it equal to head).
1624 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001626 break;
1627 }
1628}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001630/*
1631 * Digi products use fields in their channels structures that are very similar
1632 * to the c_cflag and c_iflag fields typically found in UNIX termios
1633 * structures. The below three routines allow mappings between these hardware
1634 * "flags" and their respective Linux flags.
1635 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 unsigned res = 0;
1639
Alan Coxf2cf8e22005-09-06 15:16:44 -07001640 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1642 res |= ((ch->m_cts) | (ch->m_rts));
1643 }
1644
1645 if (ch->digiext.digi_flags & RTSPACE)
1646 res |= ch->m_rts;
1647
1648 if (ch->digiext.digi_flags & DTRPACE)
1649 res |= ch->m_dtr;
1650
1651 if (ch->digiext.digi_flags & CTSPACE)
1652 res |= ch->m_cts;
1653
1654 if (ch->digiext.digi_flags & DSRPACE)
1655 res |= ch->dsr;
1656
1657 if (ch->digiext.digi_flags & DCDPACE)
1658 res |= ch->dcd;
1659
1660 if (res & (ch->m_rts))
1661 ch->digiext.digi_flags |= RTSPACE;
1662
1663 if (res & (ch->m_cts))
1664 ch->digiext.digi_flags |= CTSPACE;
1665
1666 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001667}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001670{
1671 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001672 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (ch->digiext.digi_flags & DIGI_AIXON)
1674 res |= IAIXON;
1675 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001676}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
1678static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001679{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001681 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001682 ch->digiext.digi_flags |= DIGI_FAST;
1683 /*
1684 * HUPCL bit is used by FEP to indicate fast baud table is to
1685 * be used.
1686 */
1687 res |= FEP_HUPCL;
1688 } else
1689 ch->digiext.digi_flags &= ~DIGI_FAST;
1690 /*
1691 * CBAUD has bit position 0x1000 set these days to indicate Linux
1692 * baud rate remap. Digi hardware can't handle the bit assignment.
1693 * (We use a different bit assignment for high speed.). Clear this
1694 * bit out.
1695 */
1696 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1697 /*
1698 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001699 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001700 * this is identical to the Linux implementation. However; Digi
1701 * supports one rate (76800) that Linux doesn't. This means that the
1702 * c_cflag entry that would normally mean 76800 for Digi actually means
1703 * 115200 under Linux. Without the below mapping, a stty 115200 would
1704 * only drive the board at 76800. Since the rate 230400 is also found
1705 * after 76800, the same problem afflicts us when we choose a rate of
1706 * 230400. Without the below modificiation stty 230400 would actually
1707 * give us 115200.
1708 *
1709 * There are two additional differences. The Linux value for CLOCAL
1710 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1711 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1712 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1713 * checked for a screened out prior to termios2digi_c returning. Since
1714 * CLOCAL isn't used by the board this can be ignored as long as the
1715 * returned value is used only by Digi hardware.
1716 */
1717 if (cflag & CBAUDEX) {
1718 /*
1719 * The below code is trying to guarantee that only baud rates
1720 * 115200 and 230400 are remapped. We use exclusive or because
1721 * the various baud rates share common bit positions and
1722 * therefore can't be tested for easily.
1723 */
1724 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001729}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
Alan Coxf2cf8e22005-09-06 15:16:44 -07001731/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001733{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001735 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001736 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 unsigned mval, hflow, cflag, iflag;
1738
1739 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001740 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741
1742 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001744 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1745 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001746 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001747 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001749 /*
1750 * Flush current transmit buffer by setting cmdTail pointer
1751 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1752 * buffer is empty.
1753 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1755 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001756 } else { /* Begin CBAUD not detected */
1757 /*
1758 * c_cflags have changed but that change had nothing to do with
1759 * BAUD. Propagate the change to the card.
1760 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001762 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 ch->fepcflag = cflag;
1764 /* Set baud rate, char size, stop bits, parity */
1765 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1766 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001767 /*
1768 * If the user has not forced CLOCAL and if the device is not a
1769 * CALLOUT device (Which is always CLOCAL) we set flags such
1770 * that the driver will wait on carrier detect.
1771 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 if (ts->c_cflag & CLOCAL)
Alan Cox6ed1dba2009-01-02 13:48:11 +00001773 clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 else
Alan Cox6ed1dba2009-01-02 13:48:11 +00001775 set_bit(ASYNC_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001780 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001782 /*
1783 * Command sets channels iflag structure on the board. Such
1784 * things as input soft flow control, handling of parity
1785 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001786 *
1787 * break handling, parity handling, input stripping,
1788 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001789 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1791 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001792 /*
1793 * Set the board mint value for this channel. This will cause hardware
1794 * events to be generated each time the DCD signal (Described in mint)
1795 * changes.
1796 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001797 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1799 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001800 writeb(0, &bc->mint);
1801 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001803 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001805 /*
1806 * Hard flow control has been selected but the board is not
1807 * using it. Activate hard flow control now.
1808 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 mval ^= ch->modemfake & (mval ^ ch->modem);
1812
Alan Coxf2cf8e22005-09-06 15:16:44 -07001813 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001815 /*
1816 * The below command sets the DTR and RTS mstat structure. If
1817 * hard flow control is NOT active these changes will drive the
1818 * output of the actual DTR and RTS lines. If hard flow control
1819 * is active, the changes will be saved in the mstat structure
1820 * and only asserted when hard flow control is turned off.
1821 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822
1823 /* First reset DTR & RTS; then set them */
1824 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1825 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001827 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 ch->fepstartc = ch->startc;
1829 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001830 /*
1831 * The XON / XOFF characters have changed; propagate these
1832 * changes to the card.
1833 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1835 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001836 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 ch->fepstartca = ch->startca;
1838 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001839 /*
1840 * Similar to the above, this time the auxilarly XON / XOFF
1841 * characters have changed; propagate these changes to the card.
1842 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1844 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001845}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
Alan Coxf2cf8e22005-09-06 15:16:44 -07001847/* Caller holds lock */
Alan Cox3969ffb2009-01-02 13:48:04 +00001848static void receive_data(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001849{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001851 struct ktermios *ts = NULL;
Al Virobc9a5152005-09-15 22:53:28 +01001852 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001853 int dataToRead, wrapgap, bytesAvailable;
1854 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001857 /*
1858 * This routine is called by doint when a receive data event has taken
1859 * place.
1860 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 if (ch->statusflags & RXSTOPPED)
1863 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (tty)
1865 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001867 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 wrapmask = ch->rxbufsize - 1;
1869
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001870 /*
1871 * Get the head and tail pointers to the receiver queue. Wrap the head
1872 * pointer if it has reached the end of the buffer.
1873 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001874 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001876 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
1878 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 if (bytesAvailable == 0)
1880 return;
1881
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001882 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07001883 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001884 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 return;
1886 }
1887
Alan Cox33f0f882006-01-09 20:54:13 -08001888 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 return;
1890
Alan Coxf2cf8e22005-09-06 15:16:44 -07001891 if (readb(&bc->orun)) {
1892 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07001893 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
1894 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08001895 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07001898 while (bytesAvailable > 0) {
1899 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001901 /*
1902 * Even if head has wrapped around only report the amount of
1903 * data to be equal to the size - tail. Remember memcpy can't
1904 * automaticly wrap around the receive buffer.
1905 */
Alan Cox191260a2008-04-30 00:54:16 -07001906 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
1907 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001908 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001909 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 if (dataToRead == 0)
1911 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001912 /*
1913 * Move data read from our card into the line disciplines
1914 * buffer for translation if necessary.
1915 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001916 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 tail = (tail + dataToRead) & wrapmask;
1918 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001921 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 /* Must be called with global data */
Alan Cox3969ffb2009-01-02 13:48:04 +00001923 tty_schedule_flip(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001924}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001926static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 unsigned int cmd, unsigned long arg)
1928{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001929 switch (cmd) {
1930 case DIGI_GETINFO:
1931 {
1932 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 int brd;
1934
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001935 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07001936 return -EFAULT;
1937 if (brd < 0 || brd >= num_cards || num_cards == 0)
1938 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 memset(&di, 0, sizeof(di));
1941
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001942 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 di.status = boards[brd].status;
1944 di.type = boards[brd].type ;
1945 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001946 /* Legacy fixups - just move along nothing to see */
1947 di.port = (unsigned char *)boards[brd].port ;
1948 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001950 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 return -EFAULT;
1952 break;
1953
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001956 case DIGI_POLLER:
1957 {
1958 int brd = arg & 0xff000000 >> 16;
1959 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Alan Coxf2cf8e22005-09-06 15:16:44 -07001961 if (brd < 0 || brd >= num_cards) {
1962 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001963 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001965 digi_poller_inhibited = state;
1966 break;
1967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001969 case DIGI_INIT:
1970 {
1971 /*
1972 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02001973 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001974 * responsible for setting the card to its initial
1975 * state and setting the drivers control fields to the
1976 * sutianle settings for the card in question.
1977 */
1978 int crd;
1979 for (crd = 0; crd < num_cards; crd++)
1980 post_fep_init(crd);
1981 break;
1982 }
1983 default:
1984 return -ENOTTY;
1985 }
1986 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989static int pc_tiocmget(struct tty_struct *tty, struct file *file)
1990{
Alan Coxc9f19e92009-01-02 13:47:26 +00001991 struct channel *ch = tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01001992 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 unsigned int mstat, mflag = 0;
1994 unsigned long flags;
1995
1996 if (ch)
1997 bc = ch->brdchan;
1998 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07001999 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
Alan Coxf2cf8e22005-09-06 15:16:44 -07002001 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002003 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002005 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
2007 if (mstat & ch->m_dtr)
2008 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 if (mstat & ch->m_rts)
2010 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (mstat & ch->m_cts)
2012 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 if (mstat & ch->dsr)
2014 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 if (mstat & ch->m_ri)
2016 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 if (mstat & ch->dcd)
2018 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return mflag;
2020}
2021
2022static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2023 unsigned int set, unsigned int clear)
2024{
Alan Coxc9f19e92009-01-02 13:47:26 +00002025 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 unsigned long flags;
2027
Alan Coxf2cf8e22005-09-06 15:16:44 -07002028 if (!ch)
2029 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Alan Coxf2cf8e22005-09-06 15:16:44 -07002031 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002033 * I think this modemfake stuff is broken. It doesn't correctly reflect
2034 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2035 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 */
2037 if (set & TIOCM_RTS) {
2038 ch->modemfake |= ch->m_rts;
2039 ch->modem |= ch->m_rts;
2040 }
2041 if (set & TIOCM_DTR) {
2042 ch->modemfake |= ch->m_dtr;
2043 ch->modem |= ch->m_dtr;
2044 }
2045 if (clear & TIOCM_RTS) {
2046 ch->modemfake |= ch->m_rts;
2047 ch->modem &= ~ch->m_rts;
2048 }
2049 if (clear & TIOCM_DTR) {
2050 ch->modemfake |= ch->m_dtr;
2051 ch->modem &= ~ch->m_dtr;
2052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002054 /*
2055 * The below routine generally sets up parity, baud, flow control
2056 * issues, etc.... It effect both control flags and input flags.
2057 */
Alan Cox191260a2008-04-30 00:54:16 -07002058 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002060 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 return 0;
2062}
2063
Alan Cox191260a2008-04-30 00:54:16 -07002064static int pc_ioctl(struct tty_struct *tty, struct file *file,
2065 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002066{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 unsigned long flags;
2069 unsigned int mflag, mstat;
2070 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002071 struct board_chan __iomem *bc;
Alan Coxc9f19e92009-01-02 13:47:26 +00002072 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 if (ch)
2076 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002077 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002078 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002079 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002080 case TIOCMODG:
2081 mflag = pc_tiocmget(tty, file);
2082 if (put_user(mflag, (unsigned long __user *)argp))
2083 return -EFAULT;
2084 break;
2085 case TIOCMODS:
2086 if (get_user(mstat, (unsigned __user *)argp))
2087 return -EFAULT;
2088 return pc_tiocmset(tty, file, mstat, ~mstat);
2089 case TIOCSDTR:
2090 spin_lock_irqsave(&epca_lock, flags);
2091 ch->omodem |= ch->m_dtr;
2092 globalwinon(ch);
2093 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2094 memoff(ch);
2095 spin_unlock_irqrestore(&epca_lock, flags);
2096 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002098 case TIOCCDTR:
2099 spin_lock_irqsave(&epca_lock, flags);
2100 ch->omodem &= ~ch->m_dtr;
2101 globalwinon(ch);
2102 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2103 memoff(ch);
2104 spin_unlock_irqrestore(&epca_lock, flags);
2105 break;
2106 case DIGI_GETA:
2107 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2108 return -EFAULT;
2109 break;
2110 case DIGI_SETAW:
2111 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002112 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002113 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002114 /* Setup an event to indicate when the transmit
2115 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002116 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002117 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002118 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002119 tty_wait_until_sent(tty, 0);
2120 } else {
2121 /* ldisc lock already held in ioctl */
Alan Coxa352def2008-07-16 21:53:12 +01002122 if (tty->ldisc.ops->flush_buffer)
2123 tty->ldisc.ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002124 }
Alan Cox37925e02008-04-30 00:53:17 -07002125 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002126 /* Fall Thru */
2127 case DIGI_SETA:
2128 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2129 return -EFAULT;
2130
2131 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2132 ch->dcd = ch->m_dsr;
2133 ch->dsr = ch->m_dcd;
2134 } else {
2135 ch->dcd = ch->m_dcd;
2136 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002138
2139 spin_lock_irqsave(&epca_lock, flags);
2140 globalwinon(ch);
2141
2142 /*
2143 * The below routine generally sets up parity, baud, flow
2144 * control issues, etc.... It effect both control flags and
2145 * input flags.
2146 */
Alan Cox191260a2008-04-30 00:54:16 -07002147 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002148 memoff(ch);
2149 spin_unlock_irqrestore(&epca_lock, flags);
2150 break;
2151
2152 case DIGI_GETFLOW:
2153 case DIGI_GETAFLOW:
2154 spin_lock_irqsave(&epca_lock, flags);
2155 globalwinon(ch);
2156 if (cmd == DIGI_GETFLOW) {
2157 dflow.startc = readb(&bc->startc);
2158 dflow.stopc = readb(&bc->stopc);
2159 } else {
2160 dflow.startc = readb(&bc->startca);
2161 dflow.stopc = readb(&bc->stopca);
2162 }
2163 memoff(ch);
2164 spin_unlock_irqrestore(&epca_lock, flags);
2165
2166 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2167 return -EFAULT;
2168 break;
2169
2170 case DIGI_SETAFLOW:
2171 case DIGI_SETFLOW:
2172 if (cmd == DIGI_SETFLOW) {
2173 startc = ch->startc;
2174 stopc = ch->stopc;
2175 } else {
2176 startc = ch->startca;
2177 stopc = ch->stopca;
2178 }
2179
2180 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2181 return -EFAULT;
2182
Alan Cox191260a2008-04-30 00:54:16 -07002183 if (dflow.startc != startc || dflow.stopc != stopc) {
2184 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002185 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 globalwinon(ch);
2187
Alan Coxf2cf8e22005-09-06 15:16:44 -07002188 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002189 ch->fepstartc = ch->startc = dflow.startc;
2190 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002191 fepcmd(ch, SONOFFC, ch->fepstartc,
2192 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002193 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002194 ch->fepstartca = ch->startca = dflow.startc;
2195 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002196 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2197 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 }
2199
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002200 if (ch->statusflags & TXSTOPPED)
2201 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002203 memoff(ch);
2204 spin_unlock_irqrestore(&epca_lock, flags);
2205 } /* End if setflow toggled */
2206 break;
2207 default:
2208 return -ENOIOCTLCMD;
2209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002211}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Alan Cox606d0992006-12-08 02:38:45 -08002213static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002214{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 struct channel *ch;
2216 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002217 /*
2218 * verifyChannel returns the channel from the tty struct if it is
2219 * valid. This serves as a sanity check.
2220 */
Alan Cox191260a2008-04-30 00:54:16 -07002221 ch = verifyChannel(tty);
2222
2223 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002224 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 globalwinon(ch);
2226 epcaparam(tty, ch);
2227 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002228 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
2230 if ((old_termios->c_cflag & CRTSCTS) &&
2231 ((tty->termios->c_cflag & CRTSCTS) == 0))
2232 tty->hw_stopped = 0;
2233
2234 if (!(old_termios->c_cflag & CLOCAL) &&
2235 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002236 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002239}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240
David Howellsc4028952006-11-22 14:57:56 +00002241static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002242{
David Howellsc4028952006-11-22 14:57:56 +00002243 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002245 if (ch && ch->magic == EPCA_MAGIC) {
Alan Cox3969ffb2009-01-02 13:48:04 +00002246 struct tty_struct *tty = tty_port_tty_get(&ch->port);;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
Alan Coxf2cf8e22005-09-06 15:16:44 -07002248 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002249 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002250 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002251 wake_up_interruptible(&ch->port.open_wait);
Alan Cox6ed1dba2009-01-02 13:48:11 +00002252 clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002255 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002256 }
2257}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002259/*
2260 * pc_stop and pc_start provide software flow control to the routine and the
2261 * pc_ioctl routine.
2262 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002264{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 struct channel *ch;
2266 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002267 /*
2268 * verifyChannel returns the channel from the tty struct if it is
2269 * valid. This serves as a sanity check.
2270 */
Alan Cox191260a2008-04-30 00:54:16 -07002271 ch = verifyChannel(tty);
2272 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002273 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002274 if ((ch->statusflags & TXSTOPPED) == 0) {
2275 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 ch->statusflags |= TXSTOPPED;
2280 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002282 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002283 }
2284}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
2286static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002287{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002289 /*
2290 * verifyChannel returns the channel from the tty struct if it is
2291 * valid. This serves as a sanity check.
2292 */
Alan Cox191260a2008-04-30 00:54:16 -07002293 ch = verifyChannel(tty);
2294 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002296 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002297 /* Just in case output was resumed because of a change
2298 in Digi-flow */
2299 if (ch->statusflags & TXSTOPPED) {
2300 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002301 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 globalwinon(ch);
2303 bc = ch->brdchan;
2304 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002305 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 ch->statusflags &= ~TXSTOPPED;
2309 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002311 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002312 }
2313}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002315/*
2316 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2317 * resume) the receipt of data into the kernels receive buffers. The exact
2318 * occurrence of this depends on the size of the kernels receive buffer and
2319 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2320 * more details.
2321 */
2322static void pc_throttle(struct tty_struct *tty)
2323{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 struct channel *ch;
2325 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002326 /*
2327 * verifyChannel returns the channel from the tty struct if it is
2328 * valid. This serves as a sanity check.
2329 */
Alan Cox191260a2008-04-30 00:54:16 -07002330 ch = verifyChannel(tty);
2331 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002332 spin_lock_irqsave(&epca_lock, flags);
2333 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 globalwinon(ch);
2335 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 ch->statusflags |= RXSTOPPED;
2337 memoff(ch);
2338 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002339 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002340 }
2341}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
2343static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002344{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 struct channel *ch;
2346 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002347 /*
2348 * verifyChannel returns the channel from the tty struct if it is
2349 * valid. This serves as a sanity check.
2350 */
Alan Cox191260a2008-04-30 00:54:16 -07002351 ch = verifyChannel(tty);
2352 if (ch != NULL) {
2353 /* Just in case output was resumed because of a change
2354 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002355 spin_lock_irqsave(&epca_lock, flags);
2356 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 ch->statusflags &= ~RXSTOPPED;
2360 memoff(ch);
2361 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002362 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002363 }
2364}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Alan Coxdcbf1282008-07-22 11:18:12 +01002366static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002367{
Alan Coxc9f19e92009-01-02 13:47:26 +00002368 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 unsigned long flags;
2370
Alan Coxdcbf1282008-07-22 11:18:12 +01002371 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002372 msec = 0xFFFF;
2373 else if (msec > 0xFFFE)
2374 msec = 0xFFFE;
2375 else if (msec < 1)
2376 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002377
Alan Coxf2cf8e22005-09-06 15:16:44 -07002378 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002380 /*
2381 * Maybe I should send an infinite break here, schedule() for msec
2382 * amount of time, and then stop the break. This way, the user can't
2383 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2384 * an ioctl()) more than once in msec amount of time.
2385 * Try this for now...
2386 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2388 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002389 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002390 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002391}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
Alan Coxf2cf8e22005-09-06 15:16:44 -07002393/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002395{
Al Virobc9a5152005-09-15 22:53:28 +01002396 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 globalwinon(ch);
2399 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002400 /*
2401 * When set the iempty flag request a event to be generated when the
2402 * transmit buffer is empty (If there is no BREAK in progress).
2403 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002404 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002406}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
David Howells88e88242008-07-22 11:20:45 +01002408#ifndef MODULE
2409static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002410{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 struct board_info board;
2412 int index, loop, last;
2413 char *temp, *t2;
2414 unsigned len;
2415
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002416 /*
2417 * If this routine looks a little strange it is because it is only
2418 * called if a LILO append command is given to boot the kernel with
2419 * parameters. In this way, we can provide the user a method of
2420 * changing his board configuration without rebuilding the kernel.
2421 */
2422 if (!liloconfig)
2423 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 memset(&board, 0, sizeof(board));
2426
2427 /* Assume the data is int first, later we can change it */
2428 /* I think that array position 0 of ints holds the number of args */
2429 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002430 switch (index) { /* Begin parse switch */
2431 case 1:
2432 board.status = ints[index];
2433 /*
2434 * We check for 2 (As opposed to 1; because 2 is a flag
2435 * instructing the driver to ignore epcaconfig.) For
2436 * this reason we check for 2.
2437 */
Alan Cox191260a2008-04-30 00:54:16 -07002438 if (board.status == 2) {
2439 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002440 nbdevs = 0;
2441 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002443 } /* End ignore epcaconfig as well as lilo cmd line */
2444
2445 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002446 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2447 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002448 invalid_lilo_config = 1;
2449 setup_error_code |= INVALID_BOARD_STATUS;
2450 return;
2451 }
2452 last = index;
2453 break;
2454 case 2:
2455 board.type = ints[index];
2456 if (board.type >= PCIXEM) {
2457 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2458 invalid_lilo_config = 1;
2459 setup_error_code |= INVALID_BOARD_TYPE;
2460 return;
2461 }
2462 last = index;
2463 break;
2464 case 3:
2465 board.altpin = ints[index];
2466 if (board.altpin > 1) {
2467 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2468 invalid_lilo_config = 1;
2469 setup_error_code |= INVALID_ALTPIN;
2470 return;
2471 }
2472 last = index;
2473 break;
2474
2475 case 4:
2476 board.numports = ints[index];
2477 if (board.numports < 2 || board.numports > 256) {
2478 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2479 invalid_lilo_config = 1;
2480 setup_error_code |= INVALID_NUM_PORTS;
2481 return;
2482 }
2483 nbdevs += board.numports;
2484 last = index;
2485 break;
2486
2487 case 5:
2488 board.port = ints[index];
2489 if (ints[index] <= 0) {
2490 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2491 invalid_lilo_config = 1;
2492 setup_error_code |= INVALID_PORT_BASE;
2493 return;
2494 }
2495 last = index;
2496 break;
2497
2498 case 6:
2499 board.membase = ints[index];
2500 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002501 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2502 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002503 invalid_lilo_config = 1;
2504 setup_error_code |= INVALID_MEM_BASE;
2505 return;
2506 }
2507 last = index;
2508 break;
2509
2510 default:
2511 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2512 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
2514 } /* End parse switch */
2515
Alan Coxf2cf8e22005-09-06 15:16:44 -07002516 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 /* find the next comma or terminator */
2518 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 /* While string is not null, and a comma hasn't been found */
2520 while (*temp && (*temp != ','))
2521 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 if (!*temp)
2523 temp = NULL;
2524 else
2525 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 /* Set index to the number of args + 1 */
2527 index = last + 1;
2528
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002529 switch (index) {
2530 case 1:
2531 len = strlen(str);
2532 if (strncmp("Disable", str, len) == 0)
2533 board.status = 0;
2534 else if (strncmp("Enable", str, len) == 0)
2535 board.status = 1;
2536 else {
2537 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2538 invalid_lilo_config = 1;
2539 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002541 }
2542 last = index;
2543 break;
2544
2545 case 2:
2546 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2547 if (strcmp(board_desc[loop], str) == 0)
2548 break;
2549 /*
2550 * If the index incremented above refers to a
2551 * legitamate board type set it here.
2552 */
2553 if (index < EPCA_NUM_TYPES)
2554 board.type = loop;
2555 else {
2556 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2557 invalid_lilo_config = 1;
2558 setup_error_code |= INVALID_BOARD_TYPE;
2559 return;
2560 }
2561 last = index;
2562 break;
2563
2564 case 3:
2565 len = strlen(str);
2566 if (strncmp("Disable", str, len) == 0)
2567 board.altpin = 0;
2568 else if (strncmp("Enable", str, len) == 0)
2569 board.altpin = 1;
2570 else {
2571 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2572 invalid_lilo_config = 1;
2573 setup_error_code |= INVALID_ALTPIN;
2574 return;
2575 }
2576 last = index;
2577 break;
2578
2579 case 4:
2580 t2 = str;
2581 while (isdigit(*t2))
2582 t2++;
2583
2584 if (*t2) {
2585 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2586 invalid_lilo_config = 1;
2587 setup_error_code |= INVALID_NUM_PORTS;
2588 return;
2589 }
2590
2591 /*
2592 * There is not a man page for simple_strtoul but the
2593 * code can be found in vsprintf.c. The first argument
2594 * is the string to translate (To an unsigned long
2595 * obviously), the second argument can be the address
2596 * of any character variable or a NULL. If a variable
2597 * is given, the end pointer of the string will be
2598 * stored in that variable; if a NULL is given the end
2599 * pointer will not be returned. The last argument is
2600 * the base to use. If a 0 is indicated, the routine
2601 * will attempt to determine the proper base by looking
2602 * at the values prefix (A '0' for octal, a 'x' for
2603 * hex, etc ... If a value is given it will use that
2604 * value as the base.
2605 */
2606 board.numports = simple_strtoul(str, NULL, 0);
2607 nbdevs += board.numports;
2608 last = index;
2609 break;
2610
2611 case 5:
2612 t2 = str;
2613 while (isxdigit(*t2))
2614 t2++;
2615
2616 if (*t2) {
2617 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2618 invalid_lilo_config = 1;
2619 setup_error_code |= INVALID_PORT_BASE;
2620 return;
2621 }
2622
2623 board.port = simple_strtoul(str, NULL, 16);
2624 last = index;
2625 break;
2626
2627 case 6:
2628 t2 = str;
2629 while (isxdigit(*t2))
2630 t2++;
2631
2632 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002633 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002634 invalid_lilo_config = 1;
2635 setup_error_code |= INVALID_MEM_BASE;
2636 return;
2637 }
2638 board.membase = simple_strtoul(str, NULL, 16);
2639 last = index;
2640 break;
2641 default:
2642 printk(KERN_ERR "epca: Too many string parms\n");
2643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
2645 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 } /* End while there is a string arg */
2647
Alan Coxf2cf8e22005-09-06 15:16:44 -07002648 if (last < 6) {
2649 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 return;
2651 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002655 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002657 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2658 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002661}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
David Howells88e88242008-07-22 11:20:45 +01002663static int __init epca_real_setup(char *str)
2664{
2665 int ints[11];
2666
2667 epca_setup(get_options(str, 11, ints), ints);
2668 return 1;
2669}
2670
2671__setup("digiepca", epca_real_setup);
2672#endif
2673
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674enum epic_board_types {
2675 brd_xr = 0,
2676 brd_xem,
2677 brd_cx,
2678 brd_xrj,
2679};
2680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681/* indexed directly by epic_board_types enum */
2682static struct {
2683 unsigned char board_type;
2684 unsigned bar_idx; /* PCI base address region */
2685} epca_info_tbl[] = {
2686 { PCIXR, 0, },
2687 { PCIXEM, 0, },
2688 { PCICX, 0, },
2689 { PCIXRJ, 2, },
2690};
2691
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002692static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 const struct pci_device_id *ent)
2694{
2695 static int board_num = -1;
2696 int board_idx, info_idx = ent->driver_data;
2697 unsigned long addr;
2698
2699 if (pci_enable_device(pdev))
2700 return -EIO;
2701
2702 board_num++;
2703 board_idx = board_num + num_cards;
2704 if (board_idx >= MAXBOARDS)
2705 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002706
Alan Cox191260a2008-04-30 00:54:16 -07002707 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002709 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 epca_info_tbl[info_idx].bar_idx);
2711 goto err_out;
2712 }
2713
2714 boards[board_idx].status = ENABLED;
2715 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2716 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002717 boards[board_idx].port = addr + PCI_IO_OFFSET;
2718 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719
Alan Cox191260a2008-04-30 00:54:16 -07002720 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2721 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 0x200000, addr + PCI_IO_OFFSET);
2723 goto err_out;
2724 }
2725
Alan Cox191260a2008-04-30 00:54:16 -07002726 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2727 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002729 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 0x200000, addr + PCI_IO_OFFSET);
2731 goto err_out_free_pciio;
2732 }
2733
Alan Cox191260a2008-04-30 00:54:16 -07002734 if (!request_mem_region(addr, 0x200000, "epca")) {
2735 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 0x200000, addr);
2737 goto err_out_free_iounmap;
2738 }
2739
Alan Cox191260a2008-04-30 00:54:16 -07002740 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002742 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 0x200000, addr + PCI_IO_OFFSET);
2744 goto err_out_free_memregion;
2745 }
2746
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002747 /*
2748 * I don't know what the below does, but the hardware guys say its
2749 * required on everything except PLX (In this case XRJ).
2750 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002752 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 pci_write_config_byte(pdev, 0x46, 0);
2754 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002755
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 return 0;
2757
2758err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002759 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002761 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002763 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764err_out:
2765 return -ENODEV;
2766}
2767
2768
2769static struct pci_device_id epca_pci_tbl[] = {
2770 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2771 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2772 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2773 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2774 { 0, }
2775};
2776
2777MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2778
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002779static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002780{
Alan Cox191260a2008-04-30 00:54:16 -07002781 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 epca_driver.name = "epca";
2783 epca_driver.id_table = epca_pci_tbl;
2784 epca_driver.probe = epca_init_one;
2785
2786 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002787}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788
2789MODULE_LICENSE("GPL");