blob: 6f5ffe1320f700f330beabd0481e62b5b9a56f48 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 Copyright (C) 1996 Digi International.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 For technical support please email digiLinux@dgii.com or
5 call Digi tech support at (612) 912-3456
6
Alan Coxf2cf8e22005-09-06 15:16:44 -07007 ** This driver is no longer supported by Digi **
8
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07009 Much of this design and code came from epca.c which was
10 copyright (C) 1994, 1995 Troy De Jongh, and subsquently
11 modified by David Nugent, Christoph Lameter, Mike McLagan.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070018 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070023 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070027/* See README.epca for change history --DAT*/
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/init.h>
Alexey Dobriyand43c36d2009-10-07 17:09:06 +040033#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/serial.h>
35#include <linux/delay.h>
36#include <linux/ctype.h>
37#include <linux/tty.h>
38#include <linux/tty_flip.h>
Alexey Dobriyan405f5572009-07-11 22:08:37 +040039#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/ioport.h>
41#include <linux/interrupt.h>
Alan Cox191260a2008-04-30 00:54:16 -070042#include <linux/uaccess.h>
43#include <linux/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070044#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/pci.h>
46#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070047
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#include "digi1.h"
50#include "digiFep1.h"
51#include "epca.h"
52#include "epcaconfig.h"
53
Alan Coxf2cf8e22005-09-06 15:16:44 -070054#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070057#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59
60#define MAXCARDS 7
61#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
62
63#define PFX "epca: "
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static int nbdevs, num_cards, liloconfig;
66static int digi_poller_inhibited = 1 ;
67
68static int setup_error_code;
69static int invalid_lilo_config;
70
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070071/*
72 * The ISA boards do window flipping into the same spaces so its only sane with
Alan Coxd1c815e2009-01-02 13:47:58 +000073 * a single lock. It's still pretty efficient. This lock guards the hardware
74 * and the tty_port lock guards the kernel side stuff like use counts. Take
75 * this lock inside the port lock if you must take both.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070076 */
Ingo Molnar34af9462006-06-27 02:53:55 -070077static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070078
Alan Cox191260a2008-04-30 00:54:16 -070079/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
80 to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static struct board_info boards[MAXBOARDS];
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static struct tty_driver *pc_driver;
84static struct tty_driver *pc_info;
85
86/* ------------------ Begin Digi specific structures -------------------- */
87
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070088/*
89 * digi_channels represents an array of structures that keep track of each
90 * channel of the Digi product. Information such as transmit and receive
91 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
92 * here. This structure is NOT used to overlay the cards physical channel
93 * structure.
94 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095static struct channel digi_channels[MAX_ALLOC];
96
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070097/*
98 * card_ptr is an array used to hold the address of the first channel structure
99 * of each card. This array will hold the addresses of various channels located
100 * in digi_channels.
101 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static struct channel *card_ptr[MAXCARDS];
103
104static struct timer_list epca_timer;
105
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700106/*
107 * Begin generic memory functions. These functions will be alias (point at)
108 * more specific functions dependent on the board being configured.
109 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700110static void memwinon(struct board_info *b, unsigned int win);
111static void memwinoff(struct board_info *b, unsigned int win);
112static void globalwinon(struct channel *ch);
113static void rxwinon(struct channel *ch);
114static void txwinon(struct channel *ch);
115static void memoff(struct channel *ch);
116static void assertgwinon(struct channel *ch);
117static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/* ---- Begin more 'specific' memory functions for cx_like products --- */
120
Alan Coxf2cf8e22005-09-06 15:16:44 -0700121static void pcxem_memwinon(struct board_info *b, unsigned int win);
122static void pcxem_memwinoff(struct board_info *b, unsigned int win);
123static void pcxem_globalwinon(struct channel *ch);
124static void pcxem_rxwinon(struct channel *ch);
125static void pcxem_txwinon(struct channel *ch);
126static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128/* ------ Begin more 'specific' memory functions for the pcxe ------- */
129
Alan Coxf2cf8e22005-09-06 15:16:44 -0700130static void pcxe_memwinon(struct board_info *b, unsigned int win);
131static void pcxe_memwinoff(struct board_info *b, unsigned int win);
132static void pcxe_globalwinon(struct channel *ch);
133static void pcxe_rxwinon(struct channel *ch);
134static void pcxe_txwinon(struct channel *ch);
135static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
138/* Note : pc64xe and pcxi share the same windowing routines */
139
Alan Coxf2cf8e22005-09-06 15:16:44 -0700140static void pcxi_memwinon(struct board_info *b, unsigned int win);
141static void pcxi_memwinoff(struct board_info *b, unsigned int win);
142static void pcxi_globalwinon(struct channel *ch);
143static void pcxi_rxwinon(struct channel *ch);
144static void pcxi_txwinon(struct channel *ch);
145static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147/* - Begin 'specific' do nothing memory functions needed for some cards - */
148
Alan Coxf2cf8e22005-09-06 15:16:44 -0700149static void dummy_memwinon(struct board_info *b, unsigned int win);
150static void dummy_memwinoff(struct board_info *b, unsigned int win);
151static void dummy_globalwinon(struct channel *ch);
152static void dummy_rxwinon(struct channel *ch);
153static void dummy_txwinon(struct channel *ch);
154static void dummy_memoff(struct channel *ch);
155static void dummy_assertgwinon(struct channel *ch);
156static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Alan Coxf2cf8e22005-09-06 15:16:44 -0700158static struct channel *verifyChannel(struct tty_struct *);
159static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static void epca_error(int, char *);
161static void pc_close(struct tty_struct *, struct file *);
Alan Coxd1c815e2009-01-02 13:47:58 +0000162static void shutdown(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int pc_write_room(struct tty_struct *);
165static int pc_chars_in_buffer(struct tty_struct *);
166static void pc_flush_buffer(struct tty_struct *);
167static void pc_flush_chars(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168static int pc_open(struct tty_struct *, struct file *);
169static void post_fep_init(unsigned int crd);
170static void epcapoll(unsigned long);
171static void doevent(int);
172static void fepcmd(struct channel *, int, int, int, int, int);
173static unsigned termios2digi_h(struct channel *ch, unsigned);
174static unsigned termios2digi_i(struct channel *ch, unsigned);
175static unsigned termios2digi_c(struct channel *ch, unsigned);
176static void epcaparam(struct tty_struct *, struct channel *);
Alan Cox3969ffb2009-01-02 13:48:04 +0000177static void receive_data(struct channel *, struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static int pc_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700179 unsigned int, unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180static int info_ioctl(struct tty_struct *, struct file *,
Alan Cox191260a2008-04-30 00:54:16 -0700181 unsigned int, unsigned long);
Alan Cox606d0992006-12-08 02:38:45 -0800182static void pc_set_termios(struct tty_struct *, struct ktermios *);
David Howellsc4028952006-11-22 14:57:56 +0000183static void do_softint(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184static void pc_stop(struct tty_struct *);
185static void pc_start(struct tty_struct *);
Alan Cox191260a2008-04-30 00:54:16 -0700186static void pc_throttle(struct tty_struct *tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static void pc_unthrottle(struct tty_struct *tty);
Alan Coxdcbf1282008-07-22 11:18:12 +0100188static int pc_send_break(struct tty_struct *tty, int msec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static int pc_write(struct tty_struct *, const unsigned char *, int);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700192static int pc_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193static int init_PCI(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700195/*
196 * Table of functions for each board to handle memory. Mantaining parallelism
197 * is a *very* good idea here. The idea is for the runtime code to blindly call
198 * these functions, not knowing/caring about the underlying hardware. This
199 * stuff should contain no conditionals; if more functionality is needed a
200 * different entry should be established. These calls are the interface calls
201 * and are the only functions that should be accessed. Anyone caught making
202 * direct calls deserves what they get.
203 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700204static void memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700206 b->memwinon(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
Alan Coxf2cf8e22005-09-06 15:16:44 -0700209static void memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700211 b->memwinoff(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213
Alan Coxf2cf8e22005-09-06 15:16:44 -0700214static void globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700216 ch->board->globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217}
218
Alan Coxf2cf8e22005-09-06 15:16:44 -0700219static void rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700221 ch->board->rxwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222}
223
Alan Coxf2cf8e22005-09-06 15:16:44 -0700224static void txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700226 ch->board->txwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
Alan Coxf2cf8e22005-09-06 15:16:44 -0700229static void memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700231 ch->board->memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232}
Alan Coxf2cf8e22005-09-06 15:16:44 -0700233static void assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700235 ch->board->assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236}
237
Alan Coxf2cf8e22005-09-06 15:16:44 -0700238static void assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700240 ch->board->assertmemoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241}
242
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700243/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700244static void pcxem_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Alan Cox191260a2008-04-30 00:54:16 -0700246 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
Alan Coxf2cf8e22005-09-06 15:16:44 -0700249static void pcxem_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700251 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
Alan Coxf2cf8e22005-09-06 15:16:44 -0700254static void pcxem_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
Alan Cox191260a2008-04-30 00:54:16 -0700256 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
Alan Coxf2cf8e22005-09-06 15:16:44 -0700259static void pcxem_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260{
261 outb_p(ch->rxwin, (int)ch->board->port + 1);
262}
263
Alan Coxf2cf8e22005-09-06 15:16:44 -0700264static void pcxem_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265{
266 outb_p(ch->txwin, (int)ch->board->port + 1);
267}
268
Alan Coxf2cf8e22005-09-06 15:16:44 -0700269static void pcxem_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
271 outb_p(0, (int)ch->board->port + 1);
272}
273
274/* ----------------- Begin pcxe memory window stuff ------------------ */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700275static void pcxe_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700277 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
Alan Coxf2cf8e22005-09-06 15:16:44 -0700280static void pcxe_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700282 outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700283 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
Alan Coxf2cf8e22005-09-06 15:16:44 -0700286static void pcxe_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700288 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289}
290
Alan Coxf2cf8e22005-09-06 15:16:44 -0700291static void pcxe_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700293 outb_p(ch->rxwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Alan Coxf2cf8e22005-09-06 15:16:44 -0700296static void pcxe_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700298 outb_p(ch->txwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Alan Coxf2cf8e22005-09-06 15:16:44 -0700301static void pcxe_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 outb_p(0, (int)ch->board->port);
304 outb_p(0, (int)ch->board->port + 1);
305}
306
307/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700308static void pcxi_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700310 outb_p(inb(b->port) | FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
Alan Coxf2cf8e22005-09-06 15:16:44 -0700313static void pcxi_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700315 outb_p(inb(b->port) & ~FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
Alan Coxf2cf8e22005-09-06 15:16:44 -0700318static void pcxi_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700320 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321}
322
Alan Coxf2cf8e22005-09-06 15:16:44 -0700323static void pcxi_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700325 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Alan Coxf2cf8e22005-09-06 15:16:44 -0700328static void pcxi_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700330 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Alan Coxf2cf8e22005-09-06 15:16:44 -0700333static void pcxi_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700335 outb_p(0, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337
Alan Coxf2cf8e22005-09-06 15:16:44 -0700338static void pcxi_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700340 epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341}
342
Alan Coxf2cf8e22005-09-06 15:16:44 -0700343static void pcxi_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700345 epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346}
347
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700348/*
349 * Not all of the cards need specific memory windowing routines. Some cards
350 * (Such as PCI) needs no windowing routines at all. We provide these do
351 * nothing routines so that the same code base can be used. The driver will
352 * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
353 * card. However, dependent on the card the routine may or may not do anything.
354 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700355static void dummy_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
357}
358
Alan Coxf2cf8e22005-09-06 15:16:44 -0700359static void dummy_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361}
362
Alan Coxf2cf8e22005-09-06 15:16:44 -0700363static void dummy_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364{
365}
366
Alan Coxf2cf8e22005-09-06 15:16:44 -0700367static void dummy_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369}
370
Alan Coxf2cf8e22005-09-06 15:16:44 -0700371static void dummy_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373}
374
Alan Coxf2cf8e22005-09-06 15:16:44 -0700375static void dummy_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377}
378
Alan Coxf2cf8e22005-09-06 15:16:44 -0700379static void dummy_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381}
382
Alan Coxf2cf8e22005-09-06 15:16:44 -0700383static void dummy_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385}
386
Alan Coxf2cf8e22005-09-06 15:16:44 -0700387static struct channel *verifyChannel(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700388{
389 /*
390 * This routine basically provides a sanity check. It insures that the
391 * channel returned is within the proper range of addresses as well as
392 * properly initialized. If some bogus info gets passed in
393 * through tty->driver_data this should catch it.
394 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700395 if (tty) {
Alan Coxc9f19e92009-01-02 13:47:26 +0000396 struct channel *ch = tty->driver_data;
Alan Cox191260a2008-04-30 00:54:16 -0700397 if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (ch->magic == EPCA_MAGIC)
399 return ch;
400 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return NULL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700403}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Alan Coxf2cf8e22005-09-06 15:16:44 -0700405static void pc_sched_event(struct channel *ch, int event)
406{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700407 /*
408 * We call this to schedule interrupt processing on some event. The
409 * kernel sees our request and calls the related routine in OUR driver.
410 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 ch->event |= 1 << event;
412 schedule_work(&ch->tqueue);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700413}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415static void epca_error(int line, char *msg)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700416{
Alan Cox191260a2008-04-30 00:54:16 -0700417 printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700418}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700420static void pc_close(struct tty_struct *tty, struct file *filp)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700421{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000423 struct tty_port *port;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700424 /*
425 * verifyChannel returns the channel from the tty struct if it is
426 * valid. This serves as a sanity check.
427 */
Alan Cox191260a2008-04-30 00:54:16 -0700428 ch = verifyChannel(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000429 if (ch == NULL)
430 return;
431 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Alan Cox6ed1dba2009-01-02 13:48:11 +0000433 if (tty_port_close_start(port, tty, filp) == 0)
Alan Coxd1c815e2009-01-02 13:47:58 +0000434 return;
Alan Coxd1c815e2009-01-02 13:47:58 +0000435
Alan Coxd1c815e2009-01-02 13:47:58 +0000436 pc_flush_buffer(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000437 shutdown(ch, tty);
438
Alan Cox6ed1dba2009-01-02 13:48:11 +0000439 tty_port_close_end(port, tty);
440 ch->event = 0; /* FIXME: review ch->event locking */
Alan Cox3969ffb2009-01-02 13:48:04 +0000441 tty_port_tty_set(port, NULL);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700442}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
Alan Coxd1c815e2009-01-02 13:47:58 +0000444static void shutdown(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700445{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +0100447 struct board_chan __iomem *bc;
Alan Coxd1c815e2009-01-02 13:47:58 +0000448 struct tty_port *port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Alan Coxd1c815e2009-01-02 13:47:58 +0000450 if (!(port->flags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return;
452
Alan Coxf2cf8e22005-09-06 15:16:44 -0700453 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Alan Coxf2cf8e22005-09-06 15:16:44 -0700455 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 bc = ch->brdchan;
457
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700458 /*
459 * In order for an event to be generated on the receipt of data the
460 * idata flag must be set. Since we are shutting down, this is not
461 * necessary clear this flag.
462 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700464 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700466 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700467 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
469 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 memoff(ch);
472
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700473 /*
474 * The channel has officialy been closed. The next time it is opened it
475 * will have to reinitialized. Set a flag to indicate this.
476 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 /* Prevent future Digi programmed interrupts from coming active */
Alan Coxd1c815e2009-01-02 13:47:58 +0000478 port->flags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700479 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700480}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700483{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000485
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700486 /*
487 * verifyChannel returns the channel from the tty struct if it is
488 * valid. This serves as a sanity check.
489 */
Alan Cox191260a2008-04-30 00:54:16 -0700490 ch = verifyChannel(tty);
491 if (ch != NULL) {
Alan Cox978e5952008-04-30 00:53:59 -0700492 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 tty_ldisc_flush(tty);
Alan Coxd1c815e2009-01-02 13:47:58 +0000494 shutdown(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
Alan Coxd1c815e2009-01-02 13:47:58 +0000496 ch->event = 0; /* FIXME: review locking of ch->event */
Alan Cox6ed1dba2009-01-02 13:48:11 +0000497 tty_port_hangup(&ch->port);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700498 }
499}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700501static int pc_write(struct tty_struct *tty,
Alan Cox191260a2008-04-30 00:54:16 -0700502 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700503{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700504 unsigned int head, tail;
505 int dataLen;
506 int size;
507 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 struct channel *ch;
509 unsigned long flags;
510 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100511 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700513 /*
514 * pc_write is primarily called directly by the kernel routine
515 * tty_write (Though it can also be called by put_char) found in
516 * tty_io.c. pc_write is passed a line discipline buffer where the data
517 * to be written out is stored. The line discipline implementation
518 * itself is done at the kernel level and is not brought into the
519 * driver.
520 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700522 /*
523 * verifyChannel returns the channel from the tty struct if it is
524 * valid. This serves as a sanity check.
525 */
Alan Cox191260a2008-04-30 00:54:16 -0700526 ch = verifyChannel(tty);
527 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 return 0;
529
530 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 bc = ch->brdchan;
532 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Alan Coxf2cf8e22005-09-06 15:16:44 -0700535 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 globalwinon(ch);
537
Alan Coxf2cf8e22005-09-06 15:16:44 -0700538 head = readw(&bc->tin) & (size - 1);
539 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Alan Coxf2cf8e22005-09-06 15:16:44 -0700541 if (tail != readw(&bc->tout))
542 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 tail &= (size - 1);
544
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700545 if (head >= tail) {
546 /* head has not wrapped */
547 /*
548 * remain (much like dataLen above) represents the total amount
549 * of space available on the card for data. Here dataLen
550 * represents the space existing between the head pointer and
551 * the end of buffer. This is important because a memcpy cannot
552 * be told to automatically wrap around when it hits the buffer
553 * end.
554 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 dataLen = size - head;
556 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700557 } else {
558 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 remain = tail - head - 1;
560 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700561 }
562 /*
563 * Check the space on the card. If we have more data than space; reduce
564 * the amount of data to fit the space.
565 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700568 while (bytesAvailable > 0) {
569 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700571 /*
572 * If head is not wrapped, the below will make sure the first
573 * data copy fills to the end of card buffer.
574 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100576 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 buf += dataLen;
578 head += dataLen;
579 amountCopied += dataLen;
580 bytesAvailable -= dataLen;
581
Alan Coxf2cf8e22005-09-06 15:16:44 -0700582 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 head = 0;
584 dataLen = tail;
585 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 ch->statusflags |= TXBUSY;
588 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700589 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Alan Coxf2cf8e22005-09-06 15:16:44 -0700591 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700593 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 }
595 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700596 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700597 return amountCopied;
598}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700601{
Alan Cox191260a2008-04-30 00:54:16 -0700602 int remain = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 struct channel *ch;
604 unsigned long flags;
605 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100606 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700607 /*
608 * verifyChannel returns the channel from the tty struct if it is
609 * valid. This serves as a sanity check.
610 */
Alan Cox191260a2008-04-30 00:54:16 -0700611 ch = verifyChannel(tty);
612 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700613 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 globalwinon(ch);
615
616 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700617 head = readw(&bc->tin) & (ch->txbufsize - 1);
618 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Alan Coxf2cf8e22005-09-06 15:16:44 -0700620 if (tail != readw(&bc->tout))
621 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 /* Wrap tail if necessary */
623 tail &= (ch->txbufsize - 1);
Alan Cox191260a2008-04-30 00:54:16 -0700624 remain = tail - head - 1;
625 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 remain += ch->txbufsize;
627
Alan Coxf2cf8e22005-09-06 15:16:44 -0700628 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700630 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 }
632 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700633 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 /* Return how much room is left on card */
636 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700637}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700640{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 int chars;
642 unsigned int ctail, head, tail;
643 int remain;
644 unsigned long flags;
645 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100646 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700647 /*
648 * verifyChannel returns the channel from the tty struct if it is
649 * valid. This serves as a sanity check.
650 */
Alan Cox191260a2008-04-30 00:54:16 -0700651 ch = verifyChannel(tty);
652 if (ch == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700653 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Alan Coxf2cf8e22005-09-06 15:16:44 -0700655 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 globalwinon(ch);
657
658 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700659 tail = readw(&bc->tout);
660 head = readw(&bc->tin);
661 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Alan Cox191260a2008-04-30 00:54:16 -0700663 if (tail == head && readw(&ch->mailbox->cin) == ctail &&
664 readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700666 else { /* Begin if some space on the card has been used */
667 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700669 /*
670 * The logic here is basically opposite of the above
671 * pc_write_room here we are finding the amount of bytes in the
672 * buffer filled. Not the amount of bytes empty.
673 */
Alan Cox191260a2008-04-30 00:54:16 -0700674 remain = tail - head - 1;
675 if (remain < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 remain += ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700678 /*
679 * Make it possible to wakeup anything waiting for output in
680 * tty_ioctl.c, etc.
681 *
682 * If not already set. Setup an event to indicate when the
683 * transmit buffer empties.
684 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (!(ch->statusflags & EMPTYWAIT))
Alan Cox191260a2008-04-30 00:54:16 -0700686 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700689 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700691 return chars;
692}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700695{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 unsigned int tail;
697 unsigned long flags;
698 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100699 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700700 /*
701 * verifyChannel returns the channel from the tty struct if it is
702 * valid. This serves as a sanity check.
703 */
Alan Cox191260a2008-04-30 00:54:16 -0700704 ch = verifyChannel(tty);
705 if (ch == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 return;
707
Alan Coxf2cf8e22005-09-06 15:16:44 -0700708 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700711 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700715 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700717}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700720{
721 struct channel *ch;
722 /*
723 * verifyChannel returns the channel from the tty struct if it is
724 * valid. This serves as a sanity check.
725 */
Alan Cox191260a2008-04-30 00:54:16 -0700726 ch = verifyChannel(tty);
727 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700729 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700730 /*
731 * If not already set and the transmitter is busy setup an
732 * event to indicate when the transmit empties.
733 */
Alan Cox191260a2008-04-30 00:54:16 -0700734 if ((ch->statusflags & TXBUSY) &&
735 !(ch->statusflags & EMPTYWAIT))
736 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700737 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700739}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Alan Cox6ed1dba2009-01-02 13:48:11 +0000741static int epca_carrier_raised(struct tty_port *port)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700742{
Alan Cox6ed1dba2009-01-02 13:48:11 +0000743 struct channel *ch = container_of(port, struct channel, port);
744 if (ch->imodem & ch->dcd)
745 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700747}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Alan Coxfcc8ac12009-06-11 12:24:17 +0100749static void epca_dtr_rts(struct tty_port *port, int onoff)
Alan Cox6ed1dba2009-01-02 13:48:11 +0000750{
751}
752
Alan Cox191260a2008-04-30 00:54:16 -0700753static int pc_open(struct tty_struct *tty, struct file *filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700754{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 struct channel *ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000756 struct tty_port *port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 unsigned long flags;
758 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100759 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700760 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700763 if (line < 0 || line >= nbdevs)
764 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
766 ch = &digi_channels[line];
Alan Coxd1c815e2009-01-02 13:47:58 +0000767 port = &ch->port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 boardnum = ch->boardnum;
769
770 /* Check status of board configured in system. */
771
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700772 /*
Frederik Schwarzer0211a9c2008-12-29 22:14:56 +0100773 * I check to see if the epca_setup routine detected a user error. It
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700774 * might be better to put this in pc_init, but for the moment it goes
775 * here.
776 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700777 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700779 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700781 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700783 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700785 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700787 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700789 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700791 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700793 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 tty->driver_data = NULL; /* Mark this device as 'down' */
795 return(-ENODEV);
796 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700797
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700798 bc = ch->brdchan;
799 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700801 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 }
803
Alan Coxd1c815e2009-01-02 13:47:58 +0000804 spin_lock_irqsave(&port->lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700805 /*
806 * Every time a channel is opened, increment a counter. This is
807 * necessary because we do not wish to flush and shutdown the channel
808 * until the last app holding the channel open, closes it.
809 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000810 port->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700811 /*
812 * Set a kernel structures pointer to our local channel structure. This
813 * way we can get to it when passed only a tty struct.
814 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 tty->driver_data = ch;
Alan Coxd1c815e2009-01-02 13:47:58 +0000816 port->tty = tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700817 /*
818 * If this is the first time the channel has been opened, initialize
819 * the tty->termios struct otherwise let pc_close handle it.
820 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000821 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 globalwinon(ch);
823 ch->statusflags = 0;
824
825 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100826 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700828 /*
829 * Set receive head and tail ptrs to each other. This indicates no data
830 * available to read.
831 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700832 head = readw(&bc->rin);
833 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835 /* Set the channels associated tty structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700837 /*
838 * The below routine generally sets up parity, baud, flow control
839 * issues, etc.... It effect both control flags and input flags.
840 */
Alan Cox191260a2008-04-30 00:54:16 -0700841 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000843 spin_unlock(&epca_lock);
844 port->flags |= ASYNC_INITIALIZED;
845 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
Alan Cox6ed1dba2009-01-02 13:48:11 +0000847 retval = tty_port_block_til_ready(port, tty, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700850 /*
851 * Set this again in case a hangup set it to zero while this open() was
852 * waiting for the line...
853 */
Alan Coxd1c815e2009-01-02 13:47:58 +0000854 spin_lock_irqsave(&port->lock, flags);
855 port->tty = tty;
856 spin_lock(&epca_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700859 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 memoff(ch);
Alan Coxd1c815e2009-01-02 13:47:58 +0000861 spin_unlock(&epca_lock);
862 spin_unlock_irqrestore(&port->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
865
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700866static int __init epca_module_init(void)
867{
868 return pc_init();
869}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874static void __exit epca_module_exit(void)
875{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 int count, crd;
877 struct board_info *bd;
878 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 del_timer_sync(&epca_timer);
881
Alan Cox191260a2008-04-30 00:54:16 -0700882 if (tty_unregister_driver(pc_driver) ||
883 tty_unregister_driver(pc_info)) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700884 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 return;
886 }
887 put_tty_driver(pc_driver);
888 put_tty_driver(pc_info);
889
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700890 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700892 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
894 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700895 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700896 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700897 for (count = 0; count < bd->numports; count++, ch++) {
Alan Cox3969ffb2009-01-02 13:48:04 +0000898 struct tty_struct *tty = tty_port_tty_get(&ch->port);
899 if (tty) {
900 tty_hangup(tty);
901 tty_kref_put(tty);
902 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700903 }
904 }
905 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906}
907module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Jeff Dikeb68e31d2006-10-02 02:17:18 -0700909static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 .open = pc_open,
911 .close = pc_close,
912 .write = pc_write,
913 .write_room = pc_write_room,
914 .flush_buffer = pc_flush_buffer,
915 .chars_in_buffer = pc_chars_in_buffer,
916 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 .ioctl = pc_ioctl,
918 .set_termios = pc_set_termios,
919 .stop = pc_stop,
920 .start = pc_start,
921 .throttle = pc_throttle,
922 .unthrottle = pc_unthrottle,
923 .hangup = pc_hangup,
Alan Coxdcbf1282008-07-22 11:18:12 +0100924 .break_ctl = pc_send_break
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925};
926
Alan Cox6ed1dba2009-01-02 13:48:11 +0000927static const struct tty_port_operations epca_port_ops = {
928 .carrier_raised = epca_carrier_raised,
Alan Coxfcc8ac12009-06-11 12:24:17 +0100929 .dtr_rts = epca_dtr_rts,
Alan Cox6ed1dba2009-01-02 13:48:11 +0000930};
931
Alan Cox191260a2008-04-30 00:54:16 -0700932static int info_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
934 return 0;
935}
936
Alexey Dobriyan1cceefd2009-10-03 00:12:06 +0400937static const struct tty_operations info_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 .open = info_open,
939 .ioctl = info_ioctl,
940};
941
Alan Coxf2cf8e22005-09-06 15:16:44 -0700942static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700943{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 int crd;
945 struct board_info *bd;
946 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -0700947 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 int pci_boards_found, pci_count;
950
951 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 pc_driver = alloc_tty_driver(MAX_ALLOC);
954 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -0700955 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -0700958 if (!pc_info)
959 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700961 /*
962 * If epca_setup has not been ran by LILO set num_cards to defaults;
963 * copy board structure defined by digiConfig into drivers board
964 * structure. Note : If LILO has ran epca_setup then epca_setup will
965 * handle defining num_cards as well as copying the data into the board
966 * structure.
967 */
968 if (!liloconfig) {
969 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 nbdevs = NBDEVS;
971 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700972 memcpy(&boards, &static_boards,
973 sizeof(struct board_info) * NUMCARDS);
974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700976 /*
977 * Note : If lilo was used to configure the driver and the ignore
978 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
979 * will equal 0 at this point. This is okay; PCI cards will still be
980 * picked up if detected.
981 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700983 /*
984 * Set up interrupt, we will worry about memory allocation in
985 * post_fep_init.
986 */
Alan Cox191260a2008-04-30 00:54:16 -0700987 printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700989 /*
990 * NOTE : This code assumes that the number of ports found in the
991 * boards array is correct. This could be wrong if the card in question
992 * is PCI (And therefore has no ports entry in the boards structure.)
993 * The rest of the information will be valid for PCI because the
994 * beginning of pc_init scans for PCI and determines i/o and base
995 * memory addresses. I am not sure if it is possible to read the number
996 * of ports supported by the card prior to it being booted (Since that
997 * is the state it is in when pc_init is run). Because it is not
998 * possible to query the number of supported ports until after the card
999 * has booted; we are required to calculate the card_ptrs as the card
1000 * is initialized (Inside post_fep_init). The negative thing about this
1001 * approach is that digiDload's call to GET_INFO will have a bad port
1002 * value. (Since this is called prior to post_fep_init.)
1003 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001005 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 pci_boards_found += init_PCI();
1007 num_cards += pci_boards_found;
1008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001010 pc_driver->name = "ttyD";
1011 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 pc_driver->minor_start = 0;
1013 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1014 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1015 pc_driver->init_termios = tty_std_termios;
1016 pc_driver->init_termios.c_iflag = 0;
1017 pc_driver->init_termios.c_oflag = 0;
1018 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1019 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001020 pc_driver->init_termios.c_ispeed = 9600;
1021 pc_driver->init_termios.c_ospeed = 9600;
Alan Coxdcbf1282008-07-22 11:18:12 +01001022 pc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_HARDWARE_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 tty_set_operations(pc_driver, &pc_ops);
1024
1025 pc_info->owner = THIS_MODULE;
1026 pc_info->name = "digi_ctl";
1027 pc_info->major = DIGIINFOMAJOR;
1028 pc_info->minor_start = 0;
1029 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1030 pc_info->subtype = SERIAL_TYPE_INFO;
1031 pc_info->init_termios = tty_std_termios;
1032 pc_info->init_termios.c_iflag = 0;
1033 pc_info->init_termios.c_oflag = 0;
1034 pc_info->init_termios.c_lflag = 0;
1035 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001036 pc_info->init_termios.c_ispeed = 9600;
1037 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 pc_info->flags = TTY_DRIVER_REAL_RAW;
1039 tty_set_operations(pc_info, &info_ops);
1040
1041
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001042 for (crd = 0; crd < num_cards; crd++) {
1043 /*
1044 * This is where the appropriate memory handlers for the
1045 * hardware is set. Everything at runtime blindly jumps through
1046 * these vectors.
1047 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
1049 /* defined in epcaconfig.h */
1050 bd = &boards[crd];
1051
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001052 switch (bd->type) {
1053 case PCXEM:
1054 case EISAXEM:
1055 bd->memwinon = pcxem_memwinon;
1056 bd->memwinoff = pcxem_memwinoff;
1057 bd->globalwinon = pcxem_globalwinon;
1058 bd->txwinon = pcxem_txwinon;
1059 bd->rxwinon = pcxem_rxwinon;
1060 bd->memoff = pcxem_memoff;
1061 bd->assertgwinon = dummy_assertgwinon;
1062 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 break;
1064
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001065 case PCIXEM:
1066 case PCIXRJ:
1067 case PCIXR:
1068 bd->memwinon = dummy_memwinon;
1069 bd->memwinoff = dummy_memwinoff;
1070 bd->globalwinon = dummy_globalwinon;
1071 bd->txwinon = dummy_txwinon;
1072 bd->rxwinon = dummy_rxwinon;
1073 bd->memoff = dummy_memoff;
1074 bd->assertgwinon = dummy_assertgwinon;
1075 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 break;
1077
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001078 case PCXE:
1079 case PCXEVE:
1080 bd->memwinon = pcxe_memwinon;
1081 bd->memwinoff = pcxe_memwinoff;
1082 bd->globalwinon = pcxe_globalwinon;
1083 bd->txwinon = pcxe_txwinon;
1084 bd->rxwinon = pcxe_rxwinon;
1085 bd->memoff = pcxe_memoff;
1086 bd->assertgwinon = dummy_assertgwinon;
1087 bd->assertmemoff = dummy_assertmemoff;
1088 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001090 case PCXI:
1091 case PC64XE:
1092 bd->memwinon = pcxi_memwinon;
1093 bd->memwinoff = pcxi_memwinoff;
1094 bd->globalwinon = pcxi_globalwinon;
1095 bd->txwinon = pcxi_txwinon;
1096 bd->rxwinon = pcxi_rxwinon;
1097 bd->memoff = pcxi_memoff;
1098 bd->assertgwinon = pcxi_assertgwinon;
1099 bd->assertmemoff = pcxi_assertmemoff;
1100 break;
1101
1102 default:
1103 break;
1104 }
1105
1106 /*
1107 * Some cards need a memory segment to be defined for use in
1108 * transmit and receive windowing operations. These boards are
1109 * listed in the below switch. In the case of the XI the amount
1110 * of memory on the board is variable so the memory_seg is also
1111 * variable. This code determines what they segment should be.
1112 */
1113 switch (bd->type) {
1114 case PCXE:
1115 case PCXEVE:
1116 case PC64XE:
1117 bd->memory_seg = 0xf000;
1118 break;
1119
1120 case PCXI:
1121 board_id = inb((int)bd->port);
1122 if ((board_id & 0x1) == 0x1) {
1123 /* it's an XI card */
1124 /* Is it a 64K board */
1125 if ((board_id & 0x30) == 0)
1126 bd->memory_seg = 0xf000;
1127
1128 /* Is it a 128K board */
1129 if ((board_id & 0x30) == 0x10)
1130 bd->memory_seg = 0xe000;
1131
1132 /* Is is a 256K board */
1133 if ((board_id & 0x30) == 0x20)
1134 bd->memory_seg = 0xc000;
1135
1136 /* Is it a 512K board */
1137 if ((board_id & 0x30) == 0x30)
1138 bd->memory_seg = 0x8000;
1139 } else
Alan Cox191260a2008-04-30 00:54:16 -07001140 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 -07001141 break;
1142 }
1143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Akinobu Mitadabad052006-10-17 00:10:28 -07001145 err = tty_register_driver(pc_driver);
1146 if (err) {
1147 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1148 goto out3;
1149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Akinobu Mitadabad052006-10-17 00:10:28 -07001151 err = tty_register_driver(pc_info);
1152 if (err) {
1153 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1154 goto out4;
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001157 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 init_timer(&epca_timer);
1159 epca_timer.function = epcapoll;
1160 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return 0;
1162
Akinobu Mitadabad052006-10-17 00:10:28 -07001163out4:
1164 tty_unregister_driver(pc_driver);
1165out3:
1166 put_tty_driver(pc_info);
1167out2:
1168 put_tty_driver(pc_driver);
1169out1:
1170 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001171}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001174{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001176 void __iomem *memaddr;
1177 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001179 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001180 struct channel *ch;
1181 int shrinkmem = 0, lowwater;
1182
1183 /*
1184 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1185 * responsible for setting up all the card specific stuff.
1186 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 bd = &boards[crd];
1188
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001189 /*
1190 * If this is a PCI board, get the port info. Remember PCI cards do not
1191 * have entries into the epcaconfig.h file, so we can't get the number
1192 * of ports from it. Unfortunetly, this means that anyone doing a
1193 * DIGI_GETINFO before the board has booted will get an invalid number
1194 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1195 * DIGI_INIT has been called will return the proper values.
1196 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001197 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001198 /*
1199 * Below we use XEMPORTS as a memory offset regardless of which
1200 * PCI card it is. This is because all of the supported PCI
1201 * cards have the same memory offset for the channel data. This
1202 * will have to be changed if we ever develop a PCI/XE card.
1203 * NOTE : The FEP manual states that the port offset is 0xC22
1204 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1205 * cards; not for the XEM, or CX series. On the PCI cards the
1206 * number of ports is determined by reading a ID PROM located
1207 * in the box attached to the card. The card can then determine
1208 * the index the id to determine the number of ports available.
1209 * (FYI - The id should be located at 0x1ac (And may use up to
1210 * 4 bytes if the box in question is a XEM or CX)).
1211 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001212 /* PCI cards are already remapped at this point ISA are not */
1213 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Alan Cox191260a2008-04-30 00:54:16 -07001214 epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001216 } else {
1217 /* Fix up the mappings for ISA/EISA etc */
1218 /* FIXME: 64K - can we be smarter ? */
Alan Cox191260a2008-04-30 00:54:16 -07001219 bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222 if (crd != 0)
1223 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1224 else
1225 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1226
1227 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1229
Alan Coxf2cf8e22005-09-06 15:16:44 -07001230 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001232 /*
1233 * The below assignment will set bc to point at the BEGINING of the
1234 * cards channel structures. For 1 card there will be between 8 and 64
1235 * of these structures.
1236 */
Al Virobc9a5152005-09-15 22:53:28 +01001237 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001239 /*
1240 * The below assignment will set gd to point at the BEGINING of global
1241 * memory address 0xc00. The first data in that global memory actually
1242 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1243 */
Al Virobc9a5152005-09-15 22:53:28 +01001244 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001246 /*
1247 * XEPORTS (address 0xc22) points at the number of channels the card
1248 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1249 */
Alan Cox191260a2008-04-30 00:54:16 -07001250 if ((bd->type == PCXEVE || bd->type == PCXE) &&
1251 (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 shrinkmem = 1;
1253 if (bd->type < PCIXEM)
1254 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001255 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 memwinon(bd, 0);
1257
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001258 /*
1259 * Remember ch is the main drivers channels structure, while bc is the
1260 * cards channel structure.
1261 */
1262 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001263 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001264 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Alan Cox9ae7b082008-10-13 10:32:09 +01001266 tty_port_init(&ch->port);
Alan Coxc1314a42009-01-02 13:48:17 +00001267 ch->port.ops = &epca_port_ops;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001268 ch->brdchan = bc;
1269 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001270 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001271 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Alan Coxf2cf8e22005-09-06 15:16:44 -07001273 spin_lock_irqsave(&epca_lock, flags);
1274 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001275 /*
1276 * Since some of the boards use different bitmaps for
1277 * their control signals we cannot hard code these
1278 * values and retain portability. We virtualize this
1279 * data here.
1280 */
1281 case EISAXEM:
1282 case PCXEM:
1283 case PCIXEM:
1284 case PCIXRJ:
1285 case PCIXR:
1286 ch->m_rts = 0x02;
1287 ch->m_dcd = 0x80;
1288 ch->m_dsr = 0x20;
1289 ch->m_cts = 0x10;
1290 ch->m_ri = 0x40;
1291 ch->m_dtr = 0x01;
1292 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001294 case PCXE:
1295 case PCXEVE:
1296 case PCXI:
1297 case PC64XE:
1298 ch->m_rts = 0x02;
1299 ch->m_dcd = 0x08;
1300 ch->m_dsr = 0x10;
1301 ch->m_cts = 0x20;
1302 ch->m_ri = 0x40;
1303 ch->m_dtr = 0x80;
1304 break;
1305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Alan Coxf2cf8e22005-09-06 15:16:44 -07001307 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 ch->dsr = ch->m_dcd;
1309 ch->dcd = ch->m_dsr;
1310 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001311 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 ch->dcd = ch->m_dcd;
1313 ch->dsr = ch->m_dsr;
1314 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 ch->boardnum = crd;
1317 ch->channelnum = i;
1318 ch->magic = EPCA_MAGIC;
Alan Cox3969ffb2009-01-02 13:48:04 +00001319 tty_port_tty_set(&ch->port, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Alan Coxf2cf8e22005-09-06 15:16:44 -07001321 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1323 shrinkmem = 0;
1324 }
1325
Al Virobc9a5152005-09-15 22:53:28 +01001326 tseg = readw(&bc->tseg);
1327 rseg = readw(&bc->rseg);
1328
Alan Coxf2cf8e22005-09-06 15:16:44 -07001329 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001330 case PCIXEM:
1331 case PCIXRJ:
1332 case PCIXR:
1333 /* Cover all the 2MEG cards */
1334 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1335 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1336 ch->txwin = FEPWIN | (tseg >> 11);
1337 ch->rxwin = FEPWIN | (rseg >> 11);
1338 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001340 case PCXEM:
1341 case EISAXEM:
1342 /* Cover all the 32K windowed cards */
1343 /* Mask equal to window size - 1 */
1344 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1345 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1346 ch->txwin = FEPWIN | (tseg >> 11);
1347 ch->rxwin = FEPWIN | (rseg >> 11);
1348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001350 case PCXEVE:
1351 case PCXE:
Alan Cox191260a2008-04-30 00:54:16 -07001352 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
1353 & 0x1fff);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001354 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
Alan Cox191260a2008-04-30 00:54:16 -07001355 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
1356 & 0x1fff);
1357 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001358 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001360 case PCXI:
1361 case PC64XE:
1362 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1363 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1364 ch->txwin = ch->rxwin = 0;
1365 break;
1366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001369 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001372 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1375
1376 /* Set transmitter low water mark */
1377 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1378
1379 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1381
1382 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1384
Alan Coxf2cf8e22005-09-06 15:16:44 -07001385 writew(100, &bc->edelay);
1386 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001387
Alan Coxf2cf8e22005-09-06 15:16:44 -07001388 ch->startc = readb(&bc->startc);
1389 ch->stopc = readb(&bc->stopc);
1390 ch->startca = readb(&bc->startca);
1391 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 ch->fepcflag = 0;
1394 ch->fepiflag = 0;
1395 ch->fepoflag = 0;
1396 ch->fepstartc = 0;
1397 ch->fepstopc = 0;
1398 ch->fepstartca = 0;
1399 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001400
Alan Cox6ed1dba2009-01-02 13:48:11 +00001401 ch->port.close_delay = 50;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001402
1403 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001406 printk(KERN_INFO
Alan Cox191260a2008-04-30 00:54:16 -07001407 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
1408 VERSION, board_desc[bd->type], (long)bd->port,
1409 (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001411}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001414{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 unsigned long flags;
1416 int crd;
Alan Cox191260a2008-04-30 00:54:16 -07001417 unsigned int head, tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 struct channel *ch;
1419 struct board_info *bd;
1420
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001421 /*
1422 * This routine is called upon every timer interrupt. Even though the
1423 * Digi series cards are capable of generating interrupts this method
1424 * of non-looping polling is more efficient. This routine checks for
1425 * card generated events (Such as receive data, are transmit buffer
1426 * empty) and acts on those events.
1427 */
1428 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 bd = &boards[crd];
1430 ch = card_ptr[crd];
1431
1432 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001433 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001435 /*
1436 * assertmemoff is not needed here; indeed it is an empty
1437 * subroutine. It is being kept because future boards may need
1438 * this as well as some legacy boards.
1439 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001440 spin_lock_irqsave(&epca_lock, flags);
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 assertmemoff(ch);
1443
1444 globalwinon(ch);
1445
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001446 /*
1447 * In this case head and tail actually refer to the event queue
1448 * not the transmit or receive queue.
1449 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001450 head = readw(&ch->mailbox->ein);
1451 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001453 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 if (head != tail)
1455 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 memoff(ch);
1457
Alan Coxf2cf8e22005-09-06 15:16:44 -07001458 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001461}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
1463static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001464{
Al Virobc9a5152005-09-15 22:53:28 +01001465 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 struct channel *ch, *chan0;
1467 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001468 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001469 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001470 unsigned int tail, head;
1471 int event, channel;
1472 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001474 /*
1475 * This subroutine is called by epcapoll when an event is detected
1476 * in the event queue. This routine responds to those events.
1477 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 bd = &boards[crd];
1479
1480 chan0 = card_ptr[crd];
1481 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 assertgwinon(chan0);
Alan Cox191260a2008-04-30 00:54:16 -07001483 while ((tail = readw(&chan0->mailbox->eout)) !=
1484 (head = readw(&chan0->mailbox->ein))) {
1485 /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001487 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001489 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001491 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001492 /*
1493 * The two assignments below get the current modem status
1494 * (mstat) and the previous modem status (lstat). These are
1495 * useful becuase an event could signal a change in modem
1496 * signals itself.
1497 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001498 mstat = readb(eventbuf + 2);
1499 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001502 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (channel >= bd->numports)
1504 ch = chan0;
1505 bc = ch->brdchan;
1506 goto next;
1507 }
1508
Alan Cox191260a2008-04-30 00:54:16 -07001509 bc = ch->brdchan;
1510 if (bc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 goto next;
1512
Alan Cox3969ffb2009-01-02 13:48:04 +00001513 tty = tty_port_tty_get(&ch->port);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001514 if (event & DATA_IND) { /* Begin DATA_IND */
Alan Cox3969ffb2009-01-02 13:48:04 +00001515 receive_data(ch, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 } /* End DATA_IND */
1518 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001519 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 ch->imodem = mstat;
Jiri Slabyc3301a52009-06-11 12:41:05 +01001522 if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
Alan Cox191260a2008-04-30 00:54:16 -07001523 /* We are now receiving dcd */
1524 if (mstat & ch->dcd)
Alan Cox52d41732008-07-16 21:55:02 +01001525 wake_up_interruptible(&ch->port.open_wait);
Alan Cox191260a2008-04-30 00:54:16 -07001526 else /* No dcd; hangup */
1527 pc_sched_event(ch, EPCA_EVENT_HANGUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001529 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001530 if (tty) {
1531 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001533 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001534 tty_schedule_flip(tty);
1535 } else if (event & LOWTX_IND) {
1536 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 ch->statusflags &= ~LOWWAIT;
1538 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001539 }
1540 } else if (event & EMPTYTX_IND) {
Alan Cox191260a2008-04-30 00:54:16 -07001541 /* This event is generated by
1542 setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001544 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 ch->statusflags &= ~EMPTYWAIT;
1546 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001547 }
1548 }
Alan Cox3969ffb2009-01-02 13:48:04 +00001549 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001550 }
Alan Cox191260a2008-04-30 00:54:16 -07001551next:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001553 BUG_ON(!bc);
1554 writew(1, &bc->idata);
1555 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001558}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
Alan Cox191260a2008-04-30 00:54:16 -07001561 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001562{
Al Virobc9a5152005-09-15 22:53:28 +01001563 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 unsigned int head, cmdTail, cmdStart, cmdMax;
1565 long count;
1566 int n;
1567
1568 /* This is the routine in which commands may be passed to the card. */
1569
1570 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001574 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001576 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001577 /*
1578 * We do the addition below because we do not want a max pointer
1579 * relative to cmdStart. We want a max pointer that points at the
1580 * physical end of the command queue.
1581 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001582 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 memaddr = ch->board->re_map_membase;
1584
Alan Coxf2cf8e22005-09-06 15:16:44 -07001585 if (head >= (cmdMax - cmdStart) || (head & 03)) {
Alan Cox191260a2008-04-30 00:54:16 -07001586 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n",
1587 __LINE__, cmd, head);
1588 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n",
1589 __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 return;
1591 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001592 if (bytecmd) {
1593 writeb(cmd, memaddr + head + cmdStart + 0);
1594 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001596 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001598 writeb(byte2, memaddr + head + cmdStart + 3);
1599 } else {
1600 writeb(cmd, memaddr + head + cmdStart + 0);
1601 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1602 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001605 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 count = FEPTIMEOUT;
1607
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001608 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001610 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1612 return;
1613 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001614 head = readw(&ch->mailbox->cin);
1615 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001617 /*
1618 * Basically this will break when the FEP acknowledges the
1619 * command by incrementing cmdTail (Making it equal to head).
1620 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001622 break;
1623 }
1624}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001626/*
1627 * Digi products use fields in their channels structures that are very similar
1628 * to the c_cflag and c_iflag fields typically found in UNIX termios
1629 * structures. The below three routines allow mappings between these hardware
1630 * "flags" and their respective Linux flags.
1631 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001633{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 unsigned res = 0;
1635
Alan Coxf2cf8e22005-09-06 15:16:44 -07001636 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1638 res |= ((ch->m_cts) | (ch->m_rts));
1639 }
1640
1641 if (ch->digiext.digi_flags & RTSPACE)
1642 res |= ch->m_rts;
1643
1644 if (ch->digiext.digi_flags & DTRPACE)
1645 res |= ch->m_dtr;
1646
1647 if (ch->digiext.digi_flags & CTSPACE)
1648 res |= ch->m_cts;
1649
1650 if (ch->digiext.digi_flags & DSRPACE)
1651 res |= ch->dsr;
1652
1653 if (ch->digiext.digi_flags & DCDPACE)
1654 res |= ch->dcd;
1655
1656 if (res & (ch->m_rts))
1657 ch->digiext.digi_flags |= RTSPACE;
1658
1659 if (res & (ch->m_cts))
1660 ch->digiext.digi_flags |= CTSPACE;
1661
1662 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001663}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001666{
1667 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Alan Cox191260a2008-04-30 00:54:16 -07001668 INPCK | ISTRIP | IXON | IXANY | IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (ch->digiext.digi_flags & DIGI_AIXON)
1670 res |= IAIXON;
1671 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001672}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
1674static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001675{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001677 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001678 ch->digiext.digi_flags |= DIGI_FAST;
1679 /*
1680 * HUPCL bit is used by FEP to indicate fast baud table is to
1681 * be used.
1682 */
1683 res |= FEP_HUPCL;
1684 } else
1685 ch->digiext.digi_flags &= ~DIGI_FAST;
1686 /*
1687 * CBAUD has bit position 0x1000 set these days to indicate Linux
1688 * baud rate remap. Digi hardware can't handle the bit assignment.
1689 * (We use a different bit assignment for high speed.). Clear this
1690 * bit out.
1691 */
1692 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1693 /*
1694 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001695 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001696 * this is identical to the Linux implementation. However; Digi
1697 * supports one rate (76800) that Linux doesn't. This means that the
1698 * c_cflag entry that would normally mean 76800 for Digi actually means
1699 * 115200 under Linux. Without the below mapping, a stty 115200 would
1700 * only drive the board at 76800. Since the rate 230400 is also found
1701 * after 76800, the same problem afflicts us when we choose a rate of
1702 * 230400. Without the below modificiation stty 230400 would actually
1703 * give us 115200.
1704 *
1705 * There are two additional differences. The Linux value for CLOCAL
1706 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1707 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1708 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1709 * checked for a screened out prior to termios2digi_c returning. Since
1710 * CLOCAL isn't used by the board this can be ignored as long as the
1711 * returned value is used only by Digi hardware.
1712 */
1713 if (cflag & CBAUDEX) {
1714 /*
1715 * The below code is trying to guarantee that only baud rates
1716 * 115200 and 230400 are remapped. We use exclusive or because
1717 * the various baud rates share common bit positions and
1718 * therefore can't be tested for easily.
1719 */
1720 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001725}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
Alan Coxf2cf8e22005-09-06 15:16:44 -07001727/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001729{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001731 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001732 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 unsigned mval, hflow, cflag, iflag;
1734
1735 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001736 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
1738 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001740 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1741 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001742 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001743 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001745 /*
1746 * Flush current transmit buffer by setting cmdTail pointer
1747 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1748 * buffer is empty.
1749 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1751 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001752 } else { /* Begin CBAUD not detected */
1753 /*
1754 * c_cflags have changed but that change had nothing to do with
1755 * BAUD. Propagate the change to the card.
1756 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001758 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 ch->fepcflag = cflag;
1760 /* Set baud rate, char size, stop bits, parity */
1761 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1762 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001763 /*
1764 * If the user has not forced CLOCAL and if the device is not a
1765 * CALLOUT device (Which is always CLOCAL) we set flags such
1766 * that the driver will wait on carrier detect.
1767 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 if (ts->c_cflag & CLOCAL)
Jiri Slabyc3301a52009-06-11 12:41:05 +01001769 clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 else
Jiri Slabyc3301a52009-06-11 12:41:05 +01001771 set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001776 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001778 /*
1779 * Command sets channels iflag structure on the board. Such
1780 * things as input soft flow control, handling of parity
1781 * errors, and break handling are all set here.
Alan Cox191260a2008-04-30 00:54:16 -07001782 *
1783 * break handling, parity handling, input stripping,
1784 * flow control chars
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001785 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1787 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001788 /*
1789 * Set the board mint value for this channel. This will cause hardware
1790 * events to be generated each time the DCD signal (Described in mint)
1791 * changes.
1792 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001793 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1795 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001796 writeb(0, &bc->mint);
1797 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001799 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001801 /*
1802 * Hard flow control has been selected but the board is not
1803 * using it. Activate hard flow control now.
1804 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 mval ^= ch->modemfake & (mval ^ ch->modem);
1808
Alan Coxf2cf8e22005-09-06 15:16:44 -07001809 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001811 /*
1812 * The below command sets the DTR and RTS mstat structure. If
1813 * hard flow control is NOT active these changes will drive the
1814 * output of the actual DTR and RTS lines. If hard flow control
1815 * is active, the changes will be saved in the mstat structure
1816 * and only asserted when hard flow control is turned off.
1817 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818
1819 /* First reset DTR & RTS; then set them */
1820 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1821 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001823 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 ch->fepstartc = ch->startc;
1825 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001826 /*
1827 * The XON / XOFF characters have changed; propagate these
1828 * changes to the card.
1829 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1831 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001832 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 ch->fepstartca = ch->startca;
1834 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001835 /*
1836 * Similar to the above, this time the auxilarly XON / XOFF
1837 * characters have changed; propagate these changes to the card.
1838 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1840 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001841}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
Alan Coxf2cf8e22005-09-06 15:16:44 -07001843/* Caller holds lock */
Alan Cox3969ffb2009-01-02 13:48:04 +00001844static void receive_data(struct channel *ch, struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001845{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001847 struct ktermios *ts = NULL;
Al Virobc9a5152005-09-15 22:53:28 +01001848 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001849 int dataToRead, wrapgap, bytesAvailable;
1850 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001853 /*
1854 * This routine is called by doint when a receive data event has taken
1855 * place.
1856 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (ch->statusflags & RXSTOPPED)
1859 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if (tty)
1861 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001863 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 wrapmask = ch->rxbufsize - 1;
1865
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001866 /*
1867 * Get the head and tail pointers to the receiver queue. Wrap the head
1868 * pointer if it has reached the end of the buffer.
1869 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001870 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001872 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 if (bytesAvailable == 0)
1876 return;
1877
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001878 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Cox191260a2008-04-30 00:54:16 -07001879 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001880 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return;
1882 }
1883
Alan Cox33f0f882006-01-09 20:54:13 -08001884 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 return;
1886
Alan Coxf2cf8e22005-09-06 15:16:44 -07001887 if (readb(&bc->orun)) {
1888 writeb(0, &bc->orun);
Alan Cox191260a2008-04-30 00:54:16 -07001889 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
1890 tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08001891 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 rxwinon(ch);
Alan Cox191260a2008-04-30 00:54:16 -07001894 while (bytesAvailable > 0) {
1895 /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001897 /*
1898 * Even if head has wrapped around only report the amount of
1899 * data to be equal to the size - tail. Remember memcpy can't
1900 * automaticly wrap around the receive buffer.
1901 */
Alan Cox191260a2008-04-30 00:54:16 -07001902 dataToRead = (wrapgap < bytesAvailable) ? wrapgap
1903 : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001904 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001905 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 if (dataToRead == 0)
1907 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001908 /*
1909 * Move data read from our card into the line disciplines
1910 * buffer for translation if necessary.
1911 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001912 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 tail = (tail + dataToRead) & wrapmask;
1914 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001917 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 /* Must be called with global data */
Alan Cox3969ffb2009-01-02 13:48:04 +00001919 tty_schedule_flip(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001920}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001922static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 unsigned int cmd, unsigned long arg)
1924{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001925 switch (cmd) {
1926 case DIGI_GETINFO:
1927 {
1928 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 int brd;
1930
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001931 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07001932 return -EFAULT;
1933 if (brd < 0 || brd >= num_cards || num_cards == 0)
1934 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 memset(&di, 0, sizeof(di));
1937
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001938 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 di.status = boards[brd].status;
1940 di.type = boards[brd].type ;
1941 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001942 /* Legacy fixups - just move along nothing to see */
1943 di.port = (unsigned char *)boards[brd].port ;
1944 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001946 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 return -EFAULT;
1948 break;
1949
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001952 case DIGI_POLLER:
1953 {
1954 int brd = arg & 0xff000000 >> 16;
1955 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Alan Coxf2cf8e22005-09-06 15:16:44 -07001957 if (brd < 0 || brd >= num_cards) {
1958 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001959 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001961 digi_poller_inhibited = state;
1962 break;
1963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001965 case DIGI_INIT:
1966 {
1967 /*
1968 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02001969 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001970 * responsible for setting the card to its initial
1971 * state and setting the drivers control fields to the
1972 * sutianle settings for the card in question.
1973 */
1974 int crd;
1975 for (crd = 0; crd < num_cards; crd++)
1976 post_fep_init(crd);
1977 break;
1978 }
1979 default:
1980 return -ENOTTY;
1981 }
1982 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985static int pc_tiocmget(struct tty_struct *tty, struct file *file)
1986{
Alan Coxc9f19e92009-01-02 13:47:26 +00001987 struct channel *ch = tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01001988 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 unsigned int mstat, mflag = 0;
1990 unsigned long flags;
1991
1992 if (ch)
1993 bc = ch->brdchan;
1994 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07001995 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Alan Coxf2cf8e22005-09-06 15:16:44 -07001997 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001999 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002001 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
2003 if (mstat & ch->m_dtr)
2004 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (mstat & ch->m_rts)
2006 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 if (mstat & ch->m_cts)
2008 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 if (mstat & ch->dsr)
2010 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 if (mstat & ch->m_ri)
2012 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 if (mstat & ch->dcd)
2014 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 return mflag;
2016}
2017
2018static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2019 unsigned int set, unsigned int clear)
2020{
Alan Coxc9f19e92009-01-02 13:47:26 +00002021 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 unsigned long flags;
2023
Alan Coxf2cf8e22005-09-06 15:16:44 -07002024 if (!ch)
2025 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Alan Coxf2cf8e22005-09-06 15:16:44 -07002027 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002029 * I think this modemfake stuff is broken. It doesn't correctly reflect
2030 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2031 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 */
2033 if (set & TIOCM_RTS) {
2034 ch->modemfake |= ch->m_rts;
2035 ch->modem |= ch->m_rts;
2036 }
2037 if (set & TIOCM_DTR) {
2038 ch->modemfake |= ch->m_dtr;
2039 ch->modem |= ch->m_dtr;
2040 }
2041 if (clear & TIOCM_RTS) {
2042 ch->modemfake |= ch->m_rts;
2043 ch->modem &= ~ch->m_rts;
2044 }
2045 if (clear & TIOCM_DTR) {
2046 ch->modemfake |= ch->m_dtr;
2047 ch->modem &= ~ch->m_dtr;
2048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002050 /*
2051 * The below routine generally sets up parity, baud, flow control
2052 * issues, etc.... It effect both control flags and input flags.
2053 */
Alan Cox191260a2008-04-30 00:54:16 -07002054 epcaparam(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002056 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return 0;
2058}
2059
Alan Cox191260a2008-04-30 00:54:16 -07002060static int pc_ioctl(struct tty_struct *tty, struct file *file,
2061 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 digiflow_t dflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 unsigned long flags;
2065 unsigned int mflag, mstat;
2066 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002067 struct board_chan __iomem *bc;
Alan Coxc9f19e92009-01-02 13:47:26 +00002068 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 if (ch)
2072 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002073 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002074 return -EINVAL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002075 switch (cmd) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002076 case TIOCMODG:
2077 mflag = pc_tiocmget(tty, file);
2078 if (put_user(mflag, (unsigned long __user *)argp))
2079 return -EFAULT;
2080 break;
2081 case TIOCMODS:
2082 if (get_user(mstat, (unsigned __user *)argp))
2083 return -EFAULT;
2084 return pc_tiocmset(tty, file, mstat, ~mstat);
2085 case TIOCSDTR:
2086 spin_lock_irqsave(&epca_lock, flags);
2087 ch->omodem |= ch->m_dtr;
2088 globalwinon(ch);
2089 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2090 memoff(ch);
2091 spin_unlock_irqrestore(&epca_lock, flags);
2092 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002094 case TIOCCDTR:
2095 spin_lock_irqsave(&epca_lock, flags);
2096 ch->omodem &= ~ch->m_dtr;
2097 globalwinon(ch);
2098 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2099 memoff(ch);
2100 spin_unlock_irqrestore(&epca_lock, flags);
2101 break;
2102 case DIGI_GETA:
2103 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2104 return -EFAULT;
2105 break;
2106 case DIGI_SETAW:
2107 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002108 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002109 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002110 /* Setup an event to indicate when the transmit
2111 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002112 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002113 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002114 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002115 tty_wait_until_sent(tty, 0);
2116 } else {
2117 /* ldisc lock already held in ioctl */
Alan Coxc65c9bc2009-06-11 12:50:12 +01002118 if (tty->ldisc->ops->flush_buffer)
2119 tty->ldisc->ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002120 }
Alan Cox37925e02008-04-30 00:53:17 -07002121 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002122 /* Fall Thru */
2123 case DIGI_SETA:
2124 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2125 return -EFAULT;
2126
2127 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2128 ch->dcd = ch->m_dsr;
2129 ch->dsr = ch->m_dcd;
2130 } else {
2131 ch->dcd = ch->m_dcd;
2132 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002134
2135 spin_lock_irqsave(&epca_lock, flags);
2136 globalwinon(ch);
2137
2138 /*
2139 * The below routine generally sets up parity, baud, flow
2140 * control issues, etc.... It effect both control flags and
2141 * input flags.
2142 */
Alan Cox191260a2008-04-30 00:54:16 -07002143 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002144 memoff(ch);
2145 spin_unlock_irqrestore(&epca_lock, flags);
2146 break;
2147
2148 case DIGI_GETFLOW:
2149 case DIGI_GETAFLOW:
2150 spin_lock_irqsave(&epca_lock, flags);
2151 globalwinon(ch);
2152 if (cmd == DIGI_GETFLOW) {
2153 dflow.startc = readb(&bc->startc);
2154 dflow.stopc = readb(&bc->stopc);
2155 } else {
2156 dflow.startc = readb(&bc->startca);
2157 dflow.stopc = readb(&bc->stopca);
2158 }
2159 memoff(ch);
2160 spin_unlock_irqrestore(&epca_lock, flags);
2161
2162 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2163 return -EFAULT;
2164 break;
2165
2166 case DIGI_SETAFLOW:
2167 case DIGI_SETFLOW:
2168 if (cmd == DIGI_SETFLOW) {
2169 startc = ch->startc;
2170 stopc = ch->stopc;
2171 } else {
2172 startc = ch->startca;
2173 stopc = ch->stopca;
2174 }
2175
2176 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2177 return -EFAULT;
2178
Alan Cox191260a2008-04-30 00:54:16 -07002179 if (dflow.startc != startc || dflow.stopc != stopc) {
2180 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002181 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 globalwinon(ch);
2183
Alan Coxf2cf8e22005-09-06 15:16:44 -07002184 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002185 ch->fepstartc = ch->startc = dflow.startc;
2186 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002187 fepcmd(ch, SONOFFC, ch->fepstartc,
2188 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002189 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002190 ch->fepstartca = ch->startca = dflow.startc;
2191 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002192 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2193 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002196 if (ch->statusflags & TXSTOPPED)
2197 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002199 memoff(ch);
2200 spin_unlock_irqrestore(&epca_lock, flags);
2201 } /* End if setflow toggled */
2202 break;
2203 default:
2204 return -ENOIOCTLCMD;
2205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002207}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Alan Cox606d0992006-12-08 02:38:45 -08002209static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002210{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 struct channel *ch;
2212 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002213 /*
2214 * verifyChannel returns the channel from the tty struct if it is
2215 * valid. This serves as a sanity check.
2216 */
Alan Cox191260a2008-04-30 00:54:16 -07002217 ch = verifyChannel(tty);
2218
2219 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002220 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 globalwinon(ch);
2222 epcaparam(tty, ch);
2223 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002224 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
2226 if ((old_termios->c_cflag & CRTSCTS) &&
2227 ((tty->termios->c_cflag & CRTSCTS) == 0))
2228 tty->hw_stopped = 0;
2229
2230 if (!(old_termios->c_cflag & CLOCAL) &&
2231 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002232 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002235}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
David Howellsc4028952006-11-22 14:57:56 +00002237static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002238{
David Howellsc4028952006-11-22 14:57:56 +00002239 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002241 if (ch && ch->magic == EPCA_MAGIC) {
Joe Perchesa419aef2009-08-18 11:18:35 -07002242 struct tty_struct *tty = tty_port_tty_get(&ch->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
Alan Coxf2cf8e22005-09-06 15:16:44 -07002244 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002245 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002246 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002247 wake_up_interruptible(&ch->port.open_wait);
Jiri Slabyc3301a52009-06-11 12:41:05 +01002248 clear_bit(ASYNCB_NORMAL_ACTIVE,
2249 &ch->port.flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002252 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002253 }
2254}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002256/*
2257 * pc_stop and pc_start provide software flow control to the routine and the
2258 * pc_ioctl routine.
2259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002261{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 struct channel *ch;
2263 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002264 /*
2265 * verifyChannel returns the channel from the tty struct if it is
2266 * valid. This serves as a sanity check.
2267 */
Alan Cox191260a2008-04-30 00:54:16 -07002268 ch = verifyChannel(tty);
2269 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002270 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002271 if ((ch->statusflags & TXSTOPPED) == 0) {
2272 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 ch->statusflags |= TXSTOPPED;
2277 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002279 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002280 }
2281}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002284{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002286 /*
2287 * verifyChannel returns the channel from the tty struct if it is
2288 * valid. This serves as a sanity check.
2289 */
Alan Cox191260a2008-04-30 00:54:16 -07002290 ch = verifyChannel(tty);
2291 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002293 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002294 /* Just in case output was resumed because of a change
2295 in Digi-flow */
2296 if (ch->statusflags & TXSTOPPED) {
2297 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002298 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 globalwinon(ch);
2300 bc = ch->brdchan;
2301 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002302 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 ch->statusflags &= ~TXSTOPPED;
2306 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002308 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002309 }
2310}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002312/*
2313 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2314 * resume) the receipt of data into the kernels receive buffers. The exact
2315 * occurrence of this depends on the size of the kernels receive buffer and
2316 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2317 * more details.
2318 */
2319static void pc_throttle(struct tty_struct *tty)
2320{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 struct channel *ch;
2322 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002323 /*
2324 * verifyChannel returns the channel from the tty struct if it is
2325 * valid. This serves as a sanity check.
2326 */
Alan Cox191260a2008-04-30 00:54:16 -07002327 ch = verifyChannel(tty);
2328 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002329 spin_lock_irqsave(&epca_lock, flags);
2330 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 globalwinon(ch);
2332 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 ch->statusflags |= RXSTOPPED;
2334 memoff(ch);
2335 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002336 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002337 }
2338}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
2340static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002341{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 struct channel *ch;
2343 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002344 /*
2345 * verifyChannel returns the channel from the tty struct if it is
2346 * valid. This serves as a sanity check.
2347 */
Alan Cox191260a2008-04-30 00:54:16 -07002348 ch = verifyChannel(tty);
2349 if (ch != NULL) {
2350 /* Just in case output was resumed because of a change
2351 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002352 spin_lock_irqsave(&epca_lock, flags);
2353 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 ch->statusflags &= ~RXSTOPPED;
2357 memoff(ch);
2358 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002359 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002360 }
2361}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Alan Coxdcbf1282008-07-22 11:18:12 +01002363static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002364{
Alan Coxc9f19e92009-01-02 13:47:26 +00002365 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 unsigned long flags;
2367
Alan Coxdcbf1282008-07-22 11:18:12 +01002368 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002369 msec = 0xFFFF;
2370 else if (msec > 0xFFFE)
2371 msec = 0xFFFE;
2372 else if (msec < 1)
2373 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002374
Alan Coxf2cf8e22005-09-06 15:16:44 -07002375 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002377 /*
2378 * Maybe I should send an infinite break here, schedule() for msec
2379 * amount of time, and then stop the break. This way, the user can't
2380 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2381 * an ioctl()) more than once in msec amount of time.
2382 * Try this for now...
2383 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2385 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002386 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002387 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002388}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389
Alan Coxf2cf8e22005-09-06 15:16:44 -07002390/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002392{
Al Virobc9a5152005-09-15 22:53:28 +01002393 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 globalwinon(ch);
2396 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002397 /*
2398 * When set the iempty flag request a event to be generated when the
2399 * transmit buffer is empty (If there is no BREAK in progress).
2400 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002401 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002403}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
David Howells88e88242008-07-22 11:20:45 +01002405#ifndef MODULE
2406static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002407{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 struct board_info board;
2409 int index, loop, last;
2410 char *temp, *t2;
2411 unsigned len;
2412
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002413 /*
2414 * If this routine looks a little strange it is because it is only
2415 * called if a LILO append command is given to boot the kernel with
2416 * parameters. In this way, we can provide the user a method of
2417 * changing his board configuration without rebuilding the kernel.
2418 */
2419 if (!liloconfig)
2420 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 memset(&board, 0, sizeof(board));
2423
2424 /* Assume the data is int first, later we can change it */
2425 /* I think that array position 0 of ints holds the number of args */
2426 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002427 switch (index) { /* Begin parse switch */
2428 case 1:
2429 board.status = ints[index];
2430 /*
2431 * We check for 2 (As opposed to 1; because 2 is a flag
2432 * instructing the driver to ignore epcaconfig.) For
2433 * this reason we check for 2.
2434 */
Alan Cox191260a2008-04-30 00:54:16 -07002435 if (board.status == 2) {
2436 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002437 nbdevs = 0;
2438 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002440 } /* End ignore epcaconfig as well as lilo cmd line */
2441
2442 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002443 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2444 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002445 invalid_lilo_config = 1;
2446 setup_error_code |= INVALID_BOARD_STATUS;
2447 return;
2448 }
2449 last = index;
2450 break;
2451 case 2:
2452 board.type = ints[index];
2453 if (board.type >= PCIXEM) {
2454 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2455 invalid_lilo_config = 1;
2456 setup_error_code |= INVALID_BOARD_TYPE;
2457 return;
2458 }
2459 last = index;
2460 break;
2461 case 3:
2462 board.altpin = ints[index];
2463 if (board.altpin > 1) {
2464 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2465 invalid_lilo_config = 1;
2466 setup_error_code |= INVALID_ALTPIN;
2467 return;
2468 }
2469 last = index;
2470 break;
2471
2472 case 4:
2473 board.numports = ints[index];
2474 if (board.numports < 2 || board.numports > 256) {
2475 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2476 invalid_lilo_config = 1;
2477 setup_error_code |= INVALID_NUM_PORTS;
2478 return;
2479 }
2480 nbdevs += board.numports;
2481 last = index;
2482 break;
2483
2484 case 5:
2485 board.port = ints[index];
2486 if (ints[index] <= 0) {
2487 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2488 invalid_lilo_config = 1;
2489 setup_error_code |= INVALID_PORT_BASE;
2490 return;
2491 }
2492 last = index;
2493 break;
2494
2495 case 6:
2496 board.membase = ints[index];
2497 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002498 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2499 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002500 invalid_lilo_config = 1;
2501 setup_error_code |= INVALID_MEM_BASE;
2502 return;
2503 }
2504 last = index;
2505 break;
2506
2507 default:
2508 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2509 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 } /* End parse switch */
2512
Alan Coxf2cf8e22005-09-06 15:16:44 -07002513 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 /* find the next comma or terminator */
2515 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 /* While string is not null, and a comma hasn't been found */
2517 while (*temp && (*temp != ','))
2518 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 if (!*temp)
2520 temp = NULL;
2521 else
2522 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 /* Set index to the number of args + 1 */
2524 index = last + 1;
2525
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002526 switch (index) {
2527 case 1:
2528 len = strlen(str);
2529 if (strncmp("Disable", str, len) == 0)
2530 board.status = 0;
2531 else if (strncmp("Enable", str, len) == 0)
2532 board.status = 1;
2533 else {
2534 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2535 invalid_lilo_config = 1;
2536 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002538 }
2539 last = index;
2540 break;
2541
2542 case 2:
2543 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2544 if (strcmp(board_desc[loop], str) == 0)
2545 break;
2546 /*
2547 * If the index incremented above refers to a
2548 * legitamate board type set it here.
2549 */
2550 if (index < EPCA_NUM_TYPES)
2551 board.type = loop;
2552 else {
2553 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2554 invalid_lilo_config = 1;
2555 setup_error_code |= INVALID_BOARD_TYPE;
2556 return;
2557 }
2558 last = index;
2559 break;
2560
2561 case 3:
2562 len = strlen(str);
2563 if (strncmp("Disable", str, len) == 0)
2564 board.altpin = 0;
2565 else if (strncmp("Enable", str, len) == 0)
2566 board.altpin = 1;
2567 else {
2568 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2569 invalid_lilo_config = 1;
2570 setup_error_code |= INVALID_ALTPIN;
2571 return;
2572 }
2573 last = index;
2574 break;
2575
2576 case 4:
2577 t2 = str;
2578 while (isdigit(*t2))
2579 t2++;
2580
2581 if (*t2) {
2582 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2583 invalid_lilo_config = 1;
2584 setup_error_code |= INVALID_NUM_PORTS;
2585 return;
2586 }
2587
2588 /*
2589 * There is not a man page for simple_strtoul but the
2590 * code can be found in vsprintf.c. The first argument
2591 * is the string to translate (To an unsigned long
2592 * obviously), the second argument can be the address
2593 * of any character variable or a NULL. If a variable
2594 * is given, the end pointer of the string will be
2595 * stored in that variable; if a NULL is given the end
2596 * pointer will not be returned. The last argument is
2597 * the base to use. If a 0 is indicated, the routine
2598 * will attempt to determine the proper base by looking
2599 * at the values prefix (A '0' for octal, a 'x' for
2600 * hex, etc ... If a value is given it will use that
2601 * value as the base.
2602 */
2603 board.numports = simple_strtoul(str, NULL, 0);
2604 nbdevs += board.numports;
2605 last = index;
2606 break;
2607
2608 case 5:
2609 t2 = str;
2610 while (isxdigit(*t2))
2611 t2++;
2612
2613 if (*t2) {
2614 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2615 invalid_lilo_config = 1;
2616 setup_error_code |= INVALID_PORT_BASE;
2617 return;
2618 }
2619
2620 board.port = simple_strtoul(str, NULL, 16);
2621 last = index;
2622 break;
2623
2624 case 6:
2625 t2 = str;
2626 while (isxdigit(*t2))
2627 t2++;
2628
2629 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002630 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002631 invalid_lilo_config = 1;
2632 setup_error_code |= INVALID_MEM_BASE;
2633 return;
2634 }
2635 board.membase = simple_strtoul(str, NULL, 16);
2636 last = index;
2637 break;
2638 default:
2639 printk(KERN_ERR "epca: Too many string parms\n");
2640 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
2642 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 } /* End while there is a string arg */
2644
Alan Coxf2cf8e22005-09-06 15:16:44 -07002645 if (last < 6) {
2646 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 return;
2648 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002652 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002654 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2655 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002658}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659
David Howells88e88242008-07-22 11:20:45 +01002660static int __init epca_real_setup(char *str)
2661{
2662 int ints[11];
2663
2664 epca_setup(get_options(str, 11, ints), ints);
2665 return 1;
2666}
2667
2668__setup("digiepca", epca_real_setup);
2669#endif
2670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671enum epic_board_types {
2672 brd_xr = 0,
2673 brd_xem,
2674 brd_cx,
2675 brd_xrj,
2676};
2677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678/* indexed directly by epic_board_types enum */
2679static struct {
2680 unsigned char board_type;
2681 unsigned bar_idx; /* PCI base address region */
2682} epca_info_tbl[] = {
2683 { PCIXR, 0, },
2684 { PCIXEM, 0, },
2685 { PCICX, 0, },
2686 { PCIXRJ, 2, },
2687};
2688
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002689static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 const struct pci_device_id *ent)
2691{
2692 static int board_num = -1;
2693 int board_idx, info_idx = ent->driver_data;
2694 unsigned long addr;
2695
2696 if (pci_enable_device(pdev))
2697 return -EIO;
2698
2699 board_num++;
2700 board_idx = board_num + num_cards;
2701 if (board_idx >= MAXBOARDS)
2702 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002703
Alan Cox191260a2008-04-30 00:54:16 -07002704 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002706 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 epca_info_tbl[info_idx].bar_idx);
2708 goto err_out;
2709 }
2710
2711 boards[board_idx].status = ENABLED;
2712 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2713 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002714 boards[board_idx].port = addr + PCI_IO_OFFSET;
2715 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
Alan Cox191260a2008-04-30 00:54:16 -07002717 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2718 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 0x200000, addr + PCI_IO_OFFSET);
2720 goto err_out;
2721 }
2722
Alan Cox191260a2008-04-30 00:54:16 -07002723 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2724 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002726 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 0x200000, addr + PCI_IO_OFFSET);
2728 goto err_out_free_pciio;
2729 }
2730
Alan Cox191260a2008-04-30 00:54:16 -07002731 if (!request_mem_region(addr, 0x200000, "epca")) {
2732 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 0x200000, addr);
2734 goto err_out_free_iounmap;
2735 }
2736
Alan Cox191260a2008-04-30 00:54:16 -07002737 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002739 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 0x200000, addr + PCI_IO_OFFSET);
2741 goto err_out_free_memregion;
2742 }
2743
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002744 /*
2745 * I don't know what the below does, but the hardware guys say its
2746 * required on everything except PLX (In this case XRJ).
2747 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002749 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 pci_write_config_byte(pdev, 0x46, 0);
2751 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002752
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 return 0;
2754
2755err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002756 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002758 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002760 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761err_out:
2762 return -ENODEV;
2763}
2764
2765
2766static struct pci_device_id epca_pci_tbl[] = {
2767 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2768 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2769 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2770 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2771 { 0, }
2772};
2773
2774MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2775
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002776static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002777{
Alan Cox191260a2008-04-30 00:54:16 -07002778 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 epca_driver.name = "epca";
2780 epca_driver.id_table = epca_pci_tbl;
2781 epca_driver.probe = epca_init_one;
2782
2783 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002784}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
2786MODULE_LICENSE("GPL");