blob: af7c13ca949377da39751cb78df840b21de7ff32 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 Copyright (C) 1996 Digi International.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 For technical support please email digiLinux@dgii.com or
5 call Digi tech support at (612) 912-3456
6
Alan Coxf2cf8e22005-09-06 15:16:44 -07007 ** This driver is no longer supported by Digi **
8
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07009 Much of this design and code came from epca.c which was
10 copyright (C) 1994, 1995 Troy De Jongh, and subsquently
11 modified by David Nugent, Christoph Lameter, Mike McLagan.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070018 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070023 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070027/* See README.epca for change history --DAT*/
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/init.h>
33#include <linux/serial.h>
34#include <linux/delay.h>
35#include <linux/ctype.h>
36#include <linux/tty.h>
37#include <linux/tty_flip.h>
38#include <linux/slab.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
Alan Cox191260a2008-04-30 00:54:16 -070041#include <linux/uaccess.h>
42#include <linux/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070043#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/pci.h>
45#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include "digi1.h"
49#include "digiFep1.h"
50#include "epca.h"
51#include "epcaconfig.h"
52
Alan Coxf2cf8e22005-09-06 15:16:44 -070053#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070056#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58
59#define MAXCARDS 7
60#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
61
62#define PFX "epca: "
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static int nbdevs, num_cards, liloconfig;
65static int digi_poller_inhibited = 1 ;
66
67static int setup_error_code;
68static int invalid_lilo_config;
69
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070070/*
71 * The ISA boards do window flipping into the same spaces so its only sane with
Alan Coxd1c815e2009-01-02 13:47:58 +000072 * a single lock. It's still pretty efficient. This lock guards the hardware
73 * and the tty_port lock guards the kernel side stuff like use counts. Take
74 * this lock inside the port lock if you must take both.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070075 */
Ingo Molnar34af9462006-06-27 02:53:55 -070076static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070077
Alan Cox191260a2008-04-30 00:54:16 -070078/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
79 to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static struct board_info boards[MAXBOARDS];
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct tty_driver *pc_driver;
83static struct tty_driver *pc_info;
84
85/* ------------------ Begin Digi specific structures -------------------- */
86
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070087/*
88 * digi_channels represents an array of structures that keep track of each
89 * channel of the Digi product. Information such as transmit and receive
90 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
91 * here. This structure is NOT used to overlay the cards physical channel
92 * structure.
93 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static struct channel digi_channels[MAX_ALLOC];
95
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070096/*
97 * card_ptr is an array used to hold the address of the first channel structure
98 * of each card. This array will hold the addresses of various channels located
99 * in digi_channels.
100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static struct channel *card_ptr[MAXCARDS];
102
103static struct timer_list epca_timer;
104
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700105/*
106 * Begin generic memory functions. These functions will be alias (point at)
107 * more specific functions dependent on the board being configured.
108 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700109static void memwinon(struct board_info *b, unsigned int win);
110static void memwinoff(struct board_info *b, unsigned int win);
111static void globalwinon(struct channel *ch);
112static void rxwinon(struct channel *ch);
113static void txwinon(struct channel *ch);
114static void memoff(struct channel *ch);
115static void assertgwinon(struct channel *ch);
116static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118/* ---- Begin more 'specific' memory functions for cx_like products --- */
119
Alan Coxf2cf8e22005-09-06 15:16:44 -0700120static void pcxem_memwinon(struct board_info *b, unsigned int win);
121static void pcxem_memwinoff(struct board_info *b, unsigned int win);
122static void pcxem_globalwinon(struct channel *ch);
123static void pcxem_rxwinon(struct channel *ch);
124static void pcxem_txwinon(struct channel *ch);
125static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* ------ Begin more 'specific' memory functions for the pcxe ------- */
128
Alan Coxf2cf8e22005-09-06 15:16:44 -0700129static void pcxe_memwinon(struct board_info *b, unsigned int win);
130static void pcxe_memwinoff(struct board_info *b, unsigned int win);
131static void pcxe_globalwinon(struct channel *ch);
132static void pcxe_rxwinon(struct channel *ch);
133static void pcxe_txwinon(struct channel *ch);
134static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
137/* Note : pc64xe and pcxi share the same windowing routines */
138
Alan Coxf2cf8e22005-09-06 15:16:44 -0700139static void pcxi_memwinon(struct board_info *b, unsigned int win);
140static void pcxi_memwinoff(struct board_info *b, unsigned int win);
141static void pcxi_globalwinon(struct channel *ch);
142static void pcxi_rxwinon(struct channel *ch);
143static void pcxi_txwinon(struct channel *ch);
144static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146/* - Begin 'specific' do nothing memory functions needed for some cards - */
147
Alan Coxf2cf8e22005-09-06 15:16:44 -0700148static void dummy_memwinon(struct board_info *b, unsigned int win);
149static void dummy_memwinoff(struct board_info *b, unsigned int win);
150static void dummy_globalwinon(struct channel *ch);
151static void dummy_rxwinon(struct channel *ch);
152static void dummy_txwinon(struct channel *ch);
153static void dummy_memoff(struct channel *ch);
154static void dummy_assertgwinon(struct channel *ch);
155static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Alan Coxf2cf8e22005-09-06 15:16:44 -0700157static struct channel *verifyChannel(struct tty_struct *);
158static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159static void epca_error(int, char *);
160static void pc_close(struct tty_struct *, struct file *);
Alan Coxd1c815e2009-01-02 13:47:58 +0000161static void shutdown(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int pc_write_room(struct tty_struct *);
164static int pc_chars_in_buffer(struct tty_struct *);
165static void pc_flush_buffer(struct tty_struct *);
166static void pc_flush_chars(struct tty_struct *);
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 *);
Alan Cox3969ffb2009-01-02 13:48:04 +0000176static void receive_data(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177static 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int pc_write(struct tty_struct *, const unsigned char *, int);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700191static int pc_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static int init_PCI(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700194/*
195 * Table of functions for each board to handle memory. Mantaining parallelism
196 * is a *very* good idea here. The idea is for the runtime code to blindly call
197 * these functions, not knowing/caring about the underlying hardware. This
198 * stuff should contain no conditionals; if more functionality is needed a
199 * different entry should be established. These calls are the interface calls
200 * and are the only functions that should be accessed. Anyone caught making
201 * direct calls deserves what they get.
202 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700203static void memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700205 b->memwinon(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
Alan Coxf2cf8e22005-09-06 15:16:44 -0700208static void memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700210 b->memwinoff(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
Alan Coxf2cf8e22005-09-06 15:16:44 -0700213static void globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700215 ch->board->globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Alan Coxf2cf8e22005-09-06 15:16:44 -0700218static void rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700220 ch->board->rxwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
Alan Coxf2cf8e22005-09-06 15:16:44 -0700223static void txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700225 ch->board->txwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Alan Coxf2cf8e22005-09-06 15:16:44 -0700228static void memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700230 ch->board->memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
Alan Coxf2cf8e22005-09-06 15:16:44 -0700232static void assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700234 ch->board->assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
236
Alan Coxf2cf8e22005-09-06 15:16:44 -0700237static void assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700239 ch->board->assertmemoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
241
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700242/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700243static void pcxem_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
Alan Cox191260a2008-04-30 00:54:16 -0700245 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
Alan Coxf2cf8e22005-09-06 15:16:44 -0700248static void pcxem_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700250 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
252
Alan Coxf2cf8e22005-09-06 15:16:44 -0700253static void pcxem_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
Alan Cox191260a2008-04-30 00:54:16 -0700255 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256}
257
Alan Coxf2cf8e22005-09-06 15:16:44 -0700258static void pcxem_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 outb_p(ch->rxwin, (int)ch->board->port + 1);
261}
262
Alan Coxf2cf8e22005-09-06 15:16:44 -0700263static void pcxem_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 outb_p(ch->txwin, (int)ch->board->port + 1);
266}
267
Alan Coxf2cf8e22005-09-06 15:16:44 -0700268static void pcxem_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 outb_p(0, (int)ch->board->port + 1);
271}
272
273/* ----------------- Begin pcxe memory window stuff ------------------ */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700274static void pcxe_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700276 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
Alan Coxf2cf8e22005-09-06 15:16:44 -0700279static void pcxe_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700281 outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700282 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283}
284
Alan Coxf2cf8e22005-09-06 15:16:44 -0700285static void pcxe_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700287 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288}
289
Alan Coxf2cf8e22005-09-06 15:16:44 -0700290static void pcxe_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700292 outb_p(ch->rxwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
Alan Coxf2cf8e22005-09-06 15:16:44 -0700295static void pcxe_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700297 outb_p(ch->txwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
Alan Coxf2cf8e22005-09-06 15:16:44 -0700300static void pcxe_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 outb_p(0, (int)ch->board->port);
303 outb_p(0, (int)ch->board->port + 1);
304}
305
306/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700307static void pcxi_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700309 outb_p(inb(b->port) | FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
Alan Coxf2cf8e22005-09-06 15:16:44 -0700312static void pcxi_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700314 outb_p(inb(b->port) & ~FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316
Alan Coxf2cf8e22005-09-06 15:16:44 -0700317static void pcxi_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700319 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Alan Coxf2cf8e22005-09-06 15:16:44 -0700322static void pcxi_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700324 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
Alan Coxf2cf8e22005-09-06 15:16:44 -0700327static void pcxi_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700329 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Alan Coxf2cf8e22005-09-06 15:16:44 -0700332static void pcxi_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700334 outb_p(0, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
Alan Coxf2cf8e22005-09-06 15:16:44 -0700337static void pcxi_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700339 epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340}
341
Alan Coxf2cf8e22005-09-06 15:16:44 -0700342static void pcxi_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700344 epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700347/*
348 * Not all of the cards need specific memory windowing routines. Some cards
349 * (Such as PCI) needs no windowing routines at all. We provide these do
350 * nothing routines so that the same code base can be used. The driver will
351 * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
352 * card. However, dependent on the card the routine may or may not do anything.
353 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700354static void dummy_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356}
357
Alan Coxf2cf8e22005-09-06 15:16:44 -0700358static void dummy_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
360}
361
Alan Coxf2cf8e22005-09-06 15:16:44 -0700362static void dummy_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364}
365
Alan Coxf2cf8e22005-09-06 15:16:44 -0700366static void dummy_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368}
369
Alan Coxf2cf8e22005-09-06 15:16:44 -0700370static void dummy_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372}
373
Alan Coxf2cf8e22005-09-06 15:16:44 -0700374static void dummy_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376}
377
Alan Coxf2cf8e22005-09-06 15:16:44 -0700378static void dummy_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380}
381
Alan Coxf2cf8e22005-09-06 15:16:44 -0700382static void dummy_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384}
385
Alan Coxf2cf8e22005-09-06 15:16:44 -0700386static struct channel *verifyChannel(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700387{
388 /*
389 * This routine basically provides a sanity check. It insures that the
390 * channel returned is within the proper range of addresses as well as
391 * properly initialized. If some bogus info gets passed in
392 * through tty->driver_data this should catch it.
393 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700394 if (tty) {
Alan Coxc9f19e92009-01-02 13:47:26 +0000395 struct channel *ch = tty->driver_data;
Alan Cox191260a2008-04-30 00:54:16 -0700396 if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (ch->magic == EPCA_MAGIC)
398 return ch;
399 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return NULL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700402}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Alan Coxf2cf8e22005-09-06 15:16:44 -0700404static void pc_sched_event(struct channel *ch, int event)
405{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700406 /*
407 * We call this to schedule interrupt processing on some event. The
408 * kernel sees our request and calls the related routine in OUR driver.
409 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 ch->event |= 1 << event;
411 schedule_work(&ch->tqueue);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700412}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414static void epca_error(int line, char *msg)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700415{
Alan Cox191260a2008-04-30 00:54:16 -0700416 printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700417}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700419static void pc_close(struct tty_struct *tty, struct file *filp)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700420{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000422 struct tty_port *port;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700423 /*
424 * verifyChannel returns the channel from the tty struct if it is
425 * valid. This serves as a sanity check.
426 */
Alan Cox191260a2008-04-30 00:54:16 -0700427 ch = verifyChannel(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000428 if (ch == NULL)
429 return;
430 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431
Alan Cox6ed1dba2009-01-02 13:48:11 +0000432 if (tty_port_close_start(port, tty, filp) == 0)
Alan Coxd1c815e2009-01-02 13:47:58 +0000433 return;
Alan Coxd1c815e2009-01-02 13:47:58 +0000434
Alan Coxd1c815e2009-01-02 13:47:58 +0000435 pc_flush_buffer(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000436 shutdown(ch, tty);
437
Alan Cox6ed1dba2009-01-02 13:48:11 +0000438 tty_port_close_end(port, tty);
439 ch->event = 0; /* FIXME: review ch->event locking */
Alan Cox3969ffb2009-01-02 13:48:04 +0000440 tty_port_tty_set(port, NULL);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700441}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
Alan Coxd1c815e2009-01-02 13:47:58 +0000443static void shutdown(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700444{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +0100446 struct board_chan __iomem *bc;
Alan Coxd1c815e2009-01-02 13:47:58 +0000447 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Alan Coxd1c815e2009-01-02 13:47:58 +0000449 if (!(port->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return;
451
Alan Coxf2cf8e22005-09-06 15:16:44 -0700452 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Alan Coxf2cf8e22005-09-06 15:16:44 -0700454 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 bc = ch->brdchan;
456
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700457 /*
458 * In order for an event to be generated on the receipt of data the
459 * idata flag must be set. Since we are shutting down, this is not
460 * necessary clear this flag.
461 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700463 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700465 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700466 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
468 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 memoff(ch);
471
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700472 /*
473 * The channel has officialy been closed. The next time it is opened it
474 * will have to reinitialized. Set a flag to indicate this.
475 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /* Prevent future Digi programmed interrupts from coming active */
Alan Coxd1c815e2009-01-02 13:47:58 +0000477 port->flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700478 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700479}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700482{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000484
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700485 /*
486 * verifyChannel returns the channel from the tty struct if it is
487 * valid. This serves as a sanity check.
488 */
Alan Cox191260a2008-04-30 00:54:16 -0700489 ch = verifyChannel(tty);
490 if (ch != NULL) {
Alan Cox978e5952008-04-30 00:53:59 -0700491 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 tty_ldisc_flush(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000493 shutdown(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Alan Coxd1c815e2009-01-02 13:47:58 +0000495 ch->event = 0; /* FIXME: review locking of ch->event */
Alan Cox6ed1dba2009-01-02 13:48:11 +0000496 tty_port_hangup(&ch->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700497 }
498}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700500static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700501 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700502{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700503 unsigned int head, tail;
504 int dataLen;
505 int size;
506 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct channel *ch;
508 unsigned long flags;
509 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100510 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700512 /*
513 * pc_write is primarily called directly by the kernel routine
514 * tty_write (Though it can also be called by put_char) found in
515 * tty_io.c. pc_write is passed a line discipline buffer where the data
516 * to be written out is stored. The line discipline implementation
517 * itself is done at the kernel level and is not brought into the
518 * driver.
519 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700521 /*
522 * verifyChannel returns the channel from the tty struct if it is
523 * valid. This serves as a sanity check.
524 */
Alan Cox191260a2008-04-30 00:54:16 -0700525 ch = verifyChannel(tty);
526 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 return 0;
528
529 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 bc = ch->brdchan;
531 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Alan Coxf2cf8e22005-09-06 15:16:44 -0700534 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 globalwinon(ch);
536
Alan Coxf2cf8e22005-09-06 15:16:44 -0700537 head = readw(&bc->tin) & (size - 1);
538 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Alan Coxf2cf8e22005-09-06 15:16:44 -0700540 if (tail != readw(&bc->tout))
541 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 tail &= (size - 1);
543
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700544 if (head >= tail) {
545 /* head has not wrapped */
546 /*
547 * remain (much like dataLen above) represents the total amount
548 * of space available on the card for data. Here dataLen
549 * represents the space existing between the head pointer and
550 * the end of buffer. This is important because a memcpy cannot
551 * be told to automatically wrap around when it hits the buffer
552 * end.
553 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 dataLen = size - head;
555 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700556 } else {
557 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 remain = tail - head - 1;
559 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700560 }
561 /*
562 * Check the space on the card. If we have more data than space; reduce
563 * the amount of data to fit the space.
564 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700567 while (bytesAvailable > 0) {
568 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700570 /*
571 * If head is not wrapped, the below will make sure the first
572 * data copy fills to the end of card buffer.
573 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100575 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 buf += dataLen;
577 head += dataLen;
578 amountCopied += dataLen;
579 bytesAvailable -= dataLen;
580
Alan Coxf2cf8e22005-09-06 15:16:44 -0700581 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 head = 0;
583 dataLen = tail;
584 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 ch->statusflags |= TXBUSY;
587 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700588 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Alan Coxf2cf8e22005-09-06 15:16:44 -0700590 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700592 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 }
594 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700595 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700596 return amountCopied;
597}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700600{
Alan Cox191260a2008-04-30 00:54:16 -0700601 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 struct channel *ch;
603 unsigned long flags;
604 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100605 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700606 /*
607 * verifyChannel returns the channel from the tty struct if it is
608 * valid. This serves as a sanity check.
609 */
Alan Cox191260a2008-04-30 00:54:16 -0700610 ch = verifyChannel(tty);
611 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700612 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 globalwinon(ch);
614
615 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700616 head = readw(&bc->tin) & (ch->txbufsize - 1);
617 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Alan Coxf2cf8e22005-09-06 15:16:44 -0700619 if (tail != readw(&bc->tout))
620 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 /* Wrap tail if necessary */
622 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700623 remain = tail - head - 1;
624 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 remain += ch->txbufsize;
626
Alan Coxf2cf8e22005-09-06 15:16:44 -0700627 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700629 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
631 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700632 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 /* Return how much room is left on card */
635 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700636}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700639{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 int chars;
641 unsigned int ctail, head, tail;
642 int remain;
643 unsigned long flags;
644 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100645 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700646 /*
647 * verifyChannel returns the channel from the tty struct if it is
648 * valid. This serves as a sanity check.
649 */
Alan Cox191260a2008-04-30 00:54:16 -0700650 ch = verifyChannel(tty);
651 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700652 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Alan Coxf2cf8e22005-09-06 15:16:44 -0700654 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 globalwinon(ch);
656
657 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700658 tail = readw(&bc->tout);
659 head = readw(&bc->tin);
660 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Alan Cox191260a2008-04-30 00:54:16 -0700662 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
663 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700665 else { /* Begin if some space on the card has been used */
666 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700668 /*
669 * The logic here is basically opposite of the above
670 * pc_write_room here we are finding the amount of bytes in the
671 * buffer filled. Not the amount of bytes empty.
672 */
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700677 /*
678 * Make it possible to wakeup anything waiting for output in
679 * tty_ioctl.c, etc.
680 *
681 * If not already set. Setup an event to indicate when the
682 * transmit buffer empties.
683 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700685 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700688 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700690 return chars;
691}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700694{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 unsigned int tail;
696 unsigned long flags;
697 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100698 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700699 /*
700 * verifyChannel returns the channel from the tty struct if it is
701 * valid. This serves as a sanity check.
702 */
Alan Cox191260a2008-04-30 00:54:16 -0700703 ch = verifyChannel(tty);
704 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return;
706
Alan Coxf2cf8e22005-09-06 15:16:44 -0700707 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700710 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700714 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700716}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700719{
720 struct channel *ch;
721 /*
722 * verifyChannel returns the channel from the tty struct if it is
723 * valid. This serves as a sanity check.
724 */
Alan Cox191260a2008-04-30 00:54:16 -0700725 ch = verifyChannel(tty);
726 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700728 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700729 /*
730 * If not already set and the transmitter is busy setup an
731 * event to indicate when the transmit empties.
732 */
Alan Cox191260a2008-04-30 00:54:16 -0700733 if ((ch->statusflags & TXBUSY) &&
734 !(ch->statusflags & EMPTYWAIT))
735 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700736 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700738}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Alan Cox6ed1dba2009-01-02 13:48:11 +0000740static int epca_carrier_raised(struct tty_port *port)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700741{
Alan Cox6ed1dba2009-01-02 13:48:11 +0000742 struct channel *ch = container_of(port, struct channel, port);
743 if (ch->imodem & ch->dcd)
744 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700746}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Alan Coxc1314a42009-01-02 13:48:17 +0000748static void epca_raise_dtr_rts(struct tty_port *port)
Alan Cox6ed1dba2009-01-02 13:48:11 +0000749{
750}
751
Alan Cox191260a2008-04-30 00:54:16 -0700752static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000755 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 unsigned long flags;
757 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100758 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700759 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
761 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700762 if (line < 0 || line >= nbdevs)
763 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 ch = &digi_channels[line];
Alan Coxd1c815e2009-01-02 13:47:58 +0000766 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 boardnum = ch->boardnum;
768
769 /* Check status of board configured in system. */
770
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700771 /*
Frederik Schwarzer0211a9c2008-12-29 22:14:56 +0100772 * I check to see if the epca_setup routine detected a user error. It
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700773 * might be better to put this in pc_init, but for the moment it goes
774 * here.
775 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700776 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700778 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700780 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700782 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700784 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700786 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700788 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700790 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700792 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 tty->driver_data = NULL; /* Mark this device as 'down' */
794 return(-ENODEV);
795 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700796
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700797 bc = ch->brdchan;
798 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700800 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
802
Alan Coxd1c815e2009-01-02 13:47:58 +0000803 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700804 /*
805 * Every time a channel is opened, increment a counter. This is
806 * necessary because we do not wish to flush and shutdown the channel
807 * until the last app holding the channel open, closes it.
808 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000809 port->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700810 /*
811 * Set a kernel structures pointer to our local channel structure. This
812 * way we can get to it when passed only a tty struct.
813 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 tty->driver_data = ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000815 port->tty = tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700816 /*
817 * If this is the first time the channel has been opened, initialize
818 * the tty->termios struct otherwise let pc_close handle it.
819 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000820 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 globalwinon(ch);
822 ch->statusflags = 0;
823
824 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100825 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700827 /*
828 * Set receive head and tail ptrs to each other. This indicates no data
829 * available to read.
830 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700831 head = readw(&bc->rin);
832 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 /* Set the channels associated tty structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700836 /*
837 * The below routine generally sets up parity, baud, flow control
838 * issues, etc.... It effect both control flags and input flags.
839 */
Alan Cox191260a2008-04-30 00:54:16 -0700840 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000842 spin_unlock(&epca_lock);
843 port->flags |= ASYNC_INITIALIZED;
844 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Alan Cox6ed1dba2009-01-02 13:48:11 +0000846 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700849 /*
850 * Set this again in case a hangup set it to zero while this open() was
851 * waiting for the line...
852 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000853 spin_lock_irqsave(&port->lock, flags);
854 port->tty = tty;
855 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700858 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000860 spin_unlock(&epca_lock);
861 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700865static int __init epca_module_init(void)
866{
867 return pc_init();
868}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
873static void __exit epca_module_exit(void)
874{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 int count, crd;
876 struct board_info *bd;
877 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 del_timer_sync(&epca_timer);
880
Alan Cox191260a2008-04-30 00:54:16 -0700881 if (tty_unregister_driver(pc_driver) ||
882 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700883 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return;
885 }
886 put_tty_driver(pc_driver);
887 put_tty_driver(pc_info);
888
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700889 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700891 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
893 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700894 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700895 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700896 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox3969ffb2009-01-02 13:48:04 +0000897 struct tty_struct *tty = tty_port_tty_get(&ch->port);
898 if (tty) {
899 tty_hangup(tty);
900 tty_kref_put(tty);
901 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700902 }
903 }
904 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905}
906module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700908static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 .open = pc_open,
910 .close = pc_close,
911 .write = pc_write,
912 .write_room = pc_write_room,
913 .flush_buffer = pc_flush_buffer,
914 .chars_in_buffer = pc_chars_in_buffer,
915 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 .ioctl = pc_ioctl,
917 .set_termios = pc_set_termios,
918 .stop = pc_stop,
919 .start = pc_start,
920 .throttle = pc_throttle,
921 .unthrottle = pc_unthrottle,
922 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +0100923 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924};
925
Alan Cox6ed1dba2009-01-02 13:48:11 +0000926static const struct tty_port_operations epca_port_ops = {
927 .carrier_raised = epca_carrier_raised,
928 .raise_dtr_rts = epca_raise_dtr_rts,
929};
930
Alan Cox191260a2008-04-30 00:54:16 -0700931static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932{
933 return 0;
934}
935
936static struct tty_operations info_ops = {
937 .open = info_open,
938 .ioctl = info_ioctl,
939};
940
Alan Coxf2cf8e22005-09-06 15:16:44 -0700941static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700942{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 int crd;
944 struct board_info *bd;
945 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -0700946 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 int pci_boards_found, pci_count;
949
950 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 pc_driver = alloc_tty_driver(MAX_ALLOC);
953 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -0700954 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -0700957 if (!pc_info)
958 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700960 /*
961 * If epca_setup has not been ran by LILO set num_cards to defaults;
962 * copy board structure defined by digiConfig into drivers board
963 * structure. Note : If LILO has ran epca_setup then epca_setup will
964 * handle defining num_cards as well as copying the data into the board
965 * structure.
966 */
967 if (!liloconfig) {
968 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 nbdevs = NBDEVS;
970 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700971 memcpy(&boards, &static_boards,
972 sizeof(struct board_info) * NUMCARDS);
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700975 /*
976 * Note : If lilo was used to configure the driver and the ignore
977 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
978 * will equal 0 at this point. This is okay; PCI cards will still be
979 * picked up if detected.
980 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700982 /*
983 * Set up interrupt, we will worry about memory allocation in
984 * post_fep_init.
985 */
Alan Cox191260a2008-04-30 00:54:16 -0700986 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700988 /*
989 * NOTE : This code assumes that the number of ports found in the
990 * boards array is correct. This could be wrong if the card in question
991 * is PCI (And therefore has no ports entry in the boards structure.)
992 * The rest of the information will be valid for PCI because the
993 * beginning of pc_init scans for PCI and determines i/o and base
994 * memory addresses. I am not sure if it is possible to read the number
995 * of ports supported by the card prior to it being booted (Since that
996 * is the state it is in when pc_init is run). Because it is not
997 * possible to query the number of supported ports until after the card
998 * has booted; we are required to calculate the card_ptrs as the card
999 * is initialized (Inside post_fep_init). The negative thing about this
1000 * approach is that digiDload's call to GET_INFO will have a bad port
1001 * value. (Since this is called prior to post_fep_init.)
1002 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001004 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 pci_boards_found += init_PCI();
1006 num_cards += pci_boards_found;
1007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001009 pc_driver->name = "ttyD";
1010 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 pc_driver->minor_start = 0;
1012 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1013 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1014 pc_driver->init_termios = tty_std_termios;
1015 pc_driver->init_termios.c_iflag = 0;
1016 pc_driver->init_termios.c_oflag = 0;
1017 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1018 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001019 pc_driver->init_termios.c_ispeed = 9600;
1020 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001021 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 tty_set_operations(pc_driver, &pc_ops);
1023
1024 pc_info->owner = THIS_MODULE;
1025 pc_info->name = "digi_ctl";
1026 pc_info->major = DIGIINFOMAJOR;
1027 pc_info->minor_start = 0;
1028 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1029 pc_info->subtype = SERIAL_TYPE_INFO;
1030 pc_info->init_termios = tty_std_termios;
1031 pc_info->init_termios.c_iflag = 0;
1032 pc_info->init_termios.c_oflag = 0;
1033 pc_info->init_termios.c_lflag = 0;
1034 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001035 pc_info->init_termios.c_ispeed = 9600;
1036 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 pc_info->flags = TTY_DRIVER_REAL_RAW;
1038 tty_set_operations(pc_info, &info_ops);
1039
1040
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001041 for (crd = 0; crd < num_cards; crd++) {
1042 /*
1043 * This is where the appropriate memory handlers for the
1044 * hardware is set. Everything at runtime blindly jumps through
1045 * these vectors.
1046 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
1048 /* defined in epcaconfig.h */
1049 bd = &boards[crd];
1050
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001051 switch (bd->type) {
1052 case PCXEM:
1053 case EISAXEM:
1054 bd->memwinon = pcxem_memwinon;
1055 bd->memwinoff = pcxem_memwinoff;
1056 bd->globalwinon = pcxem_globalwinon;
1057 bd->txwinon = pcxem_txwinon;
1058 bd->rxwinon = pcxem_rxwinon;
1059 bd->memoff = pcxem_memoff;
1060 bd->assertgwinon = dummy_assertgwinon;
1061 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 break;
1063
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001064 case PCIXEM:
1065 case PCIXRJ:
1066 case PCIXR:
1067 bd->memwinon = dummy_memwinon;
1068 bd->memwinoff = dummy_memwinoff;
1069 bd->globalwinon = dummy_globalwinon;
1070 bd->txwinon = dummy_txwinon;
1071 bd->rxwinon = dummy_rxwinon;
1072 bd->memoff = dummy_memoff;
1073 bd->assertgwinon = dummy_assertgwinon;
1074 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 break;
1076
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001077 case PCXE:
1078 case PCXEVE:
1079 bd->memwinon = pcxe_memwinon;
1080 bd->memwinoff = pcxe_memwinoff;
1081 bd->globalwinon = pcxe_globalwinon;
1082 bd->txwinon = pcxe_txwinon;
1083 bd->rxwinon = pcxe_rxwinon;
1084 bd->memoff = pcxe_memoff;
1085 bd->assertgwinon = dummy_assertgwinon;
1086 bd->assertmemoff = dummy_assertmemoff;
1087 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001089 case PCXI:
1090 case PC64XE:
1091 bd->memwinon = pcxi_memwinon;
1092 bd->memwinoff = pcxi_memwinoff;
1093 bd->globalwinon = pcxi_globalwinon;
1094 bd->txwinon = pcxi_txwinon;
1095 bd->rxwinon = pcxi_rxwinon;
1096 bd->memoff = pcxi_memoff;
1097 bd->assertgwinon = pcxi_assertgwinon;
1098 bd->assertmemoff = pcxi_assertmemoff;
1099 break;
1100
1101 default:
1102 break;
1103 }
1104
1105 /*
1106 * Some cards need a memory segment to be defined for use in
1107 * transmit and receive windowing operations. These boards are
1108 * listed in the below switch. In the case of the XI the amount
1109 * of memory on the board is variable so the memory_seg is also
1110 * variable. This code determines what they segment should be.
1111 */
1112 switch (bd->type) {
1113 case PCXE:
1114 case PCXEVE:
1115 case PC64XE:
1116 bd->memory_seg = 0xf000;
1117 break;
1118
1119 case PCXI:
1120 board_id = inb((int)bd->port);
1121 if ((board_id & 0x1) == 0x1) {
1122 /* it's an XI card */
1123 /* Is it a 64K board */
1124 if ((board_id & 0x30) == 0)
1125 bd->memory_seg = 0xf000;
1126
1127 /* Is it a 128K board */
1128 if ((board_id & 0x30) == 0x10)
1129 bd->memory_seg = 0xe000;
1130
1131 /* Is is a 256K board */
1132 if ((board_id & 0x30) == 0x20)
1133 bd->memory_seg = 0xc000;
1134
1135 /* Is it a 512K board */
1136 if ((board_id & 0x30) == 0x30)
1137 bd->memory_seg = 0x8000;
1138 } else
Alan Cox191260a2008-04-30 00:54:16 -07001139 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 -07001140 break;
1141 }
1142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Akinobu Mitadabad052006-10-17 00:10:28 -07001144 err = tty_register_driver(pc_driver);
1145 if (err) {
1146 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1147 goto out3;
1148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Akinobu Mitadabad052006-10-17 00:10:28 -07001150 err = tty_register_driver(pc_info);
1151 if (err) {
1152 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1153 goto out4;
1154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001156 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 init_timer(&epca_timer);
1158 epca_timer.function = epcapoll;
1159 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return 0;
1161
Akinobu Mitadabad052006-10-17 00:10:28 -07001162out4:
1163 tty_unregister_driver(pc_driver);
1164out3:
1165 put_tty_driver(pc_info);
1166out2:
1167 put_tty_driver(pc_driver);
1168out1:
1169 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001170}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
1172static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001173{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001175 void __iomem *memaddr;
1176 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001178 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001179 struct channel *ch;
1180 int shrinkmem = 0, lowwater;
1181
1182 /*
1183 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1184 * responsible for setting up all the card specific stuff.
1185 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 bd = &boards[crd];
1187
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001188 /*
1189 * If this is a PCI board, get the port info. Remember PCI cards do not
1190 * have entries into the epcaconfig.h file, so we can't get the number
1191 * of ports from it. Unfortunetly, this means that anyone doing a
1192 * DIGI_GETINFO before the board has booted will get an invalid number
1193 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1194 * DIGI_INIT has been called will return the proper values.
1195 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001196 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001197 /*
1198 * Below we use XEMPORTS as a memory offset regardless of which
1199 * PCI card it is. This is because all of the supported PCI
1200 * cards have the same memory offset for the channel data. This
1201 * will have to be changed if we ever develop a PCI/XE card.
1202 * NOTE : The FEP manual states that the port offset is 0xC22
1203 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1204 * cards; not for the XEM, or CX series. On the PCI cards the
1205 * number of ports is determined by reading a ID PROM located
1206 * in the box attached to the card. The card can then determine
1207 * the index the id to determine the number of ports available.
1208 * (FYI - The id should be located at 0x1ac (And may use up to
1209 * 4 bytes if the box in question is a XEM or CX)).
1210 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001211 /* PCI cards are already remapped at this point ISA are not */
1212 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001213 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001215 } else {
1216 /* Fix up the mappings for ISA/EISA etc */
1217 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001218 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
1221 if (crd != 0)
1222 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1223 else
1224 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1225
1226 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1228
Alan Coxf2cf8e22005-09-06 15:16:44 -07001229 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001231 /*
1232 * The below assignment will set bc to point at the BEGINING of the
1233 * cards channel structures. For 1 card there will be between 8 and 64
1234 * of these structures.
1235 */
Al Virobc9a5152005-09-15 22:53:28 +01001236 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001238 /*
1239 * The below assignment will set gd to point at the BEGINING of global
1240 * memory address 0xc00. The first data in that global memory actually
1241 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1242 */
Al Virobc9a5152005-09-15 22:53:28 +01001243 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001245 /*
1246 * XEPORTS (address 0xc22) points at the number of channels the card
1247 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1248 */
Alan Cox191260a2008-04-30 00:54:16 -07001249 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1250 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 shrinkmem = 1;
1252 if (bd->type < PCIXEM)
1253 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001254 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 memwinon(bd, 0);
1256
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001257 /*
1258 * Remember ch is the main drivers channels structure, while bc is the
1259 * cards channel structure.
1260 */
1261 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001262 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001263 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Alan Cox9ae7b082008-10-13 10:32:09 +01001265 tty_port_init(&ch->port);
Alan Coxc1314a42009-01-02 13:48:17 +00001266 ch->port.ops = &epca_port_ops;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001267 ch->brdchan = bc;
1268 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001269 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001270 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Alan Coxf2cf8e22005-09-06 15:16:44 -07001272 spin_lock_irqsave(&epca_lock, flags);
1273 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001274 /*
1275 * Since some of the boards use different bitmaps for
1276 * their control signals we cannot hard code these
1277 * values and retain portability. We virtualize this
1278 * data here.
1279 */
1280 case EISAXEM:
1281 case PCXEM:
1282 case PCIXEM:
1283 case PCIXRJ:
1284 case PCIXR:
1285 ch->m_rts = 0x02;
1286 ch->m_dcd = 0x80;
1287 ch->m_dsr = 0x20;
1288 ch->m_cts = 0x10;
1289 ch->m_ri = 0x40;
1290 ch->m_dtr = 0x01;
1291 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001293 case PCXE:
1294 case PCXEVE:
1295 case PCXI:
1296 case PC64XE:
1297 ch->m_rts = 0x02;
1298 ch->m_dcd = 0x08;
1299 ch->m_dsr = 0x10;
1300 ch->m_cts = 0x20;
1301 ch->m_ri = 0x40;
1302 ch->m_dtr = 0x80;
1303 break;
1304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Alan Coxf2cf8e22005-09-06 15:16:44 -07001306 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 ch->dsr = ch->m_dcd;
1308 ch->dcd = ch->m_dsr;
1309 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001310 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 ch->dcd = ch->m_dcd;
1312 ch->dsr = ch->m_dsr;
1313 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 ch->boardnum = crd;
1316 ch->channelnum = i;
1317 ch->magic = EPCA_MAGIC;
Alan Cox3969ffb2009-01-02 13:48:04 +00001318 tty_port_tty_set(&ch->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
Alan Coxf2cf8e22005-09-06 15:16:44 -07001320 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1322 shrinkmem = 0;
1323 }
1324
Al Virobc9a5152005-09-15 22:53:28 +01001325 tseg = readw(&bc->tseg);
1326 rseg = readw(&bc->rseg);
1327
Alan Coxf2cf8e22005-09-06 15:16:44 -07001328 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001329 case PCIXEM:
1330 case PCIXRJ:
1331 case PCIXR:
1332 /* Cover all the 2MEG cards */
1333 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1334 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1335 ch->txwin = FEPWIN | (tseg >> 11);
1336 ch->rxwin = FEPWIN | (rseg >> 11);
1337 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001339 case PCXEM:
1340 case EISAXEM:
1341 /* Cover all the 32K windowed cards */
1342 /* Mask equal to window size - 1 */
1343 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1344 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1345 ch->txwin = FEPWIN | (tseg >> 11);
1346 ch->rxwin = FEPWIN | (rseg >> 11);
1347 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001349 case PCXEVE:
1350 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001351 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1352 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001353 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001354 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1355 & 0x1fff);
1356 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001357 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001359 case PCXI:
1360 case PC64XE:
1361 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1362 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1363 ch->txwin = ch->rxwin = 0;
1364 break;
1365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
1367 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001368 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001371 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1374
1375 /* Set transmitter low water mark */
1376 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1377
1378 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1380
1381 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1383
Alan Coxf2cf8e22005-09-06 15:16:44 -07001384 writew(100, &bc->edelay);
1385 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001386
Alan Coxf2cf8e22005-09-06 15:16:44 -07001387 ch->startc = readb(&bc->startc);
1388 ch->stopc = readb(&bc->stopc);
1389 ch->startca = readb(&bc->startca);
1390 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001391
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 ch->fepcflag = 0;
1393 ch->fepiflag = 0;
1394 ch->fepoflag = 0;
1395 ch->fepstartc = 0;
1396 ch->fepstopc = 0;
1397 ch->fepstartca = 0;
1398 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001399
Alan Cox6ed1dba2009-01-02 13:48:11 +00001400 ch->port.close_delay = 50;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001401
1402 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001405 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001406 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1407 VERSION, board_desc[bd->type], (long)bd->port,
1408 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001410}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001413{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 unsigned long flags;
1415 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001416 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 struct channel *ch;
1418 struct board_info *bd;
1419
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001420 /*
1421 * This routine is called upon every timer interrupt. Even though the
1422 * Digi series cards are capable of generating interrupts this method
1423 * of non-looping polling is more efficient. This routine checks for
1424 * card generated events (Such as receive data, are transmit buffer
1425 * empty) and acts on those events.
1426 */
1427 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 bd = &boards[crd];
1429 ch = card_ptr[crd];
1430
1431 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001432 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001434 /*
1435 * assertmemoff is not needed here; indeed it is an empty
1436 * subroutine. It is being kept because future boards may need
1437 * this as well as some legacy boards.
1438 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001439 spin_lock_irqsave(&epca_lock, flags);
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 assertmemoff(ch);
1442
1443 globalwinon(ch);
1444
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001445 /*
1446 * In this case head and tail actually refer to the event queue
1447 * not the transmit or receive queue.
1448 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001449 head = readw(&ch->mailbox->ein);
1450 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001452 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (head != tail)
1454 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 memoff(ch);
1456
Alan Coxf2cf8e22005-09-06 15:16:44 -07001457 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001460}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001463{
Al Virobc9a5152005-09-15 22:53:28 +01001464 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 struct channel *ch, *chan0;
1466 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001467 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001468 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001469 unsigned int tail, head;
1470 int event, channel;
1471 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001473 /*
1474 * This subroutine is called by epcapoll when an event is detected
1475 * in the event queue. This routine responds to those events.
1476 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 bd = &boards[crd];
1478
1479 chan0 = card_ptr[crd];
1480 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001482 while ((tail = readw(&chan0->mailbox->eout)) !=
1483 (head = readw(&chan0->mailbox->ein))) {
1484 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001486 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001488 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001490 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001491 /*
1492 * The two assignments below get the current modem status
1493 * (mstat) and the previous modem status (lstat). These are
1494 * useful becuase an event could signal a change in modem
1495 * signals itself.
1496 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001497 mstat = readb(eventbuf + 2);
1498 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
1500 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001501 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if (channel >= bd->numports)
1503 ch = chan0;
1504 bc = ch->brdchan;
1505 goto next;
1506 }
1507
Alan Cox191260a2008-04-30 00:54:16 -07001508 bc = ch->brdchan;
1509 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 goto next;
1511
Alan Cox3969ffb2009-01-02 13:48:04 +00001512 tty = tty_port_tty_get(&ch->port);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001513 if (event & DATA_IND) { /* Begin DATA_IND */
Alan Cox3969ffb2009-01-02 13:48:04 +00001514 receive_data(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 } /* End DATA_IND */
1517 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001518 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 ch->imodem = mstat;
Alan Cox6ed1dba2009-01-02 13:48:11 +00001521 if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
Alan Cox191260a2008-04-30 00:54:16 -07001522 /* We are now receiving dcd */
1523 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001524 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001525 else /* No dcd; hangup */
1526 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001528 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001529 if (tty) {
1530 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001532 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001533 tty_schedule_flip(tty);
1534 } else if (event & LOWTX_IND) {
1535 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 ch->statusflags &= ~LOWWAIT;
1537 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001538 }
1539 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001540 /* This event is generated by
1541 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001543 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ch->statusflags &= ~EMPTYWAIT;
1545 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001546 }
1547 }
Alan Cox3969ffb2009-01-02 13:48:04 +00001548 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001549 }
Alan Cox191260a2008-04-30 00:54:16 -07001550next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001552 BUG_ON(!bc);
1553 writew(1, &bc->idata);
1554 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001557}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001560 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001561{
Al Virobc9a5152005-09-15 22:53:28 +01001562 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 unsigned int head, cmdTail, cmdStart, cmdMax;
1564 long count;
1565 int n;
1566
1567 /* This is the routine in which commands may be passed to the card. */
1568
1569 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001573 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001575 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001576 /*
1577 * We do the addition below because we do not want a max pointer
1578 * relative to cmdStart. We want a max pointer that points at the
1579 * physical end of the command queue.
1580 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001581 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 memaddr = ch->board->re_map_membase;
1583
Alan Coxf2cf8e22005-09-06 15:16:44 -07001584 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001585 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1586 __LINE__, cmd, head);
1587 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1588 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 return;
1590 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001591 if (bytecmd) {
1592 writeb(cmd, memaddr + head + cmdStart + 0);
1593 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001595 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001597 writeb(byte2, memaddr + head + cmdStart + 3);
1598 } else {
1599 writeb(cmd, memaddr + head + cmdStart + 0);
1600 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1601 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001604 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 count = FEPTIMEOUT;
1606
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001607 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001609 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1611 return;
1612 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001613 head = readw(&ch->mailbox->cin);
1614 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001616 /*
1617 * Basically this will break when the FEP acknowledges the
1618 * command by incrementing cmdTail (Making it equal to head).
1619 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001621 break;
1622 }
1623}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001625/*
1626 * Digi products use fields in their channels structures that are very similar
1627 * to the c_cflag and c_iflag fields typically found in UNIX termios
1628 * structures. The below three routines allow mappings between these hardware
1629 * "flags" and their respective Linux flags.
1630 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001632{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 unsigned res = 0;
1634
Alan Coxf2cf8e22005-09-06 15:16:44 -07001635 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1637 res |= ((ch->m_cts) | (ch->m_rts));
1638 }
1639
1640 if (ch->digiext.digi_flags & RTSPACE)
1641 res |= ch->m_rts;
1642
1643 if (ch->digiext.digi_flags & DTRPACE)
1644 res |= ch->m_dtr;
1645
1646 if (ch->digiext.digi_flags & CTSPACE)
1647 res |= ch->m_cts;
1648
1649 if (ch->digiext.digi_flags & DSRPACE)
1650 res |= ch->dsr;
1651
1652 if (ch->digiext.digi_flags & DCDPACE)
1653 res |= ch->dcd;
1654
1655 if (res & (ch->m_rts))
1656 ch->digiext.digi_flags |= RTSPACE;
1657
1658 if (res & (ch->m_cts))
1659 ch->digiext.digi_flags |= CTSPACE;
1660
1661 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001662}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001665{
1666 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001667 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 if (ch->digiext.digi_flags & DIGI_AIXON)
1669 res |= IAIXON;
1670 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001671}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001674{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001676 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001677 ch->digiext.digi_flags |= DIGI_FAST;
1678 /*
1679 * HUPCL bit is used by FEP to indicate fast baud table is to
1680 * be used.
1681 */
1682 res |= FEP_HUPCL;
1683 } else
1684 ch->digiext.digi_flags &= ~DIGI_FAST;
1685 /*
1686 * CBAUD has bit position 0x1000 set these days to indicate Linux
1687 * baud rate remap. Digi hardware can't handle the bit assignment.
1688 * (We use a different bit assignment for high speed.). Clear this
1689 * bit out.
1690 */
1691 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1692 /*
1693 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001694 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001695 * this is identical to the Linux implementation. However; Digi
1696 * supports one rate (76800) that Linux doesn't. This means that the
1697 * c_cflag entry that would normally mean 76800 for Digi actually means
1698 * 115200 under Linux. Without the below mapping, a stty 115200 would
1699 * only drive the board at 76800. Since the rate 230400 is also found
1700 * after 76800, the same problem afflicts us when we choose a rate of
1701 * 230400. Without the below modificiation stty 230400 would actually
1702 * give us 115200.
1703 *
1704 * There are two additional differences. The Linux value for CLOCAL
1705 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1706 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1707 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1708 * checked for a screened out prior to termios2digi_c returning. Since
1709 * CLOCAL isn't used by the board this can be ignored as long as the
1710 * returned value is used only by Digi hardware.
1711 */
1712 if (cflag & CBAUDEX) {
1713 /*
1714 * The below code is trying to guarantee that only baud rates
1715 * 115200 and 230400 are remapped. We use exclusive or because
1716 * the various baud rates share common bit positions and
1717 * therefore can't be tested for easily.
1718 */
1719 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001724}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
Alan Coxf2cf8e22005-09-06 15:16:44 -07001726/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001728{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001730 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001731 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 unsigned mval, hflow, cflag, iflag;
1733
1734 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001735 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001739 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1740 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001741 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001742 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001744 /*
1745 * Flush current transmit buffer by setting cmdTail pointer
1746 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1747 * buffer is empty.
1748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1750 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001751 } else { /* Begin CBAUD not detected */
1752 /*
1753 * c_cflags have changed but that change had nothing to do with
1754 * BAUD. Propagate the change to the card.
1755 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001757 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 ch->fepcflag = cflag;
1759 /* Set baud rate, char size, stop bits, parity */
1760 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1761 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001762 /*
1763 * If the user has not forced CLOCAL and if the device is not a
1764 * CALLOUT device (Which is always CLOCAL) we set flags such
1765 * that the driver will wait on carrier detect.
1766 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 if (ts->c_cflag & CLOCAL)
Alan Cox6ed1dba2009-01-02 13:48:11 +00001768 clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 else
Alan Cox6ed1dba2009-01-02 13:48:11 +00001770 set_bit(ASYNC_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001775 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001777 /*
1778 * Command sets channels iflag structure on the board. Such
1779 * things as input soft flow control, handling of parity
1780 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001781 *
1782 * break handling, parity handling, input stripping,
1783 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001784 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1786 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001787 /*
1788 * Set the board mint value for this channel. This will cause hardware
1789 * events to be generated each time the DCD signal (Described in mint)
1790 * changes.
1791 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001792 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1794 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001795 writeb(0, &bc->mint);
1796 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001798 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001800 /*
1801 * Hard flow control has been selected but the board is not
1802 * using it. Activate hard flow control now.
1803 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 mval ^= ch->modemfake & (mval ^ ch->modem);
1807
Alan Coxf2cf8e22005-09-06 15:16:44 -07001808 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001810 /*
1811 * The below command sets the DTR and RTS mstat structure. If
1812 * hard flow control is NOT active these changes will drive the
1813 * output of the actual DTR and RTS lines. If hard flow control
1814 * is active, the changes will be saved in the mstat structure
1815 * and only asserted when hard flow control is turned off.
1816 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 /* First reset DTR & RTS; then set them */
1819 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1820 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001822 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 ch->fepstartc = ch->startc;
1824 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001825 /*
1826 * The XON / XOFF characters have changed; propagate these
1827 * changes to the card.
1828 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1830 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001831 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 ch->fepstartca = ch->startca;
1833 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001834 /*
1835 * Similar to the above, this time the auxilarly XON / XOFF
1836 * characters have changed; propagate these changes to the card.
1837 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1839 }
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 holds lock */
Alan Cox3969ffb2009-01-02 13:48:04 +00001843static void receive_data(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001844{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001846 struct ktermios *ts = NULL;
Al Virobc9a5152005-09-15 22:53:28 +01001847 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001848 int dataToRead, wrapgap, bytesAvailable;
1849 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001852 /*
1853 * This routine is called by doint when a receive data event has taken
1854 * place.
1855 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if (ch->statusflags & RXSTOPPED)
1858 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 if (tty)
1860 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001862 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 wrapmask = ch->rxbufsize - 1;
1864
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001865 /*
1866 * Get the head and tail pointers to the receiver queue. Wrap the head
1867 * pointer if it has reached the end of the buffer.
1868 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001869 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001871 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (bytesAvailable == 0)
1875 return;
1876
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001877 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07001878 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001879 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 return;
1881 }
1882
Alan Cox33f0f882006-01-09 20:54:13 -08001883 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return;
1885
Alan Coxf2cf8e22005-09-06 15:16:44 -07001886 if (readb(&bc->orun)) {
1887 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07001888 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
1889 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08001890 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07001893 while (bytesAvailable > 0) {
1894 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001896 /*
1897 * Even if head has wrapped around only report the amount of
1898 * data to be equal to the size - tail. Remember memcpy can't
1899 * automaticly wrap around the receive buffer.
1900 */
Alan Cox191260a2008-04-30 00:54:16 -07001901 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
1902 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001903 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001904 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 if (dataToRead == 0)
1906 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001907 /*
1908 * Move data read from our card into the line disciplines
1909 * buffer for translation if necessary.
1910 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001911 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 tail = (tail + dataToRead) & wrapmask;
1913 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001916 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 /* Must be called with global data */
Alan Cox3969ffb2009-01-02 13:48:04 +00001918 tty_schedule_flip(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001919}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001921static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 unsigned int cmd, unsigned long arg)
1923{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001924 switch (cmd) {
1925 case DIGI_GETINFO:
1926 {
1927 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 int brd;
1929
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001930 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07001931 return -EFAULT;
1932 if (brd < 0 || brd >= num_cards || num_cards == 0)
1933 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
1935 memset(&di, 0, sizeof(di));
1936
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001937 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 di.status = boards[brd].status;
1939 di.type = boards[brd].type ;
1940 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001941 /* Legacy fixups - just move along nothing to see */
1942 di.port = (unsigned char *)boards[brd].port ;
1943 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001945 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return -EFAULT;
1947 break;
1948
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001951 case DIGI_POLLER:
1952 {
1953 int brd = arg & 0xff000000 >> 16;
1954 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Alan Coxf2cf8e22005-09-06 15:16:44 -07001956 if (brd < 0 || brd >= num_cards) {
1957 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001958 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001960 digi_poller_inhibited = state;
1961 break;
1962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001964 case DIGI_INIT:
1965 {
1966 /*
1967 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02001968 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001969 * responsible for setting the card to its initial
1970 * state and setting the drivers control fields to the
1971 * sutianle settings for the card in question.
1972 */
1973 int crd;
1974 for (crd = 0; crd < num_cards; crd++)
1975 post_fep_init(crd);
1976 break;
1977 }
1978 default:
1979 return -ENOTTY;
1980 }
1981 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984static int pc_tiocmget(struct tty_struct *tty, struct file *file)
1985{
Alan Coxc9f19e92009-01-02 13:47:26 +00001986 struct channel *ch = tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01001987 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 unsigned int mstat, mflag = 0;
1989 unsigned long flags;
1990
1991 if (ch)
1992 bc = ch->brdchan;
1993 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07001994 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Alan Coxf2cf8e22005-09-06 15:16:44 -07001996 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001998 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002000 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 if (mstat & ch->m_dtr)
2003 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 if (mstat & ch->m_rts)
2005 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 if (mstat & ch->m_cts)
2007 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (mstat & ch->dsr)
2009 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 if (mstat & ch->m_ri)
2011 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 if (mstat & ch->dcd)
2013 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 return mflag;
2015}
2016
2017static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2018 unsigned int set, unsigned int clear)
2019{
Alan Coxc9f19e92009-01-02 13:47:26 +00002020 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 unsigned long flags;
2022
Alan Coxf2cf8e22005-09-06 15:16:44 -07002023 if (!ch)
2024 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025
Alan Coxf2cf8e22005-09-06 15:16:44 -07002026 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002028 * I think this modemfake stuff is broken. It doesn't correctly reflect
2029 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2030 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 */
2032 if (set & TIOCM_RTS) {
2033 ch->modemfake |= ch->m_rts;
2034 ch->modem |= ch->m_rts;
2035 }
2036 if (set & TIOCM_DTR) {
2037 ch->modemfake |= ch->m_dtr;
2038 ch->modem |= ch->m_dtr;
2039 }
2040 if (clear & TIOCM_RTS) {
2041 ch->modemfake |= ch->m_rts;
2042 ch->modem &= ~ch->m_rts;
2043 }
2044 if (clear & TIOCM_DTR) {
2045 ch->modemfake |= ch->m_dtr;
2046 ch->modem &= ~ch->m_dtr;
2047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002049 /*
2050 * The below routine generally sets up parity, baud, flow control
2051 * issues, etc.... It effect both control flags and input flags.
2052 */
Alan Cox191260a2008-04-30 00:54:16 -07002053 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002055 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 return 0;
2057}
2058
Alan Cox191260a2008-04-30 00:54:16 -07002059static int pc_ioctl(struct tty_struct *tty, struct file *file,
2060 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002061{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 unsigned long flags;
2064 unsigned int mflag, mstat;
2065 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002066 struct board_chan __iomem *bc;
Alan Coxc9f19e92009-01-02 13:47:26 +00002067 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002069
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (ch)
2071 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002072 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002073 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002074 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002075 case TIOCMODG:
2076 mflag = pc_tiocmget(tty, file);
2077 if (put_user(mflag, (unsigned long __user *)argp))
2078 return -EFAULT;
2079 break;
2080 case TIOCMODS:
2081 if (get_user(mstat, (unsigned __user *)argp))
2082 return -EFAULT;
2083 return pc_tiocmset(tty, file, mstat, ~mstat);
2084 case TIOCSDTR:
2085 spin_lock_irqsave(&epca_lock, flags);
2086 ch->omodem |= ch->m_dtr;
2087 globalwinon(ch);
2088 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2089 memoff(ch);
2090 spin_unlock_irqrestore(&epca_lock, flags);
2091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002093 case TIOCCDTR:
2094 spin_lock_irqsave(&epca_lock, flags);
2095 ch->omodem &= ~ch->m_dtr;
2096 globalwinon(ch);
2097 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2098 memoff(ch);
2099 spin_unlock_irqrestore(&epca_lock, flags);
2100 break;
2101 case DIGI_GETA:
2102 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2103 return -EFAULT;
2104 break;
2105 case DIGI_SETAW:
2106 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002107 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002108 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002109 /* Setup an event to indicate when the transmit
2110 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002111 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002112 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002113 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002114 tty_wait_until_sent(tty, 0);
2115 } else {
2116 /* ldisc lock already held in ioctl */
Alan Coxa352def2008-07-16 21:53:12 +01002117 if (tty->ldisc.ops->flush_buffer)
2118 tty->ldisc.ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002119 }
Alan Cox37925e02008-04-30 00:53:17 -07002120 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002121 /* Fall Thru */
2122 case DIGI_SETA:
2123 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2124 return -EFAULT;
2125
2126 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2127 ch->dcd = ch->m_dsr;
2128 ch->dsr = ch->m_dcd;
2129 } else {
2130 ch->dcd = ch->m_dcd;
2131 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002133
2134 spin_lock_irqsave(&epca_lock, flags);
2135 globalwinon(ch);
2136
2137 /*
2138 * The below routine generally sets up parity, baud, flow
2139 * control issues, etc.... It effect both control flags and
2140 * input flags.
2141 */
Alan Cox191260a2008-04-30 00:54:16 -07002142 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002143 memoff(ch);
2144 spin_unlock_irqrestore(&epca_lock, flags);
2145 break;
2146
2147 case DIGI_GETFLOW:
2148 case DIGI_GETAFLOW:
2149 spin_lock_irqsave(&epca_lock, flags);
2150 globalwinon(ch);
2151 if (cmd == DIGI_GETFLOW) {
2152 dflow.startc = readb(&bc->startc);
2153 dflow.stopc = readb(&bc->stopc);
2154 } else {
2155 dflow.startc = readb(&bc->startca);
2156 dflow.stopc = readb(&bc->stopca);
2157 }
2158 memoff(ch);
2159 spin_unlock_irqrestore(&epca_lock, flags);
2160
2161 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2162 return -EFAULT;
2163 break;
2164
2165 case DIGI_SETAFLOW:
2166 case DIGI_SETFLOW:
2167 if (cmd == DIGI_SETFLOW) {
2168 startc = ch->startc;
2169 stopc = ch->stopc;
2170 } else {
2171 startc = ch->startca;
2172 stopc = ch->stopca;
2173 }
2174
2175 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2176 return -EFAULT;
2177
Alan Cox191260a2008-04-30 00:54:16 -07002178 if (dflow.startc != startc || dflow.stopc != stopc) {
2179 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002180 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 globalwinon(ch);
2182
Alan Coxf2cf8e22005-09-06 15:16:44 -07002183 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002184 ch->fepstartc = ch->startc = dflow.startc;
2185 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002186 fepcmd(ch, SONOFFC, ch->fepstartc,
2187 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002188 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002189 ch->fepstartca = ch->startca = dflow.startc;
2190 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002191 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2192 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 }
2194
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002195 if (ch->statusflags & TXSTOPPED)
2196 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002198 memoff(ch);
2199 spin_unlock_irqrestore(&epca_lock, flags);
2200 } /* End if setflow toggled */
2201 break;
2202 default:
2203 return -ENOIOCTLCMD;
2204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002206}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Alan Cox606d0992006-12-08 02:38:45 -08002208static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002209{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 struct channel *ch;
2211 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002212 /*
2213 * verifyChannel returns the channel from the tty struct if it is
2214 * valid. This serves as a sanity check.
2215 */
Alan Cox191260a2008-04-30 00:54:16 -07002216 ch = verifyChannel(tty);
2217
2218 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002219 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 globalwinon(ch);
2221 epcaparam(tty, ch);
2222 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002223 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
2225 if ((old_termios->c_cflag & CRTSCTS) &&
2226 ((tty->termios->c_cflag & CRTSCTS) == 0))
2227 tty->hw_stopped = 0;
2228
2229 if (!(old_termios->c_cflag & CLOCAL) &&
2230 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002231 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002234}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
David Howellsc4028952006-11-22 14:57:56 +00002236static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002237{
David Howellsc4028952006-11-22 14:57:56 +00002238 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002240 if (ch && ch->magic == EPCA_MAGIC) {
Alan Cox3969ffb2009-01-02 13:48:04 +00002241 struct tty_struct *tty = tty_port_tty_get(&ch->port);;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Alan Coxf2cf8e22005-09-06 15:16:44 -07002243 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002244 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002245 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002246 wake_up_interruptible(&ch->port.open_wait);
Alan Cox6ed1dba2009-01-02 13:48:11 +00002247 clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002250 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002251 }
2252}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002254/*
2255 * pc_stop and pc_start provide software flow control to the routine and the
2256 * pc_ioctl routine.
2257 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 struct channel *ch;
2261 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002262 /*
2263 * verifyChannel returns the channel from the tty struct if it is
2264 * valid. This serves as a sanity check.
2265 */
Alan Cox191260a2008-04-30 00:54:16 -07002266 ch = verifyChannel(tty);
2267 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002268 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002269 if ((ch->statusflags & TXSTOPPED) == 0) {
2270 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 ch->statusflags |= TXSTOPPED;
2275 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002277 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002278 }
2279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002282{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002284 /*
2285 * verifyChannel returns the channel from the tty struct if it is
2286 * valid. This serves as a sanity check.
2287 */
Alan Cox191260a2008-04-30 00:54:16 -07002288 ch = verifyChannel(tty);
2289 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002291 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002292 /* Just in case output was resumed because of a change
2293 in Digi-flow */
2294 if (ch->statusflags & TXSTOPPED) {
2295 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002296 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 globalwinon(ch);
2298 bc = ch->brdchan;
2299 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002300 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 ch->statusflags &= ~TXSTOPPED;
2304 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002306 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002307 }
2308}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002310/*
2311 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2312 * resume) the receipt of data into the kernels receive buffers. The exact
2313 * occurrence of this depends on the size of the kernels receive buffer and
2314 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2315 * more details.
2316 */
2317static void pc_throttle(struct tty_struct *tty)
2318{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 struct channel *ch;
2320 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002321 /*
2322 * verifyChannel returns the channel from the tty struct if it is
2323 * valid. This serves as a sanity check.
2324 */
Alan Cox191260a2008-04-30 00:54:16 -07002325 ch = verifyChannel(tty);
2326 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002327 spin_lock_irqsave(&epca_lock, flags);
2328 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 globalwinon(ch);
2330 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 ch->statusflags |= RXSTOPPED;
2332 memoff(ch);
2333 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002334 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002335 }
2336}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
2338static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002339{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 struct channel *ch;
2341 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002342 /*
2343 * verifyChannel returns the channel from the tty struct if it is
2344 * valid. This serves as a sanity check.
2345 */
Alan Cox191260a2008-04-30 00:54:16 -07002346 ch = verifyChannel(tty);
2347 if (ch != NULL) {
2348 /* Just in case output was resumed because of a change
2349 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002350 spin_lock_irqsave(&epca_lock, flags);
2351 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 ch->statusflags &= ~RXSTOPPED;
2355 memoff(ch);
2356 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002357 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002358 }
2359}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Alan Coxdcbf1282008-07-22 11:18:12 +01002361static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002362{
Alan Coxc9f19e92009-01-02 13:47:26 +00002363 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 unsigned long flags;
2365
Alan Coxdcbf1282008-07-22 11:18:12 +01002366 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002367 msec = 0xFFFF;
2368 else if (msec > 0xFFFE)
2369 msec = 0xFFFE;
2370 else if (msec < 1)
2371 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002372
Alan Coxf2cf8e22005-09-06 15:16:44 -07002373 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002375 /*
2376 * Maybe I should send an infinite break here, schedule() for msec
2377 * amount of time, and then stop the break. This way, the user can't
2378 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2379 * an ioctl()) more than once in msec amount of time.
2380 * Try this for now...
2381 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2383 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002384 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002385 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002386}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Alan Coxf2cf8e22005-09-06 15:16:44 -07002388/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002390{
Al Virobc9a5152005-09-15 22:53:28 +01002391 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 globalwinon(ch);
2394 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002395 /*
2396 * When set the iempty flag request a event to be generated when the
2397 * transmit buffer is empty (If there is no BREAK in progress).
2398 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002399 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002401}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
David Howells88e88242008-07-22 11:20:45 +01002403#ifndef MODULE
2404static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002405{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 struct board_info board;
2407 int index, loop, last;
2408 char *temp, *t2;
2409 unsigned len;
2410
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002411 /*
2412 * If this routine looks a little strange it is because it is only
2413 * called if a LILO append command is given to boot the kernel with
2414 * parameters. In this way, we can provide the user a method of
2415 * changing his board configuration without rebuilding the kernel.
2416 */
2417 if (!liloconfig)
2418 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 memset(&board, 0, sizeof(board));
2421
2422 /* Assume the data is int first, later we can change it */
2423 /* I think that array position 0 of ints holds the number of args */
2424 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002425 switch (index) { /* Begin parse switch */
2426 case 1:
2427 board.status = ints[index];
2428 /*
2429 * We check for 2 (As opposed to 1; because 2 is a flag
2430 * instructing the driver to ignore epcaconfig.) For
2431 * this reason we check for 2.
2432 */
Alan Cox191260a2008-04-30 00:54:16 -07002433 if (board.status == 2) {
2434 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002435 nbdevs = 0;
2436 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002438 } /* End ignore epcaconfig as well as lilo cmd line */
2439
2440 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002441 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2442 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002443 invalid_lilo_config = 1;
2444 setup_error_code |= INVALID_BOARD_STATUS;
2445 return;
2446 }
2447 last = index;
2448 break;
2449 case 2:
2450 board.type = ints[index];
2451 if (board.type >= PCIXEM) {
2452 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2453 invalid_lilo_config = 1;
2454 setup_error_code |= INVALID_BOARD_TYPE;
2455 return;
2456 }
2457 last = index;
2458 break;
2459 case 3:
2460 board.altpin = ints[index];
2461 if (board.altpin > 1) {
2462 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2463 invalid_lilo_config = 1;
2464 setup_error_code |= INVALID_ALTPIN;
2465 return;
2466 }
2467 last = index;
2468 break;
2469
2470 case 4:
2471 board.numports = ints[index];
2472 if (board.numports < 2 || board.numports > 256) {
2473 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2474 invalid_lilo_config = 1;
2475 setup_error_code |= INVALID_NUM_PORTS;
2476 return;
2477 }
2478 nbdevs += board.numports;
2479 last = index;
2480 break;
2481
2482 case 5:
2483 board.port = ints[index];
2484 if (ints[index] <= 0) {
2485 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2486 invalid_lilo_config = 1;
2487 setup_error_code |= INVALID_PORT_BASE;
2488 return;
2489 }
2490 last = index;
2491 break;
2492
2493 case 6:
2494 board.membase = ints[index];
2495 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002496 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2497 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002498 invalid_lilo_config = 1;
2499 setup_error_code |= INVALID_MEM_BASE;
2500 return;
2501 }
2502 last = index;
2503 break;
2504
2505 default:
2506 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2507 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 } /* End parse switch */
2510
Alan Coxf2cf8e22005-09-06 15:16:44 -07002511 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 /* find the next comma or terminator */
2513 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 /* While string is not null, and a comma hasn't been found */
2515 while (*temp && (*temp != ','))
2516 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (!*temp)
2518 temp = NULL;
2519 else
2520 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 /* Set index to the number of args + 1 */
2522 index = last + 1;
2523
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002524 switch (index) {
2525 case 1:
2526 len = strlen(str);
2527 if (strncmp("Disable", str, len) == 0)
2528 board.status = 0;
2529 else if (strncmp("Enable", str, len) == 0)
2530 board.status = 1;
2531 else {
2532 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2533 invalid_lilo_config = 1;
2534 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002536 }
2537 last = index;
2538 break;
2539
2540 case 2:
2541 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2542 if (strcmp(board_desc[loop], str) == 0)
2543 break;
2544 /*
2545 * If the index incremented above refers to a
2546 * legitamate board type set it here.
2547 */
2548 if (index < EPCA_NUM_TYPES)
2549 board.type = loop;
2550 else {
2551 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2552 invalid_lilo_config = 1;
2553 setup_error_code |= INVALID_BOARD_TYPE;
2554 return;
2555 }
2556 last = index;
2557 break;
2558
2559 case 3:
2560 len = strlen(str);
2561 if (strncmp("Disable", str, len) == 0)
2562 board.altpin = 0;
2563 else if (strncmp("Enable", str, len) == 0)
2564 board.altpin = 1;
2565 else {
2566 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2567 invalid_lilo_config = 1;
2568 setup_error_code |= INVALID_ALTPIN;
2569 return;
2570 }
2571 last = index;
2572 break;
2573
2574 case 4:
2575 t2 = str;
2576 while (isdigit(*t2))
2577 t2++;
2578
2579 if (*t2) {
2580 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2581 invalid_lilo_config = 1;
2582 setup_error_code |= INVALID_NUM_PORTS;
2583 return;
2584 }
2585
2586 /*
2587 * There is not a man page for simple_strtoul but the
2588 * code can be found in vsprintf.c. The first argument
2589 * is the string to translate (To an unsigned long
2590 * obviously), the second argument can be the address
2591 * of any character variable or a NULL. If a variable
2592 * is given, the end pointer of the string will be
2593 * stored in that variable; if a NULL is given the end
2594 * pointer will not be returned. The last argument is
2595 * the base to use. If a 0 is indicated, the routine
2596 * will attempt to determine the proper base by looking
2597 * at the values prefix (A '0' for octal, a 'x' for
2598 * hex, etc ... If a value is given it will use that
2599 * value as the base.
2600 */
2601 board.numports = simple_strtoul(str, NULL, 0);
2602 nbdevs += board.numports;
2603 last = index;
2604 break;
2605
2606 case 5:
2607 t2 = str;
2608 while (isxdigit(*t2))
2609 t2++;
2610
2611 if (*t2) {
2612 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2613 invalid_lilo_config = 1;
2614 setup_error_code |= INVALID_PORT_BASE;
2615 return;
2616 }
2617
2618 board.port = simple_strtoul(str, NULL, 16);
2619 last = index;
2620 break;
2621
2622 case 6:
2623 t2 = str;
2624 while (isxdigit(*t2))
2625 t2++;
2626
2627 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002628 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002629 invalid_lilo_config = 1;
2630 setup_error_code |= INVALID_MEM_BASE;
2631 return;
2632 }
2633 board.membase = simple_strtoul(str, NULL, 16);
2634 last = index;
2635 break;
2636 default:
2637 printk(KERN_ERR "epca: Too many string parms\n");
2638 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 } /* End while there is a string arg */
2642
Alan Coxf2cf8e22005-09-06 15:16:44 -07002643 if (last < 6) {
2644 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 return;
2646 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002650 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002652 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2653 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002656}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
David Howells88e88242008-07-22 11:20:45 +01002658static int __init epca_real_setup(char *str)
2659{
2660 int ints[11];
2661
2662 epca_setup(get_options(str, 11, ints), ints);
2663 return 1;
2664}
2665
2666__setup("digiepca", epca_real_setup);
2667#endif
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669enum epic_board_types {
2670 brd_xr = 0,
2671 brd_xem,
2672 brd_cx,
2673 brd_xrj,
2674};
2675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676/* indexed directly by epic_board_types enum */
2677static struct {
2678 unsigned char board_type;
2679 unsigned bar_idx; /* PCI base address region */
2680} epca_info_tbl[] = {
2681 { PCIXR, 0, },
2682 { PCIXEM, 0, },
2683 { PCICX, 0, },
2684 { PCIXRJ, 2, },
2685};
2686
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002687static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 const struct pci_device_id *ent)
2689{
2690 static int board_num = -1;
2691 int board_idx, info_idx = ent->driver_data;
2692 unsigned long addr;
2693
2694 if (pci_enable_device(pdev))
2695 return -EIO;
2696
2697 board_num++;
2698 board_idx = board_num + num_cards;
2699 if (board_idx >= MAXBOARDS)
2700 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002701
Alan Cox191260a2008-04-30 00:54:16 -07002702 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002704 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 epca_info_tbl[info_idx].bar_idx);
2706 goto err_out;
2707 }
2708
2709 boards[board_idx].status = ENABLED;
2710 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2711 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002712 boards[board_idx].port = addr + PCI_IO_OFFSET;
2713 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Alan Cox191260a2008-04-30 00:54:16 -07002715 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2716 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 0x200000, addr + PCI_IO_OFFSET);
2718 goto err_out;
2719 }
2720
Alan Cox191260a2008-04-30 00:54:16 -07002721 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2722 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002724 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 0x200000, addr + PCI_IO_OFFSET);
2726 goto err_out_free_pciio;
2727 }
2728
Alan Cox191260a2008-04-30 00:54:16 -07002729 if (!request_mem_region(addr, 0x200000, "epca")) {
2730 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 0x200000, addr);
2732 goto err_out_free_iounmap;
2733 }
2734
Alan Cox191260a2008-04-30 00:54:16 -07002735 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002737 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 0x200000, addr + PCI_IO_OFFSET);
2739 goto err_out_free_memregion;
2740 }
2741
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002742 /*
2743 * I don't know what the below does, but the hardware guys say its
2744 * required on everything except PLX (In this case XRJ).
2745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002747 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 pci_write_config_byte(pdev, 0x46, 0);
2749 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002750
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return 0;
2752
2753err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002754 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002756 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002758 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759err_out:
2760 return -ENODEV;
2761}
2762
2763
2764static struct pci_device_id epca_pci_tbl[] = {
2765 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2766 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2767 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2768 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2769 { 0, }
2770};
2771
2772MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2773
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002774static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002775{
Alan Cox191260a2008-04-30 00:54:16 -07002776 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 epca_driver.name = "epca";
2778 epca_driver.id_table = epca_pci_tbl;
2779 epca_driver.probe = epca_init_one;
2780
2781 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002782}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784MODULE_LICENSE("GPL");