blob: 9d9ae1ca2925b825a526b093011c88d3a66ffa53 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 Copyright (C) 1996 Digi International.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 For technical support please email digiLinux@dgii.com or
5 call Digi tech support at (612) 912-3456
6
Alan Coxf2cf8e22005-09-06 15:16:44 -07007 ** This driver is no longer supported by Digi **
8
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07009 Much of this design and code came from epca.c which was
10 copyright (C) 1994, 1995 Troy De Jongh, and subsquently
11 modified by David Nugent, Christoph Lameter, Mike McLagan.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070018 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070023 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070027/* See README.epca for change history --DAT*/
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/init.h>
33#include <linux/serial.h>
34#include <linux/delay.h>
35#include <linux/ctype.h>
36#include <linux/tty.h>
37#include <linux/tty_flip.h>
38#include <linux/slab.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
Alan Cox191260a2008-04-30 00:54:16 -070041#include <linux/uaccess.h>
42#include <linux/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070043#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/pci.h>
45#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include "digi1.h"
49#include "digiFep1.h"
50#include "epca.h"
51#include "epcaconfig.h"
52
Alan Coxf2cf8e22005-09-06 15:16:44 -070053#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070056#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58
59#define MAXCARDS 7
60#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
61
62#define PFX "epca: "
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static int nbdevs, num_cards, liloconfig;
65static int digi_poller_inhibited = 1 ;
66
67static int setup_error_code;
68static int invalid_lilo_config;
69
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070070/*
71 * The ISA boards do window flipping into the same spaces so its only sane with
72 * a single lock. It's still pretty efficient.
73 */
Ingo Molnar34af9462006-06-27 02:53:55 -070074static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070075
Alan Cox191260a2008-04-30 00:54:16 -070076/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
77 to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static struct board_info boards[MAXBOARDS];
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static struct tty_driver *pc_driver;
81static struct tty_driver *pc_info;
82
83/* ------------------ Begin Digi specific structures -------------------- */
84
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070085/*
86 * digi_channels represents an array of structures that keep track of each
87 * channel of the Digi product. Information such as transmit and receive
88 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
89 * here. This structure is NOT used to overlay the cards physical channel
90 * structure.
91 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static struct channel digi_channels[MAX_ALLOC];
93
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070094/*
95 * card_ptr is an array used to hold the address of the first channel structure
96 * of each card. This array will hold the addresses of various channels located
97 * in digi_channels.
98 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099static struct channel *card_ptr[MAXCARDS];
100
101static struct timer_list epca_timer;
102
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700103/*
104 * Begin generic memory functions. These functions will be alias (point at)
105 * more specific functions dependent on the board being configured.
106 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700107static void memwinon(struct board_info *b, unsigned int win);
108static void memwinoff(struct board_info *b, unsigned int win);
109static void globalwinon(struct channel *ch);
110static void rxwinon(struct channel *ch);
111static void txwinon(struct channel *ch);
112static void memoff(struct channel *ch);
113static void assertgwinon(struct channel *ch);
114static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116/* ---- Begin more 'specific' memory functions for cx_like products --- */
117
Alan Coxf2cf8e22005-09-06 15:16:44 -0700118static void pcxem_memwinon(struct board_info *b, unsigned int win);
119static void pcxem_memwinoff(struct board_info *b, unsigned int win);
120static void pcxem_globalwinon(struct channel *ch);
121static void pcxem_rxwinon(struct channel *ch);
122static void pcxem_txwinon(struct channel *ch);
123static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
125/* ------ Begin more 'specific' memory functions for the pcxe ------- */
126
Alan Coxf2cf8e22005-09-06 15:16:44 -0700127static void pcxe_memwinon(struct board_info *b, unsigned int win);
128static void pcxe_memwinoff(struct board_info *b, unsigned int win);
129static void pcxe_globalwinon(struct channel *ch);
130static void pcxe_rxwinon(struct channel *ch);
131static void pcxe_txwinon(struct channel *ch);
132static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
135/* Note : pc64xe and pcxi share the same windowing routines */
136
Alan Coxf2cf8e22005-09-06 15:16:44 -0700137static void pcxi_memwinon(struct board_info *b, unsigned int win);
138static void pcxi_memwinoff(struct board_info *b, unsigned int win);
139static void pcxi_globalwinon(struct channel *ch);
140static void pcxi_rxwinon(struct channel *ch);
141static void pcxi_txwinon(struct channel *ch);
142static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144/* - Begin 'specific' do nothing memory functions needed for some cards - */
145
Alan Coxf2cf8e22005-09-06 15:16:44 -0700146static void dummy_memwinon(struct board_info *b, unsigned int win);
147static void dummy_memwinoff(struct board_info *b, unsigned int win);
148static void dummy_globalwinon(struct channel *ch);
149static void dummy_rxwinon(struct channel *ch);
150static void dummy_txwinon(struct channel *ch);
151static void dummy_memoff(struct channel *ch);
152static void dummy_assertgwinon(struct channel *ch);
153static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Alan Coxf2cf8e22005-09-06 15:16:44 -0700155static struct channel *verifyChannel(struct tty_struct *);
156static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static void epca_error(int, char *);
158static void pc_close(struct tty_struct *, struct file *);
159static void shutdown(struct channel *);
160static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static int pc_write_room(struct tty_struct *);
162static int pc_chars_in_buffer(struct tty_struct *);
163static void pc_flush_buffer(struct tty_struct *);
164static void pc_flush_chars(struct tty_struct *);
165static int block_til_ready(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700166 struct channel *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167static int pc_open(struct tty_struct *, struct file *);
168static void post_fep_init(unsigned int crd);
169static void epcapoll(unsigned long);
170static void doevent(int);
171static void fepcmd(struct channel *, int, int, int, int, int);
172static unsigned termios2digi_h(struct channel *ch, unsigned);
173static unsigned termios2digi_i(struct channel *ch, unsigned);
174static unsigned termios2digi_c(struct channel *ch, unsigned);
175static void epcaparam(struct tty_struct *, struct channel *);
176static void receive_data(struct channel *);
177static int pc_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700178 unsigned int, unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int info_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700180 unsigned int, unsigned long);
Alan Cox606d0992006-12-08 02:38:45 -0800181static void pc_set_termios(struct tty_struct *, struct ktermios *);
David Howellsc4028952006-11-22 14:57:56 +0000182static void do_softint(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static void pc_stop(struct tty_struct *);
184static void pc_start(struct tty_struct *);
Alan Cox191260a2008-04-30 00:54:16 -0700185static void pc_throttle(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186static void pc_unthrottle(struct tty_struct *tty);
Alan Coxdcbf1282008-07-22 11:18:12 +0100187static int pc_send_break(struct tty_struct *tty, int msec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
Alan Cox191260a2008-04-30 00:54:16 -0700189static void epca_setup(char *, int *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static int pc_write(struct tty_struct *, const unsigned char *, int);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700192static int pc_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193static int init_PCI(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700195/*
196 * Table of functions for each board to handle memory. Mantaining parallelism
197 * is a *very* good idea here. The idea is for the runtime code to blindly call
198 * these functions, not knowing/caring about the underlying hardware. This
199 * stuff should contain no conditionals; if more functionality is needed a
200 * different entry should be established. These calls are the interface calls
201 * and are the only functions that should be accessed. Anyone caught making
202 * direct calls deserves what they get.
203 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700204static void memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700206 b->memwinon(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
Alan Coxf2cf8e22005-09-06 15:16:44 -0700209static void memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700211 b->memwinoff(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213
Alan Coxf2cf8e22005-09-06 15:16:44 -0700214static void globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700216 ch->board->globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
Alan Coxf2cf8e22005-09-06 15:16:44 -0700219static void rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700221 ch->board->rxwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Alan Coxf2cf8e22005-09-06 15:16:44 -0700224static void txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700226 ch->board->txwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
Alan Coxf2cf8e22005-09-06 15:16:44 -0700229static void memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700231 ch->board->memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
Alan Coxf2cf8e22005-09-06 15:16:44 -0700233static void assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700235 ch->board->assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
Alan Coxf2cf8e22005-09-06 15:16:44 -0700238static void assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700240 ch->board->assertmemoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241}
242
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700243/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700244static void pcxem_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Alan Cox191260a2008-04-30 00:54:16 -0700246 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
Alan Coxf2cf8e22005-09-06 15:16:44 -0700249static void pcxem_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700251 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
Alan Coxf2cf8e22005-09-06 15:16:44 -0700254static void pcxem_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
Alan Cox191260a2008-04-30 00:54:16 -0700256 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
Alan Coxf2cf8e22005-09-06 15:16:44 -0700259static void pcxem_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
261 outb_p(ch->rxwin, (int)ch->board->port + 1);
262}
263
Alan Coxf2cf8e22005-09-06 15:16:44 -0700264static void pcxem_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 outb_p(ch->txwin, (int)ch->board->port + 1);
267}
268
Alan Coxf2cf8e22005-09-06 15:16:44 -0700269static void pcxem_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
271 outb_p(0, (int)ch->board->port + 1);
272}
273
274/* ----------------- Begin pcxe memory window stuff ------------------ */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700275static void pcxe_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700277 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
Alan Coxf2cf8e22005-09-06 15:16:44 -0700280static void pcxe_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700282 outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700283 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
Alan Coxf2cf8e22005-09-06 15:16:44 -0700286static void pcxe_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700288 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289}
290
Alan Coxf2cf8e22005-09-06 15:16:44 -0700291static void pcxe_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700293 outb_p(ch->rxwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Alan Coxf2cf8e22005-09-06 15:16:44 -0700296static void pcxe_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700298 outb_p(ch->txwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Alan Coxf2cf8e22005-09-06 15:16:44 -0700301static void pcxe_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 outb_p(0, (int)ch->board->port);
304 outb_p(0, (int)ch->board->port + 1);
305}
306
307/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700308static void pcxi_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700310 outb_p(inb(b->port) | FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
Alan Coxf2cf8e22005-09-06 15:16:44 -0700313static void pcxi_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700315 outb_p(inb(b->port) & ~FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
Alan Coxf2cf8e22005-09-06 15:16:44 -0700318static void pcxi_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700320 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
322
Alan Coxf2cf8e22005-09-06 15:16:44 -0700323static void pcxi_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700325 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Alan Coxf2cf8e22005-09-06 15:16:44 -0700328static void pcxi_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700330 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Alan Coxf2cf8e22005-09-06 15:16:44 -0700333static void pcxi_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700335 outb_p(0, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Alan Coxf2cf8e22005-09-06 15:16:44 -0700338static void pcxi_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700340 epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341}
342
Alan Coxf2cf8e22005-09-06 15:16:44 -0700343static void pcxi_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700345 epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700348/*
349 * Not all of the cards need specific memory windowing routines. Some cards
350 * (Such as PCI) needs no windowing routines at all. We provide these do
351 * nothing routines so that the same code base can be used. The driver will
352 * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
353 * card. However, dependent on the card the routine may or may not do anything.
354 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700355static void dummy_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357}
358
Alan Coxf2cf8e22005-09-06 15:16:44 -0700359static void dummy_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361}
362
Alan Coxf2cf8e22005-09-06 15:16:44 -0700363static void dummy_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365}
366
Alan Coxf2cf8e22005-09-06 15:16:44 -0700367static void dummy_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369}
370
Alan Coxf2cf8e22005-09-06 15:16:44 -0700371static void dummy_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373}
374
Alan Coxf2cf8e22005-09-06 15:16:44 -0700375static void dummy_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377}
378
Alan Coxf2cf8e22005-09-06 15:16:44 -0700379static void dummy_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381}
382
Alan Coxf2cf8e22005-09-06 15:16:44 -0700383static void dummy_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385}
386
Alan Coxf2cf8e22005-09-06 15:16:44 -0700387static struct channel *verifyChannel(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700388{
389 /*
390 * This routine basically provides a sanity check. It insures that the
391 * channel returned is within the proper range of addresses as well as
392 * properly initialized. If some bogus info gets passed in
393 * through tty->driver_data this should catch it.
394 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700395 if (tty) {
396 struct channel *ch = (struct channel *)tty->driver_data;
Alan Cox191260a2008-04-30 00:54:16 -0700397 if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (ch->magic == EPCA_MAGIC)
399 return ch;
400 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return NULL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700403}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Alan Coxf2cf8e22005-09-06 15:16:44 -0700405static void pc_sched_event(struct channel *ch, int event)
406{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700407 /*
408 * We call this to schedule interrupt processing on some event. The
409 * kernel sees our request and calls the related routine in OUR driver.
410 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 ch->event |= 1 << event;
412 schedule_work(&ch->tqueue);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700413}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415static void epca_error(int line, char *msg)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700416{
Alan Cox191260a2008-04-30 00:54:16 -0700417 printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700418}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700420static void pc_close(struct tty_struct *tty, struct file *filp)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700421{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 struct channel *ch;
423 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700424 /*
425 * verifyChannel returns the channel from the tty struct if it is
426 * valid. This serves as a sanity check.
427 */
Alan Cox191260a2008-04-30 00:54:16 -0700428 ch = verifyChannel(tty);
429 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700430 spin_lock_irqsave(&epca_lock, flags);
431 if (tty_hung_up_p(filp)) {
432 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return;
434 }
Alan Cox52d41732008-07-16 21:55:02 +0100435 if (ch->port.count-- > 1) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700436 /* Begin channel is open more than once */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700437 /*
438 * Return without doing anything. Someone might still
439 * be using the channel.
440 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700441 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 /* Port open only once go ahead with shutdown & reset */
Alan Cox52d41732008-07-16 21:55:02 +0100445 BUG_ON(ch->port.count < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700447 /*
448 * Let the rest of the driver know the channel is being closed.
449 * This becomes important if an open is attempted before close
450 * is finished.
451 */
Alan Cox52d41732008-07-16 21:55:02 +0100452 ch->port.flags |= ASYNC_CLOSING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 tty->closing = 1;
454
Alan Coxf2cf8e22005-09-06 15:16:44 -0700455 spin_unlock_irqrestore(&epca_lock, flags);
456
Alan Cox52d41732008-07-16 21:55:02 +0100457 if (ch->port.flags & ASYNC_INITIALIZED) {
Alan Cox191260a2008-04-30 00:54:16 -0700458 /* Setup an event to indicate when the
459 transmit buffer empties */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700460 setup_empty_event(tty, ch);
Alan Cox191260a2008-04-30 00:54:16 -0700461 /* 30 seconds timeout */
462 tty_wait_until_sent(tty, 3000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 }
Alan Cox978e5952008-04-30 00:53:59 -0700464 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 tty_ldisc_flush(tty);
467 shutdown(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700468
469 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 tty->closing = 0;
471 ch->event = 0;
Alan Cox52d41732008-07-16 21:55:02 +0100472 ch->port.tty = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700473 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
Alan Cox52d41732008-07-16 21:55:02 +0100475 if (ch->port.blocked_open) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700476 if (ch->close_delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 msleep_interruptible(jiffies_to_msecs(ch->close_delay));
Alan Cox52d41732008-07-16 21:55:02 +0100478 wake_up_interruptible(&ch->port.open_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700479 }
Alan Cox52d41732008-07-16 21:55:02 +0100480 ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
Alan Cox191260a2008-04-30 00:54:16 -0700481 ASYNC_CLOSING);
Alan Cox52d41732008-07-16 21:55:02 +0100482 wake_up_interruptible(&ch->port.close_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700483 }
484}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486static void shutdown(struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700487{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 unsigned long flags;
489 struct tty_struct *tty;
Al Virobc9a5152005-09-15 22:53:28 +0100490 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Alan Cox52d41732008-07-16 21:55:02 +0100492 if (!(ch->port.flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return;
494
Alan Coxf2cf8e22005-09-06 15:16:44 -0700495 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Alan Coxf2cf8e22005-09-06 15:16:44 -0700497 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 bc = ch->brdchan;
499
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700500 /*
501 * In order for an event to be generated on the receipt of data the
502 * idata flag must be set. Since we are shutting down, this is not
503 * necessary clear this flag.
504 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700506 writeb(0, &bc->idata);
Alan Cox52d41732008-07-16 21:55:02 +0100507 tty = ch->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700509 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700510 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
512 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 memoff(ch);
515
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700516 /*
517 * The channel has officialy been closed. The next time it is opened it
518 * will have to reinitialized. Set a flag to indicate this.
519 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 /* Prevent future Digi programmed interrupts from coming active */
Alan Cox52d41732008-07-16 21:55:02 +0100521 ch->port.flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700522 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700523}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700526{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700528 /*
529 * verifyChannel returns the channel from the tty struct if it is
530 * valid. This serves as a sanity check.
531 */
Alan Cox191260a2008-04-30 00:54:16 -0700532 ch = verifyChannel(tty);
533 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 unsigned long flags;
535
Alan Cox978e5952008-04-30 00:53:59 -0700536 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 tty_ldisc_flush(tty);
538 shutdown(ch);
539
Alan Coxf2cf8e22005-09-06 15:16:44 -0700540 spin_lock_irqsave(&epca_lock, flags);
Alan Cox52d41732008-07-16 21:55:02 +0100541 ch->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 ch->event = 0;
Alan Cox52d41732008-07-16 21:55:02 +0100543 ch->port.count = 0;
544 ch->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700545 spin_unlock_irqrestore(&epca_lock, flags);
Alan Cox52d41732008-07-16 21:55:02 +0100546 wake_up_interruptible(&ch->port.open_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700547 }
548}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700550static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700551 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700552{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700553 unsigned int head, tail;
554 int dataLen;
555 int size;
556 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 struct channel *ch;
558 unsigned long flags;
559 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100560 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700562 /*
563 * pc_write is primarily called directly by the kernel routine
564 * tty_write (Though it can also be called by put_char) found in
565 * tty_io.c. pc_write is passed a line discipline buffer where the data
566 * to be written out is stored. The line discipline implementation
567 * itself is done at the kernel level and is not brought into the
568 * driver.
569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700571 /*
572 * verifyChannel returns the channel from the tty struct if it is
573 * valid. This serves as a sanity check.
574 */
Alan Cox191260a2008-04-30 00:54:16 -0700575 ch = verifyChannel(tty);
576 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return 0;
578
579 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 bc = ch->brdchan;
581 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Alan Coxf2cf8e22005-09-06 15:16:44 -0700584 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 globalwinon(ch);
586
Alan Coxf2cf8e22005-09-06 15:16:44 -0700587 head = readw(&bc->tin) & (size - 1);
588 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Alan Coxf2cf8e22005-09-06 15:16:44 -0700590 if (tail != readw(&bc->tout))
591 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 tail &= (size - 1);
593
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700594 if (head >= tail) {
595 /* head has not wrapped */
596 /*
597 * remain (much like dataLen above) represents the total amount
598 * of space available on the card for data. Here dataLen
599 * represents the space existing between the head pointer and
600 * the end of buffer. This is important because a memcpy cannot
601 * be told to automatically wrap around when it hits the buffer
602 * end.
603 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 dataLen = size - head;
605 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700606 } else {
607 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 remain = tail - head - 1;
609 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700610 }
611 /*
612 * Check the space on the card. If we have more data than space; reduce
613 * the amount of data to fit the space.
614 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700617 while (bytesAvailable > 0) {
618 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700620 /*
621 * If head is not wrapped, the below will make sure the first
622 * data copy fills to the end of card buffer.
623 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100625 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 buf += dataLen;
627 head += dataLen;
628 amountCopied += dataLen;
629 bytesAvailable -= dataLen;
630
Alan Coxf2cf8e22005-09-06 15:16:44 -0700631 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 head = 0;
633 dataLen = tail;
634 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 ch->statusflags |= TXBUSY;
637 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700638 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
Alan Coxf2cf8e22005-09-06 15:16:44 -0700640 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700642 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700645 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700646 return amountCopied;
647}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700650{
Alan Cox191260a2008-04-30 00:54:16 -0700651 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 struct channel *ch;
653 unsigned long flags;
654 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100655 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700656 /*
657 * verifyChannel returns the channel from the tty struct if it is
658 * valid. This serves as a sanity check.
659 */
Alan Cox191260a2008-04-30 00:54:16 -0700660 ch = verifyChannel(tty);
661 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700662 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 globalwinon(ch);
664
665 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700666 head = readw(&bc->tin) & (ch->txbufsize - 1);
667 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Alan Coxf2cf8e22005-09-06 15:16:44 -0700669 if (tail != readw(&bc->tout))
670 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 /* Wrap tail if necessary */
672 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700673 remain = tail - head - 1;
674 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 remain += ch->txbufsize;
676
Alan Coxf2cf8e22005-09-06 15:16:44 -0700677 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700679 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700682 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /* Return how much room is left on card */
685 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700686}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700689{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 int chars;
691 unsigned int ctail, head, tail;
692 int remain;
693 unsigned long flags;
694 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100695 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700696 /*
697 * verifyChannel returns the channel from the tty struct if it is
698 * valid. This serves as a sanity check.
699 */
Alan Cox191260a2008-04-30 00:54:16 -0700700 ch = verifyChannel(tty);
701 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700702 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Alan Coxf2cf8e22005-09-06 15:16:44 -0700704 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 globalwinon(ch);
706
707 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700708 tail = readw(&bc->tout);
709 head = readw(&bc->tin);
710 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Alan Cox191260a2008-04-30 00:54:16 -0700712 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
713 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700715 else { /* Begin if some space on the card has been used */
716 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700718 /*
719 * The logic here is basically opposite of the above
720 * pc_write_room here we are finding the amount of bytes in the
721 * buffer filled. Not the amount of bytes empty.
722 */
Alan Cox191260a2008-04-30 00:54:16 -0700723 remain = tail - head - 1;
724 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 remain += ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700727 /*
728 * Make it possible to wakeup anything waiting for output in
729 * tty_ioctl.c, etc.
730 *
731 * If not already set. Setup an event to indicate when the
732 * transmit buffer empties.
733 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700735 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700738 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700740 return chars;
741}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700744{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 unsigned int tail;
746 unsigned long flags;
747 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100748 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700749 /*
750 * verifyChannel returns the channel from the tty struct if it is
751 * valid. This serves as a sanity check.
752 */
Alan Cox191260a2008-04-30 00:54:16 -0700753 ch = verifyChannel(tty);
754 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return;
756
Alan Coxf2cf8e22005-09-06 15:16:44 -0700757 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700760 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700764 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700766}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700769{
770 struct channel *ch;
771 /*
772 * verifyChannel returns the channel from the tty struct if it is
773 * valid. This serves as a sanity check.
774 */
Alan Cox191260a2008-04-30 00:54:16 -0700775 ch = verifyChannel(tty);
776 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700778 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700779 /*
780 * If not already set and the transmitter is busy setup an
781 * event to indicate when the transmit empties.
782 */
Alan Cox191260a2008-04-30 00:54:16 -0700783 if ((ch->statusflags & TXBUSY) &&
784 !(ch->statusflags & EMPTYWAIT))
785 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700786 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700788}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700790static int block_til_ready(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700791 struct file *filp, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700792{
Alan Cox191260a2008-04-30 00:54:16 -0700793 DECLARE_WAITQUEUE(wait, current);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700794 int retval, do_clocal = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 unsigned long flags;
796
Alan Coxf2cf8e22005-09-06 15:16:44 -0700797 if (tty_hung_up_p(filp)) {
Alan Cox52d41732008-07-16 21:55:02 +0100798 if (ch->port.flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 retval = -EAGAIN;
800 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700801 retval = -ERESTARTSYS;
802 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700805 /*
806 * If the device is in the middle of being closed, then block until
807 * it's done, and then try again.
808 */
Alan Cox52d41732008-07-16 21:55:02 +0100809 if (ch->port.flags & ASYNC_CLOSING) {
810 interruptible_sleep_on(&ch->port.close_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Alan Cox52d41732008-07-16 21:55:02 +0100812 if (ch->port.flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return -EAGAIN;
814 else
815 return -ERESTARTSYS;
816 }
817
Alan Coxf2cf8e22005-09-06 15:16:44 -0700818 if (filp->f_flags & O_NONBLOCK) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700819 /*
820 * If non-blocking mode is set, then make the check up front
821 * and then exit.
822 */
Alan Cox52d41732008-07-16 21:55:02 +0100823 ch->port.flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return 0;
825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (tty->termios->c_cflag & CLOCAL)
827 do_clocal = 1;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700828 /* Block waiting for the carrier detect and the line to become free */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 retval = 0;
Alan Cox52d41732008-07-16 21:55:02 +0100831 add_wait_queue(&ch->port.open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Alan Coxf2cf8e22005-09-06 15:16:44 -0700833 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 /* We dec count so that pc_close will know when to free things */
835 if (!tty_hung_up_p(filp))
Alan Cox52d41732008-07-16 21:55:02 +0100836 ch->port.count--;
837 ch->port.blocked_open++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700838 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 if (tty_hung_up_p(filp) ||
Alan Cox52d41732008-07-16 21:55:02 +0100841 !(ch->port.flags & ASYNC_INITIALIZED)) {
842 if (ch->port.flags & ASYNC_HUP_NOTIFY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 retval = -EAGAIN;
844 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700845 retval = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 break;
847 }
Alan Cox52d41732008-07-16 21:55:02 +0100848 if (!(ch->port.flags & ASYNC_CLOSING) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 (do_clocal || (ch->imodem & ch->dcd)))
850 break;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700851 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 retval = -ERESTARTSYS;
853 break;
854 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700855 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700856 /*
857 * Allow someone else to be scheduled. We will occasionally go
858 * through this loop until one of the above conditions change.
859 * The below schedule call will allow other processes to enter
860 * and prevent this loop from hogging the cpu.
861 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 schedule();
Alan Coxf2cf8e22005-09-06 15:16:44 -0700863 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700866 __set_current_state(TASK_RUNNING);
Alan Cox52d41732008-07-16 21:55:02 +0100867 remove_wait_queue(&ch->port.open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (!tty_hung_up_p(filp))
Alan Cox52d41732008-07-16 21:55:02 +0100869 ch->port.count++;
870 ch->port.blocked_open--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Alan Coxf2cf8e22005-09-06 15:16:44 -0700872 spin_unlock_irqrestore(&epca_lock, flags);
873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (retval)
875 return retval;
876
Alan Cox52d41732008-07-16 21:55:02 +0100877 ch->port.flags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700879}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Alan Cox191260a2008-04-30 00:54:16 -0700881static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700882{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 struct channel *ch;
884 unsigned long flags;
885 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100886 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700887 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
889 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700890 if (line < 0 || line >= nbdevs)
891 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 ch = &digi_channels[line];
894 boardnum = ch->boardnum;
895
896 /* Check status of board configured in system. */
897
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700898 /*
899 * I check to see if the epca_setup routine detected an user error. It
900 * might be better to put this in pc_init, but for the moment it goes
901 * here.
902 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700903 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700905 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700907 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700909 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700911 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700913 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700915 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700917 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700919 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 tty->driver_data = NULL; /* Mark this device as 'down' */
921 return(-ENODEV);
922 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700923
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700924 bc = ch->brdchan;
925 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700927 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
929
Alan Coxf2cf8e22005-09-06 15:16:44 -0700930 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700931 /*
932 * Every time a channel is opened, increment a counter. This is
933 * necessary because we do not wish to flush and shutdown the channel
934 * until the last app holding the channel open, closes it.
935 */
Alan Cox52d41732008-07-16 21:55:02 +0100936 ch->port.count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700937 /*
938 * Set a kernel structures pointer to our local channel structure. This
939 * way we can get to it when passed only a tty struct.
940 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 tty->driver_data = ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700942 /*
943 * If this is the first time the channel has been opened, initialize
944 * the tty->termios struct otherwise let pc_close handle it.
945 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 globalwinon(ch);
947 ch->statusflags = 0;
948
949 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100950 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700952 /*
953 * Set receive head and tail ptrs to each other. This indicates no data
954 * available to read.
955 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700956 head = readw(&bc->rin);
957 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 /* Set the channels associated tty structure */
Alan Cox52d41732008-07-16 21:55:02 +0100960 ch->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700962 /*
963 * The below routine generally sets up parity, baud, flow control
964 * issues, etc.... It effect both control flags and input flags.
965 */
Alan Cox191260a2008-04-30 00:54:16 -0700966 epcaparam(tty, ch);
Alan Cox52d41732008-07-16 21:55:02 +0100967 ch->port.flags |= ASYNC_INITIALIZED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700969 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 retval = block_til_ready(tty, filp, ch);
972 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700974 /*
975 * Set this again in case a hangup set it to zero while this open() was
976 * waiting for the line...
977 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700978 spin_lock_irqsave(&epca_lock, flags);
Alan Cox52d41732008-07-16 21:55:02 +0100979 ch->port.tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700982 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700984 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700988static int __init epca_module_init(void)
989{
990 return pc_init();
991}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996static void __exit epca_module_exit(void)
997{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 int count, crd;
999 struct board_info *bd;
1000 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 del_timer_sync(&epca_timer);
1003
Alan Cox191260a2008-04-30 00:54:16 -07001004 if (tty_unregister_driver(pc_driver) ||
1005 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001006 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return;
1008 }
1009 put_tty_driver(pc_driver);
1010 put_tty_driver(pc_info);
1011
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001012 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001014 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
1016 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001017 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001018 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001019 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox52d41732008-07-16 21:55:02 +01001020 if (ch && ch->port.tty)
1021 tty_hangup(ch->port.tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001022 }
1023 }
1024 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025}
1026module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001028static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 .open = pc_open,
1030 .close = pc_close,
1031 .write = pc_write,
1032 .write_room = pc_write_room,
1033 .flush_buffer = pc_flush_buffer,
1034 .chars_in_buffer = pc_chars_in_buffer,
1035 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 .ioctl = pc_ioctl,
1037 .set_termios = pc_set_termios,
1038 .stop = pc_stop,
1039 .start = pc_start,
1040 .throttle = pc_throttle,
1041 .unthrottle = pc_unthrottle,
1042 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +01001043 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044};
1045
Alan Cox191260a2008-04-30 00:54:16 -07001046static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
1048 return 0;
1049}
1050
1051static struct tty_operations info_ops = {
1052 .open = info_open,
1053 .ioctl = info_ioctl,
1054};
1055
Alan Coxf2cf8e22005-09-06 15:16:44 -07001056static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001057{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 int crd;
1059 struct board_info *bd;
1060 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -07001061 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 int pci_boards_found, pci_count;
1064
1065 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 pc_driver = alloc_tty_driver(MAX_ALLOC);
1068 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -07001069 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -07001072 if (!pc_info)
1073 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001075 /*
1076 * If epca_setup has not been ran by LILO set num_cards to defaults;
1077 * copy board structure defined by digiConfig into drivers board
1078 * structure. Note : If LILO has ran epca_setup then epca_setup will
1079 * handle defining num_cards as well as copying the data into the board
1080 * structure.
1081 */
1082 if (!liloconfig) {
1083 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 nbdevs = NBDEVS;
1085 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001086 memcpy(&boards, &static_boards,
1087 sizeof(struct board_info) * NUMCARDS);
1088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001090 /*
1091 * Note : If lilo was used to configure the driver and the ignore
1092 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
1093 * will equal 0 at this point. This is okay; PCI cards will still be
1094 * picked up if detected.
1095 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001097 /*
1098 * Set up interrupt, we will worry about memory allocation in
1099 * post_fep_init.
1100 */
Alan Cox191260a2008-04-30 00:54:16 -07001101 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001103 /*
1104 * NOTE : This code assumes that the number of ports found in the
1105 * boards array is correct. This could be wrong if the card in question
1106 * is PCI (And therefore has no ports entry in the boards structure.)
1107 * The rest of the information will be valid for PCI because the
1108 * beginning of pc_init scans for PCI and determines i/o and base
1109 * memory addresses. I am not sure if it is possible to read the number
1110 * of ports supported by the card prior to it being booted (Since that
1111 * is the state it is in when pc_init is run). Because it is not
1112 * possible to query the number of supported ports until after the card
1113 * has booted; we are required to calculate the card_ptrs as the card
1114 * is initialized (Inside post_fep_init). The negative thing about this
1115 * approach is that digiDload's call to GET_INFO will have a bad port
1116 * value. (Since this is called prior to post_fep_init.)
1117 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001119 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 pci_boards_found += init_PCI();
1121 num_cards += pci_boards_found;
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001124 pc_driver->name = "ttyD";
1125 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 pc_driver->minor_start = 0;
1127 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1128 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1129 pc_driver->init_termios = tty_std_termios;
1130 pc_driver->init_termios.c_iflag = 0;
1131 pc_driver->init_termios.c_oflag = 0;
1132 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1133 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001134 pc_driver->init_termios.c_ispeed = 9600;
1135 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001136 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 tty_set_operations(pc_driver, &pc_ops);
1138
1139 pc_info->owner = THIS_MODULE;
1140 pc_info->name = "digi_ctl";
1141 pc_info->major = DIGIINFOMAJOR;
1142 pc_info->minor_start = 0;
1143 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1144 pc_info->subtype = SERIAL_TYPE_INFO;
1145 pc_info->init_termios = tty_std_termios;
1146 pc_info->init_termios.c_iflag = 0;
1147 pc_info->init_termios.c_oflag = 0;
1148 pc_info->init_termios.c_lflag = 0;
1149 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001150 pc_info->init_termios.c_ispeed = 9600;
1151 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 pc_info->flags = TTY_DRIVER_REAL_RAW;
1153 tty_set_operations(pc_info, &info_ops);
1154
1155
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001156 for (crd = 0; crd < num_cards; crd++) {
1157 /*
1158 * This is where the appropriate memory handlers for the
1159 * hardware is set. Everything at runtime blindly jumps through
1160 * these vectors.
1161 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 /* defined in epcaconfig.h */
1164 bd = &boards[crd];
1165
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001166 switch (bd->type) {
1167 case PCXEM:
1168 case EISAXEM:
1169 bd->memwinon = pcxem_memwinon;
1170 bd->memwinoff = pcxem_memwinoff;
1171 bd->globalwinon = pcxem_globalwinon;
1172 bd->txwinon = pcxem_txwinon;
1173 bd->rxwinon = pcxem_rxwinon;
1174 bd->memoff = pcxem_memoff;
1175 bd->assertgwinon = dummy_assertgwinon;
1176 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 break;
1178
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001179 case PCIXEM:
1180 case PCIXRJ:
1181 case PCIXR:
1182 bd->memwinon = dummy_memwinon;
1183 bd->memwinoff = dummy_memwinoff;
1184 bd->globalwinon = dummy_globalwinon;
1185 bd->txwinon = dummy_txwinon;
1186 bd->rxwinon = dummy_rxwinon;
1187 bd->memoff = dummy_memoff;
1188 bd->assertgwinon = dummy_assertgwinon;
1189 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 break;
1191
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001192 case PCXE:
1193 case PCXEVE:
1194 bd->memwinon = pcxe_memwinon;
1195 bd->memwinoff = pcxe_memwinoff;
1196 bd->globalwinon = pcxe_globalwinon;
1197 bd->txwinon = pcxe_txwinon;
1198 bd->rxwinon = pcxe_rxwinon;
1199 bd->memoff = pcxe_memoff;
1200 bd->assertgwinon = dummy_assertgwinon;
1201 bd->assertmemoff = dummy_assertmemoff;
1202 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001204 case PCXI:
1205 case PC64XE:
1206 bd->memwinon = pcxi_memwinon;
1207 bd->memwinoff = pcxi_memwinoff;
1208 bd->globalwinon = pcxi_globalwinon;
1209 bd->txwinon = pcxi_txwinon;
1210 bd->rxwinon = pcxi_rxwinon;
1211 bd->memoff = pcxi_memoff;
1212 bd->assertgwinon = pcxi_assertgwinon;
1213 bd->assertmemoff = pcxi_assertmemoff;
1214 break;
1215
1216 default:
1217 break;
1218 }
1219
1220 /*
1221 * Some cards need a memory segment to be defined for use in
1222 * transmit and receive windowing operations. These boards are
1223 * listed in the below switch. In the case of the XI the amount
1224 * of memory on the board is variable so the memory_seg is also
1225 * variable. This code determines what they segment should be.
1226 */
1227 switch (bd->type) {
1228 case PCXE:
1229 case PCXEVE:
1230 case PC64XE:
1231 bd->memory_seg = 0xf000;
1232 break;
1233
1234 case PCXI:
1235 board_id = inb((int)bd->port);
1236 if ((board_id & 0x1) == 0x1) {
1237 /* it's an XI card */
1238 /* Is it a 64K board */
1239 if ((board_id & 0x30) == 0)
1240 bd->memory_seg = 0xf000;
1241
1242 /* Is it a 128K board */
1243 if ((board_id & 0x30) == 0x10)
1244 bd->memory_seg = 0xe000;
1245
1246 /* Is is a 256K board */
1247 if ((board_id & 0x30) == 0x20)
1248 bd->memory_seg = 0xc000;
1249
1250 /* Is it a 512K board */
1251 if ((board_id & 0x30) == 0x30)
1252 bd->memory_seg = 0x8000;
1253 } else
Alan Cox191260a2008-04-30 00:54:16 -07001254 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 -07001255 break;
1256 }
1257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Akinobu Mitadabad052006-10-17 00:10:28 -07001259 err = tty_register_driver(pc_driver);
1260 if (err) {
1261 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1262 goto out3;
1263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Akinobu Mitadabad052006-10-17 00:10:28 -07001265 err = tty_register_driver(pc_info);
1266 if (err) {
1267 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1268 goto out4;
1269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001271 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 init_timer(&epca_timer);
1273 epca_timer.function = epcapoll;
1274 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 return 0;
1276
Akinobu Mitadabad052006-10-17 00:10:28 -07001277out4:
1278 tty_unregister_driver(pc_driver);
1279out3:
1280 put_tty_driver(pc_info);
1281out2:
1282 put_tty_driver(pc_driver);
1283out1:
1284 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001285}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
1287static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001288{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001290 void __iomem *memaddr;
1291 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001293 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001294 struct channel *ch;
1295 int shrinkmem = 0, lowwater;
1296
1297 /*
1298 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1299 * responsible for setting up all the card specific stuff.
1300 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 bd = &boards[crd];
1302
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001303 /*
1304 * If this is a PCI board, get the port info. Remember PCI cards do not
1305 * have entries into the epcaconfig.h file, so we can't get the number
1306 * of ports from it. Unfortunetly, this means that anyone doing a
1307 * DIGI_GETINFO before the board has booted will get an invalid number
1308 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1309 * DIGI_INIT has been called will return the proper values.
1310 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001311 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001312 /*
1313 * Below we use XEMPORTS as a memory offset regardless of which
1314 * PCI card it is. This is because all of the supported PCI
1315 * cards have the same memory offset for the channel data. This
1316 * will have to be changed if we ever develop a PCI/XE card.
1317 * NOTE : The FEP manual states that the port offset is 0xC22
1318 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1319 * cards; not for the XEM, or CX series. On the PCI cards the
1320 * number of ports is determined by reading a ID PROM located
1321 * in the box attached to the card. The card can then determine
1322 * the index the id to determine the number of ports available.
1323 * (FYI - The id should be located at 0x1ac (And may use up to
1324 * 4 bytes if the box in question is a XEM or CX)).
1325 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001326 /* PCI cards are already remapped at this point ISA are not */
1327 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001328 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001330 } else {
1331 /* Fix up the mappings for ISA/EISA etc */
1332 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001333 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336 if (crd != 0)
1337 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1338 else
1339 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1340
1341 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1343
Alan Coxf2cf8e22005-09-06 15:16:44 -07001344 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001346 /*
1347 * The below assignment will set bc to point at the BEGINING of the
1348 * cards channel structures. For 1 card there will be between 8 and 64
1349 * of these structures.
1350 */
Al Virobc9a5152005-09-15 22:53:28 +01001351 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001353 /*
1354 * The below assignment will set gd to point at the BEGINING of global
1355 * memory address 0xc00. The first data in that global memory actually
1356 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1357 */
Al Virobc9a5152005-09-15 22:53:28 +01001358 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001360 /*
1361 * XEPORTS (address 0xc22) points at the number of channels the card
1362 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1363 */
Alan Cox191260a2008-04-30 00:54:16 -07001364 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1365 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 shrinkmem = 1;
1367 if (bd->type < PCIXEM)
1368 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001369 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 memwinon(bd, 0);
1371
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001372 /*
1373 * Remember ch is the main drivers channels structure, while bc is the
1374 * cards channel structure.
1375 */
1376 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001377 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001378 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001380 ch->brdchan = bc;
1381 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001382 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001383 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Alan Coxf2cf8e22005-09-06 15:16:44 -07001385 spin_lock_irqsave(&epca_lock, flags);
1386 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001387 /*
1388 * Since some of the boards use different bitmaps for
1389 * their control signals we cannot hard code these
1390 * values and retain portability. We virtualize this
1391 * data here.
1392 */
1393 case EISAXEM:
1394 case PCXEM:
1395 case PCIXEM:
1396 case PCIXRJ:
1397 case PCIXR:
1398 ch->m_rts = 0x02;
1399 ch->m_dcd = 0x80;
1400 ch->m_dsr = 0x20;
1401 ch->m_cts = 0x10;
1402 ch->m_ri = 0x40;
1403 ch->m_dtr = 0x01;
1404 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001406 case PCXE:
1407 case PCXEVE:
1408 case PCXI:
1409 case PC64XE:
1410 ch->m_rts = 0x02;
1411 ch->m_dcd = 0x08;
1412 ch->m_dsr = 0x10;
1413 ch->m_cts = 0x20;
1414 ch->m_ri = 0x40;
1415 ch->m_dtr = 0x80;
1416 break;
1417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Alan Coxf2cf8e22005-09-06 15:16:44 -07001419 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 ch->dsr = ch->m_dcd;
1421 ch->dcd = ch->m_dsr;
1422 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001423 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 ch->dcd = ch->m_dcd;
1425 ch->dsr = ch->m_dsr;
1426 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 ch->boardnum = crd;
1429 ch->channelnum = i;
1430 ch->magic = EPCA_MAGIC;
Alan Cox52d41732008-07-16 21:55:02 +01001431 ch->port.tty = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Alan Coxf2cf8e22005-09-06 15:16:44 -07001433 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1435 shrinkmem = 0;
1436 }
1437
Al Virobc9a5152005-09-15 22:53:28 +01001438 tseg = readw(&bc->tseg);
1439 rseg = readw(&bc->rseg);
1440
Alan Coxf2cf8e22005-09-06 15:16:44 -07001441 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001442 case PCIXEM:
1443 case PCIXRJ:
1444 case PCIXR:
1445 /* Cover all the 2MEG cards */
1446 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1447 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1448 ch->txwin = FEPWIN | (tseg >> 11);
1449 ch->rxwin = FEPWIN | (rseg >> 11);
1450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001452 case PCXEM:
1453 case EISAXEM:
1454 /* Cover all the 32K windowed cards */
1455 /* Mask equal to window size - 1 */
1456 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1457 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1458 ch->txwin = FEPWIN | (tseg >> 11);
1459 ch->rxwin = FEPWIN | (rseg >> 11);
1460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001462 case PCXEVE:
1463 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001464 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1465 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001466 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001467 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1468 & 0x1fff);
1469 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001470 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001472 case PCXI:
1473 case PC64XE:
1474 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1475 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1476 ch->txwin = ch->rxwin = 0;
1477 break;
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001481 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001484 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001485
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1487
1488 /* Set transmitter low water mark */
1489 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1490
1491 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1493
1494 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1496
Alan Coxf2cf8e22005-09-06 15:16:44 -07001497 writew(100, &bc->edelay);
1498 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001499
Alan Coxf2cf8e22005-09-06 15:16:44 -07001500 ch->startc = readb(&bc->startc);
1501 ch->stopc = readb(&bc->stopc);
1502 ch->startca = readb(&bc->startca);
1503 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001504
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 ch->fepcflag = 0;
1506 ch->fepiflag = 0;
1507 ch->fepoflag = 0;
1508 ch->fepstartc = 0;
1509 ch->fepstopc = 0;
1510 ch->fepstartca = 0;
1511 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 ch->close_delay = 50;
Alan Cox52d41732008-07-16 21:55:02 +01001514 ch->port.count = 0;
1515 ch->port.blocked_open = 0;
1516 init_waitqueue_head(&ch->port.open_wait);
1517 init_waitqueue_head(&ch->port.close_wait);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001518
1519 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001522 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001523 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1524 VERSION, board_desc[bd->type], (long)bd->port,
1525 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001527}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
1529static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001530{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 unsigned long flags;
1532 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001533 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 struct channel *ch;
1535 struct board_info *bd;
1536
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001537 /*
1538 * This routine is called upon every timer interrupt. Even though the
1539 * Digi series cards are capable of generating interrupts this method
1540 * of non-looping polling is more efficient. This routine checks for
1541 * card generated events (Such as receive data, are transmit buffer
1542 * empty) and acts on those events.
1543 */
1544 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 bd = &boards[crd];
1546 ch = card_ptr[crd];
1547
1548 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001549 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001551 /*
1552 * assertmemoff is not needed here; indeed it is an empty
1553 * subroutine. It is being kept because future boards may need
1554 * this as well as some legacy boards.
1555 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001556 spin_lock_irqsave(&epca_lock, flags);
1557
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 assertmemoff(ch);
1559
1560 globalwinon(ch);
1561
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001562 /*
1563 * In this case head and tail actually refer to the event queue
1564 * not the transmit or receive queue.
1565 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001566 head = readw(&ch->mailbox->ein);
1567 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001569 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (head != tail)
1571 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 memoff(ch);
1573
Alan Coxf2cf8e22005-09-06 15:16:44 -07001574 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001577}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001580{
Al Virobc9a5152005-09-15 22:53:28 +01001581 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 struct channel *ch, *chan0;
1583 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001584 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001585 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001586 unsigned int tail, head;
1587 int event, channel;
1588 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001590 /*
1591 * This subroutine is called by epcapoll when an event is detected
1592 * in the event queue. This routine responds to those events.
1593 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 bd = &boards[crd];
1595
1596 chan0 = card_ptr[crd];
1597 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001599 while ((tail = readw(&chan0->mailbox->eout)) !=
1600 (head = readw(&chan0->mailbox->ein))) {
1601 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001603 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001605 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001607 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001608 /*
1609 * The two assignments below get the current modem status
1610 * (mstat) and the previous modem status (lstat). These are
1611 * useful becuase an event could signal a change in modem
1612 * signals itself.
1613 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001614 mstat = readb(eventbuf + 2);
1615 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001618 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 if (channel >= bd->numports)
1620 ch = chan0;
1621 bc = ch->brdchan;
1622 goto next;
1623 }
1624
Alan Cox191260a2008-04-30 00:54:16 -07001625 bc = ch->brdchan;
1626 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 goto next;
1628
Alan Coxf2cf8e22005-09-06 15:16:44 -07001629 if (event & DATA_IND) { /* Begin DATA_IND */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 receive_data(ch);
1631 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 } /* End DATA_IND */
1633 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001634 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 ch->imodem = mstat;
Alan Cox52d41732008-07-16 21:55:02 +01001637 if (ch->port.flags & ASYNC_CHECK_CD) {
Alan Cox191260a2008-04-30 00:54:16 -07001638 /* We are now receiving dcd */
1639 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001640 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001641 else /* No dcd; hangup */
1642 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001644 }
Alan Cox52d41732008-07-16 21:55:02 +01001645 tty = ch->port.tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001646 if (tty) {
1647 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001649 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001650 tty_schedule_flip(tty);
1651 } else if (event & LOWTX_IND) {
1652 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 ch->statusflags &= ~LOWWAIT;
1654 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001655 }
1656 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001657 /* This event is generated by
1658 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001660 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 ch->statusflags &= ~EMPTYWAIT;
1662 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001663 }
1664 }
1665 }
Alan Cox191260a2008-04-30 00:54:16 -07001666next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001668 BUG_ON(!bc);
1669 writew(1, &bc->idata);
1670 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001673}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001676 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001677{
Al Virobc9a5152005-09-15 22:53:28 +01001678 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 unsigned int head, cmdTail, cmdStart, cmdMax;
1680 long count;
1681 int n;
1682
1683 /* This is the routine in which commands may be passed to the card. */
1684
1685 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001689 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001691 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001692 /*
1693 * We do the addition below because we do not want a max pointer
1694 * relative to cmdStart. We want a max pointer that points at the
1695 * physical end of the command queue.
1696 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001697 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 memaddr = ch->board->re_map_membase;
1699
Alan Coxf2cf8e22005-09-06 15:16:44 -07001700 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001701 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1702 __LINE__, cmd, head);
1703 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1704 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 return;
1706 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001707 if (bytecmd) {
1708 writeb(cmd, memaddr + head + cmdStart + 0);
1709 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001711 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001713 writeb(byte2, memaddr + head + cmdStart + 3);
1714 } else {
1715 writeb(cmd, memaddr + head + cmdStart + 0);
1716 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1717 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001720 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 count = FEPTIMEOUT;
1722
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001723 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001725 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1727 return;
1728 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001729 head = readw(&ch->mailbox->cin);
1730 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001732 /*
1733 * Basically this will break when the FEP acknowledges the
1734 * command by incrementing cmdTail (Making it equal to head).
1735 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001737 break;
1738 }
1739}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001741/*
1742 * Digi products use fields in their channels structures that are very similar
1743 * to the c_cflag and c_iflag fields typically found in UNIX termios
1744 * structures. The below three routines allow mappings between these hardware
1745 * "flags" and their respective Linux flags.
1746 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001748{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 unsigned res = 0;
1750
Alan Coxf2cf8e22005-09-06 15:16:44 -07001751 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1753 res |= ((ch->m_cts) | (ch->m_rts));
1754 }
1755
1756 if (ch->digiext.digi_flags & RTSPACE)
1757 res |= ch->m_rts;
1758
1759 if (ch->digiext.digi_flags & DTRPACE)
1760 res |= ch->m_dtr;
1761
1762 if (ch->digiext.digi_flags & CTSPACE)
1763 res |= ch->m_cts;
1764
1765 if (ch->digiext.digi_flags & DSRPACE)
1766 res |= ch->dsr;
1767
1768 if (ch->digiext.digi_flags & DCDPACE)
1769 res |= ch->dcd;
1770
1771 if (res & (ch->m_rts))
1772 ch->digiext.digi_flags |= RTSPACE;
1773
1774 if (res & (ch->m_cts))
1775 ch->digiext.digi_flags |= CTSPACE;
1776
1777 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001778}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001781{
1782 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001783 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 if (ch->digiext.digi_flags & DIGI_AIXON)
1785 res |= IAIXON;
1786 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001787}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
1789static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001790{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001792 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001793 ch->digiext.digi_flags |= DIGI_FAST;
1794 /*
1795 * HUPCL bit is used by FEP to indicate fast baud table is to
1796 * be used.
1797 */
1798 res |= FEP_HUPCL;
1799 } else
1800 ch->digiext.digi_flags &= ~DIGI_FAST;
1801 /*
1802 * CBAUD has bit position 0x1000 set these days to indicate Linux
1803 * baud rate remap. Digi hardware can't handle the bit assignment.
1804 * (We use a different bit assignment for high speed.). Clear this
1805 * bit out.
1806 */
1807 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1808 /*
1809 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001810 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001811 * this is identical to the Linux implementation. However; Digi
1812 * supports one rate (76800) that Linux doesn't. This means that the
1813 * c_cflag entry that would normally mean 76800 for Digi actually means
1814 * 115200 under Linux. Without the below mapping, a stty 115200 would
1815 * only drive the board at 76800. Since the rate 230400 is also found
1816 * after 76800, the same problem afflicts us when we choose a rate of
1817 * 230400. Without the below modificiation stty 230400 would actually
1818 * give us 115200.
1819 *
1820 * There are two additional differences. The Linux value for CLOCAL
1821 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1822 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1823 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1824 * checked for a screened out prior to termios2digi_c returning. Since
1825 * CLOCAL isn't used by the board this can be ignored as long as the
1826 * returned value is used only by Digi hardware.
1827 */
1828 if (cflag & CBAUDEX) {
1829 /*
1830 * The below code is trying to guarantee that only baud rates
1831 * 115200 and 230400 are remapped. We use exclusive or because
1832 * the various baud rates share common bit positions and
1833 * therefore can't be tested for easily.
1834 */
1835 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001840}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
Alan Coxf2cf8e22005-09-06 15:16:44 -07001842/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001844{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001846 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001847 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 unsigned mval, hflow, cflag, iflag;
1849
1850 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001851 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
1853 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001855 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1856 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001857 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001858 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001860 /*
1861 * Flush current transmit buffer by setting cmdTail pointer
1862 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1863 * buffer is empty.
1864 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1866 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001867 } else { /* Begin CBAUD not detected */
1868 /*
1869 * c_cflags have changed but that change had nothing to do with
1870 * BAUD. Propagate the change to the card.
1871 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001873 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 ch->fepcflag = cflag;
1875 /* Set baud rate, char size, stop bits, parity */
1876 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1877 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001878 /*
1879 * If the user has not forced CLOCAL and if the device is not a
1880 * CALLOUT device (Which is always CLOCAL) we set flags such
1881 * that the driver will wait on carrier detect.
1882 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 if (ts->c_cflag & CLOCAL)
Alan Cox52d41732008-07-16 21:55:02 +01001884 ch->port.flags &= ~ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 else
Alan Cox52d41732008-07-16 21:55:02 +01001886 ch->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001891 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001893 /*
1894 * Command sets channels iflag structure on the board. Such
1895 * things as input soft flow control, handling of parity
1896 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001897 *
1898 * break handling, parity handling, input stripping,
1899 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001900 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1902 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001903 /*
1904 * Set the board mint value for this channel. This will cause hardware
1905 * events to be generated each time the DCD signal (Described in mint)
1906 * changes.
1907 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001908 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1910 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001911 writeb(0, &bc->mint);
1912 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001914 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001916 /*
1917 * Hard flow control has been selected but the board is not
1918 * using it. Activate hard flow control now.
1919 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 mval ^= ch->modemfake & (mval ^ ch->modem);
1923
Alan Coxf2cf8e22005-09-06 15:16:44 -07001924 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001926 /*
1927 * The below command sets the DTR and RTS mstat structure. If
1928 * hard flow control is NOT active these changes will drive the
1929 * output of the actual DTR and RTS lines. If hard flow control
1930 * is active, the changes will be saved in the mstat structure
1931 * and only asserted when hard flow control is turned off.
1932 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933
1934 /* First reset DTR & RTS; then set them */
1935 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1936 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001938 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 ch->fepstartc = ch->startc;
1940 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001941 /*
1942 * The XON / XOFF characters have changed; propagate these
1943 * changes to the card.
1944 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1946 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001947 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 ch->fepstartca = ch->startca;
1949 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001950 /*
1951 * Similar to the above, this time the auxilarly XON / XOFF
1952 * characters have changed; propagate these changes to the card.
1953 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1955 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001956}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Alan Coxf2cf8e22005-09-06 15:16:44 -07001958/* Caller holds lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959static void receive_data(struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001960{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001962 struct ktermios *ts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 struct tty_struct *tty;
Al Virobc9a5152005-09-15 22:53:28 +01001964 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001965 int dataToRead, wrapgap, bytesAvailable;
1966 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001969 /*
1970 * This routine is called by doint when a receive data event has taken
1971 * place.
1972 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 if (ch->statusflags & RXSTOPPED)
1975 return;
Alan Cox52d41732008-07-16 21:55:02 +01001976 tty = ch->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 if (tty)
1978 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001980 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 wrapmask = ch->rxbufsize - 1;
1982
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001983 /*
1984 * Get the head and tail pointers to the receiver queue. Wrap the head
1985 * pointer if it has reached the end of the buffer.
1986 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001987 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001989 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
1991 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 if (bytesAvailable == 0)
1993 return;
1994
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001995 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07001996 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001997 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 return;
1999 }
2000
Alan Cox33f0f882006-01-09 20:54:13 -08002001 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 return;
2003
Alan Coxf2cf8e22005-09-06 15:16:44 -07002004 if (readb(&bc->orun)) {
2005 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07002006 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
2007 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08002008 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07002011 while (bytesAvailable > 0) {
2012 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002014 /*
2015 * Even if head has wrapped around only report the amount of
2016 * data to be equal to the size - tail. Remember memcpy can't
2017 * automaticly wrap around the receive buffer.
2018 */
Alan Cox191260a2008-04-30 00:54:16 -07002019 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
2020 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002021 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08002022 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 if (dataToRead == 0)
2024 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002025 /*
2026 * Move data read from our card into the line disciplines
2027 * buffer for translation if necessary.
2028 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002029 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 tail = (tail + dataToRead) & wrapmask;
2031 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002034 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 /* Must be called with global data */
Alan Cox52d41732008-07-16 21:55:02 +01002036 tty_schedule_flip(ch->port.tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002037}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002039static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 unsigned int cmd, unsigned long arg)
2041{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002042 switch (cmd) {
2043 case DIGI_GETINFO:
2044 {
2045 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 int brd;
2047
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002048 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07002049 return -EFAULT;
2050 if (brd < 0 || brd >= num_cards || num_cards == 0)
2051 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052
2053 memset(&di, 0, sizeof(di));
2054
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002055 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 di.status = boards[brd].status;
2057 di.type = boards[brd].type ;
2058 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002059 /* Legacy fixups - just move along nothing to see */
2060 di.port = (unsigned char *)boards[brd].port ;
2061 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002063 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 return -EFAULT;
2065 break;
2066
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002069 case DIGI_POLLER:
2070 {
2071 int brd = arg & 0xff000000 >> 16;
2072 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Alan Coxf2cf8e22005-09-06 15:16:44 -07002074 if (brd < 0 || brd >= num_cards) {
2075 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002076 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002078 digi_poller_inhibited = state;
2079 break;
2080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002082 case DIGI_INIT:
2083 {
2084 /*
2085 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02002086 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002087 * responsible for setting the card to its initial
2088 * state and setting the drivers control fields to the
2089 * sutianle settings for the card in question.
2090 */
2091 int crd;
2092 for (crd = 0; crd < num_cards; crd++)
2093 post_fep_init(crd);
2094 break;
2095 }
2096 default:
2097 return -ENOTTY;
2098 }
2099 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
2102static int pc_tiocmget(struct tty_struct *tty, struct file *file)
2103{
2104 struct channel *ch = (struct channel *) tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01002105 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 unsigned int mstat, mflag = 0;
2107 unsigned long flags;
2108
2109 if (ch)
2110 bc = ch->brdchan;
2111 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002112 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
Alan Coxf2cf8e22005-09-06 15:16:44 -07002114 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002116 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002118 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
2120 if (mstat & ch->m_dtr)
2121 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 if (mstat & ch->m_rts)
2123 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if (mstat & ch->m_cts)
2125 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if (mstat & ch->dsr)
2127 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if (mstat & ch->m_ri)
2129 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 if (mstat & ch->dcd)
2131 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 return mflag;
2133}
2134
2135static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2136 unsigned int set, unsigned int clear)
2137{
2138 struct channel *ch = (struct channel *) tty->driver_data;
2139 unsigned long flags;
2140
Alan Coxf2cf8e22005-09-06 15:16:44 -07002141 if (!ch)
2142 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Alan Coxf2cf8e22005-09-06 15:16:44 -07002144 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002146 * I think this modemfake stuff is broken. It doesn't correctly reflect
2147 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2148 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 */
2150 if (set & TIOCM_RTS) {
2151 ch->modemfake |= ch->m_rts;
2152 ch->modem |= ch->m_rts;
2153 }
2154 if (set & TIOCM_DTR) {
2155 ch->modemfake |= ch->m_dtr;
2156 ch->modem |= ch->m_dtr;
2157 }
2158 if (clear & TIOCM_RTS) {
2159 ch->modemfake |= ch->m_rts;
2160 ch->modem &= ~ch->m_rts;
2161 }
2162 if (clear & TIOCM_DTR) {
2163 ch->modemfake |= ch->m_dtr;
2164 ch->modem &= ~ch->m_dtr;
2165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002167 /*
2168 * The below routine generally sets up parity, baud, flow control
2169 * issues, etc.... It effect both control flags and input flags.
2170 */
Alan Cox191260a2008-04-30 00:54:16 -07002171 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002173 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 return 0;
2175}
2176
Alan Cox191260a2008-04-30 00:54:16 -07002177static int pc_ioctl(struct tty_struct *tty, struct file *file,
2178 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002179{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 unsigned long flags;
2182 unsigned int mflag, mstat;
2183 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002184 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 struct channel *ch = (struct channel *) tty->driver_data;
2186 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002187
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 if (ch)
2189 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002190 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002191 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002192 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002193 case TIOCMODG:
2194 mflag = pc_tiocmget(tty, file);
2195 if (put_user(mflag, (unsigned long __user *)argp))
2196 return -EFAULT;
2197 break;
2198 case TIOCMODS:
2199 if (get_user(mstat, (unsigned __user *)argp))
2200 return -EFAULT;
2201 return pc_tiocmset(tty, file, mstat, ~mstat);
2202 case TIOCSDTR:
2203 spin_lock_irqsave(&epca_lock, flags);
2204 ch->omodem |= ch->m_dtr;
2205 globalwinon(ch);
2206 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2207 memoff(ch);
2208 spin_unlock_irqrestore(&epca_lock, flags);
2209 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002211 case TIOCCDTR:
2212 spin_lock_irqsave(&epca_lock, flags);
2213 ch->omodem &= ~ch->m_dtr;
2214 globalwinon(ch);
2215 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2216 memoff(ch);
2217 spin_unlock_irqrestore(&epca_lock, flags);
2218 break;
2219 case DIGI_GETA:
2220 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2221 return -EFAULT;
2222 break;
2223 case DIGI_SETAW:
2224 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002225 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002226 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002227 /* Setup an event to indicate when the transmit
2228 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002229 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002230 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002231 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002232 tty_wait_until_sent(tty, 0);
2233 } else {
2234 /* ldisc lock already held in ioctl */
Alan Coxa352def2008-07-16 21:53:12 +01002235 if (tty->ldisc.ops->flush_buffer)
2236 tty->ldisc.ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002237 }
Alan Cox37925e02008-04-30 00:53:17 -07002238 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002239 /* Fall Thru */
2240 case DIGI_SETA:
2241 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2242 return -EFAULT;
2243
2244 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2245 ch->dcd = ch->m_dsr;
2246 ch->dsr = ch->m_dcd;
2247 } else {
2248 ch->dcd = ch->m_dcd;
2249 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002251
2252 spin_lock_irqsave(&epca_lock, flags);
2253 globalwinon(ch);
2254
2255 /*
2256 * The below routine generally sets up parity, baud, flow
2257 * control issues, etc.... It effect both control flags and
2258 * input flags.
2259 */
Alan Cox191260a2008-04-30 00:54:16 -07002260 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002261 memoff(ch);
2262 spin_unlock_irqrestore(&epca_lock, flags);
2263 break;
2264
2265 case DIGI_GETFLOW:
2266 case DIGI_GETAFLOW:
2267 spin_lock_irqsave(&epca_lock, flags);
2268 globalwinon(ch);
2269 if (cmd == DIGI_GETFLOW) {
2270 dflow.startc = readb(&bc->startc);
2271 dflow.stopc = readb(&bc->stopc);
2272 } else {
2273 dflow.startc = readb(&bc->startca);
2274 dflow.stopc = readb(&bc->stopca);
2275 }
2276 memoff(ch);
2277 spin_unlock_irqrestore(&epca_lock, flags);
2278
2279 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2280 return -EFAULT;
2281 break;
2282
2283 case DIGI_SETAFLOW:
2284 case DIGI_SETFLOW:
2285 if (cmd == DIGI_SETFLOW) {
2286 startc = ch->startc;
2287 stopc = ch->stopc;
2288 } else {
2289 startc = ch->startca;
2290 stopc = ch->stopca;
2291 }
2292
2293 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2294 return -EFAULT;
2295
Alan Cox191260a2008-04-30 00:54:16 -07002296 if (dflow.startc != startc || dflow.stopc != stopc) {
2297 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002298 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 globalwinon(ch);
2300
Alan Coxf2cf8e22005-09-06 15:16:44 -07002301 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002302 ch->fepstartc = ch->startc = dflow.startc;
2303 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002304 fepcmd(ch, SONOFFC, ch->fepstartc,
2305 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002306 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002307 ch->fepstartca = ch->startca = dflow.startc;
2308 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002309 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2310 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 }
2312
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002313 if (ch->statusflags & TXSTOPPED)
2314 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002316 memoff(ch);
2317 spin_unlock_irqrestore(&epca_lock, flags);
2318 } /* End if setflow toggled */
2319 break;
2320 default:
2321 return -ENOIOCTLCMD;
2322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002324}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Alan Cox606d0992006-12-08 02:38:45 -08002326static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002327{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 struct channel *ch;
2329 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002330 /*
2331 * verifyChannel returns the channel from the tty struct if it is
2332 * valid. This serves as a sanity check.
2333 */
Alan Cox191260a2008-04-30 00:54:16 -07002334 ch = verifyChannel(tty);
2335
2336 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002337 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 globalwinon(ch);
2339 epcaparam(tty, ch);
2340 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002341 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
2343 if ((old_termios->c_cflag & CRTSCTS) &&
2344 ((tty->termios->c_cflag & CRTSCTS) == 0))
2345 tty->hw_stopped = 0;
2346
2347 if (!(old_termios->c_cflag & CLOCAL) &&
2348 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002349 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002352}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
David Howellsc4028952006-11-22 14:57:56 +00002354static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002355{
David Howellsc4028952006-11-22 14:57:56 +00002356 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002358 if (ch && ch->magic == EPCA_MAGIC) {
Alan Cox52d41732008-07-16 21:55:02 +01002359 struct tty_struct *tty = ch->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Alan Coxf2cf8e22005-09-06 15:16:44 -07002361 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002362 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002363 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002364 wake_up_interruptible(&ch->port.open_wait);
2365 ch->port.flags &= ~ASYNC_NORMAL_ACTIVE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002368 }
2369}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002371/*
2372 * pc_stop and pc_start provide software flow control to the routine and the
2373 * pc_ioctl routine.
2374 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002376{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 struct channel *ch;
2378 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002379 /*
2380 * verifyChannel returns the channel from the tty struct if it is
2381 * valid. This serves as a sanity check.
2382 */
Alan Cox191260a2008-04-30 00:54:16 -07002383 ch = verifyChannel(tty);
2384 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002385 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002386 if ((ch->statusflags & TXSTOPPED) == 0) {
2387 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 ch->statusflags |= TXSTOPPED;
2392 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002394 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002395 }
2396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002399{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002401 /*
2402 * verifyChannel returns the channel from the tty struct if it is
2403 * valid. This serves as a sanity check.
2404 */
Alan Cox191260a2008-04-30 00:54:16 -07002405 ch = verifyChannel(tty);
2406 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002408 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002409 /* Just in case output was resumed because of a change
2410 in Digi-flow */
2411 if (ch->statusflags & TXSTOPPED) {
2412 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002413 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 globalwinon(ch);
2415 bc = ch->brdchan;
2416 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002417 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 ch->statusflags &= ~TXSTOPPED;
2421 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002423 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002424 }
2425}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002427/*
2428 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2429 * resume) the receipt of data into the kernels receive buffers. The exact
2430 * occurrence of this depends on the size of the kernels receive buffer and
2431 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2432 * more details.
2433 */
2434static void pc_throttle(struct tty_struct *tty)
2435{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 struct channel *ch;
2437 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002438 /*
2439 * verifyChannel returns the channel from the tty struct if it is
2440 * valid. This serves as a sanity check.
2441 */
Alan Cox191260a2008-04-30 00:54:16 -07002442 ch = verifyChannel(tty);
2443 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002444 spin_lock_irqsave(&epca_lock, flags);
2445 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 globalwinon(ch);
2447 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 ch->statusflags |= RXSTOPPED;
2449 memoff(ch);
2450 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002451 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002452 }
2453}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
2455static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002456{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 struct channel *ch;
2458 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002459 /*
2460 * verifyChannel returns the channel from the tty struct if it is
2461 * valid. This serves as a sanity check.
2462 */
Alan Cox191260a2008-04-30 00:54:16 -07002463 ch = verifyChannel(tty);
2464 if (ch != NULL) {
2465 /* Just in case output was resumed because of a change
2466 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002467 spin_lock_irqsave(&epca_lock, flags);
2468 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 ch->statusflags &= ~RXSTOPPED;
2472 memoff(ch);
2473 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002474 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002475 }
2476}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477
Alan Coxdcbf1282008-07-22 11:18:12 +01002478static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002479{
Alan Coxdcbf1282008-07-22 11:18:12 +01002480 struct channel *ch = (struct channel *) tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 unsigned long flags;
2482
Alan Coxdcbf1282008-07-22 11:18:12 +01002483 if (msec == -1)
2484 return -EOPNOTSUPP;
2485
Alan Coxf2cf8e22005-09-06 15:16:44 -07002486 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002488 /*
2489 * Maybe I should send an infinite break here, schedule() for msec
2490 * amount of time, and then stop the break. This way, the user can't
2491 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2492 * an ioctl()) more than once in msec amount of time.
2493 * Try this for now...
2494 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2496 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002497 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002498 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002499}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
Alan Coxf2cf8e22005-09-06 15:16:44 -07002501/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002503{
Al Virobc9a5152005-09-15 22:53:28 +01002504 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 globalwinon(ch);
2507 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002508 /*
2509 * When set the iempty flag request a event to be generated when the
2510 * transmit buffer is empty (If there is no BREAK in progress).
2511 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002512 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002514}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
Alan Cox191260a2008-04-30 00:54:16 -07002516static void epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002517{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 struct board_info board;
2519 int index, loop, last;
2520 char *temp, *t2;
2521 unsigned len;
2522
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002523 /*
2524 * If this routine looks a little strange it is because it is only
2525 * called if a LILO append command is given to boot the kernel with
2526 * parameters. In this way, we can provide the user a method of
2527 * changing his board configuration without rebuilding the kernel.
2528 */
2529 if (!liloconfig)
2530 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532 memset(&board, 0, sizeof(board));
2533
2534 /* Assume the data is int first, later we can change it */
2535 /* I think that array position 0 of ints holds the number of args */
2536 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002537 switch (index) { /* Begin parse switch */
2538 case 1:
2539 board.status = ints[index];
2540 /*
2541 * We check for 2 (As opposed to 1; because 2 is a flag
2542 * instructing the driver to ignore epcaconfig.) For
2543 * this reason we check for 2.
2544 */
Alan Cox191260a2008-04-30 00:54:16 -07002545 if (board.status == 2) {
2546 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002547 nbdevs = 0;
2548 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002550 } /* End ignore epcaconfig as well as lilo cmd line */
2551
2552 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002553 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2554 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002555 invalid_lilo_config = 1;
2556 setup_error_code |= INVALID_BOARD_STATUS;
2557 return;
2558 }
2559 last = index;
2560 break;
2561 case 2:
2562 board.type = ints[index];
2563 if (board.type >= PCIXEM) {
2564 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2565 invalid_lilo_config = 1;
2566 setup_error_code |= INVALID_BOARD_TYPE;
2567 return;
2568 }
2569 last = index;
2570 break;
2571 case 3:
2572 board.altpin = ints[index];
2573 if (board.altpin > 1) {
2574 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2575 invalid_lilo_config = 1;
2576 setup_error_code |= INVALID_ALTPIN;
2577 return;
2578 }
2579 last = index;
2580 break;
2581
2582 case 4:
2583 board.numports = ints[index];
2584 if (board.numports < 2 || board.numports > 256) {
2585 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2586 invalid_lilo_config = 1;
2587 setup_error_code |= INVALID_NUM_PORTS;
2588 return;
2589 }
2590 nbdevs += board.numports;
2591 last = index;
2592 break;
2593
2594 case 5:
2595 board.port = ints[index];
2596 if (ints[index] <= 0) {
2597 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2598 invalid_lilo_config = 1;
2599 setup_error_code |= INVALID_PORT_BASE;
2600 return;
2601 }
2602 last = index;
2603 break;
2604
2605 case 6:
2606 board.membase = ints[index];
2607 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002608 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2609 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002610 invalid_lilo_config = 1;
2611 setup_error_code |= INVALID_MEM_BASE;
2612 return;
2613 }
2614 last = index;
2615 break;
2616
2617 default:
2618 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2619 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 } /* End parse switch */
2622
Alan Coxf2cf8e22005-09-06 15:16:44 -07002623 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 /* find the next comma or terminator */
2625 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 /* While string is not null, and a comma hasn't been found */
2627 while (*temp && (*temp != ','))
2628 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 if (!*temp)
2630 temp = NULL;
2631 else
2632 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 /* Set index to the number of args + 1 */
2634 index = last + 1;
2635
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002636 switch (index) {
2637 case 1:
2638 len = strlen(str);
2639 if (strncmp("Disable", str, len) == 0)
2640 board.status = 0;
2641 else if (strncmp("Enable", str, len) == 0)
2642 board.status = 1;
2643 else {
2644 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2645 invalid_lilo_config = 1;
2646 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002648 }
2649 last = index;
2650 break;
2651
2652 case 2:
2653 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2654 if (strcmp(board_desc[loop], str) == 0)
2655 break;
2656 /*
2657 * If the index incremented above refers to a
2658 * legitamate board type set it here.
2659 */
2660 if (index < EPCA_NUM_TYPES)
2661 board.type = loop;
2662 else {
2663 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2664 invalid_lilo_config = 1;
2665 setup_error_code |= INVALID_BOARD_TYPE;
2666 return;
2667 }
2668 last = index;
2669 break;
2670
2671 case 3:
2672 len = strlen(str);
2673 if (strncmp("Disable", str, len) == 0)
2674 board.altpin = 0;
2675 else if (strncmp("Enable", str, len) == 0)
2676 board.altpin = 1;
2677 else {
2678 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2679 invalid_lilo_config = 1;
2680 setup_error_code |= INVALID_ALTPIN;
2681 return;
2682 }
2683 last = index;
2684 break;
2685
2686 case 4:
2687 t2 = str;
2688 while (isdigit(*t2))
2689 t2++;
2690
2691 if (*t2) {
2692 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2693 invalid_lilo_config = 1;
2694 setup_error_code |= INVALID_NUM_PORTS;
2695 return;
2696 }
2697
2698 /*
2699 * There is not a man page for simple_strtoul but the
2700 * code can be found in vsprintf.c. The first argument
2701 * is the string to translate (To an unsigned long
2702 * obviously), the second argument can be the address
2703 * of any character variable or a NULL. If a variable
2704 * is given, the end pointer of the string will be
2705 * stored in that variable; if a NULL is given the end
2706 * pointer will not be returned. The last argument is
2707 * the base to use. If a 0 is indicated, the routine
2708 * will attempt to determine the proper base by looking
2709 * at the values prefix (A '0' for octal, a 'x' for
2710 * hex, etc ... If a value is given it will use that
2711 * value as the base.
2712 */
2713 board.numports = simple_strtoul(str, NULL, 0);
2714 nbdevs += board.numports;
2715 last = index;
2716 break;
2717
2718 case 5:
2719 t2 = str;
2720 while (isxdigit(*t2))
2721 t2++;
2722
2723 if (*t2) {
2724 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2725 invalid_lilo_config = 1;
2726 setup_error_code |= INVALID_PORT_BASE;
2727 return;
2728 }
2729
2730 board.port = simple_strtoul(str, NULL, 16);
2731 last = index;
2732 break;
2733
2734 case 6:
2735 t2 = str;
2736 while (isxdigit(*t2))
2737 t2++;
2738
2739 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002740 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002741 invalid_lilo_config = 1;
2742 setup_error_code |= INVALID_MEM_BASE;
2743 return;
2744 }
2745 board.membase = simple_strtoul(str, NULL, 16);
2746 last = index;
2747 break;
2748 default:
2749 printk(KERN_ERR "epca: Too many string parms\n");
2750 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 }
2752 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 } /* End while there is a string arg */
2754
Alan Coxf2cf8e22005-09-06 15:16:44 -07002755 if (last < 6) {
2756 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return;
2758 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002762 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002764 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2765 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002768}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
2770enum epic_board_types {
2771 brd_xr = 0,
2772 brd_xem,
2773 brd_cx,
2774 brd_xrj,
2775};
2776
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777/* indexed directly by epic_board_types enum */
2778static struct {
2779 unsigned char board_type;
2780 unsigned bar_idx; /* PCI base address region */
2781} epca_info_tbl[] = {
2782 { PCIXR, 0, },
2783 { PCIXEM, 0, },
2784 { PCICX, 0, },
2785 { PCIXRJ, 2, },
2786};
2787
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002788static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 const struct pci_device_id *ent)
2790{
2791 static int board_num = -1;
2792 int board_idx, info_idx = ent->driver_data;
2793 unsigned long addr;
2794
2795 if (pci_enable_device(pdev))
2796 return -EIO;
2797
2798 board_num++;
2799 board_idx = board_num + num_cards;
2800 if (board_idx >= MAXBOARDS)
2801 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002802
Alan Cox191260a2008-04-30 00:54:16 -07002803 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002805 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 epca_info_tbl[info_idx].bar_idx);
2807 goto err_out;
2808 }
2809
2810 boards[board_idx].status = ENABLED;
2811 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2812 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002813 boards[board_idx].port = addr + PCI_IO_OFFSET;
2814 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815
Alan Cox191260a2008-04-30 00:54:16 -07002816 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2817 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 0x200000, addr + PCI_IO_OFFSET);
2819 goto err_out;
2820 }
2821
Alan Cox191260a2008-04-30 00:54:16 -07002822 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2823 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002825 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 0x200000, addr + PCI_IO_OFFSET);
2827 goto err_out_free_pciio;
2828 }
2829
Alan Cox191260a2008-04-30 00:54:16 -07002830 if (!request_mem_region(addr, 0x200000, "epca")) {
2831 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 0x200000, addr);
2833 goto err_out_free_iounmap;
2834 }
2835
Alan Cox191260a2008-04-30 00:54:16 -07002836 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002838 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 0x200000, addr + PCI_IO_OFFSET);
2840 goto err_out_free_memregion;
2841 }
2842
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002843 /*
2844 * I don't know what the below does, but the hardware guys say its
2845 * required on everything except PLX (In this case XRJ).
2846 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002848 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 pci_write_config_byte(pdev, 0x46, 0);
2850 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002851
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 return 0;
2853
2854err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002855 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002857 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002859 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860err_out:
2861 return -ENODEV;
2862}
2863
2864
2865static struct pci_device_id epca_pci_tbl[] = {
2866 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2867 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2868 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2869 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2870 { 0, }
2871};
2872
2873MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2874
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002875static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002876{
Alan Cox191260a2008-04-30 00:54:16 -07002877 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 epca_driver.name = "epca";
2879 epca_driver.id_table = epca_pci_tbl;
2880 epca_driver.probe = epca_init_one;
2881
2882 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002883}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
2885MODULE_LICENSE("GPL");