blob: d9df46aa0fbafa8988e4d0fda760d18bd6e09b76 [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>
Alan Cox7cc34fd2010-06-01 22:52:48 +020039#include <linux/slab.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:
2108 if (cmd == DIGI_SETAW) {
Alan Cox191260a2008-04-30 00:54:16 -07002109 /* Setup an event to indicate when the transmit
2110 buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002111 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002112 setup_empty_event(tty, ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002113 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002114 tty_wait_until_sent(tty, 0);
2115 } else {
2116 /* ldisc lock already held in ioctl */
Alan Coxc65c9bc2009-06-11 12:50:12 +01002117 if (tty->ldisc->ops->flush_buffer)
2118 tty->ldisc->ops->flush_buffer(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002119 }
2120 /* Fall Thru */
2121 case DIGI_SETA:
2122 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2123 return -EFAULT;
2124
2125 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2126 ch->dcd = ch->m_dsr;
2127 ch->dsr = ch->m_dcd;
2128 } else {
2129 ch->dcd = ch->m_dcd;
2130 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002132
2133 spin_lock_irqsave(&epca_lock, flags);
2134 globalwinon(ch);
2135
2136 /*
2137 * The below routine generally sets up parity, baud, flow
2138 * control issues, etc.... It effect both control flags and
2139 * input flags.
2140 */
Alan Cox191260a2008-04-30 00:54:16 -07002141 epcaparam(tty, ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002142 memoff(ch);
2143 spin_unlock_irqrestore(&epca_lock, flags);
2144 break;
2145
2146 case DIGI_GETFLOW:
2147 case DIGI_GETAFLOW:
2148 spin_lock_irqsave(&epca_lock, flags);
2149 globalwinon(ch);
2150 if (cmd == DIGI_GETFLOW) {
2151 dflow.startc = readb(&bc->startc);
2152 dflow.stopc = readb(&bc->stopc);
2153 } else {
2154 dflow.startc = readb(&bc->startca);
2155 dflow.stopc = readb(&bc->stopca);
2156 }
2157 memoff(ch);
2158 spin_unlock_irqrestore(&epca_lock, flags);
2159
2160 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2161 return -EFAULT;
2162 break;
2163
2164 case DIGI_SETAFLOW:
2165 case DIGI_SETFLOW:
2166 if (cmd == DIGI_SETFLOW) {
2167 startc = ch->startc;
2168 stopc = ch->stopc;
2169 } else {
2170 startc = ch->startca;
2171 stopc = ch->stopca;
2172 }
2173
2174 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2175 return -EFAULT;
2176
Alan Cox191260a2008-04-30 00:54:16 -07002177 if (dflow.startc != startc || dflow.stopc != stopc) {
2178 /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002179 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 globalwinon(ch);
2181
Alan Coxf2cf8e22005-09-06 15:16:44 -07002182 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002183 ch->fepstartc = ch->startc = dflow.startc;
2184 ch->fepstopc = ch->stopc = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002185 fepcmd(ch, SONOFFC, ch->fepstartc,
2186 ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002187 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002188 ch->fepstartca = ch->startca = dflow.startc;
2189 ch->fepstopca = ch->stopca = dflow.stopc;
Alan Cox191260a2008-04-30 00:54:16 -07002190 fepcmd(ch, SAUXONOFFC, ch->fepstartca,
2191 ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002194 if (ch->statusflags & TXSTOPPED)
2195 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002197 memoff(ch);
2198 spin_unlock_irqrestore(&epca_lock, flags);
2199 } /* End if setflow toggled */
2200 break;
2201 default:
2202 return -ENOIOCTLCMD;
2203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002205}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Alan Cox606d0992006-12-08 02:38:45 -08002207static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002208{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 struct channel *ch;
2210 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002211 /*
2212 * verifyChannel returns the channel from the tty struct if it is
2213 * valid. This serves as a sanity check.
2214 */
Alan Cox191260a2008-04-30 00:54:16 -07002215 ch = verifyChannel(tty);
2216
2217 if (ch != NULL) { /* Begin if channel valid */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002218 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 globalwinon(ch);
2220 epcaparam(tty, ch);
2221 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002222 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 if ((old_termios->c_cflag & CRTSCTS) &&
2225 ((tty->termios->c_cflag & CRTSCTS) == 0))
2226 tty->hw_stopped = 0;
2227
2228 if (!(old_termios->c_cflag & CLOCAL) &&
2229 (tty->termios->c_cflag & CLOCAL))
Alan Cox52d41732008-07-16 21:55:02 +01002230 wake_up_interruptible(&ch->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002233}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
David Howellsc4028952006-11-22 14:57:56 +00002235static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002236{
David Howellsc4028952006-11-22 14:57:56 +00002237 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002239 if (ch && ch->magic == EPCA_MAGIC) {
Joe Perchesa419aef2009-08-18 11:18:35 -07002240 struct tty_struct *tty = tty_port_tty_get(&ch->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Alan Coxf2cf8e22005-09-06 15:16:44 -07002242 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002243 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Alan Cox191260a2008-04-30 00:54:16 -07002244 tty_hangup(tty);
Alan Cox52d41732008-07-16 21:55:02 +01002245 wake_up_interruptible(&ch->port.open_wait);
Jiri Slabyc3301a52009-06-11 12:41:05 +01002246 clear_bit(ASYNCB_NORMAL_ACTIVE,
2247 &ch->port.flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 }
Alan Cox3969ffb2009-01-02 13:48:04 +00002250 tty_kref_put(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002251 }
2252}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002254/*
2255 * pc_stop and pc_start provide software flow control to the routine and the
2256 * pc_ioctl routine.
2257 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 struct channel *ch;
2261 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002262 /*
2263 * verifyChannel returns the channel from the tty struct if it is
2264 * valid. This serves as a sanity check.
2265 */
Alan Cox191260a2008-04-30 00:54:16 -07002266 ch = verifyChannel(tty);
2267 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002268 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002269 if ((ch->statusflags & TXSTOPPED) == 0) {
2270 /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 ch->statusflags |= TXSTOPPED;
2275 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002277 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002278 }
2279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002282{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002284 /*
2285 * verifyChannel returns the channel from the tty struct if it is
2286 * valid. This serves as a sanity check.
2287 */
Alan Cox191260a2008-04-30 00:54:16 -07002288 ch = verifyChannel(tty);
2289 if (ch != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002291 spin_lock_irqsave(&epca_lock, flags);
Alan Cox191260a2008-04-30 00:54:16 -07002292 /* Just in case output was resumed because of a change
2293 in Digi-flow */
2294 if (ch->statusflags & TXSTOPPED) {
2295 /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002296 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 globalwinon(ch);
2298 bc = ch->brdchan;
2299 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002300 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 ch->statusflags &= ~TXSTOPPED;
2304 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002306 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002307 }
2308}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002310/*
2311 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2312 * resume) the receipt of data into the kernels receive buffers. The exact
2313 * occurrence of this depends on the size of the kernels receive buffer and
2314 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2315 * more details.
2316 */
2317static void pc_throttle(struct tty_struct *tty)
2318{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 struct channel *ch;
2320 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002321 /*
2322 * verifyChannel returns the channel from the tty struct if it is
2323 * valid. This serves as a sanity check.
2324 */
Alan Cox191260a2008-04-30 00:54:16 -07002325 ch = verifyChannel(tty);
2326 if (ch != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002327 spin_lock_irqsave(&epca_lock, flags);
2328 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 globalwinon(ch);
2330 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 ch->statusflags |= RXSTOPPED;
2332 memoff(ch);
2333 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002334 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002335 }
2336}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
2338static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002339{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 struct channel *ch;
2341 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002342 /*
2343 * verifyChannel returns the channel from the tty struct if it is
2344 * valid. This serves as a sanity check.
2345 */
Alan Cox191260a2008-04-30 00:54:16 -07002346 ch = verifyChannel(tty);
2347 if (ch != NULL) {
2348 /* Just in case output was resumed because of a change
2349 in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002350 spin_lock_irqsave(&epca_lock, flags);
2351 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 ch->statusflags &= ~RXSTOPPED;
2355 memoff(ch);
2356 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002357 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002358 }
2359}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Alan Coxdcbf1282008-07-22 11:18:12 +01002361static int pc_send_break(struct tty_struct *tty, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002362{
Alan Coxc9f19e92009-01-02 13:47:26 +00002363 struct channel *ch = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 unsigned long flags;
2365
Alan Coxdcbf1282008-07-22 11:18:12 +01002366 if (msec == -1)
Alan Cox252883e2008-10-17 20:28:25 +01002367 msec = 0xFFFF;
2368 else if (msec > 0xFFFE)
2369 msec = 0xFFFE;
2370 else if (msec < 1)
2371 msec = 1;
Alan Coxdcbf1282008-07-22 11:18:12 +01002372
Alan Coxf2cf8e22005-09-06 15:16:44 -07002373 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002375 /*
2376 * Maybe I should send an infinite break here, schedule() for msec
2377 * amount of time, and then stop the break. This way, the user can't
2378 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2379 * an ioctl()) more than once in msec amount of time.
2380 * Try this for now...
2381 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2383 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002384 spin_unlock_irqrestore(&epca_lock, flags);
Alan Coxdcbf1282008-07-22 11:18:12 +01002385 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002386}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
Alan Coxf2cf8e22005-09-06 15:16:44 -07002388/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002390{
Al Virobc9a5152005-09-15 22:53:28 +01002391 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 globalwinon(ch);
2394 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002395 /*
2396 * When set the iempty flag request a event to be generated when the
2397 * transmit buffer is empty (If there is no BREAK in progress).
2398 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002399 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002401}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
David Howells88e88242008-07-22 11:20:45 +01002403#ifndef MODULE
2404static void __init epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002405{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 struct board_info board;
2407 int index, loop, last;
2408 char *temp, *t2;
2409 unsigned len;
2410
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002411 /*
2412 * If this routine looks a little strange it is because it is only
2413 * called if a LILO append command is given to boot the kernel with
2414 * parameters. In this way, we can provide the user a method of
2415 * changing his board configuration without rebuilding the kernel.
2416 */
2417 if (!liloconfig)
2418 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 memset(&board, 0, sizeof(board));
2421
2422 /* Assume the data is int first, later we can change it */
2423 /* I think that array position 0 of ints holds the number of args */
2424 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002425 switch (index) { /* Begin parse switch */
2426 case 1:
2427 board.status = ints[index];
2428 /*
2429 * We check for 2 (As opposed to 1; because 2 is a flag
2430 * instructing the driver to ignore epcaconfig.) For
2431 * this reason we check for 2.
2432 */
Alan Cox191260a2008-04-30 00:54:16 -07002433 if (board.status == 2) {
2434 /* Begin ignore epcaconfig as well as lilo cmd line */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002435 nbdevs = 0;
2436 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002438 } /* End ignore epcaconfig as well as lilo cmd line */
2439
2440 if (board.status > 2) {
Alan Cox191260a2008-04-30 00:54:16 -07002441 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
2442 board.status);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002443 invalid_lilo_config = 1;
2444 setup_error_code |= INVALID_BOARD_STATUS;
2445 return;
2446 }
2447 last = index;
2448 break;
2449 case 2:
2450 board.type = ints[index];
2451 if (board.type >= PCIXEM) {
2452 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2453 invalid_lilo_config = 1;
2454 setup_error_code |= INVALID_BOARD_TYPE;
2455 return;
2456 }
2457 last = index;
2458 break;
2459 case 3:
2460 board.altpin = ints[index];
2461 if (board.altpin > 1) {
2462 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2463 invalid_lilo_config = 1;
2464 setup_error_code |= INVALID_ALTPIN;
2465 return;
2466 }
2467 last = index;
2468 break;
2469
2470 case 4:
2471 board.numports = ints[index];
2472 if (board.numports < 2 || board.numports > 256) {
2473 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2474 invalid_lilo_config = 1;
2475 setup_error_code |= INVALID_NUM_PORTS;
2476 return;
2477 }
2478 nbdevs += board.numports;
2479 last = index;
2480 break;
2481
2482 case 5:
2483 board.port = ints[index];
2484 if (ints[index] <= 0) {
2485 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2486 invalid_lilo_config = 1;
2487 setup_error_code |= INVALID_PORT_BASE;
2488 return;
2489 }
2490 last = index;
2491 break;
2492
2493 case 6:
2494 board.membase = ints[index];
2495 if (ints[index] <= 0) {
Alan Cox191260a2008-04-30 00:54:16 -07002496 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",
2497 (unsigned int)board.membase);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002498 invalid_lilo_config = 1;
2499 setup_error_code |= INVALID_MEM_BASE;
2500 return;
2501 }
2502 last = index;
2503 break;
2504
2505 default:
2506 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2507 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 } /* End parse switch */
2510
Alan Coxf2cf8e22005-09-06 15:16:44 -07002511 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 /* find the next comma or terminator */
2513 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 /* While string is not null, and a comma hasn't been found */
2515 while (*temp && (*temp != ','))
2516 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (!*temp)
2518 temp = NULL;
2519 else
2520 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 /* Set index to the number of args + 1 */
2522 index = last + 1;
2523
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002524 switch (index) {
2525 case 1:
2526 len = strlen(str);
2527 if (strncmp("Disable", str, len) == 0)
2528 board.status = 0;
2529 else if (strncmp("Enable", str, len) == 0)
2530 board.status = 1;
2531 else {
2532 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2533 invalid_lilo_config = 1;
2534 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002536 }
2537 last = index;
2538 break;
2539
2540 case 2:
2541 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2542 if (strcmp(board_desc[loop], str) == 0)
2543 break;
2544 /*
2545 * If the index incremented above refers to a
2546 * legitamate board type set it here.
2547 */
2548 if (index < EPCA_NUM_TYPES)
2549 board.type = loop;
2550 else {
2551 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2552 invalid_lilo_config = 1;
2553 setup_error_code |= INVALID_BOARD_TYPE;
2554 return;
2555 }
2556 last = index;
2557 break;
2558
2559 case 3:
2560 len = strlen(str);
2561 if (strncmp("Disable", str, len) == 0)
2562 board.altpin = 0;
2563 else if (strncmp("Enable", str, len) == 0)
2564 board.altpin = 1;
2565 else {
2566 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2567 invalid_lilo_config = 1;
2568 setup_error_code |= INVALID_ALTPIN;
2569 return;
2570 }
2571 last = index;
2572 break;
2573
2574 case 4:
2575 t2 = str;
2576 while (isdigit(*t2))
2577 t2++;
2578
2579 if (*t2) {
2580 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2581 invalid_lilo_config = 1;
2582 setup_error_code |= INVALID_NUM_PORTS;
2583 return;
2584 }
2585
2586 /*
2587 * There is not a man page for simple_strtoul but the
2588 * code can be found in vsprintf.c. The first argument
2589 * is the string to translate (To an unsigned long
2590 * obviously), the second argument can be the address
2591 * of any character variable or a NULL. If a variable
2592 * is given, the end pointer of the string will be
2593 * stored in that variable; if a NULL is given the end
2594 * pointer will not be returned. The last argument is
2595 * the base to use. If a 0 is indicated, the routine
2596 * will attempt to determine the proper base by looking
2597 * at the values prefix (A '0' for octal, a 'x' for
2598 * hex, etc ... If a value is given it will use that
2599 * value as the base.
2600 */
2601 board.numports = simple_strtoul(str, NULL, 0);
2602 nbdevs += board.numports;
2603 last = index;
2604 break;
2605
2606 case 5:
2607 t2 = str;
2608 while (isxdigit(*t2))
2609 t2++;
2610
2611 if (*t2) {
2612 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2613 invalid_lilo_config = 1;
2614 setup_error_code |= INVALID_PORT_BASE;
2615 return;
2616 }
2617
2618 board.port = simple_strtoul(str, NULL, 16);
2619 last = index;
2620 break;
2621
2622 case 6:
2623 t2 = str;
2624 while (isxdigit(*t2))
2625 t2++;
2626
2627 if (*t2) {
Alan Cox191260a2008-04-30 00:54:16 -07002628 printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002629 invalid_lilo_config = 1;
2630 setup_error_code |= INVALID_MEM_BASE;
2631 return;
2632 }
2633 board.membase = simple_strtoul(str, NULL, 16);
2634 last = index;
2635 break;
2636 default:
2637 printk(KERN_ERR "epca: Too many string parms\n");
2638 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 }
2640 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 } /* End while there is a string arg */
2642
Alan Coxf2cf8e22005-09-06 15:16:44 -07002643 if (last < 6) {
2644 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 return;
2646 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 /* Copies our local copy of board into boards */
Alan Cox191260a2008-04-30 00:54:16 -07002650 memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002652 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2653 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002656}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
David Howells88e88242008-07-22 11:20:45 +01002658static int __init epca_real_setup(char *str)
2659{
2660 int ints[11];
2661
2662 epca_setup(get_options(str, 11, ints), ints);
2663 return 1;
2664}
2665
2666__setup("digiepca", epca_real_setup);
2667#endif
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669enum epic_board_types {
2670 brd_xr = 0,
2671 brd_xem,
2672 brd_cx,
2673 brd_xrj,
2674};
2675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676/* indexed directly by epic_board_types enum */
2677static struct {
2678 unsigned char board_type;
2679 unsigned bar_idx; /* PCI base address region */
2680} epca_info_tbl[] = {
2681 { PCIXR, 0, },
2682 { PCIXEM, 0, },
2683 { PCICX, 0, },
2684 { PCIXRJ, 2, },
2685};
2686
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002687static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 const struct pci_device_id *ent)
2689{
2690 static int board_num = -1;
2691 int board_idx, info_idx = ent->driver_data;
2692 unsigned long addr;
2693
2694 if (pci_enable_device(pdev))
2695 return -EIO;
2696
2697 board_num++;
2698 board_idx = board_num + num_cards;
2699 if (board_idx >= MAXBOARDS)
2700 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002701
Alan Cox191260a2008-04-30 00:54:16 -07002702 addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 if (!addr) {
Alan Cox191260a2008-04-30 00:54:16 -07002704 printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 epca_info_tbl[info_idx].bar_idx);
2706 goto err_out;
2707 }
2708
2709 boards[board_idx].status = ENABLED;
2710 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2711 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002712 boards[board_idx].port = addr + PCI_IO_OFFSET;
2713 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Alan Cox191260a2008-04-30 00:54:16 -07002715 if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2716 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 0x200000, addr + PCI_IO_OFFSET);
2718 goto err_out;
2719 }
2720
Alan Cox191260a2008-04-30 00:54:16 -07002721 boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
2722 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 if (!boards[board_idx].re_map_port) {
Alan Cox191260a2008-04-30 00:54:16 -07002724 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 0x200000, addr + PCI_IO_OFFSET);
2726 goto err_out_free_pciio;
2727 }
2728
Alan Cox191260a2008-04-30 00:54:16 -07002729 if (!request_mem_region(addr, 0x200000, "epca")) {
2730 printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 0x200000, addr);
2732 goto err_out_free_iounmap;
2733 }
2734
Alan Cox191260a2008-04-30 00:54:16 -07002735 boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (!boards[board_idx].re_map_membase) {
Alan Cox191260a2008-04-30 00:54:16 -07002737 printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 0x200000, addr + PCI_IO_OFFSET);
2739 goto err_out_free_memregion;
2740 }
2741
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002742 /*
2743 * I don't know what the below does, but the hardware guys say its
2744 * required on everything except PLX (In this case XRJ).
2745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002747 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 pci_write_config_byte(pdev, 0x46, 0);
2749 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002750
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return 0;
2752
2753err_out_free_memregion:
Alan Cox191260a2008-04-30 00:54:16 -07002754 release_mem_region(addr, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755err_out_free_iounmap:
Alan Cox191260a2008-04-30 00:54:16 -07002756 iounmap(boards[board_idx].re_map_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757err_out_free_pciio:
Alan Cox191260a2008-04-30 00:54:16 -07002758 release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759err_out:
2760 return -ENODEV;
2761}
2762
2763
2764static struct pci_device_id epca_pci_tbl[] = {
2765 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2766 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2767 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2768 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2769 { 0, }
2770};
2771
2772MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2773
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002774static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002775{
Alan Cox191260a2008-04-30 00:54:16 -07002776 memset(&epca_driver, 0, sizeof(epca_driver));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 epca_driver.name = "epca";
2778 epca_driver.id_table = epca_pci_tbl;
2779 epca_driver.probe = epca_init_one;
2780
2781 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002782}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784MODULE_LICENSE("GPL");