blob: 17b044a71e026fc8c943de8ea5bf64c852abc75c [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>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040033#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/serial.h>
35#include <linux/delay.h>
36#include <linux/ctype.h>
37#include <linux/tty.h>
38#include <linux/tty_flip.h>
39#include <linux/slab.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040040#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/ioport.h>
42#include <linux/interrupt.h>
Alan Cox191260a2008-04-30 00:54:16 -070043#include <linux/uaccess.h>
44#include <linux/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070045#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/pci.h>
47#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070048
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50#include "digi1.h"
51#include "digiFep1.h"
52#include "epca.h"
53#include "epcaconfig.h"
54
Alan Coxf2cf8e22005-09-06 15:16:44 -070055#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070058#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60
61#define MAXCARDS 7
62#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
63
64#define PFX "epca: "
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static int nbdevs, num_cards, liloconfig;
67static int digi_poller_inhibited = 1 ;
68
69static int setup_error_code;
70static int invalid_lilo_config;
71
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070072/*
73 * The ISA boards do window flipping into the same spaces so its only sane with
Alan Coxd1c815e2009-01-02 13:47:58 +000074 * a single lock. It's still pretty efficient. This lock guards the hardware
75 * and the tty_port lock guards the kernel side stuff like use counts. Take
76 * this lock inside the port lock if you must take both.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070077 */
Ingo Molnar34af9462006-06-27 02:53:55 -070078static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070079
Alan Cox191260a2008-04-30 00:54:16 -070080/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
81 to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct board_info boards[MAXBOARDS];
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static struct tty_driver *pc_driver;
85static struct tty_driver *pc_info;
86
87/* ------------------ Begin Digi specific structures -------------------- */
88
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070089/*
90 * digi_channels represents an array of structures that keep track of each
91 * channel of the Digi product. Information such as transmit and receive
92 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
93 * here. This structure is NOT used to overlay the cards physical channel
94 * structure.
95 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070096static struct channel digi_channels[MAX_ALLOC];
97
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070098/*
99 * card_ptr is an array used to hold the address of the first channel structure
100 * of each card. This array will hold the addresses of various channels located
101 * in digi_channels.
102 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static struct channel *card_ptr[MAXCARDS];
104
105static struct timer_list epca_timer;
106
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700107/*
108 * Begin generic memory functions. These functions will be alias (point at)
109 * more specific functions dependent on the board being configured.
110 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700111static void memwinon(struct board_info *b, unsigned int win);
112static void memwinoff(struct board_info *b, unsigned int win);
113static void globalwinon(struct channel *ch);
114static void rxwinon(struct channel *ch);
115static void txwinon(struct channel *ch);
116static void memoff(struct channel *ch);
117static void assertgwinon(struct channel *ch);
118static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120/* ---- Begin more 'specific' memory functions for cx_like products --- */
121
Alan Coxf2cf8e22005-09-06 15:16:44 -0700122static void pcxem_memwinon(struct board_info *b, unsigned int win);
123static void pcxem_memwinoff(struct board_info *b, unsigned int win);
124static void pcxem_globalwinon(struct channel *ch);
125static void pcxem_rxwinon(struct channel *ch);
126static void pcxem_txwinon(struct channel *ch);
127static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128
129/* ------ Begin more 'specific' memory functions for the pcxe ------- */
130
Alan Coxf2cf8e22005-09-06 15:16:44 -0700131static void pcxe_memwinon(struct board_info *b, unsigned int win);
132static void pcxe_memwinoff(struct board_info *b, unsigned int win);
133static void pcxe_globalwinon(struct channel *ch);
134static void pcxe_rxwinon(struct channel *ch);
135static void pcxe_txwinon(struct channel *ch);
136static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
139/* Note : pc64xe and pcxi share the same windowing routines */
140
Alan Coxf2cf8e22005-09-06 15:16:44 -0700141static void pcxi_memwinon(struct board_info *b, unsigned int win);
142static void pcxi_memwinoff(struct board_info *b, unsigned int win);
143static void pcxi_globalwinon(struct channel *ch);
144static void pcxi_rxwinon(struct channel *ch);
145static void pcxi_txwinon(struct channel *ch);
146static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148/* - Begin 'specific' do nothing memory functions needed for some cards - */
149
Alan Coxf2cf8e22005-09-06 15:16:44 -0700150static void dummy_memwinon(struct board_info *b, unsigned int win);
151static void dummy_memwinoff(struct board_info *b, unsigned int win);
152static void dummy_globalwinon(struct channel *ch);
153static void dummy_rxwinon(struct channel *ch);
154static void dummy_txwinon(struct channel *ch);
155static void dummy_memoff(struct channel *ch);
156static void dummy_assertgwinon(struct channel *ch);
157static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Alan Coxf2cf8e22005-09-06 15:16:44 -0700159static struct channel *verifyChannel(struct tty_struct *);
160static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static void epca_error(int, char *);
162static void pc_close(struct tty_struct *, struct file *);
Alan Coxd1c815e2009-01-02 13:47:58 +0000163static void shutdown(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int pc_write_room(struct tty_struct *);
166static int pc_chars_in_buffer(struct tty_struct *);
167static void pc_flush_buffer(struct tty_struct *);
168static void pc_flush_chars(struct tty_struct *);
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;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700425 /*
426 * verifyChannel returns the channel from the tty struct if it is
427 * valid. This serves as a sanity check.
428 */
Alan Cox191260a2008-04-30 00:54:16 -0700429 ch = verifyChannel(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000430 if (ch == NULL)
431 return;
432 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Alan Cox6ed1dba2009-01-02 13:48:11 +0000434 if (tty_port_close_start(port, tty, filp) == 0)
Alan Coxd1c815e2009-01-02 13:47:58 +0000435 return;
Alan Coxd1c815e2009-01-02 13:47:58 +0000436
Alan Coxd1c815e2009-01-02 13:47:58 +0000437 pc_flush_buffer(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000438 shutdown(ch, tty);
439
Alan Cox6ed1dba2009-01-02 13:48:11 +0000440 tty_port_close_end(port, tty);
441 ch->event = 0; /* FIXME: review ch->event locking */
Alan Cox3969ffb2009-01-02 13:48:04 +0000442 tty_port_tty_set(port, NULL);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700443}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
Alan Coxd1c815e2009-01-02 13:47:58 +0000445static void shutdown(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700446{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +0100448 struct board_chan __iomem *bc;
Alan Coxd1c815e2009-01-02 13:47:58 +0000449 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Alan Coxd1c815e2009-01-02 13:47:58 +0000451 if (!(port->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return;
453
Alan Coxf2cf8e22005-09-06 15:16:44 -0700454 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
Alan Coxf2cf8e22005-09-06 15:16:44 -0700456 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 bc = ch->brdchan;
458
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700459 /*
460 * In order for an event to be generated on the receipt of data the
461 * idata flag must be set. Since we are shutting down, this is not
462 * necessary clear this flag.
463 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700465 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700467 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700468 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
470 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 memoff(ch);
473
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700474 /*
475 * The channel has officialy been closed. The next time it is opened it
476 * will have to reinitialized. Set a flag to indicate this.
477 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* Prevent future Digi programmed interrupts from coming active */
Alan Coxd1c815e2009-01-02 13:47:58 +0000479 port->flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700480 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700481}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700484{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000486
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700487 /*
488 * verifyChannel returns the channel from the tty struct if it is
489 * valid. This serves as a sanity check.
490 */
Alan Cox191260a2008-04-30 00:54:16 -0700491 ch = verifyChannel(tty);
492 if (ch != NULL) {
Alan Cox978e5952008-04-30 00:53:59 -0700493 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 tty_ldisc_flush(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000495 shutdown(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Alan Coxd1c815e2009-01-02 13:47:58 +0000497 ch->event = 0; /* FIXME: review locking of ch->event */
Alan Cox6ed1dba2009-01-02 13:48:11 +0000498 tty_port_hangup(&ch->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700499 }
500}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700502static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700503 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700504{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700505 unsigned int head, tail;
506 int dataLen;
507 int size;
508 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 struct channel *ch;
510 unsigned long flags;
511 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100512 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700514 /*
515 * pc_write is primarily called directly by the kernel routine
516 * tty_write (Though it can also be called by put_char) found in
517 * tty_io.c. pc_write is passed a line discipline buffer where the data
518 * to be written out is stored. The line discipline implementation
519 * itself is done at the kernel level and is not brought into the
520 * driver.
521 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700523 /*
524 * verifyChannel returns the channel from the tty struct if it is
525 * valid. This serves as a sanity check.
526 */
Alan Cox191260a2008-04-30 00:54:16 -0700527 ch = verifyChannel(tty);
528 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return 0;
530
531 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 bc = ch->brdchan;
533 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Alan Coxf2cf8e22005-09-06 15:16:44 -0700536 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 globalwinon(ch);
538
Alan Coxf2cf8e22005-09-06 15:16:44 -0700539 head = readw(&bc->tin) & (size - 1);
540 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Alan Coxf2cf8e22005-09-06 15:16:44 -0700542 if (tail != readw(&bc->tout))
543 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 tail &= (size - 1);
545
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700546 if (head >= tail) {
547 /* head has not wrapped */
548 /*
549 * remain (much like dataLen above) represents the total amount
550 * of space available on the card for data. Here dataLen
551 * represents the space existing between the head pointer and
552 * the end of buffer. This is important because a memcpy cannot
553 * be told to automatically wrap around when it hits the buffer
554 * end.
555 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 dataLen = size - head;
557 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700558 } else {
559 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 remain = tail - head - 1;
561 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700562 }
563 /*
564 * Check the space on the card. If we have more data than space; reduce
565 * the amount of data to fit the space.
566 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700569 while (bytesAvailable > 0) {
570 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700572 /*
573 * If head is not wrapped, the below will make sure the first
574 * data copy fills to the end of card buffer.
575 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100577 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 buf += dataLen;
579 head += dataLen;
580 amountCopied += dataLen;
581 bytesAvailable -= dataLen;
582
Alan Coxf2cf8e22005-09-06 15:16:44 -0700583 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 head = 0;
585 dataLen = tail;
586 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 ch->statusflags |= TXBUSY;
589 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700590 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Alan Coxf2cf8e22005-09-06 15:16:44 -0700592 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700594 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
596 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700597 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700598 return amountCopied;
599}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700602{
Alan Cox191260a2008-04-30 00:54:16 -0700603 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 struct channel *ch;
605 unsigned long flags;
606 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100607 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700608 /*
609 * verifyChannel returns the channel from the tty struct if it is
610 * valid. This serves as a sanity check.
611 */
Alan Cox191260a2008-04-30 00:54:16 -0700612 ch = verifyChannel(tty);
613 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700614 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 globalwinon(ch);
616
617 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700618 head = readw(&bc->tin) & (ch->txbufsize - 1);
619 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Alan Coxf2cf8e22005-09-06 15:16:44 -0700621 if (tail != readw(&bc->tout))
622 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 /* Wrap tail if necessary */
624 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700625 remain = tail - head - 1;
626 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 remain += ch->txbufsize;
628
Alan Coxf2cf8e22005-09-06 15:16:44 -0700629 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700631 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
633 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700634 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 /* Return how much room is left on card */
637 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700638}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700641{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 int chars;
643 unsigned int ctail, head, tail;
644 int remain;
645 unsigned long flags;
646 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100647 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700648 /*
649 * verifyChannel returns the channel from the tty struct if it is
650 * valid. This serves as a sanity check.
651 */
Alan Cox191260a2008-04-30 00:54:16 -0700652 ch = verifyChannel(tty);
653 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700654 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Alan Coxf2cf8e22005-09-06 15:16:44 -0700656 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 globalwinon(ch);
658
659 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700660 tail = readw(&bc->tout);
661 head = readw(&bc->tin);
662 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Alan Cox191260a2008-04-30 00:54:16 -0700664 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
665 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700667 else { /* Begin if some space on the card has been used */
668 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700670 /*
671 * The logic here is basically opposite of the above
672 * pc_write_room here we are finding the amount of bytes in the
673 * buffer filled. Not the amount of bytes empty.
674 */
Alan Cox191260a2008-04-30 00:54:16 -0700675 remain = tail - head - 1;
676 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 remain += ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700679 /*
680 * Make it possible to wakeup anything waiting for output in
681 * tty_ioctl.c, etc.
682 *
683 * If not already set. Setup an event to indicate when the
684 * transmit buffer empties.
685 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700687 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700690 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700692 return chars;
693}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700696{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 unsigned int tail;
698 unsigned long flags;
699 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100700 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700701 /*
702 * verifyChannel returns the channel from the tty struct if it is
703 * valid. This serves as a sanity check.
704 */
Alan Cox191260a2008-04-30 00:54:16 -0700705 ch = verifyChannel(tty);
706 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return;
708
Alan Coxf2cf8e22005-09-06 15:16:44 -0700709 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700712 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700716 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700718}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700721{
722 struct channel *ch;
723 /*
724 * verifyChannel returns the channel from the tty struct if it is
725 * valid. This serves as a sanity check.
726 */
Alan Cox191260a2008-04-30 00:54:16 -0700727 ch = verifyChannel(tty);
728 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700730 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700731 /*
732 * If not already set and the transmitter is busy setup an
733 * event to indicate when the transmit empties.
734 */
Alan Cox191260a2008-04-30 00:54:16 -0700735 if ((ch->statusflags & TXBUSY) &&
736 !(ch->statusflags & EMPTYWAIT))
737 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700738 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700740}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Alan Cox6ed1dba2009-01-02 13:48:11 +0000742static int epca_carrier_raised(struct tty_port *port)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700743{
Alan Cox6ed1dba2009-01-02 13:48:11 +0000744 struct channel *ch = container_of(port, struct channel, port);
745 if (ch->imodem & ch->dcd)
746 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700748}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Alan Coxfcc8ac12009-06-11 12:24:17 +0100750static void epca_dtr_rts(struct tty_port *port, int onoff)
Alan Cox6ed1dba2009-01-02 13:48:11 +0000751{
752}
753
Alan Cox191260a2008-04-30 00:54:16 -0700754static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700755{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000757 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 unsigned long flags;
759 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100760 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700761 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700764 if (line < 0 || line >= nbdevs)
765 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 ch = &digi_channels[line];
Alan Coxd1c815e2009-01-02 13:47:58 +0000768 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 boardnum = ch->boardnum;
770
771 /* Check status of board configured in system. */
772
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700773 /*
Frederik Schwarzer0211a9c2008-12-29 22:14:56 +0100774 * I check to see if the epca_setup routine detected a user error. It
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700775 * might be better to put this in pc_init, but for the moment it goes
776 * here.
777 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700778 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700780 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700782 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700784 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700786 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700788 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700790 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700792 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700794 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 tty->driver_data = NULL; /* Mark this device as 'down' */
796 return(-ENODEV);
797 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700798
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700799 bc = ch->brdchan;
800 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700802 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804
Alan Coxd1c815e2009-01-02 13:47:58 +0000805 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700806 /*
807 * Every time a channel is opened, increment a counter. This is
808 * necessary because we do not wish to flush and shutdown the channel
809 * until the last app holding the channel open, closes it.
810 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000811 port->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700812 /*
813 * Set a kernel structures pointer to our local channel structure. This
814 * way we can get to it when passed only a tty struct.
815 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 tty->driver_data = ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000817 port->tty = tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700818 /*
819 * If this is the first time the channel has been opened, initialize
820 * the tty->termios struct otherwise let pc_close handle it.
821 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000822 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 globalwinon(ch);
824 ch->statusflags = 0;
825
826 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100827 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700829 /*
830 * Set receive head and tail ptrs to each other. This indicates no data
831 * available to read.
832 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700833 head = readw(&bc->rin);
834 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 /* Set the channels associated tty structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700838 /*
839 * The below routine generally sets up parity, baud, flow control
840 * issues, etc.... It effect both control flags and input flags.
841 */
Alan Cox191260a2008-04-30 00:54:16 -0700842 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000844 spin_unlock(&epca_lock);
845 port->flags |= ASYNC_INITIALIZED;
846 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Alan Cox6ed1dba2009-01-02 13:48:11 +0000848 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700851 /*
852 * Set this again in case a hangup set it to zero while this open() was
853 * waiting for the line...
854 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000855 spin_lock_irqsave(&port->lock, flags);
856 port->tty = tty;
857 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700860 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000862 spin_unlock(&epca_lock);
863 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700867static int __init epca_module_init(void)
868{
869 return pc_init();
870}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875static void __exit epca_module_exit(void)
876{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 int count, crd;
878 struct board_info *bd;
879 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 del_timer_sync(&epca_timer);
882
Alan Cox191260a2008-04-30 00:54:16 -0700883 if (tty_unregister_driver(pc_driver) ||
884 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700885 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return;
887 }
888 put_tty_driver(pc_driver);
889 put_tty_driver(pc_info);
890
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700891 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700893 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
895 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700896 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700897 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700898 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox3969ffb2009-01-02 13:48:04 +0000899 struct tty_struct *tty = tty_port_tty_get(&ch->port);
900 if (tty) {
901 tty_hangup(tty);
902 tty_kref_put(tty);
903 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700904 }
905 }
906 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907}
908module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700910static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 .open = pc_open,
912 .close = pc_close,
913 .write = pc_write,
914 .write_room = pc_write_room,
915 .flush_buffer = pc_flush_buffer,
916 .chars_in_buffer = pc_chars_in_buffer,
917 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 .ioctl = pc_ioctl,
919 .set_termios = pc_set_termios,
920 .stop = pc_stop,
921 .start = pc_start,
922 .throttle = pc_throttle,
923 .unthrottle = pc_unthrottle,
924 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +0100925 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926};
927
Alan Cox6ed1dba2009-01-02 13:48:11 +0000928static const struct tty_port_operations epca_port_ops = {
929 .carrier_raised = epca_carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +0100930 .dtr_rts = epca_dtr_rts,
Alan Cox6ed1dba2009-01-02 13:48:11 +0000931};
932
Alan Cox191260a2008-04-30 00:54:16 -0700933static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 return 0;
936}
937
Alexey Dobriyan1cceefd2009-10-03 00:12:06 +0400938static const struct tty_operations info_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 .open = info_open,
940 .ioctl = info_ioctl,
941};
942
Alan Coxf2cf8e22005-09-06 15:16:44 -0700943static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700944{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 int crd;
946 struct board_info *bd;
947 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -0700948 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 int pci_boards_found, pci_count;
951
952 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 pc_driver = alloc_tty_driver(MAX_ALLOC);
955 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -0700956 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -0700959 if (!pc_info)
960 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700962 /*
963 * If epca_setup has not been ran by LILO set num_cards to defaults;
964 * copy board structure defined by digiConfig into drivers board
965 * structure. Note : If LILO has ran epca_setup then epca_setup will
966 * handle defining num_cards as well as copying the data into the board
967 * structure.
968 */
969 if (!liloconfig) {
970 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 nbdevs = NBDEVS;
972 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700973 memcpy(&boards, &static_boards,
974 sizeof(struct board_info) * NUMCARDS);
975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700977 /*
978 * Note : If lilo was used to configure the driver and the ignore
979 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
980 * will equal 0 at this point. This is okay; PCI cards will still be
981 * picked up if detected.
982 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700984 /*
985 * Set up interrupt, we will worry about memory allocation in
986 * post_fep_init.
987 */
Alan Cox191260a2008-04-30 00:54:16 -0700988 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700990 /*
991 * NOTE : This code assumes that the number of ports found in the
992 * boards array is correct. This could be wrong if the card in question
993 * is PCI (And therefore has no ports entry in the boards structure.)
994 * The rest of the information will be valid for PCI because the
995 * beginning of pc_init scans for PCI and determines i/o and base
996 * memory addresses. I am not sure if it is possible to read the number
997 * of ports supported by the card prior to it being booted (Since that
998 * is the state it is in when pc_init is run). Because it is not
999 * possible to query the number of supported ports until after the card
1000 * has booted; we are required to calculate the card_ptrs as the card
1001 * is initialized (Inside post_fep_init). The negative thing about this
1002 * approach is that digiDload's call to GET_INFO will have a bad port
1003 * value. (Since this is called prior to post_fep_init.)
1004 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001006 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 pci_boards_found += init_PCI();
1008 num_cards += pci_boards_found;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001011 pc_driver->name = "ttyD";
1012 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 pc_driver->minor_start = 0;
1014 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1015 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1016 pc_driver->init_termios = tty_std_termios;
1017 pc_driver->init_termios.c_iflag = 0;
1018 pc_driver->init_termios.c_oflag = 0;
1019 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1020 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001021 pc_driver->init_termios.c_ispeed = 9600;
1022 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001023 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 tty_set_operations(pc_driver, &pc_ops);
1025
1026 pc_info->owner = THIS_MODULE;
1027 pc_info->name = "digi_ctl";
1028 pc_info->major = DIGIINFOMAJOR;
1029 pc_info->minor_start = 0;
1030 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1031 pc_info->subtype = SERIAL_TYPE_INFO;
1032 pc_info->init_termios = tty_std_termios;
1033 pc_info->init_termios.c_iflag = 0;
1034 pc_info->init_termios.c_oflag = 0;
1035 pc_info->init_termios.c_lflag = 0;
1036 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001037 pc_info->init_termios.c_ispeed = 9600;
1038 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 pc_info->flags = TTY_DRIVER_REAL_RAW;
1040 tty_set_operations(pc_info, &info_ops);
1041
1042
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001043 for (crd = 0; crd < num_cards; crd++) {
1044 /*
1045 * This is where the appropriate memory handlers for the
1046 * hardware is set. Everything at runtime blindly jumps through
1047 * these vectors.
1048 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050 /* defined in epcaconfig.h */
1051 bd = &boards[crd];
1052
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001053 switch (bd->type) {
1054 case PCXEM:
1055 case EISAXEM:
1056 bd->memwinon = pcxem_memwinon;
1057 bd->memwinoff = pcxem_memwinoff;
1058 bd->globalwinon = pcxem_globalwinon;
1059 bd->txwinon = pcxem_txwinon;
1060 bd->rxwinon = pcxem_rxwinon;
1061 bd->memoff = pcxem_memoff;
1062 bd->assertgwinon = dummy_assertgwinon;
1063 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 break;
1065
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001066 case PCIXEM:
1067 case PCIXRJ:
1068 case PCIXR:
1069 bd->memwinon = dummy_memwinon;
1070 bd->memwinoff = dummy_memwinoff;
1071 bd->globalwinon = dummy_globalwinon;
1072 bd->txwinon = dummy_txwinon;
1073 bd->rxwinon = dummy_rxwinon;
1074 bd->memoff = dummy_memoff;
1075 bd->assertgwinon = dummy_assertgwinon;
1076 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 break;
1078
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001079 case PCXE:
1080 case PCXEVE:
1081 bd->memwinon = pcxe_memwinon;
1082 bd->memwinoff = pcxe_memwinoff;
1083 bd->globalwinon = pcxe_globalwinon;
1084 bd->txwinon = pcxe_txwinon;
1085 bd->rxwinon = pcxe_rxwinon;
1086 bd->memoff = pcxe_memoff;
1087 bd->assertgwinon = dummy_assertgwinon;
1088 bd->assertmemoff = dummy_assertmemoff;
1089 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001091 case PCXI:
1092 case PC64XE:
1093 bd->memwinon = pcxi_memwinon;
1094 bd->memwinoff = pcxi_memwinoff;
1095 bd->globalwinon = pcxi_globalwinon;
1096 bd->txwinon = pcxi_txwinon;
1097 bd->rxwinon = pcxi_rxwinon;
1098 bd->memoff = pcxi_memoff;
1099 bd->assertgwinon = pcxi_assertgwinon;
1100 bd->assertmemoff = pcxi_assertmemoff;
1101 break;
1102
1103 default:
1104 break;
1105 }
1106
1107 /*
1108 * Some cards need a memory segment to be defined for use in
1109 * transmit and receive windowing operations. These boards are
1110 * listed in the below switch. In the case of the XI the amount
1111 * of memory on the board is variable so the memory_seg is also
1112 * variable. This code determines what they segment should be.
1113 */
1114 switch (bd->type) {
1115 case PCXE:
1116 case PCXEVE:
1117 case PC64XE:
1118 bd->memory_seg = 0xf000;
1119 break;
1120
1121 case PCXI:
1122 board_id = inb((int)bd->port);
1123 if ((board_id & 0x1) == 0x1) {
1124 /* it's an XI card */
1125 /* Is it a 64K board */
1126 if ((board_id & 0x30) == 0)
1127 bd->memory_seg = 0xf000;
1128
1129 /* Is it a 128K board */
1130 if ((board_id & 0x30) == 0x10)
1131 bd->memory_seg = 0xe000;
1132
1133 /* Is is a 256K board */
1134 if ((board_id & 0x30) == 0x20)
1135 bd->memory_seg = 0xc000;
1136
1137 /* Is it a 512K board */
1138 if ((board_id & 0x30) == 0x30)
1139 bd->memory_seg = 0x8000;
1140 } else
Alan Cox191260a2008-04-30 00:54:16 -07001141 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 -07001142 break;
1143 }
1144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Akinobu Mitadabad052006-10-17 00:10:28 -07001146 err = tty_register_driver(pc_driver);
1147 if (err) {
1148 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1149 goto out3;
1150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Akinobu Mitadabad052006-10-17 00:10:28 -07001152 err = tty_register_driver(pc_info);
1153 if (err) {
1154 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1155 goto out4;
1156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001158 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 init_timer(&epca_timer);
1160 epca_timer.function = epcapoll;
1161 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 return 0;
1163
Akinobu Mitadabad052006-10-17 00:10:28 -07001164out4:
1165 tty_unregister_driver(pc_driver);
1166out3:
1167 put_tty_driver(pc_info);
1168out2:
1169 put_tty_driver(pc_driver);
1170out1:
1171 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001172}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
1174static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001175{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001177 void __iomem *memaddr;
1178 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001180 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001181 struct channel *ch;
1182 int shrinkmem = 0, lowwater;
1183
1184 /*
1185 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1186 * responsible for setting up all the card specific stuff.
1187 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 bd = &boards[crd];
1189
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001190 /*
1191 * If this is a PCI board, get the port info. Remember PCI cards do not
1192 * have entries into the epcaconfig.h file, so we can't get the number
1193 * of ports from it. Unfortunetly, this means that anyone doing a
1194 * DIGI_GETINFO before the board has booted will get an invalid number
1195 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1196 * DIGI_INIT has been called will return the proper values.
1197 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001198 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001199 /*
1200 * Below we use XEMPORTS as a memory offset regardless of which
1201 * PCI card it is. This is because all of the supported PCI
1202 * cards have the same memory offset for the channel data. This
1203 * will have to be changed if we ever develop a PCI/XE card.
1204 * NOTE : The FEP manual states that the port offset is 0xC22
1205 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1206 * cards; not for the XEM, or CX series. On the PCI cards the
1207 * number of ports is determined by reading a ID PROM located
1208 * in the box attached to the card. The card can then determine
1209 * the index the id to determine the number of ports available.
1210 * (FYI - The id should be located at 0x1ac (And may use up to
1211 * 4 bytes if the box in question is a XEM or CX)).
1212 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001213 /* PCI cards are already remapped at this point ISA are not */
1214 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001215 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001217 } else {
1218 /* Fix up the mappings for ISA/EISA etc */
1219 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001220 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223 if (crd != 0)
1224 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1225 else
1226 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1227
1228 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1230
Alan Coxf2cf8e22005-09-06 15:16:44 -07001231 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001233 /*
1234 * The below assignment will set bc to point at the BEGINING of the
1235 * cards channel structures. For 1 card there will be between 8 and 64
1236 * of these structures.
1237 */
Al Virobc9a5152005-09-15 22:53:28 +01001238 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001240 /*
1241 * The below assignment will set gd to point at the BEGINING of global
1242 * memory address 0xc00. The first data in that global memory actually
1243 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1244 */
Al Virobc9a5152005-09-15 22:53:28 +01001245 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001247 /*
1248 * XEPORTS (address 0xc22) points at the number of channels the card
1249 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1250 */
Alan Cox191260a2008-04-30 00:54:16 -07001251 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1252 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 shrinkmem = 1;
1254 if (bd->type < PCIXEM)
1255 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001256 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 memwinon(bd, 0);
1258
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001259 /*
1260 * Remember ch is the main drivers channels structure, while bc is the
1261 * cards channel structure.
1262 */
1263 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001264 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001265 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Alan Cox9ae7b082008-10-13 10:32:09 +01001267 tty_port_init(&ch->port);
Alan Coxc1314a42009-01-02 13:48:17 +00001268 ch->port.ops = &epca_port_ops;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001269 ch->brdchan = bc;
1270 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001271 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001272 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Alan Coxf2cf8e22005-09-06 15:16:44 -07001274 spin_lock_irqsave(&epca_lock, flags);
1275 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001276 /*
1277 * Since some of the boards use different bitmaps for
1278 * their control signals we cannot hard code these
1279 * values and retain portability. We virtualize this
1280 * data here.
1281 */
1282 case EISAXEM:
1283 case PCXEM:
1284 case PCIXEM:
1285 case PCIXRJ:
1286 case PCIXR:
1287 ch->m_rts = 0x02;
1288 ch->m_dcd = 0x80;
1289 ch->m_dsr = 0x20;
1290 ch->m_cts = 0x10;
1291 ch->m_ri = 0x40;
1292 ch->m_dtr = 0x01;
1293 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001295 case PCXE:
1296 case PCXEVE:
1297 case PCXI:
1298 case PC64XE:
1299 ch->m_rts = 0x02;
1300 ch->m_dcd = 0x08;
1301 ch->m_dsr = 0x10;
1302 ch->m_cts = 0x20;
1303 ch->m_ri = 0x40;
1304 ch->m_dtr = 0x80;
1305 break;
1306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307
Alan Coxf2cf8e22005-09-06 15:16:44 -07001308 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 ch->dsr = ch->m_dcd;
1310 ch->dcd = ch->m_dsr;
1311 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001312 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 ch->dcd = ch->m_dcd;
1314 ch->dsr = ch->m_dsr;
1315 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 ch->boardnum = crd;
1318 ch->channelnum = i;
1319 ch->magic = EPCA_MAGIC;
Alan Cox3969ffb2009-01-02 13:48:04 +00001320 tty_port_tty_set(&ch->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
Alan Coxf2cf8e22005-09-06 15:16:44 -07001322 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1324 shrinkmem = 0;
1325 }
1326
Al Virobc9a5152005-09-15 22:53:28 +01001327 tseg = readw(&bc->tseg);
1328 rseg = readw(&bc->rseg);
1329
Alan Coxf2cf8e22005-09-06 15:16:44 -07001330 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001331 case PCIXEM:
1332 case PCIXRJ:
1333 case PCIXR:
1334 /* Cover all the 2MEG cards */
1335 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1336 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1337 ch->txwin = FEPWIN | (tseg >> 11);
1338 ch->rxwin = FEPWIN | (rseg >> 11);
1339 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001341 case PCXEM:
1342 case EISAXEM:
1343 /* Cover all the 32K windowed cards */
1344 /* Mask equal to window size - 1 */
1345 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1346 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1347 ch->txwin = FEPWIN | (tseg >> 11);
1348 ch->rxwin = FEPWIN | (rseg >> 11);
1349 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001351 case PCXEVE:
1352 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001353 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1354 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001355 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001356 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1357 & 0x1fff);
1358 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001359 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001361 case PCXI:
1362 case PC64XE:
1363 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1364 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1365 ch->txwin = ch->rxwin = 0;
1366 break;
1367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
1369 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001370 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001373 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1376
1377 /* Set transmitter low water mark */
1378 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1379
1380 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1382
1383 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1385
Alan Coxf2cf8e22005-09-06 15:16:44 -07001386 writew(100, &bc->edelay);
1387 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001388
Alan Coxf2cf8e22005-09-06 15:16:44 -07001389 ch->startc = readb(&bc->startc);
1390 ch->stopc = readb(&bc->stopc);
1391 ch->startca = readb(&bc->startca);
1392 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001393
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 ch->fepcflag = 0;
1395 ch->fepiflag = 0;
1396 ch->fepoflag = 0;
1397 ch->fepstartc = 0;
1398 ch->fepstopc = 0;
1399 ch->fepstartca = 0;
1400 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001401
Alan Cox6ed1dba2009-01-02 13:48:11 +00001402 ch->port.close_delay = 50;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001403
1404 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001407 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001408 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1409 VERSION, board_desc[bd->type], (long)bd->port,
1410 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001412}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
1414static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001415{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 unsigned long flags;
1417 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001418 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 struct channel *ch;
1420 struct board_info *bd;
1421
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001422 /*
1423 * This routine is called upon every timer interrupt. Even though the
1424 * Digi series cards are capable of generating interrupts this method
1425 * of non-looping polling is more efficient. This routine checks for
1426 * card generated events (Such as receive data, are transmit buffer
1427 * empty) and acts on those events.
1428 */
1429 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 bd = &boards[crd];
1431 ch = card_ptr[crd];
1432
1433 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001434 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001436 /*
1437 * assertmemoff is not needed here; indeed it is an empty
1438 * subroutine. It is being kept because future boards may need
1439 * this as well as some legacy boards.
1440 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001441 spin_lock_irqsave(&epca_lock, flags);
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 assertmemoff(ch);
1444
1445 globalwinon(ch);
1446
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001447 /*
1448 * In this case head and tail actually refer to the event queue
1449 * not the transmit or receive queue.
1450 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001451 head = readw(&ch->mailbox->ein);
1452 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001454 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (head != tail)
1456 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 memoff(ch);
1458
Alan Coxf2cf8e22005-09-06 15:16:44 -07001459 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001462}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
1464static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001465{
Al Virobc9a5152005-09-15 22:53:28 +01001466 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 struct channel *ch, *chan0;
1468 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001469 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001470 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001471 unsigned int tail, head;
1472 int event, channel;
1473 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001475 /*
1476 * This subroutine is called by epcapoll when an event is detected
1477 * in the event queue. This routine responds to those events.
1478 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 bd = &boards[crd];
1480
1481 chan0 = card_ptr[crd];
1482 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001484 while ((tail = readw(&chan0->mailbox->eout)) !=
1485 (head = readw(&chan0->mailbox->ein))) {
1486 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001488 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001490 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001492 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001493 /*
1494 * The two assignments below get the current modem status
1495 * (mstat) and the previous modem status (lstat). These are
1496 * useful becuase an event could signal a change in modem
1497 * signals itself.
1498 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001499 mstat = readb(eventbuf + 2);
1500 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001503 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if (channel >= bd->numports)
1505 ch = chan0;
1506 bc = ch->brdchan;
1507 goto next;
1508 }
1509
Alan Cox191260a2008-04-30 00:54:16 -07001510 bc = ch->brdchan;
1511 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 goto next;
1513
Alan Cox3969ffb2009-01-02 13:48:04 +00001514 tty = tty_port_tty_get(&ch->port);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001515 if (event & DATA_IND) { /* Begin DATA_IND */
Alan Cox3969ffb2009-01-02 13:48:04 +00001516 receive_data(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 } /* End DATA_IND */
1519 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001520 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 ch->imodem = mstat;
Jiri Slabyc3301a52009-06-11 12:41:05 +01001523 if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
Alan Cox191260a2008-04-30 00:54:16 -07001524 /* We are now receiving dcd */
1525 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001526 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001527 else /* No dcd; hangup */
1528 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001530 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001531 if (tty) {
1532 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001534 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001535 tty_schedule_flip(tty);
1536 } else if (event & LOWTX_IND) {
1537 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 ch->statusflags &= ~LOWWAIT;
1539 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001540 }
1541 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001542 /* This event is generated by
1543 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001545 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 ch->statusflags &= ~EMPTYWAIT;
1547 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001548 }
1549 }
Alan Cox3969ffb2009-01-02 13:48:04 +00001550 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001551 }
Alan Cox191260a2008-04-30 00:54:16 -07001552next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001554 BUG_ON(!bc);
1555 writew(1, &bc->idata);
1556 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001559}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
1561static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001562 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001563{
Al Virobc9a5152005-09-15 22:53:28 +01001564 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 unsigned int head, cmdTail, cmdStart, cmdMax;
1566 long count;
1567 int n;
1568
1569 /* This is the routine in which commands may be passed to the card. */
1570
1571 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001575 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001577 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001578 /*
1579 * We do the addition below because we do not want a max pointer
1580 * relative to cmdStart. We want a max pointer that points at the
1581 * physical end of the command queue.
1582 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001583 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 memaddr = ch->board->re_map_membase;
1585
Alan Coxf2cf8e22005-09-06 15:16:44 -07001586 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001587 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1588 __LINE__, cmd, head);
1589 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1590 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 return;
1592 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001593 if (bytecmd) {
1594 writeb(cmd, memaddr + head + cmdStart + 0);
1595 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001597 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001599 writeb(byte2, memaddr + head + cmdStart + 3);
1600 } else {
1601 writeb(cmd, memaddr + head + cmdStart + 0);
1602 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1603 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001606 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 count = FEPTIMEOUT;
1608
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001609 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001611 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1613 return;
1614 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001615 head = readw(&ch->mailbox->cin);
1616 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001618 /*
1619 * Basically this will break when the FEP acknowledges the
1620 * command by incrementing cmdTail (Making it equal to head).
1621 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001623 break;
1624 }
1625}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001627/*
1628 * Digi products use fields in their channels structures that are very similar
1629 * to the c_cflag and c_iflag fields typically found in UNIX termios
1630 * structures. The below three routines allow mappings between these hardware
1631 * "flags" and their respective Linux flags.
1632 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001634{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 unsigned res = 0;
1636
Alan Coxf2cf8e22005-09-06 15:16:44 -07001637 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1639 res |= ((ch->m_cts) | (ch->m_rts));
1640 }
1641
1642 if (ch->digiext.digi_flags & RTSPACE)
1643 res |= ch->m_rts;
1644
1645 if (ch->digiext.digi_flags & DTRPACE)
1646 res |= ch->m_dtr;
1647
1648 if (ch->digiext.digi_flags & CTSPACE)
1649 res |= ch->m_cts;
1650
1651 if (ch->digiext.digi_flags & DSRPACE)
1652 res |= ch->dsr;
1653
1654 if (ch->digiext.digi_flags & DCDPACE)
1655 res |= ch->dcd;
1656
1657 if (res & (ch->m_rts))
1658 ch->digiext.digi_flags |= RTSPACE;
1659
1660 if (res & (ch->m_cts))
1661 ch->digiext.digi_flags |= CTSPACE;
1662
1663 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001664}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001667{
1668 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001669 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (ch->digiext.digi_flags & DIGI_AIXON)
1671 res |= IAIXON;
1672 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001673}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001676{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001678 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001679 ch->digiext.digi_flags |= DIGI_FAST;
1680 /*
1681 * HUPCL bit is used by FEP to indicate fast baud table is to
1682 * be used.
1683 */
1684 res |= FEP_HUPCL;
1685 } else
1686 ch->digiext.digi_flags &= ~DIGI_FAST;
1687 /*
1688 * CBAUD has bit position 0x1000 set these days to indicate Linux
1689 * baud rate remap. Digi hardware can't handle the bit assignment.
1690 * (We use a different bit assignment for high speed.). Clear this
1691 * bit out.
1692 */
1693 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1694 /*
1695 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001696 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001697 * this is identical to the Linux implementation. However; Digi
1698 * supports one rate (76800) that Linux doesn't. This means that the
1699 * c_cflag entry that would normally mean 76800 for Digi actually means
1700 * 115200 under Linux. Without the below mapping, a stty 115200 would
1701 * only drive the board at 76800. Since the rate 230400 is also found
1702 * after 76800, the same problem afflicts us when we choose a rate of
1703 * 230400. Without the below modificiation stty 230400 would actually
1704 * give us 115200.
1705 *
1706 * There are two additional differences. The Linux value for CLOCAL
1707 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1708 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1709 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1710 * checked for a screened out prior to termios2digi_c returning. Since
1711 * CLOCAL isn't used by the board this can be ignored as long as the
1712 * returned value is used only by Digi hardware.
1713 */
1714 if (cflag & CBAUDEX) {
1715 /*
1716 * The below code is trying to guarantee that only baud rates
1717 * 115200 and 230400 are remapped. We use exclusive or because
1718 * the various baud rates share common bit positions and
1719 * therefore can't be tested for easily.
1720 */
1721 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001726}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
Alan Coxf2cf8e22005-09-06 15:16:44 -07001728/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001730{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001732 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001733 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 unsigned mval, hflow, cflag, iflag;
1735
1736 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001737 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001741 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1742 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001743 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001744 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001746 /*
1747 * Flush current transmit buffer by setting cmdTail pointer
1748 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1749 * buffer is empty.
1750 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1752 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001753 } else { /* Begin CBAUD not detected */
1754 /*
1755 * c_cflags have changed but that change had nothing to do with
1756 * BAUD. Propagate the change to the card.
1757 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001759 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 ch->fepcflag = cflag;
1761 /* Set baud rate, char size, stop bits, parity */
1762 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1763 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001764 /*
1765 * If the user has not forced CLOCAL and if the device is not a
1766 * CALLOUT device (Which is always CLOCAL) we set flags such
1767 * that the driver will wait on carrier detect.
1768 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 if (ts->c_cflag & CLOCAL)
Jiri Slabyc3301a52009-06-11 12:41:05 +01001770 clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 else
Jiri Slabyc3301a52009-06-11 12:41:05 +01001772 set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001777 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001779 /*
1780 * Command sets channels iflag structure on the board. Such
1781 * things as input soft flow control, handling of parity
1782 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001783 *
1784 * break handling, parity handling, input stripping,
1785 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001786 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1788 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001789 /*
1790 * Set the board mint value for this channel. This will cause hardware
1791 * events to be generated each time the DCD signal (Described in mint)
1792 * changes.
1793 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001794 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1796 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001797 writeb(0, &bc->mint);
1798 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001800 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001802 /*
1803 * Hard flow control has been selected but the board is not
1804 * using it. Activate hard flow control now.
1805 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 mval ^= ch->modemfake & (mval ^ ch->modem);
1809
Alan Coxf2cf8e22005-09-06 15:16:44 -07001810 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001812 /*
1813 * The below command sets the DTR and RTS mstat structure. If
1814 * hard flow control is NOT active these changes will drive the
1815 * output of the actual DTR and RTS lines. If hard flow control
1816 * is active, the changes will be saved in the mstat structure
1817 * and only asserted when hard flow control is turned off.
1818 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
1820 /* First reset DTR & RTS; then set them */
1821 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1822 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001824 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 ch->fepstartc = ch->startc;
1826 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001827 /*
1828 * The XON / XOFF characters have changed; propagate these
1829 * changes to the card.
1830 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1832 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001833 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 ch->fepstartca = ch->startca;
1835 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001836 /*
1837 * Similar to the above, this time the auxilarly XON / XOFF
1838 * characters have changed; propagate these changes to the card.
1839 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1841 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001842}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Alan Coxf2cf8e22005-09-06 15:16:44 -07001844/* Caller holds lock */
Alan Cox3969ffb2009-01-02 13:48:04 +00001845static void receive_data(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001846{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001848 struct ktermios *ts = NULL;
Al Virobc9a5152005-09-15 22:53:28 +01001849 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001850 int dataToRead, wrapgap, bytesAvailable;
1851 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001854 /*
1855 * This routine is called by doint when a receive data event has taken
1856 * place.
1857 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if (ch->statusflags & RXSTOPPED)
1860 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 if (tty)
1862 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001864 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 wrapmask = ch->rxbufsize - 1;
1866
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001867 /*
1868 * Get the head and tail pointers to the receiver queue. Wrap the head
1869 * pointer if it has reached the end of the buffer.
1870 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001871 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001873 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (bytesAvailable == 0)
1877 return;
1878
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001879 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07001880 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001881 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 return;
1883 }
1884
Alan Cox33f0f882006-01-09 20:54:13 -08001885 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return;
1887
Alan Coxf2cf8e22005-09-06 15:16:44 -07001888 if (readb(&bc->orun)) {
1889 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07001890 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
1891 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08001892 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07001895 while (bytesAvailable > 0) {
1896 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001898 /*
1899 * Even if head has wrapped around only report the amount of
1900 * data to be equal to the size - tail. Remember memcpy can't
1901 * automaticly wrap around the receive buffer.
1902 */
Alan Cox191260a2008-04-30 00:54:16 -07001903 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
1904 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001905 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001906 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 if (dataToRead == 0)
1908 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001909 /*
1910 * Move data read from our card into the line disciplines
1911 * buffer for translation if necessary.
1912 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001913 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 tail = (tail + dataToRead) & wrapmask;
1915 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001918 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 /* Must be called with global data */
Alan Cox3969ffb2009-01-02 13:48:04 +00001920 tty_schedule_flip(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001921}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001923static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 unsigned int cmd, unsigned long arg)
1925{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001926 switch (cmd) {
1927 case DIGI_GETINFO:
1928 {
1929 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 int brd;
1931
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001932 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07001933 return -EFAULT;
1934 if (brd < 0 || brd >= num_cards || num_cards == 0)
1935 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937 memset(&di, 0, sizeof(di));
1938
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001939 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 di.status = boards[brd].status;
1941 di.type = boards[brd].type ;
1942 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001943 /* Legacy fixups - just move along nothing to see */
1944 di.port = (unsigned char *)boards[brd].port ;
1945 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001947 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 return -EFAULT;
1949 break;
1950
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001953 case DIGI_POLLER:
1954 {
1955 int brd = arg & 0xff000000 >> 16;
1956 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Alan Coxf2cf8e22005-09-06 15:16:44 -07001958 if (brd < 0 || brd >= num_cards) {
1959 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001960 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001962 digi_poller_inhibited = state;
1963 break;
1964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001966 case DIGI_INIT:
1967 {
1968 /*
1969 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02001970 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001971 * responsible for setting the card to its initial
1972 * state and setting the drivers control fields to the
1973 * sutianle settings for the card in question.
1974 */
1975 int crd;
1976 for (crd = 0; crd < num_cards; crd++)
1977 post_fep_init(crd);
1978 break;
1979 }
1980 default:
1981 return -ENOTTY;
1982 }
1983 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986static int pc_tiocmget(struct tty_struct *tty, struct file *file)
1987{
Alan Coxc9f19e92009-01-02 13:47:26 +00001988 struct channel *ch = tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01001989 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 unsigned int mstat, mflag = 0;
1991 unsigned long flags;
1992
1993 if (ch)
1994 bc = ch->brdchan;
1995 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07001996 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Alan Coxf2cf8e22005-09-06 15:16:44 -07001998 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002000 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002002 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003
2004 if (mstat & ch->m_dtr)
2005 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 if (mstat & ch->m_rts)
2007 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (mstat & ch->m_cts)
2009 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (mstat & ch->dsr)
2011 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if (mstat & ch->m_ri)
2013 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 if (mstat & ch->dcd)
2015 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 return mflag;
2017}
2018
2019static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2020 unsigned int set, unsigned int clear)
2021{
Alan Coxc9f19e92009-01-02 13:47:26 +00002022 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 unsigned long flags;
2024
Alan Coxf2cf8e22005-09-06 15:16:44 -07002025 if (!ch)
2026 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Alan Coxf2cf8e22005-09-06 15:16:44 -07002028 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002030 * I think this modemfake stuff is broken. It doesn't correctly reflect
2031 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2032 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 */
2034 if (set & TIOCM_RTS) {
2035 ch->modemfake |= ch->m_rts;
2036 ch->modem |= ch->m_rts;
2037 }
2038 if (set & TIOCM_DTR) {
2039 ch->modemfake |= ch->m_dtr;
2040 ch->modem |= ch->m_dtr;
2041 }
2042 if (clear & TIOCM_RTS) {
2043 ch->modemfake |= ch->m_rts;
2044 ch->modem &= ~ch->m_rts;
2045 }
2046 if (clear & TIOCM_DTR) {
2047 ch->modemfake |= ch->m_dtr;
2048 ch->modem &= ~ch->m_dtr;
2049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002051 /*
2052 * The below routine generally sets up parity, baud, flow control
2053 * issues, etc.... It effect both control flags and input flags.
2054 */
Alan Cox191260a2008-04-30 00:54:16 -07002055 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002057 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 return 0;
2059}
2060
Alan Cox191260a2008-04-30 00:54:16 -07002061static int pc_ioctl(struct tty_struct *tty, struct file *file,
2062 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002063{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 unsigned long flags;
2066 unsigned int mflag, mstat;
2067 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002068 struct board_chan __iomem *bc;
Alan Coxc9f19e92009-01-02 13:47:26 +00002069 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002071
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 if (ch)
2073 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002074 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002075 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002076 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002077 case TIOCMODG:
2078 mflag = pc_tiocmget(tty, file);
2079 if (put_user(mflag, (unsigned long __user *)argp))
2080 return -EFAULT;
2081 break;
2082 case TIOCMODS:
2083 if (get_user(mstat, (unsigned __user *)argp))
2084 return -EFAULT;
2085 return pc_tiocmset(tty, file, mstat, ~mstat);
2086 case TIOCSDTR:
2087 spin_lock_irqsave(&epca_lock, flags);
2088 ch->omodem |= ch->m_dtr;
2089 globalwinon(ch);
2090 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2091 memoff(ch);
2092 spin_unlock_irqrestore(&epca_lock, flags);
2093 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002095 case TIOCCDTR:
2096 spin_lock_irqsave(&epca_lock, flags);
2097 ch->omodem &= ~ch->m_dtr;
2098 globalwinon(ch);
2099 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2100 memoff(ch);
2101 spin_unlock_irqrestore(&epca_lock, flags);
2102 break;
2103 case DIGI_GETA:
2104 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2105 return -EFAULT;
2106 break;
2107 case DIGI_SETAW:
2108 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002109 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002110 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002111 /* Setup an event to indicate when the transmit
2112 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002113 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002114 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002115 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002116 tty_wait_until_sent(tty, 0);
2117 } else {
2118 /* ldisc lock already held in ioctl */
Alan Coxc65c9bc2009-06-11 12:50:12 +01002119 if (tty->ldisc->ops->flush_buffer)
2120 tty->ldisc->ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002121 }
Alan Cox37925e02008-04-30 00:53:17 -07002122 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002123 /* Fall Thru */
2124 case DIGI_SETA:
2125 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2126 return -EFAULT;
2127
2128 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2129 ch->dcd = ch->m_dsr;
2130 ch->dsr = ch->m_dcd;
2131 } else {
2132 ch->dcd = ch->m_dcd;
2133 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002135
2136 spin_lock_irqsave(&epca_lock, flags);
2137 globalwinon(ch);
2138
2139 /*
2140 * The below routine generally sets up parity, baud, flow
2141 * control issues, etc.... It effect both control flags and
2142 * input flags.
2143 */
Alan Cox191260a2008-04-30 00:54:16 -07002144 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002145 memoff(ch);
2146 spin_unlock_irqrestore(&epca_lock, flags);
2147 break;
2148
2149 case DIGI_GETFLOW:
2150 case DIGI_GETAFLOW:
2151 spin_lock_irqsave(&epca_lock, flags);
2152 globalwinon(ch);
2153 if (cmd == DIGI_GETFLOW) {
2154 dflow.startc = readb(&bc->startc);
2155 dflow.stopc = readb(&bc->stopc);
2156 } else {
2157 dflow.startc = readb(&bc->startca);
2158 dflow.stopc = readb(&bc->stopca);
2159 }
2160 memoff(ch);
2161 spin_unlock_irqrestore(&epca_lock, flags);
2162
2163 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2164 return -EFAULT;
2165 break;
2166
2167 case DIGI_SETAFLOW:
2168 case DIGI_SETFLOW:
2169 if (cmd == DIGI_SETFLOW) {
2170 startc = ch->startc;
2171 stopc = ch->stopc;
2172 } else {
2173 startc = ch->startca;
2174 stopc = ch->stopca;
2175 }
2176
2177 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2178 return -EFAULT;
2179
Alan Cox191260a2008-04-30 00:54:16 -07002180 if (dflow.startc != startc || dflow.stopc != stopc) {
2181 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002182 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 globalwinon(ch);
2184
Alan Coxf2cf8e22005-09-06 15:16:44 -07002185 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002186 ch->fepstartc = ch->startc = dflow.startc;
2187 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002188 fepcmd(ch, SONOFFC, ch->fepstartc,
2189 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002190 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002191 ch->fepstartca = ch->startca = dflow.startc;
2192 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002193 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2194 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002197 if (ch->statusflags & TXSTOPPED)
2198 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002200 memoff(ch);
2201 spin_unlock_irqrestore(&epca_lock, flags);
2202 } /* End if setflow toggled */
2203 break;
2204 default:
2205 return -ENOIOCTLCMD;
2206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002208}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Alan Cox606d0992006-12-08 02:38:45 -08002210static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002211{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 struct channel *ch;
2213 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002214 /*
2215 * verifyChannel returns the channel from the tty struct if it is
2216 * valid. This serves as a sanity check.
2217 */
Alan Cox191260a2008-04-30 00:54:16 -07002218 ch = verifyChannel(tty);
2219
2220 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002221 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 globalwinon(ch);
2223 epcaparam(tty, ch);
2224 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002225 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
2227 if ((old_termios->c_cflag & CRTSCTS) &&
2228 ((tty->termios->c_cflag & CRTSCTS) == 0))
2229 tty->hw_stopped = 0;
2230
2231 if (!(old_termios->c_cflag & CLOCAL) &&
2232 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002233 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002236}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
David Howellsc4028952006-11-22 14:57:56 +00002238static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002239{
David Howellsc4028952006-11-22 14:57:56 +00002240 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002242 if (ch && ch->magic == EPCA_MAGIC) {
Joe Perchesa419aef2009-08-18 11:18:35 -07002243 struct tty_struct *tty = tty_port_tty_get(&ch->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
Alan Coxf2cf8e22005-09-06 15:16:44 -07002245 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002246 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002247 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002248 wake_up_interruptible(&ch->port.open_wait);
Jiri Slabyc3301a52009-06-11 12:41:05 +01002249 clear_bit(ASYNCB_NORMAL_ACTIVE,
2250 &ch->port.flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002253 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002254 }
2255}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002257/*
2258 * pc_stop and pc_start provide software flow control to the routine and the
2259 * pc_ioctl routine.
2260 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002262{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 struct channel *ch;
2264 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002265 /*
2266 * verifyChannel returns the channel from the tty struct if it is
2267 * valid. This serves as a sanity check.
2268 */
Alan Cox191260a2008-04-30 00:54:16 -07002269 ch = verifyChannel(tty);
2270 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002271 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002272 if ((ch->statusflags & TXSTOPPED) == 0) {
2273 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 ch->statusflags |= TXSTOPPED;
2278 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002280 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002281 }
2282}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002285{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002287 /*
2288 * verifyChannel returns the channel from the tty struct if it is
2289 * valid. This serves as a sanity check.
2290 */
Alan Cox191260a2008-04-30 00:54:16 -07002291 ch = verifyChannel(tty);
2292 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002294 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002295 /* Just in case output was resumed because of a change
2296 in Digi-flow */
2297 if (ch->statusflags & TXSTOPPED) {
2298 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002299 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 globalwinon(ch);
2301 bc = ch->brdchan;
2302 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002303 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 ch->statusflags &= ~TXSTOPPED;
2307 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002309 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002310 }
2311}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002313/*
2314 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2315 * resume) the receipt of data into the kernels receive buffers. The exact
2316 * occurrence of this depends on the size of the kernels receive buffer and
2317 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2318 * more details.
2319 */
2320static void pc_throttle(struct tty_struct *tty)
2321{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 struct channel *ch;
2323 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002324 /*
2325 * verifyChannel returns the channel from the tty struct if it is
2326 * valid. This serves as a sanity check.
2327 */
Alan Cox191260a2008-04-30 00:54:16 -07002328 ch = verifyChannel(tty);
2329 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002330 spin_lock_irqsave(&epca_lock, flags);
2331 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 globalwinon(ch);
2333 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 ch->statusflags |= RXSTOPPED;
2335 memoff(ch);
2336 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002337 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002338 }
2339}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
2341static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002342{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 struct channel *ch;
2344 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002345 /*
2346 * verifyChannel returns the channel from the tty struct if it is
2347 * valid. This serves as a sanity check.
2348 */
Alan Cox191260a2008-04-30 00:54:16 -07002349 ch = verifyChannel(tty);
2350 if (ch != NULL) {
2351 /* Just in case output was resumed because of a change
2352 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002353 spin_lock_irqsave(&epca_lock, flags);
2354 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 ch->statusflags &= ~RXSTOPPED;
2358 memoff(ch);
2359 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002360 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002361 }
2362}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Alan Coxdcbf1282008-07-22 11:18:12 +01002364static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002365{
Alan Coxc9f19e92009-01-02 13:47:26 +00002366 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 unsigned long flags;
2368
Alan Coxdcbf1282008-07-22 11:18:12 +01002369 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002370 msec = 0xFFFF;
2371 else if (msec > 0xFFFE)
2372 msec = 0xFFFE;
2373 else if (msec < 1)
2374 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002375
Alan Coxf2cf8e22005-09-06 15:16:44 -07002376 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002378 /*
2379 * Maybe I should send an infinite break here, schedule() for msec
2380 * amount of time, and then stop the break. This way, the user can't
2381 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2382 * an ioctl()) more than once in msec amount of time.
2383 * Try this for now...
2384 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2386 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002387 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002388 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002389}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Alan Coxf2cf8e22005-09-06 15:16:44 -07002391/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002393{
Al Virobc9a5152005-09-15 22:53:28 +01002394 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 globalwinon(ch);
2397 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002398 /*
2399 * When set the iempty flag request a event to be generated when the
2400 * transmit buffer is empty (If there is no BREAK in progress).
2401 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002402 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002404}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
David Howells88e88242008-07-22 11:20:45 +01002406#ifndef MODULE
2407static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002408{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 struct board_info board;
2410 int index, loop, last;
2411 char *temp, *t2;
2412 unsigned len;
2413
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002414 /*
2415 * If this routine looks a little strange it is because it is only
2416 * called if a LILO append command is given to boot the kernel with
2417 * parameters. In this way, we can provide the user a method of
2418 * changing his board configuration without rebuilding the kernel.
2419 */
2420 if (!liloconfig)
2421 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423 memset(&board, 0, sizeof(board));
2424
2425 /* Assume the data is int first, later we can change it */
2426 /* I think that array position 0 of ints holds the number of args */
2427 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002428 switch (index) { /* Begin parse switch */
2429 case 1:
2430 board.status = ints[index];
2431 /*
2432 * We check for 2 (As opposed to 1; because 2 is a flag
2433 * instructing the driver to ignore epcaconfig.) For
2434 * this reason we check for 2.
2435 */
Alan Cox191260a2008-04-30 00:54:16 -07002436 if (board.status == 2) {
2437 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002438 nbdevs = 0;
2439 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002441 } /* End ignore epcaconfig as well as lilo cmd line */
2442
2443 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002444 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2445 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002446 invalid_lilo_config = 1;
2447 setup_error_code |= INVALID_BOARD_STATUS;
2448 return;
2449 }
2450 last = index;
2451 break;
2452 case 2:
2453 board.type = ints[index];
2454 if (board.type >= PCIXEM) {
2455 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2456 invalid_lilo_config = 1;
2457 setup_error_code |= INVALID_BOARD_TYPE;
2458 return;
2459 }
2460 last = index;
2461 break;
2462 case 3:
2463 board.altpin = ints[index];
2464 if (board.altpin > 1) {
2465 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2466 invalid_lilo_config = 1;
2467 setup_error_code |= INVALID_ALTPIN;
2468 return;
2469 }
2470 last = index;
2471 break;
2472
2473 case 4:
2474 board.numports = ints[index];
2475 if (board.numports < 2 || board.numports > 256) {
2476 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2477 invalid_lilo_config = 1;
2478 setup_error_code |= INVALID_NUM_PORTS;
2479 return;
2480 }
2481 nbdevs += board.numports;
2482 last = index;
2483 break;
2484
2485 case 5:
2486 board.port = ints[index];
2487 if (ints[index] <= 0) {
2488 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2489 invalid_lilo_config = 1;
2490 setup_error_code |= INVALID_PORT_BASE;
2491 return;
2492 }
2493 last = index;
2494 break;
2495
2496 case 6:
2497 board.membase = ints[index];
2498 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002499 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2500 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002501 invalid_lilo_config = 1;
2502 setup_error_code |= INVALID_MEM_BASE;
2503 return;
2504 }
2505 last = index;
2506 break;
2507
2508 default:
2509 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2510 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 } /* End parse switch */
2513
Alan Coxf2cf8e22005-09-06 15:16:44 -07002514 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 /* find the next comma or terminator */
2516 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 /* While string is not null, and a comma hasn't been found */
2518 while (*temp && (*temp != ','))
2519 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 if (!*temp)
2521 temp = NULL;
2522 else
2523 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 /* Set index to the number of args + 1 */
2525 index = last + 1;
2526
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002527 switch (index) {
2528 case 1:
2529 len = strlen(str);
2530 if (strncmp("Disable", str, len) == 0)
2531 board.status = 0;
2532 else if (strncmp("Enable", str, len) == 0)
2533 board.status = 1;
2534 else {
2535 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2536 invalid_lilo_config = 1;
2537 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002539 }
2540 last = index;
2541 break;
2542
2543 case 2:
2544 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2545 if (strcmp(board_desc[loop], str) == 0)
2546 break;
2547 /*
2548 * If the index incremented above refers to a
2549 * legitamate board type set it here.
2550 */
2551 if (index < EPCA_NUM_TYPES)
2552 board.type = loop;
2553 else {
2554 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2555 invalid_lilo_config = 1;
2556 setup_error_code |= INVALID_BOARD_TYPE;
2557 return;
2558 }
2559 last = index;
2560 break;
2561
2562 case 3:
2563 len = strlen(str);
2564 if (strncmp("Disable", str, len) == 0)
2565 board.altpin = 0;
2566 else if (strncmp("Enable", str, len) == 0)
2567 board.altpin = 1;
2568 else {
2569 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2570 invalid_lilo_config = 1;
2571 setup_error_code |= INVALID_ALTPIN;
2572 return;
2573 }
2574 last = index;
2575 break;
2576
2577 case 4:
2578 t2 = str;
2579 while (isdigit(*t2))
2580 t2++;
2581
2582 if (*t2) {
2583 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2584 invalid_lilo_config = 1;
2585 setup_error_code |= INVALID_NUM_PORTS;
2586 return;
2587 }
2588
2589 /*
2590 * There is not a man page for simple_strtoul but the
2591 * code can be found in vsprintf.c. The first argument
2592 * is the string to translate (To an unsigned long
2593 * obviously), the second argument can be the address
2594 * of any character variable or a NULL. If a variable
2595 * is given, the end pointer of the string will be
2596 * stored in that variable; if a NULL is given the end
2597 * pointer will not be returned. The last argument is
2598 * the base to use. If a 0 is indicated, the routine
2599 * will attempt to determine the proper base by looking
2600 * at the values prefix (A '0' for octal, a 'x' for
2601 * hex, etc ... If a value is given it will use that
2602 * value as the base.
2603 */
2604 board.numports = simple_strtoul(str, NULL, 0);
2605 nbdevs += board.numports;
2606 last = index;
2607 break;
2608
2609 case 5:
2610 t2 = str;
2611 while (isxdigit(*t2))
2612 t2++;
2613
2614 if (*t2) {
2615 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2616 invalid_lilo_config = 1;
2617 setup_error_code |= INVALID_PORT_BASE;
2618 return;
2619 }
2620
2621 board.port = simple_strtoul(str, NULL, 16);
2622 last = index;
2623 break;
2624
2625 case 6:
2626 t2 = str;
2627 while (isxdigit(*t2))
2628 t2++;
2629
2630 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002631 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002632 invalid_lilo_config = 1;
2633 setup_error_code |= INVALID_MEM_BASE;
2634 return;
2635 }
2636 board.membase = simple_strtoul(str, NULL, 16);
2637 last = index;
2638 break;
2639 default:
2640 printk(KERN_ERR "epca: Too many string parms\n");
2641 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 } /* End while there is a string arg */
2645
Alan Coxf2cf8e22005-09-06 15:16:44 -07002646 if (last < 6) {
2647 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return;
2649 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002653 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002655 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2656 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002659}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
David Howells88e88242008-07-22 11:20:45 +01002661static int __init epca_real_setup(char *str)
2662{
2663 int ints[11];
2664
2665 epca_setup(get_options(str, 11, ints), ints);
2666 return 1;
2667}
2668
2669__setup("digiepca", epca_real_setup);
2670#endif
2671
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672enum epic_board_types {
2673 brd_xr = 0,
2674 brd_xem,
2675 brd_cx,
2676 brd_xrj,
2677};
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679/* indexed directly by epic_board_types enum */
2680static struct {
2681 unsigned char board_type;
2682 unsigned bar_idx; /* PCI base address region */
2683} epca_info_tbl[] = {
2684 { PCIXR, 0, },
2685 { PCIXEM, 0, },
2686 { PCICX, 0, },
2687 { PCIXRJ, 2, },
2688};
2689
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002690static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 const struct pci_device_id *ent)
2692{
2693 static int board_num = -1;
2694 int board_idx, info_idx = ent->driver_data;
2695 unsigned long addr;
2696
2697 if (pci_enable_device(pdev))
2698 return -EIO;
2699
2700 board_num++;
2701 board_idx = board_num + num_cards;
2702 if (board_idx >= MAXBOARDS)
2703 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002704
Alan Cox191260a2008-04-30 00:54:16 -07002705 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002707 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 epca_info_tbl[info_idx].bar_idx);
2709 goto err_out;
2710 }
2711
2712 boards[board_idx].status = ENABLED;
2713 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2714 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002715 boards[board_idx].port = addr + PCI_IO_OFFSET;
2716 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Alan Cox191260a2008-04-30 00:54:16 -07002718 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2719 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 0x200000, addr + PCI_IO_OFFSET);
2721 goto err_out;
2722 }
2723
Alan Cox191260a2008-04-30 00:54:16 -07002724 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2725 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002727 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 0x200000, addr + PCI_IO_OFFSET);
2729 goto err_out_free_pciio;
2730 }
2731
Alan Cox191260a2008-04-30 00:54:16 -07002732 if (!request_mem_region(addr, 0x200000, "epca")) {
2733 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 0x200000, addr);
2735 goto err_out_free_iounmap;
2736 }
2737
Alan Cox191260a2008-04-30 00:54:16 -07002738 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002740 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 0x200000, addr + PCI_IO_OFFSET);
2742 goto err_out_free_memregion;
2743 }
2744
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002745 /*
2746 * I don't know what the below does, but the hardware guys say its
2747 * required on everything except PLX (In this case XRJ).
2748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002750 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 pci_write_config_byte(pdev, 0x46, 0);
2752 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 return 0;
2755
2756err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002757 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002759 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002761 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762err_out:
2763 return -ENODEV;
2764}
2765
2766
2767static struct pci_device_id epca_pci_tbl[] = {
2768 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2769 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2770 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2771 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2772 { 0, }
2773};
2774
2775MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2776
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002777static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002778{
Alan Cox191260a2008-04-30 00:54:16 -07002779 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 epca_driver.name = "epca";
2781 epca_driver.id_table = epca_pci_tbl;
2782 epca_driver.probe = epca_init_one;
2783
2784 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002785}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
2787MODULE_LICENSE("GPL");