blob: 39c6a36e395bbee0586822d98f1072047c740e24 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 Copyright (C) 1996 Digi International.
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 For technical support please email digiLinux@dgii.com or
5 call Digi tech support at (612) 912-3456
6
Alan Coxf2cf8e22005-09-06 15:16:44 -07007 ** This driver is no longer supported by Digi **
8
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07009 Much of this design and code came from epca.c which was
10 copyright (C) 1994, 1995 Troy De Jongh, and subsquently
11 modified by David Nugent, Christoph Lameter, Mike McLagan.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070013 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070018 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070023 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070027/* See README.epca for change history --DAT*/
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/kernel.h>
31#include <linux/types.h>
32#include <linux/init.h>
33#include <linux/serial.h>
34#include <linux/delay.h>
35#include <linux/ctype.h>
36#include <linux/tty.h>
37#include <linux/tty_flip.h>
38#include <linux/slab.h>
39#include <linux/ioport.h>
40#include <linux/interrupt.h>
41#include <asm/uaccess.h>
42#include <asm/io.h>
Alan Coxf2cf8e22005-09-06 15:16:44 -070043#include <linux/spinlock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/pci.h>
45#include "digiPCI.h"
Alan Coxf2cf8e22005-09-06 15:16:44 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include "digi1.h"
49#include "digiFep1.h"
50#include "epca.h"
51#include "epcaconfig.h"
52
Alan Coxf2cf8e22005-09-06 15:16:44 -070053#define VERSION "1.3.0.1-LK2.6"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/* This major needs to be submitted to Linux to join the majors list */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070056#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58
59#define MAXCARDS 7
60#define epcaassert(x, msg) if (!(x)) epca_error(__LINE__, msg)
61
62#define PFX "epca: "
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static int nbdevs, num_cards, liloconfig;
65static int digi_poller_inhibited = 1 ;
66
67static int setup_error_code;
68static int invalid_lilo_config;
69
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070070/*
71 * The ISA boards do window flipping into the same spaces so its only sane with
72 * a single lock. It's still pretty efficient.
73 */
Ingo Molnar34af9462006-06-27 02:53:55 -070074static DEFINE_SPINLOCK(epca_lock);
Alan Coxf2cf8e22005-09-06 15:16:44 -070075
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070076/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static struct board_info boards[MAXBOARDS];
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static struct tty_driver *pc_driver;
80static struct tty_driver *pc_info;
81
82/* ------------------ Begin Digi specific structures -------------------- */
83
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070084/*
85 * digi_channels represents an array of structures that keep track of each
86 * channel of the Digi product. Information such as transmit and receive
87 * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
88 * here. This structure is NOT used to overlay the cards physical channel
89 * structure.
90 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070091static struct channel digi_channels[MAX_ALLOC];
92
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -070093/*
94 * card_ptr is an array used to hold the address of the first channel structure
95 * of each card. This array will hold the addresses of various channels located
96 * in digi_channels.
97 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070098static struct channel *card_ptr[MAXCARDS];
99
100static struct timer_list epca_timer;
101
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700102/*
103 * Begin generic memory functions. These functions will be alias (point at)
104 * more specific functions dependent on the board being configured.
105 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700106static void memwinon(struct board_info *b, unsigned int win);
107static void memwinoff(struct board_info *b, unsigned int win);
108static void globalwinon(struct channel *ch);
109static void rxwinon(struct channel *ch);
110static void txwinon(struct channel *ch);
111static void memoff(struct channel *ch);
112static void assertgwinon(struct channel *ch);
113static void assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115/* ---- Begin more 'specific' memory functions for cx_like products --- */
116
Alan Coxf2cf8e22005-09-06 15:16:44 -0700117static void pcxem_memwinon(struct board_info *b, unsigned int win);
118static void pcxem_memwinoff(struct board_info *b, unsigned int win);
119static void pcxem_globalwinon(struct channel *ch);
120static void pcxem_rxwinon(struct channel *ch);
121static void pcxem_txwinon(struct channel *ch);
122static void pcxem_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124/* ------ Begin more 'specific' memory functions for the pcxe ------- */
125
Alan Coxf2cf8e22005-09-06 15:16:44 -0700126static void pcxe_memwinon(struct board_info *b, unsigned int win);
127static void pcxe_memwinoff(struct board_info *b, unsigned int win);
128static void pcxe_globalwinon(struct channel *ch);
129static void pcxe_rxwinon(struct channel *ch);
130static void pcxe_txwinon(struct channel *ch);
131static void pcxe_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133/* ---- Begin more 'specific' memory functions for the pc64xe and pcxi ---- */
134/* Note : pc64xe and pcxi share the same windowing routines */
135
Alan Coxf2cf8e22005-09-06 15:16:44 -0700136static void pcxi_memwinon(struct board_info *b, unsigned int win);
137static void pcxi_memwinoff(struct board_info *b, unsigned int win);
138static void pcxi_globalwinon(struct channel *ch);
139static void pcxi_rxwinon(struct channel *ch);
140static void pcxi_txwinon(struct channel *ch);
141static void pcxi_memoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143/* - Begin 'specific' do nothing memory functions needed for some cards - */
144
Alan Coxf2cf8e22005-09-06 15:16:44 -0700145static void dummy_memwinon(struct board_info *b, unsigned int win);
146static void dummy_memwinoff(struct board_info *b, unsigned int win);
147static void dummy_globalwinon(struct channel *ch);
148static void dummy_rxwinon(struct channel *ch);
149static void dummy_txwinon(struct channel *ch);
150static void dummy_memoff(struct channel *ch);
151static void dummy_assertgwinon(struct channel *ch);
152static void dummy_assertmemoff(struct channel *ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Alan Coxf2cf8e22005-09-06 15:16:44 -0700154static struct channel *verifyChannel(struct tty_struct *);
155static void pc_sched_event(struct channel *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static void epca_error(int, char *);
157static void pc_close(struct tty_struct *, struct file *);
158static void shutdown(struct channel *);
159static void pc_hangup(struct tty_struct *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static int pc_write_room(struct tty_struct *);
161static int pc_chars_in_buffer(struct tty_struct *);
162static void pc_flush_buffer(struct tty_struct *);
163static void pc_flush_chars(struct tty_struct *);
164static int block_til_ready(struct tty_struct *, struct file *,
165 struct channel *);
166static int pc_open(struct tty_struct *, struct file *);
167static void post_fep_init(unsigned int crd);
168static void epcapoll(unsigned long);
169static void doevent(int);
170static void fepcmd(struct channel *, int, int, int, int, int);
171static unsigned termios2digi_h(struct channel *ch, unsigned);
172static unsigned termios2digi_i(struct channel *ch, unsigned);
173static unsigned termios2digi_c(struct channel *ch, unsigned);
174static void epcaparam(struct tty_struct *, struct channel *);
175static void receive_data(struct channel *);
176static int pc_ioctl(struct tty_struct *, struct file *,
177 unsigned int, unsigned long);
178static int info_ioctl(struct tty_struct *, struct file *,
179 unsigned int, unsigned long);
Alan Cox606d0992006-12-08 02:38:45 -0800180static void pc_set_termios(struct tty_struct *, struct ktermios *);
David Howellsc4028952006-11-22 14:57:56 +0000181static void do_softint(struct work_struct *work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static void pc_stop(struct tty_struct *);
183static void pc_start(struct tty_struct *);
184static void pc_throttle(struct tty_struct * tty);
185static void pc_unthrottle(struct tty_struct *tty);
186static void digi_send_break(struct channel *ch, int msec);
187static void setup_empty_event(struct tty_struct *tty, struct channel *ch);
188void epca_setup(char *, int *);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int pc_write(struct tty_struct *, const unsigned char *, int);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700191static int pc_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static int init_PCI(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700194/*
195 * Table of functions for each board to handle memory. Mantaining parallelism
196 * is a *very* good idea here. The idea is for the runtime code to blindly call
197 * these functions, not knowing/caring about the underlying hardware. This
198 * stuff should contain no conditionals; if more functionality is needed a
199 * different entry should be established. These calls are the interface calls
200 * and are the only functions that should be accessed. Anyone caught making
201 * direct calls deserves what they get.
202 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700203static void memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700205 b->memwinon(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
Alan Coxf2cf8e22005-09-06 15:16:44 -0700208static void memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700210 b->memwinoff(b, win);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211}
212
Alan Coxf2cf8e22005-09-06 15:16:44 -0700213static void globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700215 ch->board->globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Alan Coxf2cf8e22005-09-06 15:16:44 -0700218static void rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700220 ch->board->rxwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
Alan Coxf2cf8e22005-09-06 15:16:44 -0700223static void txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700225 ch->board->txwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Alan Coxf2cf8e22005-09-06 15:16:44 -0700228static void memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700230 ch->board->memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
Alan Coxf2cf8e22005-09-06 15:16:44 -0700232static void assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700234 ch->board->assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
236
Alan Coxf2cf8e22005-09-06 15:16:44 -0700237static void assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700239 ch->board->assertmemoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
241
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700242/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700243static void pcxem_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700245 outb_p(FEPWIN|win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246}
247
Alan Coxf2cf8e22005-09-06 15:16:44 -0700248static void pcxem_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700250 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
252
Alan Coxf2cf8e22005-09-06 15:16:44 -0700253static void pcxem_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
255 outb_p( FEPWIN, (int)ch->board->port + 1);
256}
257
Alan Coxf2cf8e22005-09-06 15:16:44 -0700258static void pcxem_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 outb_p(ch->rxwin, (int)ch->board->port + 1);
261}
262
Alan Coxf2cf8e22005-09-06 15:16:44 -0700263static void pcxem_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 outb_p(ch->txwin, (int)ch->board->port + 1);
266}
267
Alan Coxf2cf8e22005-09-06 15:16:44 -0700268static void pcxem_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 outb_p(0, (int)ch->board->port + 1);
271}
272
273/* ----------------- Begin pcxe memory window stuff ------------------ */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700274static void pcxe_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700276 outb_p(FEPWIN | win, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
Alan Coxf2cf8e22005-09-06 15:16:44 -0700279static void pcxe_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700281 outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700282 outb_p(0, b->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283}
284
Alan Coxf2cf8e22005-09-06 15:16:44 -0700285static void pcxe_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700287 outb_p(FEPWIN, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288}
289
Alan Coxf2cf8e22005-09-06 15:16:44 -0700290static void pcxe_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700292 outb_p(ch->rxwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
Alan Coxf2cf8e22005-09-06 15:16:44 -0700295static void pcxe_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700297 outb_p(ch->txwin, (int)ch->board->port + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
Alan Coxf2cf8e22005-09-06 15:16:44 -0700300static void pcxe_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 outb_p(0, (int)ch->board->port);
303 outb_p(0, (int)ch->board->port + 1);
304}
305
306/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700307static void pcxi_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700309 outb_p(inb(b->port) | FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
Alan Coxf2cf8e22005-09-06 15:16:44 -0700312static void pcxi_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700314 outb_p(inb(b->port) & ~FEPMEM, b->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316
Alan Coxf2cf8e22005-09-06 15:16:44 -0700317static void pcxi_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700319 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Alan Coxf2cf8e22005-09-06 15:16:44 -0700322static void pcxi_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700324 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325}
326
Alan Coxf2cf8e22005-09-06 15:16:44 -0700327static void pcxi_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700329 outb_p(FEPMEM, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Alan Coxf2cf8e22005-09-06 15:16:44 -0700332static void pcxi_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700334 outb_p(0, ch->board->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
Alan Coxf2cf8e22005-09-06 15:16:44 -0700337static void pcxi_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700339 epcaassert(inb(ch->board->port) & FEPMEM, "Global memory off");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340}
341
Alan Coxf2cf8e22005-09-06 15:16:44 -0700342static void pcxi_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700344 epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345}
346
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700347/*
348 * Not all of the cards need specific memory windowing routines. Some cards
349 * (Such as PCI) needs no windowing routines at all. We provide these do
350 * nothing routines so that the same code base can be used. The driver will
351 * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
352 * card. However, dependent on the card the routine may or may not do anything.
353 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700354static void dummy_memwinon(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
356}
357
Alan Coxf2cf8e22005-09-06 15:16:44 -0700358static void dummy_memwinoff(struct board_info *b, unsigned int win)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
360}
361
Alan Coxf2cf8e22005-09-06 15:16:44 -0700362static void dummy_globalwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
364}
365
Alan Coxf2cf8e22005-09-06 15:16:44 -0700366static void dummy_rxwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368}
369
Alan Coxf2cf8e22005-09-06 15:16:44 -0700370static void dummy_txwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372}
373
Alan Coxf2cf8e22005-09-06 15:16:44 -0700374static void dummy_memoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376}
377
Alan Coxf2cf8e22005-09-06 15:16:44 -0700378static void dummy_assertgwinon(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380}
381
Alan Coxf2cf8e22005-09-06 15:16:44 -0700382static void dummy_assertmemoff(struct channel *ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384}
385
Alan Coxf2cf8e22005-09-06 15:16:44 -0700386static struct channel *verifyChannel(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700387{
388 /*
389 * This routine basically provides a sanity check. It insures that the
390 * channel returned is within the proper range of addresses as well as
391 * properly initialized. If some bogus info gets passed in
392 * through tty->driver_data this should catch it.
393 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700394 if (tty) {
395 struct channel *ch = (struct channel *)tty->driver_data;
396 if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 if (ch->magic == EPCA_MAGIC)
398 return ch;
399 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return NULL;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700402}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
Alan Coxf2cf8e22005-09-06 15:16:44 -0700404static void pc_sched_event(struct channel *ch, int event)
405{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700406 /*
407 * We call this to schedule interrupt processing on some event. The
408 * kernel sees our request and calls the related routine in OUR driver.
409 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 ch->event |= 1 << event;
411 schedule_work(&ch->tqueue);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700412}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414static void epca_error(int line, char *msg)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700415{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700417}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700419static void pc_close(struct tty_struct *tty, struct file *filp)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700420{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 struct channel *ch;
422 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700423 /*
424 * verifyChannel returns the channel from the tty struct if it is
425 * valid. This serves as a sanity check.
426 */
427 if ((ch = verifyChannel(tty)) != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -0700428 spin_lock_irqsave(&epca_lock, flags);
429 if (tty_hung_up_p(filp)) {
430 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 return;
432 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700433 if (ch->count-- > 1) {
434 /* Begin channel is open more than once */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700435 /*
436 * Return without doing anything. Someone might still
437 * be using the channel.
438 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700439 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 /* Port open only once go ahead with shutdown & reset */
Eric Sesterhenn56ee4822006-03-26 18:17:21 +0200444 BUG_ON(ch->count < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700446 /*
447 * Let the rest of the driver know the channel is being closed.
448 * This becomes important if an open is attempted before close
449 * is finished.
450 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 ch->asyncflags |= ASYNC_CLOSING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 tty->closing = 1;
453
Alan Coxf2cf8e22005-09-06 15:16:44 -0700454 spin_unlock_irqrestore(&epca_lock, flags);
455
456 if (ch->asyncflags & ASYNC_INITIALIZED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 /* Setup an event to indicate when the transmit buffer empties */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700458 setup_empty_event(tty, ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
460 }
Alan Cox978e5952008-04-30 00:53:59 -0700461 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 tty_ldisc_flush(tty);
464 shutdown(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700465
466 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 tty->closing = 0;
468 ch->event = 0;
469 ch->tty = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700470 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700472 if (ch->blocked_open) {
473 if (ch->close_delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 msleep_interruptible(jiffies_to_msecs(ch->close_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 wake_up_interruptible(&ch->open_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700476 }
477 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 ASYNC_CLOSING);
479 wake_up_interruptible(&ch->close_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700480 }
481}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483static void shutdown(struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700484{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 unsigned long flags;
486 struct tty_struct *tty;
Al Virobc9a5152005-09-15 22:53:28 +0100487 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700489 if (!(ch->asyncflags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return;
491
Alan Coxf2cf8e22005-09-06 15:16:44 -0700492 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
Alan Coxf2cf8e22005-09-06 15:16:44 -0700494 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 bc = ch->brdchan;
496
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700497 /*
498 * In order for an event to be generated on the receipt of data the
499 * idata flag must be set. Since we are shutting down, this is not
500 * necessary clear this flag.
501 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if (bc)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700503 writeb(0, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 tty = ch->tty;
505
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700506 /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700507 if (tty->termios->c_cflag & HUPCL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 ch->omodem &= ~(ch->m_rts | ch->m_dtr);
509 fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 memoff(ch);
512
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700513 /*
514 * The channel has officialy been closed. The next time it is opened it
515 * will have to reinitialized. Set a flag to indicate this.
516 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 /* Prevent future Digi programmed interrupts from coming active */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 ch->asyncflags &= ~ASYNC_INITIALIZED;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700519 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700520}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522static void pc_hangup(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700523{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700526 /*
527 * verifyChannel returns the channel from the tty struct if it is
528 * valid. This serves as a sanity check.
529 */
530 if ((ch = verifyChannel(tty)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 unsigned long flags;
532
Alan Cox978e5952008-04-30 00:53:59 -0700533 pc_flush_buffer(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 tty_ldisc_flush(tty);
535 shutdown(ch);
536
Alan Coxf2cf8e22005-09-06 15:16:44 -0700537 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 ch->tty = NULL;
539 ch->event = 0;
540 ch->count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700542 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 wake_up_interruptible(&ch->open_wait);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700544 }
545}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700547static int pc_write(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 const unsigned char *buf, int bytesAvailable)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700549{
Alan Coxf2cf8e22005-09-06 15:16:44 -0700550 unsigned int head, tail;
551 int dataLen;
552 int size;
553 int amountCopied;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 struct channel *ch;
555 unsigned long flags;
556 int remain;
Al Virobc9a5152005-09-15 22:53:28 +0100557 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700559 /*
560 * pc_write is primarily called directly by the kernel routine
561 * tty_write (Though it can also be called by put_char) found in
562 * tty_io.c. pc_write is passed a line discipline buffer where the data
563 * to be written out is stored. The line discipline implementation
564 * itself is done at the kernel level and is not brought into the
565 * driver.
566 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700568 /*
569 * verifyChannel returns the channel from the tty struct if it is
570 * valid. This serves as a sanity check.
571 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if ((ch = verifyChannel(tty)) == NULL)
573 return 0;
574
575 /* Make a pointer to the channel data structure found on the board. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 bc = ch->brdchan;
577 size = ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 amountCopied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Alan Coxf2cf8e22005-09-06 15:16:44 -0700580 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 globalwinon(ch);
582
Alan Coxf2cf8e22005-09-06 15:16:44 -0700583 head = readw(&bc->tin) & (size - 1);
584 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Alan Coxf2cf8e22005-09-06 15:16:44 -0700586 if (tail != readw(&bc->tout))
587 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 tail &= (size - 1);
589
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700590 if (head >= tail) {
591 /* head has not wrapped */
592 /*
593 * remain (much like dataLen above) represents the total amount
594 * of space available on the card for data. Here dataLen
595 * represents the space existing between the head pointer and
596 * the end of buffer. This is important because a memcpy cannot
597 * be told to automatically wrap around when it hits the buffer
598 * end.
599 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 dataLen = size - head;
601 remain = size - (head - tail) - 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700602 } else {
603 /* head has wrapped around */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 remain = tail - head - 1;
605 dataLen = remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700606 }
607 /*
608 * Check the space on the card. If we have more data than space; reduce
609 * the amount of data to fit the space.
610 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 bytesAvailable = min(remain, bytesAvailable);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 txwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700613 while (bytesAvailable > 0) {
614 /* there is data to copy onto card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700616 /*
617 * If head is not wrapped, the below will make sure the first
618 * data copy fills to the end of card buffer.
619 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 dataLen = min(bytesAvailable, dataLen);
Al Virobc9a5152005-09-15 22:53:28 +0100621 memcpy_toio(ch->txptr + head, buf, dataLen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 buf += dataLen;
623 head += dataLen;
624 amountCopied += dataLen;
625 bytesAvailable -= dataLen;
626
Alan Coxf2cf8e22005-09-06 15:16:44 -0700627 if (head >= size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 head = 0;
629 dataLen = tail;
630 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 ch->statusflags |= TXBUSY;
633 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700634 writew(head, &bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Alan Coxf2cf8e22005-09-06 15:16:44 -0700636 if ((ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700638 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
640 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700641 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700642 return amountCopied;
643}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645static int pc_write_room(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700646{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 int remain;
648 struct channel *ch;
649 unsigned long flags;
650 unsigned int head, tail;
Al Virobc9a5152005-09-15 22:53:28 +0100651 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 remain = 0;
654
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700655 /*
656 * verifyChannel returns the channel from the tty struct if it is
657 * valid. This serves as a sanity check.
658 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700659 if ((ch = verifyChannel(tty)) != NULL) {
660 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 globalwinon(ch);
662
663 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700664 head = readw(&bc->tin) & (ch->txbufsize - 1);
665 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Alan Coxf2cf8e22005-09-06 15:16:44 -0700667 if (tail != readw(&bc->tout))
668 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 /* Wrap tail if necessary */
670 tail &= (ch->txbufsize - 1);
671
672 if ((remain = tail - head - 1) < 0 )
673 remain += ch->txbufsize;
674
Alan Coxf2cf8e22005-09-06 15:16:44 -0700675 if (remain && (ch->statusflags & LOWWAIT) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 ch->statusflags |= LOWWAIT;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700677 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 }
679 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700680 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 /* Return how much room is left on card */
683 return remain;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700684}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686static int pc_chars_in_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700687{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 int chars;
689 unsigned int ctail, head, tail;
690 int remain;
691 unsigned long flags;
692 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100693 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700695 /*
696 * verifyChannel returns the channel from the tty struct if it is
697 * valid. This serves as a sanity check.
698 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if ((ch = verifyChannel(tty)) == NULL)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700700 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Alan Coxf2cf8e22005-09-06 15:16:44 -0700702 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 globalwinon(ch);
704
705 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700706 tail = readw(&bc->tout);
707 head = readw(&bc->tin);
708 ctail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Alan Coxf2cf8e22005-09-06 15:16:44 -0700710 if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 chars = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700712 else { /* Begin if some space on the card has been used */
713 head = readw(&bc->tin) & (ch->txbufsize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 tail &= (ch->txbufsize - 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700715 /*
716 * The logic here is basically opposite of the above
717 * pc_write_room here we are finding the amount of bytes in the
718 * buffer filled. Not the amount of bytes empty.
719 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if ((remain = tail - head - 1) < 0 )
721 remain += ch->txbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 chars = (int)(ch->txbufsize - remain);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700723 /*
724 * Make it possible to wakeup anything waiting for output in
725 * tty_ioctl.c, etc.
726 *
727 * If not already set. Setup an event to indicate when the
728 * transmit buffer empties.
729 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 if (!(ch->statusflags & EMPTYWAIT))
731 setup_empty_event(tty,ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 } /* End if some space on the card has been used */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700734 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 /* Return number of characters residing on card. */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700736 return chars;
737}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739static void pc_flush_buffer(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700740{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 unsigned int tail;
742 unsigned long flags;
743 struct channel *ch;
Al Virobc9a5152005-09-15 22:53:28 +0100744 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700745 /*
746 * verifyChannel returns the channel from the tty struct if it is
747 * valid. This serves as a sanity check.
748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if ((ch = verifyChannel(tty)) == NULL)
750 return;
751
Alan Coxf2cf8e22005-09-06 15:16:44 -0700752 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700755 tail = readw(&bc->tout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 /* Have FEP move tout pointer; effectively flushing transmit buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700759 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700761}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
763static void pc_flush_chars(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700764{
765 struct channel *ch;
766 /*
767 * verifyChannel returns the channel from the tty struct if it is
768 * valid. This serves as a sanity check.
769 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700770 if ((ch = verifyChannel(tty)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700772 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700773 /*
774 * If not already set and the transmitter is busy setup an
775 * event to indicate when the transmit empties.
776 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
778 setup_empty_event(tty,ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700779 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700781}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700783static int block_til_ready(struct tty_struct *tty,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 struct file *filp, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700785{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 DECLARE_WAITQUEUE(wait,current);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700787 int retval, do_clocal = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 unsigned long flags;
789
Alan Coxf2cf8e22005-09-06 15:16:44 -0700790 if (tty_hung_up_p(filp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 if (ch->asyncflags & ASYNC_HUP_NOTIFY)
792 retval = -EAGAIN;
793 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700794 retval = -ERESTARTSYS;
795 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700798 /*
799 * If the device is in the middle of being closed, then block until
800 * it's done, and then try again.
801 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700802 if (ch->asyncflags & ASYNC_CLOSING) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 interruptible_sleep_on(&ch->close_wait);
804
805 if (ch->asyncflags & ASYNC_HUP_NOTIFY)
806 return -EAGAIN;
807 else
808 return -ERESTARTSYS;
809 }
810
Alan Coxf2cf8e22005-09-06 15:16:44 -0700811 if (filp->f_flags & O_NONBLOCK) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700812 /*
813 * If non-blocking mode is set, then make the check up front
814 * and then exit.
815 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 return 0;
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 if (tty->termios->c_cflag & CLOCAL)
820 do_clocal = 1;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700821 /* Block waiting for the carrier detect and the line to become free */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 retval = 0;
824 add_wait_queue(&ch->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Alan Coxf2cf8e22005-09-06 15:16:44 -0700826 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 /* We dec count so that pc_close will know when to free things */
828 if (!tty_hung_up_p(filp))
829 ch->count--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 ch->blocked_open++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700831 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if (tty_hung_up_p(filp) ||
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700834 !(ch->asyncflags & ASYNC_INITIALIZED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 {
836 if (ch->asyncflags & ASYNC_HUP_NOTIFY)
837 retval = -EAGAIN;
838 else
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700839 retval = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 break;
841 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700842 if (!(ch->asyncflags & ASYNC_CLOSING) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 (do_clocal || (ch->imodem & ch->dcd)))
844 break;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700845 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 retval = -ERESTARTSYS;
847 break;
848 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700849 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700850 /*
851 * Allow someone else to be scheduled. We will occasionally go
852 * through this loop until one of the above conditions change.
853 * The below schedule call will allow other processes to enter
854 * and prevent this loop from hogging the cpu.
855 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 schedule();
Alan Coxf2cf8e22005-09-06 15:16:44 -0700857 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Milind Arun Choudharycc0a8fb2007-05-08 00:30:52 -0700860 __set_current_state(TASK_RUNNING);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 remove_wait_queue(&ch->open_wait, &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (!tty_hung_up_p(filp))
863 ch->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 ch->blocked_open--;
865
Alan Coxf2cf8e22005-09-06 15:16:44 -0700866 spin_unlock_irqrestore(&epca_lock, flags);
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (retval)
869 return retval;
870
871 ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700873}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875static int pc_open(struct tty_struct *tty, struct file * filp)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700876{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 struct channel *ch;
878 unsigned long flags;
879 int line, retval, boardnum;
Al Virobc9a5152005-09-15 22:53:28 +0100880 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700881 unsigned int head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 line = tty->index;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700884 if (line < 0 || line >= nbdevs)
885 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 ch = &digi_channels[line];
888 boardnum = ch->boardnum;
889
890 /* Check status of board configured in system. */
891
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700892 /*
893 * I check to see if the epca_setup routine detected an user error. It
894 * might be better to put this in pc_init, but for the moment it goes
895 * here.
896 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700897 if (invalid_lilo_config) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 if (setup_error_code & INVALID_BOARD_TYPE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700899 printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (setup_error_code & INVALID_NUM_PORTS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700901 printk(KERN_ERR "epca: pc_open: Invalid number of ports specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 if (setup_error_code & INVALID_MEM_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700903 printk(KERN_ERR "epca: pc_open: Invalid board memory address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (setup_error_code & INVALID_PORT_BASE)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700905 printk(KERN_ERR "epca; pc_open: Invalid board port address specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if (setup_error_code & INVALID_BOARD_STATUS)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700907 printk(KERN_ERR "epca: pc_open: Invalid board status specified in kernel options.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 if (setup_error_code & INVALID_ALTPIN)
Alan Coxf2cf8e22005-09-06 15:16:44 -0700909 printk(KERN_ERR "epca: pc_open: Invalid board altpin specified in kernel options;\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 tty->driver_data = NULL; /* Mark this device as 'down' */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700911 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 }
Alan Coxf2cf8e22005-09-06 15:16:44 -0700913 if (boardnum >= num_cards || boards[boardnum].status == DISABLED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 tty->driver_data = NULL; /* Mark this device as 'down' */
915 return(-ENODEV);
916 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700917
Harvey Harrison11fb09b2008-04-30 00:53:52 -0700918 bc = ch->brdchan;
919 if (bc == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 tty->driver_data = NULL;
Alan Coxf2cf8e22005-09-06 15:16:44 -0700921 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 }
923
Alan Coxf2cf8e22005-09-06 15:16:44 -0700924 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700925 /*
926 * Every time a channel is opened, increment a counter. This is
927 * necessary because we do not wish to flush and shutdown the channel
928 * until the last app holding the channel open, closes it.
929 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 ch->count++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700931 /*
932 * Set a kernel structures pointer to our local channel structure. This
933 * way we can get to it when passed only a tty struct.
934 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 tty->driver_data = ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700936 /*
937 * If this is the first time the channel has been opened, initialize
938 * the tty->termios struct otherwise let pc_close handle it.
939 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 globalwinon(ch);
941 ch->statusflags = 0;
942
943 /* Save boards current modem status */
Al Virobc9a5152005-09-15 22:53:28 +0100944 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700946 /*
947 * Set receive head and tail ptrs to each other. This indicates no data
948 * available to read.
949 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700950 head = readw(&bc->rin);
951 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 /* Set the channels associated tty structure */
954 ch->tty = tty;
955
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700956 /*
957 * The below routine generally sets up parity, baud, flow control
958 * issues, etc.... It effect both control flags and input flags.
959 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 epcaparam(tty,ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 ch->asyncflags |= ASYNC_INITIALIZED;
962 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700963 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 retval = block_til_ready(tty, filp, ch);
966 if (retval)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return retval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700968 /*
969 * Set this again in case a hangup set it to zero while this open() was
970 * waiting for the line...
971 */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700972 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 ch->tty = tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 /* Enable Digi Data events */
Alan Coxf2cf8e22005-09-06 15:16:44 -0700976 writeb(1, &bc->idata);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -0700978 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980}
981
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700982static int __init epca_module_init(void)
983{
984 return pc_init();
985}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986module_init(epca_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988static struct pci_driver epca_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
990static void __exit epca_module_exit(void)
991{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 int count, crd;
993 struct board_info *bd;
994 struct channel *ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 del_timer_sync(&epca_timer);
997
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -0700998 if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001000 printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return;
1002 }
1003 put_tty_driver(pc_driver);
1004 put_tty_driver(pc_info);
1005
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001006 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 bd = &boards[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001008 if (!bd) { /* sanity check */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
1010 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001011 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001012 ch = card_ptr[crd];
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001013 for (count = 0; count < bd->numports; count++, ch++) {
Jiri Slabyb3218a72006-10-04 02:15:27 -07001014 if (ch && ch->tty)
1015 tty_hangup(ch->tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001016 }
1017 }
1018 pci_unregister_driver(&epca_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019}
1020module_exit(epca_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Jeff Dikeb68e31d2006-10-02 02:17:18 -07001022static const struct tty_operations pc_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 .open = pc_open,
1024 .close = pc_close,
1025 .write = pc_write,
1026 .write_room = pc_write_room,
1027 .flush_buffer = pc_flush_buffer,
1028 .chars_in_buffer = pc_chars_in_buffer,
1029 .flush_chars = pc_flush_chars,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 .ioctl = pc_ioctl,
1031 .set_termios = pc_set_termios,
1032 .stop = pc_stop,
1033 .start = pc_start,
1034 .throttle = pc_throttle,
1035 .unthrottle = pc_unthrottle,
1036 .hangup = pc_hangup,
1037};
1038
1039static int info_open(struct tty_struct *tty, struct file * filp)
1040{
1041 return 0;
1042}
1043
1044static struct tty_operations info_ops = {
1045 .open = info_open,
1046 .ioctl = info_ioctl,
1047};
1048
Alan Coxf2cf8e22005-09-06 15:16:44 -07001049static int __init pc_init(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001050{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 int crd;
1052 struct board_info *bd;
1053 unsigned char board_id = 0;
Akinobu Mitadabad052006-10-17 00:10:28 -07001054 int err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 int pci_boards_found, pci_count;
1057
1058 pci_count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 pc_driver = alloc_tty_driver(MAX_ALLOC);
1061 if (!pc_driver)
Akinobu Mitadabad052006-10-17 00:10:28 -07001062 goto out1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064 pc_info = alloc_tty_driver(MAX_ALLOC);
Akinobu Mitadabad052006-10-17 00:10:28 -07001065 if (!pc_info)
1066 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001068 /*
1069 * If epca_setup has not been ran by LILO set num_cards to defaults;
1070 * copy board structure defined by digiConfig into drivers board
1071 * structure. Note : If LILO has ran epca_setup then epca_setup will
1072 * handle defining num_cards as well as copying the data into the board
1073 * structure.
1074 */
1075 if (!liloconfig) {
1076 /* driver has been configured via. epcaconfig */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 nbdevs = NBDEVS;
1078 num_cards = NUMCARDS;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001079 memcpy(&boards, &static_boards,
1080 sizeof(struct board_info) * NUMCARDS);
1081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001083 /*
1084 * Note : If lilo was used to configure the driver and the ignore
1085 * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
1086 * will equal 0 at this point. This is okay; PCI cards will still be
1087 * picked up if detected.
1088 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001090 /*
1091 * Set up interrupt, we will worry about memory allocation in
1092 * post_fep_init.
1093 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
1095
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001096 /*
1097 * NOTE : This code assumes that the number of ports found in the
1098 * boards array is correct. This could be wrong if the card in question
1099 * is PCI (And therefore has no ports entry in the boards structure.)
1100 * The rest of the information will be valid for PCI because the
1101 * beginning of pc_init scans for PCI and determines i/o and base
1102 * memory addresses. I am not sure if it is possible to read the number
1103 * of ports supported by the card prior to it being booted (Since that
1104 * is the state it is in when pc_init is run). Because it is not
1105 * possible to query the number of supported ports until after the card
1106 * has booted; we are required to calculate the card_ptrs as the card
1107 * is initialized (Inside post_fep_init). The negative thing about this
1108 * approach is that digiDload's call to GET_INFO will have a bad port
1109 * value. (Since this is called prior to post_fep_init.)
1110 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 pci_boards_found = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001112 if (num_cards < MAXBOARDS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 pci_boards_found += init_PCI();
1114 num_cards += pci_boards_found;
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 pc_driver->owner = THIS_MODULE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001117 pc_driver->name = "ttyD";
1118 pc_driver->major = DIGI_MAJOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 pc_driver->minor_start = 0;
1120 pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
1121 pc_driver->subtype = SERIAL_TYPE_NORMAL;
1122 pc_driver->init_termios = tty_std_termios;
1123 pc_driver->init_termios.c_iflag = 0;
1124 pc_driver->init_termios.c_oflag = 0;
1125 pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
1126 pc_driver->init_termios.c_lflag = 0;
Alan Cox606d0992006-12-08 02:38:45 -08001127 pc_driver->init_termios.c_ispeed = 9600;
1128 pc_driver->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 pc_driver->flags = TTY_DRIVER_REAL_RAW;
1130 tty_set_operations(pc_driver, &pc_ops);
1131
1132 pc_info->owner = THIS_MODULE;
1133 pc_info->name = "digi_ctl";
1134 pc_info->major = DIGIINFOMAJOR;
1135 pc_info->minor_start = 0;
1136 pc_info->type = TTY_DRIVER_TYPE_SERIAL;
1137 pc_info->subtype = SERIAL_TYPE_INFO;
1138 pc_info->init_termios = tty_std_termios;
1139 pc_info->init_termios.c_iflag = 0;
1140 pc_info->init_termios.c_oflag = 0;
1141 pc_info->init_termios.c_lflag = 0;
1142 pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
Alan Cox606d0992006-12-08 02:38:45 -08001143 pc_info->init_termios.c_ispeed = 9600;
1144 pc_info->init_termios.c_ospeed = 9600;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 pc_info->flags = TTY_DRIVER_REAL_RAW;
1146 tty_set_operations(pc_info, &info_ops);
1147
1148
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001149 for (crd = 0; crd < num_cards; crd++) {
1150 /*
1151 * This is where the appropriate memory handlers for the
1152 * hardware is set. Everything at runtime blindly jumps through
1153 * these vectors.
1154 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
1156 /* defined in epcaconfig.h */
1157 bd = &boards[crd];
1158
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001159 switch (bd->type) {
1160 case PCXEM:
1161 case EISAXEM:
1162 bd->memwinon = pcxem_memwinon;
1163 bd->memwinoff = pcxem_memwinoff;
1164 bd->globalwinon = pcxem_globalwinon;
1165 bd->txwinon = pcxem_txwinon;
1166 bd->rxwinon = pcxem_rxwinon;
1167 bd->memoff = pcxem_memoff;
1168 bd->assertgwinon = dummy_assertgwinon;
1169 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001172 case PCIXEM:
1173 case PCIXRJ:
1174 case PCIXR:
1175 bd->memwinon = dummy_memwinon;
1176 bd->memwinoff = dummy_memwinoff;
1177 bd->globalwinon = dummy_globalwinon;
1178 bd->txwinon = dummy_txwinon;
1179 bd->rxwinon = dummy_rxwinon;
1180 bd->memoff = dummy_memoff;
1181 bd->assertgwinon = dummy_assertgwinon;
1182 bd->assertmemoff = dummy_assertmemoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 break;
1184
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001185 case PCXE:
1186 case PCXEVE:
1187 bd->memwinon = pcxe_memwinon;
1188 bd->memwinoff = pcxe_memwinoff;
1189 bd->globalwinon = pcxe_globalwinon;
1190 bd->txwinon = pcxe_txwinon;
1191 bd->rxwinon = pcxe_rxwinon;
1192 bd->memoff = pcxe_memoff;
1193 bd->assertgwinon = dummy_assertgwinon;
1194 bd->assertmemoff = dummy_assertmemoff;
1195 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001197 case PCXI:
1198 case PC64XE:
1199 bd->memwinon = pcxi_memwinon;
1200 bd->memwinoff = pcxi_memwinoff;
1201 bd->globalwinon = pcxi_globalwinon;
1202 bd->txwinon = pcxi_txwinon;
1203 bd->rxwinon = pcxi_rxwinon;
1204 bd->memoff = pcxi_memoff;
1205 bd->assertgwinon = pcxi_assertgwinon;
1206 bd->assertmemoff = pcxi_assertmemoff;
1207 break;
1208
1209 default:
1210 break;
1211 }
1212
1213 /*
1214 * Some cards need a memory segment to be defined for use in
1215 * transmit and receive windowing operations. These boards are
1216 * listed in the below switch. In the case of the XI the amount
1217 * of memory on the board is variable so the memory_seg is also
1218 * variable. This code determines what they segment should be.
1219 */
1220 switch (bd->type) {
1221 case PCXE:
1222 case PCXEVE:
1223 case PC64XE:
1224 bd->memory_seg = 0xf000;
1225 break;
1226
1227 case PCXI:
1228 board_id = inb((int)bd->port);
1229 if ((board_id & 0x1) == 0x1) {
1230 /* it's an XI card */
1231 /* Is it a 64K board */
1232 if ((board_id & 0x30) == 0)
1233 bd->memory_seg = 0xf000;
1234
1235 /* Is it a 128K board */
1236 if ((board_id & 0x30) == 0x10)
1237 bd->memory_seg = 0xe000;
1238
1239 /* Is is a 256K board */
1240 if ((board_id & 0x30) == 0x20)
1241 bd->memory_seg = 0xc000;
1242
1243 /* Is it a 512K board */
1244 if ((board_id & 0x30) == 0x30)
1245 bd->memory_seg = 0x8000;
1246 } else
1247 printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
1248 break;
1249 }
1250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Akinobu Mitadabad052006-10-17 00:10:28 -07001252 err = tty_register_driver(pc_driver);
1253 if (err) {
1254 printk(KERN_ERR "Couldn't register Digi PC/ driver");
1255 goto out3;
1256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Akinobu Mitadabad052006-10-17 00:10:28 -07001258 err = tty_register_driver(pc_info);
1259 if (err) {
1260 printk(KERN_ERR "Couldn't register Digi PC/ info ");
1261 goto out4;
1262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001264 /* Start up the poller to check for events on all enabled boards */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 init_timer(&epca_timer);
1266 epca_timer.function = epcapoll;
1267 mod_timer(&epca_timer, jiffies + HZ/25);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return 0;
1269
Akinobu Mitadabad052006-10-17 00:10:28 -07001270out4:
1271 tty_unregister_driver(pc_driver);
1272out3:
1273 put_tty_driver(pc_info);
1274out2:
1275 put_tty_driver(pc_driver);
1276out1:
1277 return err;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001278}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280static void post_fep_init(unsigned int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001281{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 int i;
Al Virobc9a5152005-09-15 22:53:28 +01001283 void __iomem *memaddr;
1284 struct global_data __iomem *gd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001286 struct board_chan __iomem *bc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001287 struct channel *ch;
1288 int shrinkmem = 0, lowwater;
1289
1290 /*
1291 * This call is made by the user via. the ioctl call DIGI_INIT. It is
1292 * responsible for setting up all the card specific stuff.
1293 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 bd = &boards[crd];
1295
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001296 /*
1297 * If this is a PCI board, get the port info. Remember PCI cards do not
1298 * have entries into the epcaconfig.h file, so we can't get the number
1299 * of ports from it. Unfortunetly, this means that anyone doing a
1300 * DIGI_GETINFO before the board has booted will get an invalid number
1301 * of ports returned (It should return 0). Calls to DIGI_GETINFO after
1302 * DIGI_INIT has been called will return the proper values.
1303 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001304 if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001305 /*
1306 * Below we use XEMPORTS as a memory offset regardless of which
1307 * PCI card it is. This is because all of the supported PCI
1308 * cards have the same memory offset for the channel data. This
1309 * will have to be changed if we ever develop a PCI/XE card.
1310 * NOTE : The FEP manual states that the port offset is 0xC22
1311 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
1312 * cards; not for the XEM, or CX series. On the PCI cards the
1313 * number of ports is determined by reading a ID PROM located
1314 * in the box attached to the card. The card can then determine
1315 * the index the id to determine the number of ports available.
1316 * (FYI - The id should be located at 0x1ac (And may use up to
1317 * 4 bytes if the box in question is a XEM or CX)).
1318 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001319 /* PCI cards are already remapped at this point ISA are not */
1320 bd->numports = readw(bd->re_map_membase + XEMPORTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
1322 nbdevs += (bd->numports);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001323 } else {
1324 /* Fix up the mappings for ISA/EISA etc */
1325 /* FIXME: 64K - can we be smarter ? */
1326 bd->re_map_membase = ioremap(bd->membase, 0x10000);
1327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 if (crd != 0)
1330 card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;
1331 else
1332 card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */
1333
1334 ch = card_ptr[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");
1336
Alan Coxf2cf8e22005-09-06 15:16:44 -07001337 memaddr = bd->re_map_membase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001339 /*
1340 * The below assignment will set bc to point at the BEGINING of the
1341 * cards channel structures. For 1 card there will be between 8 and 64
1342 * of these structures.
1343 */
Al Virobc9a5152005-09-15 22:53:28 +01001344 bc = memaddr + CHANSTRUCT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001346 /*
1347 * The below assignment will set gd to point at the BEGINING of global
1348 * memory address 0xc00. The first data in that global memory actually
1349 * starts at address 0xc1a. The command in pointer begins at 0xd10.
1350 */
Al Virobc9a5152005-09-15 22:53:28 +01001351 gd = memaddr + GLOBAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001353 /*
1354 * XEPORTS (address 0xc22) points at the number of channels the card
1355 * supports. (For 64XE, XI, XEM, and XR use 0xc02)
1356 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001357 if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 shrinkmem = 1;
1359 if (bd->type < PCIXEM)
1360 if (!request_region((int)bd->port, 4, board_desc[bd->type]))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001361 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 memwinon(bd, 0);
1363
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001364 /*
1365 * Remember ch is the main drivers channels structure, while bc is the
1366 * cards channel structure.
1367 */
1368 for (i = 0; i < bd->numports; i++, ch++, bc++) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07001369 unsigned long flags;
Al Virobc9a5152005-09-15 22:53:28 +01001370 u16 tseg, rseg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001372 ch->brdchan = bc;
1373 ch->mailbox = gd;
David Howellsc4028952006-11-22 14:57:56 +00001374 INIT_WORK(&ch->tqueue, do_softint);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001375 ch->board = &boards[crd];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Alan Coxf2cf8e22005-09-06 15:16:44 -07001377 spin_lock_irqsave(&epca_lock, flags);
1378 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001379 /*
1380 * Since some of the boards use different bitmaps for
1381 * their control signals we cannot hard code these
1382 * values and retain portability. We virtualize this
1383 * data here.
1384 */
1385 case EISAXEM:
1386 case PCXEM:
1387 case PCIXEM:
1388 case PCIXRJ:
1389 case PCIXR:
1390 ch->m_rts = 0x02;
1391 ch->m_dcd = 0x80;
1392 ch->m_dsr = 0x20;
1393 ch->m_cts = 0x10;
1394 ch->m_ri = 0x40;
1395 ch->m_dtr = 0x01;
1396 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001398 case PCXE:
1399 case PCXEVE:
1400 case PCXI:
1401 case PC64XE:
1402 ch->m_rts = 0x02;
1403 ch->m_dcd = 0x08;
1404 ch->m_dsr = 0x10;
1405 ch->m_cts = 0x20;
1406 ch->m_ri = 0x40;
1407 ch->m_dtr = 0x80;
1408 break;
1409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Alan Coxf2cf8e22005-09-06 15:16:44 -07001411 if (boards[crd].altpin) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 ch->dsr = ch->m_dcd;
1413 ch->dcd = ch->m_dsr;
1414 ch->digiext.digi_flags |= DIGI_ALTPIN;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001415 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 ch->dcd = ch->m_dcd;
1417 ch->dsr = ch->m_dsr;
1418 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 ch->boardnum = crd;
1421 ch->channelnum = i;
1422 ch->magic = EPCA_MAGIC;
1423 ch->tty = NULL;
1424
Alan Coxf2cf8e22005-09-06 15:16:44 -07001425 if (shrinkmem) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 fepcmd(ch, SETBUFFER, 32, 0, 0, 0);
1427 shrinkmem = 0;
1428 }
1429
Al Virobc9a5152005-09-15 22:53:28 +01001430 tseg = readw(&bc->tseg);
1431 rseg = readw(&bc->rseg);
1432
Alan Coxf2cf8e22005-09-06 15:16:44 -07001433 switch (bd->type) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001434 case PCIXEM:
1435 case PCIXRJ:
1436 case PCIXR:
1437 /* Cover all the 2MEG cards */
1438 ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
1439 ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
1440 ch->txwin = FEPWIN | (tseg >> 11);
1441 ch->rxwin = FEPWIN | (rseg >> 11);
1442 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001444 case PCXEM:
1445 case EISAXEM:
1446 /* Cover all the 32K windowed cards */
1447 /* Mask equal to window size - 1 */
1448 ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
1449 ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
1450 ch->txwin = FEPWIN | (tseg >> 11);
1451 ch->rxwin = FEPWIN | (rseg >> 11);
1452 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001454 case PCXEVE:
1455 case PCXE:
1456 ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
1457 ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
1458 ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
1459 ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
1460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001462 case PCXI:
1463 case PC64XE:
1464 ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
1465 ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
1466 ch->txwin = ch->rxwin = 0;
1467 break;
1468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
1470 ch->txbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001471 ch->txbufsize = readw(&bc->tmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 ch->rxbufhead = 0;
Al Virobc9a5152005-09-15 22:53:28 +01001474 ch->rxbufsize = readw(&bc->rmax) + 1;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001475
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
1477
1478 /* Set transmitter low water mark */
1479 fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
1480
1481 /* Set receiver low water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
1483
1484 /* Set receiver high water mark */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
1486
Alan Coxf2cf8e22005-09-06 15:16:44 -07001487 writew(100, &bc->edelay);
1488 writeb(1, &bc->idata);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001489
Alan Coxf2cf8e22005-09-06 15:16:44 -07001490 ch->startc = readb(&bc->startc);
1491 ch->stopc = readb(&bc->stopc);
1492 ch->startca = readb(&bc->startca);
1493 ch->stopca = readb(&bc->stopca);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 ch->fepcflag = 0;
1496 ch->fepiflag = 0;
1497 ch->fepoflag = 0;
1498 ch->fepstartc = 0;
1499 ch->fepstopc = 0;
1500 ch->fepstartca = 0;
1501 ch->fepstopca = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 ch->close_delay = 50;
1504 ch->count = 0;
1505 ch->blocked_open = 0;
1506 init_waitqueue_head(&ch->open_wait);
1507 init_waitqueue_head(&ch->close_wait);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001508
1509 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001512 printk(KERN_INFO
1513 "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 memwinoff(bd, 0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001516}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518static void epcapoll(unsigned long ignored)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001519{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 unsigned long flags;
1521 int crd;
1522 volatile unsigned int head, tail;
1523 struct channel *ch;
1524 struct board_info *bd;
1525
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001526 /*
1527 * This routine is called upon every timer interrupt. Even though the
1528 * Digi series cards are capable of generating interrupts this method
1529 * of non-looping polling is more efficient. This routine checks for
1530 * card generated events (Such as receive data, are transmit buffer
1531 * empty) and acts on those events.
1532 */
1533 for (crd = 0; crd < num_cards; crd++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 bd = &boards[crd];
1535 ch = card_ptr[crd];
1536
1537 if ((bd->status == DISABLED) || digi_poller_inhibited)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001538 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001540 /*
1541 * assertmemoff is not needed here; indeed it is an empty
1542 * subroutine. It is being kept because future boards may need
1543 * this as well as some legacy boards.
1544 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001545 spin_lock_irqsave(&epca_lock, flags);
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 assertmemoff(ch);
1548
1549 globalwinon(ch);
1550
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001551 /*
1552 * In this case head and tail actually refer to the event queue
1553 * not the transmit or receive queue.
1554 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001555 head = readw(&ch->mailbox->ein);
1556 tail = readw(&ch->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001558 /* If head isn't equal to tail we have an event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 if (head != tail)
1560 doevent(crd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 memoff(ch);
1562
Alan Coxf2cf8e22005-09-06 15:16:44 -07001563 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 } /* End for each card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 mod_timer(&epca_timer, jiffies + (HZ / 25));
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001566}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568static void doevent(int crd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001569{
Al Virobc9a5152005-09-15 22:53:28 +01001570 void __iomem *eventbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 struct channel *ch, *chan0;
1572 static struct tty_struct *tty;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001573 struct board_info *bd;
Al Virobc9a5152005-09-15 22:53:28 +01001574 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001575 unsigned int tail, head;
1576 int event, channel;
1577 int mstat, lstat;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001579 /*
1580 * This subroutine is called by epcapoll when an event is detected
1581 * in the event queue. This routine responds to those events.
1582 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 bd = &boards[crd];
1584
1585 chan0 = card_ptr[crd];
1586 epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 assertgwinon(chan0);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001588 while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 assertgwinon(chan0);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001590 eventbuf = bd->re_map_membase + tail + ISTART;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 /* Get the channel the event occurred on */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001592 channel = readb(eventbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 /* Get the actual event code that occurred */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001594 event = readb(eventbuf + 1);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001595 /*
1596 * The two assignments below get the current modem status
1597 * (mstat) and the previous modem status (lstat). These are
1598 * useful becuase an event could signal a change in modem
1599 * signals itself.
1600 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001601 mstat = readb(eventbuf + 2);
1602 lstat = readb(eventbuf + 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
1604 ch = chan0 + channel;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001605 if ((unsigned)channel >= bd->numports || !ch) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (channel >= bd->numports)
1607 ch = chan0;
1608 bc = ch->brdchan;
1609 goto next;
1610 }
1611
1612 if ((bc = ch->brdchan) == NULL)
1613 goto next;
1614
Alan Coxf2cf8e22005-09-06 15:16:44 -07001615 if (event & DATA_IND) { /* Begin DATA_IND */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 receive_data(ch);
1617 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 } /* End DATA_IND */
1619 /* else *//* Fix for DCD transition missed bug */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001620 if (event & MODEMCHG_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* A modem signal change has been indicated */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 ch->imodem = mstat;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001623 if (ch->asyncflags & ASYNC_CHECK_CD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (mstat & ch->dcd) /* We are now receiving dcd */
1625 wake_up_interruptible(&ch->open_wait);
1626 else
1627 pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
1628 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 tty = ch->tty;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001631 if (tty) {
1632 if (event & BREAK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 /* A break has been indicated */
Alan Cox33f0f882006-01-09 20:54:13 -08001634 tty_insert_flip_char(tty, 0, TTY_BREAK);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001635 tty_schedule_flip(tty);
1636 } else if (event & LOWTX_IND) {
1637 if (ch->statusflags & LOWWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 ch->statusflags &= ~LOWWAIT;
1639 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001640 }
1641 } else if (event & EMPTYTX_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 /* This event is generated by setup_empty_event */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 ch->statusflags &= ~TXBUSY;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001644 if (ch->statusflags & EMPTYWAIT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 ch->statusflags &= ~EMPTYWAIT;
1646 tty_wakeup(tty);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001647 }
1648 }
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 next:
1651 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001652 BUG_ON(!bc);
1653 writew(1, &bc->idata);
1654 writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 globalwinon(chan0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 } /* End while something in event queue */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001657}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
1659static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
1660 int byte2, int ncmds, int bytecmd)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001661{
Al Virobc9a5152005-09-15 22:53:28 +01001662 unchar __iomem *memaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 unsigned int head, cmdTail, cmdStart, cmdMax;
1664 long count;
1665 int n;
1666
1667 /* This is the routine in which commands may be passed to the card. */
1668
1669 if (ch->board->status == DISABLED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 /* Remember head (As well as max) is just an offset not a base addr */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001673 head = readw(&ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 /* cmdStart is a base address */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001675 cmdStart = readw(&ch->mailbox->cstart);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001676 /*
1677 * We do the addition below because we do not want a max pointer
1678 * relative to cmdStart. We want a max pointer that points at the
1679 * physical end of the command queue.
1680 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001681 cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 memaddr = ch->board->re_map_membase;
1683
Alan Coxf2cf8e22005-09-06 15:16:44 -07001684 if (head >= (cmdMax - cmdStart) || (head & 03)) {
1685 printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head);
1686 printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return;
1688 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001689 if (bytecmd) {
1690 writeb(cmd, memaddr + head + cmdStart + 0);
1691 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 /* Below word_or_byte is bits to set */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001693 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 /* Below byte2 is bits to reset */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001695 writeb(byte2, memaddr + head + cmdStart + 3);
1696 } else {
1697 writeb(cmd, memaddr + head + cmdStart + 0);
1698 writeb(ch->channelnum, memaddr + head + cmdStart + 1);
1699 writeb(word_or_byte, memaddr + head + cmdStart + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 head = (head + 4) & (cmdMax - cmdStart - 4);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001702 writew(head, &ch->mailbox->cin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 count = FEPTIMEOUT;
1704
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001705 for (;;) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 count--;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001707 if (count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
1709 return;
1710 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001711 head = readw(&ch->mailbox->cin);
1712 cmdTail = readw(&ch->mailbox->cout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 n = (head - cmdTail) & (cmdMax - cmdStart - 4);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001714 /*
1715 * Basically this will break when the FEP acknowledges the
1716 * command by incrementing cmdTail (Making it equal to head).
1717 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 if (n <= ncmds * (sizeof(short) * 4))
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001719 break;
1720 }
1721}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001723/*
1724 * Digi products use fields in their channels structures that are very similar
1725 * to the c_cflag and c_iflag fields typically found in UNIX termios
1726 * structures. The below three routines allow mappings between these hardware
1727 * "flags" and their respective Linux flags.
1728 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001730{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 unsigned res = 0;
1732
Alan Coxf2cf8e22005-09-06 15:16:44 -07001733 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 ch->digiext.digi_flags |= (RTSPACE | CTSPACE);
1735 res |= ((ch->m_cts) | (ch->m_rts));
1736 }
1737
1738 if (ch->digiext.digi_flags & RTSPACE)
1739 res |= ch->m_rts;
1740
1741 if (ch->digiext.digi_flags & DTRPACE)
1742 res |= ch->m_dtr;
1743
1744 if (ch->digiext.digi_flags & CTSPACE)
1745 res |= ch->m_cts;
1746
1747 if (ch->digiext.digi_flags & DSRPACE)
1748 res |= ch->dsr;
1749
1750 if (ch->digiext.digi_flags & DCDPACE)
1751 res |= ch->dcd;
1752
1753 if (res & (ch->m_rts))
1754 ch->digiext.digi_flags |= RTSPACE;
1755
1756 if (res & (ch->m_cts))
1757 ch->digiext.digi_flags |= CTSPACE;
1758
1759 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001760}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001763{
1764 unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 INPCK | ISTRIP|IXON|IXANY|IXOFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 if (ch->digiext.digi_flags & DIGI_AIXON)
1767 res |= IAIXON;
1768 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001769}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001772{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 unsigned res = 0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001774 if (cflag & CBAUDEX) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001775 ch->digiext.digi_flags |= DIGI_FAST;
1776 /*
1777 * HUPCL bit is used by FEP to indicate fast baud table is to
1778 * be used.
1779 */
1780 res |= FEP_HUPCL;
1781 } else
1782 ch->digiext.digi_flags &= ~DIGI_FAST;
1783 /*
1784 * CBAUD has bit position 0x1000 set these days to indicate Linux
1785 * baud rate remap. Digi hardware can't handle the bit assignment.
1786 * (We use a different bit assignment for high speed.). Clear this
1787 * bit out.
1788 */
1789 res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
1790 /*
1791 * This gets a little confusing. The Digi cards have their own
Joe Perches8dfba4d2008-02-03 17:11:42 +02001792 * representation of c_cflags controlling baud rate. For the most part
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001793 * this is identical to the Linux implementation. However; Digi
1794 * supports one rate (76800) that Linux doesn't. This means that the
1795 * c_cflag entry that would normally mean 76800 for Digi actually means
1796 * 115200 under Linux. Without the below mapping, a stty 115200 would
1797 * only drive the board at 76800. Since the rate 230400 is also found
1798 * after 76800, the same problem afflicts us when we choose a rate of
1799 * 230400. Without the below modificiation stty 230400 would actually
1800 * give us 115200.
1801 *
1802 * There are two additional differences. The Linux value for CLOCAL
1803 * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
1804 * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
1805 * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
1806 * checked for a screened out prior to termios2digi_c returning. Since
1807 * CLOCAL isn't used by the board this can be ignored as long as the
1808 * returned value is used only by Digi hardware.
1809 */
1810 if (cflag & CBAUDEX) {
1811 /*
1812 * The below code is trying to guarantee that only baud rates
1813 * 115200 and 230400 are remapped. We use exclusive or because
1814 * the various baud rates share common bit positions and
1815 * therefore can't be tested for easily.
1816 */
1817 if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 res += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 return res;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001822}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
Alan Coxf2cf8e22005-09-06 15:16:44 -07001824/* Caller must hold the locks */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825static void epcaparam(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001826{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 unsigned int cmdHead;
Alan Cox606d0992006-12-08 02:38:45 -08001828 struct ktermios *ts;
Al Virobc9a5152005-09-15 22:53:28 +01001829 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 unsigned mval, hflow, cflag, iflag;
1831
1832 bc = ch->brdchan;
Harvey Harrison11fb09b2008-04-30 00:53:52 -07001833 epcaassert(bc != NULL, "bc out of range");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
1835 assertgwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 ts = tty->termios;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001837 if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */
1838 cmdHead = readw(&bc->rin);
Al Virobc9a5152005-09-15 22:53:28 +01001839 writew(cmdHead, &bc->rout);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001840 cmdHead = readw(&bc->tin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 /* Changing baud in mid-stream transmission can be wonderful */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001842 /*
1843 * Flush current transmit buffer by setting cmdTail pointer
1844 * (tout) to cmdHead pointer (tin). Hopefully the transmit
1845 * buffer is empty.
1846 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
1848 mval = 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001849 } else { /* Begin CBAUD not detected */
1850 /*
1851 * c_cflags have changed but that change had nothing to do with
1852 * BAUD. Propagate the change to the card.
1853 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 cflag = termios2digi_c(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001855 if (cflag != ch->fepcflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 ch->fepcflag = cflag;
1857 /* Set baud rate, char size, stop bits, parity */
1858 fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
1859 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001860 /*
1861 * If the user has not forced CLOCAL and if the device is not a
1862 * CALLOUT device (Which is always CLOCAL) we set flags such
1863 * that the driver will wait on carrier detect.
1864 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 if (ts->c_cflag & CLOCAL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 ch->asyncflags &= ~ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 ch->asyncflags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 mval = ch->m_dtr | ch->m_rts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 } /* End CBAUD not detected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 iflag = termios2digi_i(ch, ts->c_iflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 /* Check input mode flags */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001873 if (iflag != ch->fepiflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 ch->fepiflag = iflag;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001875 /*
1876 * Command sets channels iflag structure on the board. Such
1877 * things as input soft flow control, handling of parity
1878 * errors, and break handling are all set here.
1879 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 /* break handling, parity handling, input stripping, flow control chars */
1881 fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
1882 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001883 /*
1884 * Set the board mint value for this channel. This will cause hardware
1885 * events to be generated each time the DCD signal (Described in mint)
1886 * changes.
1887 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001888 writeb(ch->dcd, &bc->mint);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
1890 if (ch->digiext.digi_flags & DIGI_FORCEDCD)
Alan Coxf2cf8e22005-09-06 15:16:44 -07001891 writeb(0, &bc->mint);
1892 ch->imodem = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 hflow = termios2digi_h(ch, ts->c_cflag);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001894 if (hflow != ch->hflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 ch->hflow = hflow;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001896 /*
1897 * Hard flow control has been selected but the board is not
1898 * using it. Activate hard flow control now.
1899 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
1901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 mval ^= ch->modemfake & (mval ^ ch->modem);
1903
Alan Coxf2cf8e22005-09-06 15:16:44 -07001904 if (ch->omodem ^ mval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 ch->omodem = mval;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001906 /*
1907 * The below command sets the DTR and RTS mstat structure. If
1908 * hard flow control is NOT active these changes will drive the
1909 * output of the actual DTR and RTS lines. If hard flow control
1910 * is active, the changes will be saved in the mstat structure
1911 * and only asserted when hard flow control is turned off.
1912 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
1914 /* First reset DTR & RTS; then set them */
1915 fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
1916 fepcmd(ch, SETMODEM, mval, 0, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001918 if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 ch->fepstartc = ch->startc;
1920 ch->fepstopc = ch->stopc;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001921 /*
1922 * The XON / XOFF characters have changed; propagate these
1923 * changes to the card.
1924 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
1926 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07001927 if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 ch->fepstartca = ch->startca;
1929 ch->fepstopca = ch->stopca;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001930 /*
1931 * Similar to the above, this time the auxilarly XON / XOFF
1932 * characters have changed; propagate these changes to the card.
1933 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
1935 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001936}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
Alan Coxf2cf8e22005-09-06 15:16:44 -07001938/* Caller holds lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939static void receive_data(struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001940{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 unchar *rptr;
Alan Cox606d0992006-12-08 02:38:45 -08001942 struct ktermios *ts = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 struct tty_struct *tty;
Al Virobc9a5152005-09-15 22:53:28 +01001944 struct board_chan __iomem *bc;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001945 int dataToRead, wrapgap, bytesAvailable;
1946 unsigned int tail, head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 unsigned int wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001949 /*
1950 * This routine is called by doint when a receive data event has taken
1951 * place.
1952 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 if (ch->statusflags & RXSTOPPED)
1955 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 tty = ch->tty;
1957 if (tty)
1958 ts = tty->termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 bc = ch->brdchan;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001960 BUG_ON(!bc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 wrapmask = ch->rxbufsize - 1;
1962
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001963 /*
1964 * Get the head and tail pointers to the receiver queue. Wrap the head
1965 * pointer if it has reached the end of the buffer.
1966 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001967 head = readw(&bc->rin);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 head &= wrapmask;
Alan Coxf2cf8e22005-09-06 15:16:44 -07001969 tail = readw(&bc->rout) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970
1971 bytesAvailable = (head - tail) & wrapmask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 if (bytesAvailable == 0)
1973 return;
1974
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001975 /* If CREAD bit is off or device not open, set TX tail to head */
Alan Coxf2cf8e22005-09-06 15:16:44 -07001976 if (!tty || !ts || !(ts->c_cflag & CREAD)) {
Al Virobc9a5152005-09-15 22:53:28 +01001977 writew(head, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 return;
1979 }
1980
Alan Cox33f0f882006-01-09 20:54:13 -08001981 if (tty_buffer_request_room(tty, bytesAvailable + 1) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return;
1983
Alan Coxf2cf8e22005-09-06 15:16:44 -07001984 if (readb(&bc->orun)) {
1985 writeb(0, &bc->orun);
1986 printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
Alan Cox33f0f882006-01-09 20:54:13 -08001987 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 rxwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07001990 while (bytesAvailable > 0) { /* Begin while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001992 /*
1993 * Even if head has wrapped around only report the amount of
1994 * data to be equal to the size - tail. Remember memcpy can't
1995 * automaticly wrap around the receive buffer.
1996 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07001998 /* Make sure we don't overflow the buffer */
Alan Cox33f0f882006-01-09 20:54:13 -08001999 dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 if (dataToRead == 0)
2001 break;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002002 /*
2003 * Move data read from our card into the line disciplines
2004 * buffer for translation if necessary.
2005 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002006 memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 tail = (tail + dataToRead) & wrapmask;
2008 bytesAvailable -= dataToRead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 } /* End while there is data on the card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002011 writew(tail, &bc->rout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 /* Must be called with global data */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002013 tty_schedule_flip(ch->tty);
2014}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002016static int info_ioctl(struct tty_struct *tty, struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 unsigned int cmd, unsigned long arg)
2018{
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002019 switch (cmd) {
2020 case DIGI_GETINFO:
2021 {
2022 struct digi_info di;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 int brd;
2024
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002025 if (get_user(brd, (unsigned int __user *)arg))
Alan Coxf2cf8e22005-09-06 15:16:44 -07002026 return -EFAULT;
2027 if (brd < 0 || brd >= num_cards || num_cards == 0)
2028 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 memset(&di, 0, sizeof(di));
2031
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002032 di.board = brd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 di.status = boards[brd].status;
2034 di.type = boards[brd].type ;
2035 di.numports = boards[brd].numports ;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002036 /* Legacy fixups - just move along nothing to see */
2037 di.port = (unsigned char *)boards[brd].port ;
2038 di.membase = (unsigned char *)boards[brd].membase ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002040 if (copy_to_user((void __user *)arg, &di, sizeof(di)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 return -EFAULT;
2042 break;
2043
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002046 case DIGI_POLLER:
2047 {
2048 int brd = arg & 0xff000000 >> 16;
2049 unsigned char state = arg & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
Alan Coxf2cf8e22005-09-06 15:16:44 -07002051 if (brd < 0 || brd >= num_cards) {
2052 printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002053 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002055 digi_poller_inhibited = state;
2056 break;
2057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002059 case DIGI_INIT:
2060 {
2061 /*
2062 * This call is made by the apps to complete the
Joe Perches8dfba4d2008-02-03 17:11:42 +02002063 * initialization of the board(s). This routine is
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002064 * responsible for setting the card to its initial
2065 * state and setting the drivers control fields to the
2066 * sutianle settings for the card in question.
2067 */
2068 int crd;
2069 for (crd = 0; crd < num_cards; crd++)
2070 post_fep_init(crd);
2071 break;
2072 }
2073 default:
2074 return -ENOTTY;
2075 }
2076 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079static int pc_tiocmget(struct tty_struct *tty, struct file *file)
2080{
2081 struct channel *ch = (struct channel *) tty->driver_data;
Al Virobc9a5152005-09-15 22:53:28 +01002082 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 unsigned int mstat, mflag = 0;
2084 unsigned long flags;
2085
2086 if (ch)
2087 bc = ch->brdchan;
2088 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002089 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Alan Coxf2cf8e22005-09-06 15:16:44 -07002091 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 globalwinon(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002093 mstat = readb(&bc->mstat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002095 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
2097 if (mstat & ch->m_dtr)
2098 mflag |= TIOCM_DTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 if (mstat & ch->m_rts)
2100 mflag |= TIOCM_RTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 if (mstat & ch->m_cts)
2102 mflag |= TIOCM_CTS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 if (mstat & ch->dsr)
2104 mflag |= TIOCM_DSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 if (mstat & ch->m_ri)
2106 mflag |= TIOCM_RI;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 if (mstat & ch->dcd)
2108 mflag |= TIOCM_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 return mflag;
2110}
2111
2112static int pc_tiocmset(struct tty_struct *tty, struct file *file,
2113 unsigned int set, unsigned int clear)
2114{
2115 struct channel *ch = (struct channel *) tty->driver_data;
2116 unsigned long flags;
2117
Alan Coxf2cf8e22005-09-06 15:16:44 -07002118 if (!ch)
2119 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
Alan Coxf2cf8e22005-09-06 15:16:44 -07002121 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 /*
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002123 * I think this modemfake stuff is broken. It doesn't correctly reflect
2124 * the behaviour desired by the TIOCM* ioctls. Therefore this is
2125 * probably broken.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 */
2127 if (set & TIOCM_RTS) {
2128 ch->modemfake |= ch->m_rts;
2129 ch->modem |= ch->m_rts;
2130 }
2131 if (set & TIOCM_DTR) {
2132 ch->modemfake |= ch->m_dtr;
2133 ch->modem |= ch->m_dtr;
2134 }
2135 if (clear & TIOCM_RTS) {
2136 ch->modemfake |= ch->m_rts;
2137 ch->modem &= ~ch->m_rts;
2138 }
2139 if (clear & TIOCM_DTR) {
2140 ch->modemfake |= ch->m_dtr;
2141 ch->modem &= ~ch->m_dtr;
2142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002144 /*
2145 * The below routine generally sets up parity, baud, flow control
2146 * issues, etc.... It effect both control flags and input flags.
2147 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 epcaparam(tty,ch);
2149 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002150 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 return 0;
2152}
2153
2154static int pc_ioctl(struct tty_struct *tty, struct file * file,
2155 unsigned int cmd, unsigned long arg)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002156{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 digiflow_t dflow;
2158 int retval;
2159 unsigned long flags;
2160 unsigned int mflag, mstat;
2161 unsigned char startc, stopc;
Al Virobc9a5152005-09-15 22:53:28 +01002162 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 struct channel *ch = (struct channel *) tty->driver_data;
2164 void __user *argp = (void __user *)arg;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 if (ch)
2167 bc = ch->brdchan;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002168 else
Alan Coxf2cf8e22005-09-06 15:16:44 -07002169 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002171 /*
2172 * For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
2173 * /usr/src/linux/drivers/char for a good example. In particular think
2174 * about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
2175 */
2176 switch (cmd) {
2177 case TCSBRK: /* SVID version: non-zero arg --> no break */
2178 retval = tty_check_change(tty);
2179 if (retval)
2180 return retval;
2181 /* Setup an event to indicate when the transmit buffer empties */
2182 spin_lock_irqsave(&epca_lock, flags);
2183 setup_empty_event(tty,ch);
2184 spin_unlock_irqrestore(&epca_lock, flags);
2185 tty_wait_until_sent(tty, 0);
2186 if (!arg)
2187 digi_send_break(ch, HZ / 4); /* 1/4 second */
2188 return 0;
2189 case TCSBRKP: /* support for POSIX tcsendbreak() */
2190 retval = tty_check_change(tty);
2191 if (retval)
2192 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002194 /* Setup an event to indicate when the transmit buffer empties */
2195 spin_lock_irqsave(&epca_lock, flags);
2196 setup_empty_event(tty,ch);
2197 spin_unlock_irqrestore(&epca_lock, flags);
2198 tty_wait_until_sent(tty, 0);
2199 digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
2200 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002201 case TIOCMODG:
2202 mflag = pc_tiocmget(tty, file);
2203 if (put_user(mflag, (unsigned long __user *)argp))
2204 return -EFAULT;
2205 break;
2206 case TIOCMODS:
2207 if (get_user(mstat, (unsigned __user *)argp))
2208 return -EFAULT;
2209 return pc_tiocmset(tty, file, mstat, ~mstat);
2210 case TIOCSDTR:
2211 spin_lock_irqsave(&epca_lock, flags);
2212 ch->omodem |= ch->m_dtr;
2213 globalwinon(ch);
2214 fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
2215 memoff(ch);
2216 spin_unlock_irqrestore(&epca_lock, flags);
2217 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002219 case TIOCCDTR:
2220 spin_lock_irqsave(&epca_lock, flags);
2221 ch->omodem &= ~ch->m_dtr;
2222 globalwinon(ch);
2223 fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
2224 memoff(ch);
2225 spin_unlock_irqrestore(&epca_lock, flags);
2226 break;
2227 case DIGI_GETA:
2228 if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
2229 return -EFAULT;
2230 break;
2231 case DIGI_SETAW:
2232 case DIGI_SETAF:
Alan Cox37925e02008-04-30 00:53:17 -07002233 lock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002234 if (cmd == DIGI_SETAW) {
2235 /* Setup an event to indicate when the transmit buffer empties */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002236 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002237 setup_empty_event(tty,ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002238 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002239 tty_wait_until_sent(tty, 0);
2240 } else {
2241 /* ldisc lock already held in ioctl */
2242 if (tty->ldisc.flush_buffer)
2243 tty->ldisc.flush_buffer(tty);
2244 }
Alan Cox37925e02008-04-30 00:53:17 -07002245 unlock_kernel();
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002246 /* Fall Thru */
2247 case DIGI_SETA:
2248 if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
2249 return -EFAULT;
2250
2251 if (ch->digiext.digi_flags & DIGI_ALTPIN) {
2252 ch->dcd = ch->m_dsr;
2253 ch->dsr = ch->m_dcd;
2254 } else {
2255 ch->dcd = ch->m_dcd;
2256 ch->dsr = ch->m_dsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002258
2259 spin_lock_irqsave(&epca_lock, flags);
2260 globalwinon(ch);
2261
2262 /*
2263 * The below routine generally sets up parity, baud, flow
2264 * control issues, etc.... It effect both control flags and
2265 * input flags.
2266 */
2267 epcaparam(tty,ch);
2268 memoff(ch);
2269 spin_unlock_irqrestore(&epca_lock, flags);
2270 break;
2271
2272 case DIGI_GETFLOW:
2273 case DIGI_GETAFLOW:
2274 spin_lock_irqsave(&epca_lock, flags);
2275 globalwinon(ch);
2276 if (cmd == DIGI_GETFLOW) {
2277 dflow.startc = readb(&bc->startc);
2278 dflow.stopc = readb(&bc->stopc);
2279 } else {
2280 dflow.startc = readb(&bc->startca);
2281 dflow.stopc = readb(&bc->stopca);
2282 }
2283 memoff(ch);
2284 spin_unlock_irqrestore(&epca_lock, flags);
2285
2286 if (copy_to_user(argp, &dflow, sizeof(dflow)))
2287 return -EFAULT;
2288 break;
2289
2290 case DIGI_SETAFLOW:
2291 case DIGI_SETFLOW:
2292 if (cmd == DIGI_SETFLOW) {
2293 startc = ch->startc;
2294 stopc = ch->stopc;
2295 } else {
2296 startc = ch->startca;
2297 stopc = ch->stopca;
2298 }
2299
2300 if (copy_from_user(&dflow, argp, sizeof(dflow)))
2301 return -EFAULT;
2302
2303 if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002304 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 globalwinon(ch);
2306
Alan Coxf2cf8e22005-09-06 15:16:44 -07002307 if (cmd == DIGI_SETFLOW) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002308 ch->fepstartc = ch->startc = dflow.startc;
2309 ch->fepstopc = ch->stopc = dflow.stopc;
2310 fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002311 } else {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002312 ch->fepstartca = ch->startca = dflow.startc;
2313 ch->fepstopca = ch->stopca = dflow.stopc;
2314 fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 }
2316
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002317 if (ch->statusflags & TXSTOPPED)
2318 pc_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002320 memoff(ch);
2321 spin_unlock_irqrestore(&epca_lock, flags);
2322 } /* End if setflow toggled */
2323 break;
2324 default:
2325 return -ENOIOCTLCMD;
2326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 return 0;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002328}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Alan Cox606d0992006-12-08 02:38:45 -08002330static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002331{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 struct channel *ch;
2333 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002334 /*
2335 * verifyChannel returns the channel from the tty struct if it is
2336 * valid. This serves as a sanity check.
2337 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002338 if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
2339 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 globalwinon(ch);
2341 epcaparam(tty, ch);
2342 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002343 spin_unlock_irqrestore(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345 if ((old_termios->c_cflag & CRTSCTS) &&
2346 ((tty->termios->c_cflag & CRTSCTS) == 0))
2347 tty->hw_stopped = 0;
2348
2349 if (!(old_termios->c_cflag & CLOCAL) &&
2350 (tty->termios->c_cflag & CLOCAL))
2351 wake_up_interruptible(&ch->open_wait);
2352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 } /* End if channel valid */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002354}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
David Howellsc4028952006-11-22 14:57:56 +00002356static void do_softint(struct work_struct *work)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002357{
David Howellsc4028952006-11-22 14:57:56 +00002358 struct channel *ch = container_of(work, struct channel, tqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 /* Called in response to a modem change event */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002360 if (ch && ch->magic == EPCA_MAGIC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 struct tty_struct *tty = ch->tty;
2362
Alan Coxf2cf8e22005-09-06 15:16:44 -07002363 if (tty && tty->driver_data) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002364 if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 tty_hangup(tty); /* FIXME: module removal race here - AKPM */
2366 wake_up_interruptible(&ch->open_wait);
2367 ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002370 }
2371}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002373/*
2374 * pc_stop and pc_start provide software flow control to the routine and the
2375 * pc_ioctl routine.
2376 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377static void pc_stop(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002378{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 struct channel *ch;
2380 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002381 /*
2382 * verifyChannel returns the channel from the tty struct if it is
2383 * valid. This serves as a sanity check.
2384 */
2385 if ((ch = verifyChannel(tty)) != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002386 spin_lock_irqsave(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002387 if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 /* STOP transmitting now !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 fepcmd(ch, PAUSETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 ch->statusflags |= TXSTOPPED;
2392 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 } /* End if transmit stop requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002394 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002395 }
2396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398static void pc_start(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002399{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 struct channel *ch;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002401 /*
2402 * verifyChannel returns the channel from the tty struct if it is
2403 * valid. This serves as a sanity check.
2404 */
2405 if ((ch = verifyChannel(tty)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 unsigned long flags;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002407 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 /* Just in case output was resumed because of a change in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002409 if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */
Al Virobc9a5152005-09-15 22:53:28 +01002410 struct board_chan __iomem *bc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 globalwinon(ch);
2412 bc = ch->brdchan;
2413 if (ch->statusflags & LOWWAIT)
Alan Coxf2cf8e22005-09-06 15:16:44 -07002414 writeb(1, &bc->ilow);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* Okay, you can start transmitting again... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 fepcmd(ch, RESUMETX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 ch->statusflags &= ~TXSTOPPED;
2418 memoff(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 } /* End transmit resume requested */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002420 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002421 }
2422}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002424/*
2425 * The below routines pc_throttle and pc_unthrottle are used to slow (And
2426 * resume) the receipt of data into the kernels receive buffers. The exact
2427 * occurrence of this depends on the size of the kernels receive buffer and
2428 * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
2429 * more details.
2430 */
2431static void pc_throttle(struct tty_struct *tty)
2432{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 struct channel *ch;
2434 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002435 /*
2436 * verifyChannel returns the channel from the tty struct if it is
2437 * valid. This serves as a sanity check.
2438 */
2439 if ((ch = verifyChannel(tty)) != NULL) {
Alan Coxf2cf8e22005-09-06 15:16:44 -07002440 spin_lock_irqsave(&epca_lock, flags);
2441 if ((ch->statusflags & RXSTOPPED) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 globalwinon(ch);
2443 fepcmd(ch, PAUSERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 ch->statusflags |= RXSTOPPED;
2445 memoff(ch);
2446 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002447 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002448 }
2449}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451static void pc_unthrottle(struct tty_struct *tty)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002452{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 struct channel *ch;
2454 unsigned long flags;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002455 /*
2456 * verifyChannel returns the channel from the tty struct if it is
2457 * valid. This serves as a sanity check.
2458 */
2459 if ((ch = verifyChannel(tty)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 /* Just in case output was resumed because of a change in Digi-flow */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002461 spin_lock_irqsave(&epca_lock, flags);
2462 if (ch->statusflags & RXSTOPPED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 globalwinon(ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 fepcmd(ch, RESUMERX, 0, 0, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 ch->statusflags &= ~RXSTOPPED;
2466 memoff(ch);
2467 }
Alan Coxf2cf8e22005-09-06 15:16:44 -07002468 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002469 }
2470}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002472static void digi_send_break(struct channel *ch, int msec)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002473{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 unsigned long flags;
2475
Alan Coxf2cf8e22005-09-06 15:16:44 -07002476 spin_lock_irqsave(&epca_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 globalwinon(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002478 /*
2479 * Maybe I should send an infinite break here, schedule() for msec
2480 * amount of time, and then stop the break. This way, the user can't
2481 * screw up the FEP by causing digi_send_break() to be called (i.e. via
2482 * an ioctl()) more than once in msec amount of time.
2483 * Try this for now...
2484 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
2486 memoff(ch);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002487 spin_unlock_irqrestore(&epca_lock, flags);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002488}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Alan Coxf2cf8e22005-09-06 15:16:44 -07002490/* Caller MUST hold the lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002492{
Al Virobc9a5152005-09-15 22:53:28 +01002493 struct board_chan __iomem *bc = ch->brdchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 globalwinon(ch);
2496 ch->statusflags |= EMPTYWAIT;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002497 /*
2498 * When set the iempty flag request a event to be generated when the
2499 * transmit buffer is empty (If there is no BREAK in progress).
2500 */
Alan Coxf2cf8e22005-09-06 15:16:44 -07002501 writeb(1, &bc->iempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 memoff(ch);
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002503}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505void epca_setup(char *str, int *ints)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002506{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 struct board_info board;
2508 int index, loop, last;
2509 char *temp, *t2;
2510 unsigned len;
2511
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002512 /*
2513 * If this routine looks a little strange it is because it is only
2514 * called if a LILO append command is given to boot the kernel with
2515 * parameters. In this way, we can provide the user a method of
2516 * changing his board configuration without rebuilding the kernel.
2517 */
2518 if (!liloconfig)
2519 liloconfig = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 memset(&board, 0, sizeof(board));
2522
2523 /* Assume the data is int first, later we can change it */
2524 /* I think that array position 0 of ints holds the number of args */
2525 for (last = 0, index = 1; index <= ints[0]; index++)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002526 switch (index) { /* Begin parse switch */
2527 case 1:
2528 board.status = ints[index];
2529 /*
2530 * We check for 2 (As opposed to 1; because 2 is a flag
2531 * instructing the driver to ignore epcaconfig.) For
2532 * this reason we check for 2.
2533 */
2534 if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
2535 nbdevs = 0;
2536 num_cards = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002538 } /* End ignore epcaconfig as well as lilo cmd line */
2539
2540 if (board.status > 2) {
2541 printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
2542 invalid_lilo_config = 1;
2543 setup_error_code |= INVALID_BOARD_STATUS;
2544 return;
2545 }
2546 last = index;
2547 break;
2548 case 2:
2549 board.type = ints[index];
2550 if (board.type >= PCIXEM) {
2551 printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
2552 invalid_lilo_config = 1;
2553 setup_error_code |= INVALID_BOARD_TYPE;
2554 return;
2555 }
2556 last = index;
2557 break;
2558 case 3:
2559 board.altpin = ints[index];
2560 if (board.altpin > 1) {
2561 printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
2562 invalid_lilo_config = 1;
2563 setup_error_code |= INVALID_ALTPIN;
2564 return;
2565 }
2566 last = index;
2567 break;
2568
2569 case 4:
2570 board.numports = ints[index];
2571 if (board.numports < 2 || board.numports > 256) {
2572 printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
2573 invalid_lilo_config = 1;
2574 setup_error_code |= INVALID_NUM_PORTS;
2575 return;
2576 }
2577 nbdevs += board.numports;
2578 last = index;
2579 break;
2580
2581 case 5:
2582 board.port = ints[index];
2583 if (ints[index] <= 0) {
2584 printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
2585 invalid_lilo_config = 1;
2586 setup_error_code |= INVALID_PORT_BASE;
2587 return;
2588 }
2589 last = index;
2590 break;
2591
2592 case 6:
2593 board.membase = ints[index];
2594 if (ints[index] <= 0) {
2595 printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
2596 invalid_lilo_config = 1;
2597 setup_error_code |= INVALID_MEM_BASE;
2598 return;
2599 }
2600 last = index;
2601 break;
2602
2603 default:
2604 printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
2605 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
2607 } /* End parse switch */
2608
Alan Coxf2cf8e22005-09-06 15:16:44 -07002609 while (str && *str) { /* Begin while there is a string arg */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 /* find the next comma or terminator */
2611 temp = str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 /* While string is not null, and a comma hasn't been found */
2613 while (*temp && (*temp != ','))
2614 temp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 if (!*temp)
2616 temp = NULL;
2617 else
2618 *temp++ = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 /* Set index to the number of args + 1 */
2620 index = last + 1;
2621
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002622 switch (index) {
2623 case 1:
2624 len = strlen(str);
2625 if (strncmp("Disable", str, len) == 0)
2626 board.status = 0;
2627 else if (strncmp("Enable", str, len) == 0)
2628 board.status = 1;
2629 else {
2630 printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
2631 invalid_lilo_config = 1;
2632 setup_error_code |= INVALID_BOARD_STATUS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002634 }
2635 last = index;
2636 break;
2637
2638 case 2:
2639 for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
2640 if (strcmp(board_desc[loop], str) == 0)
2641 break;
2642 /*
2643 * If the index incremented above refers to a
2644 * legitamate board type set it here.
2645 */
2646 if (index < EPCA_NUM_TYPES)
2647 board.type = loop;
2648 else {
2649 printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
2650 invalid_lilo_config = 1;
2651 setup_error_code |= INVALID_BOARD_TYPE;
2652 return;
2653 }
2654 last = index;
2655 break;
2656
2657 case 3:
2658 len = strlen(str);
2659 if (strncmp("Disable", str, len) == 0)
2660 board.altpin = 0;
2661 else if (strncmp("Enable", str, len) == 0)
2662 board.altpin = 1;
2663 else {
2664 printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
2665 invalid_lilo_config = 1;
2666 setup_error_code |= INVALID_ALTPIN;
2667 return;
2668 }
2669 last = index;
2670 break;
2671
2672 case 4:
2673 t2 = str;
2674 while (isdigit(*t2))
2675 t2++;
2676
2677 if (*t2) {
2678 printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
2679 invalid_lilo_config = 1;
2680 setup_error_code |= INVALID_NUM_PORTS;
2681 return;
2682 }
2683
2684 /*
2685 * There is not a man page for simple_strtoul but the
2686 * code can be found in vsprintf.c. The first argument
2687 * is the string to translate (To an unsigned long
2688 * obviously), the second argument can be the address
2689 * of any character variable or a NULL. If a variable
2690 * is given, the end pointer of the string will be
2691 * stored in that variable; if a NULL is given the end
2692 * pointer will not be returned. The last argument is
2693 * the base to use. If a 0 is indicated, the routine
2694 * will attempt to determine the proper base by looking
2695 * at the values prefix (A '0' for octal, a 'x' for
2696 * hex, etc ... If a value is given it will use that
2697 * value as the base.
2698 */
2699 board.numports = simple_strtoul(str, NULL, 0);
2700 nbdevs += board.numports;
2701 last = index;
2702 break;
2703
2704 case 5:
2705 t2 = str;
2706 while (isxdigit(*t2))
2707 t2++;
2708
2709 if (*t2) {
2710 printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
2711 invalid_lilo_config = 1;
2712 setup_error_code |= INVALID_PORT_BASE;
2713 return;
2714 }
2715
2716 board.port = simple_strtoul(str, NULL, 16);
2717 last = index;
2718 break;
2719
2720 case 6:
2721 t2 = str;
2722 while (isxdigit(*t2))
2723 t2++;
2724
2725 if (*t2) {
2726 printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
2727 invalid_lilo_config = 1;
2728 setup_error_code |= INVALID_MEM_BASE;
2729 return;
2730 }
2731 board.membase = simple_strtoul(str, NULL, 16);
2732 last = index;
2733 break;
2734 default:
2735 printk(KERN_ERR "epca: Too many string parms\n");
2736 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
2738 str = temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 } /* End while there is a string arg */
2740
Alan Coxf2cf8e22005-09-06 15:16:44 -07002741 if (last < 6) {
2742 printk(KERN_ERR "epca: Insufficient parms specified\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 return;
2744 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002745
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 /* I should REALLY validate the stuff here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 /* Copies our local copy of board into boards */
2748 memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 /* Does this get called once per lilo arg are what ? */
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002750 printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
2751 num_cards, board_desc[board.type],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 board.numports, (int)board.port, (unsigned int) board.membase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 num_cards++;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002754}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
2756enum epic_board_types {
2757 brd_xr = 0,
2758 brd_xem,
2759 brd_cx,
2760 brd_xrj,
2761};
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763/* indexed directly by epic_board_types enum */
2764static struct {
2765 unsigned char board_type;
2766 unsigned bar_idx; /* PCI base address region */
2767} epca_info_tbl[] = {
2768 { PCIXR, 0, },
2769 { PCIXEM, 0, },
2770 { PCICX, 0, },
2771 { PCIXRJ, 2, },
2772};
2773
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002774static int __devinit epca_init_one(struct pci_dev *pdev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 const struct pci_device_id *ent)
2776{
2777 static int board_num = -1;
2778 int board_idx, info_idx = ent->driver_data;
2779 unsigned long addr;
2780
2781 if (pci_enable_device(pdev))
2782 return -EIO;
2783
2784 board_num++;
2785 board_idx = board_num + num_cards;
2786 if (board_idx >= MAXBOARDS)
2787 goto err_out;
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002788
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx);
2790 if (!addr) {
2791 printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n",
2792 epca_info_tbl[info_idx].bar_idx);
2793 goto err_out;
2794 }
2795
2796 boards[board_idx].status = ENABLED;
2797 boards[board_idx].type = epca_info_tbl[info_idx].board_type;
2798 boards[board_idx].numports = 0x0;
Alan Coxf2cf8e22005-09-06 15:16:44 -07002799 boards[board_idx].port = addr + PCI_IO_OFFSET;
2800 boards[board_idx].membase = addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) {
2803 printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
2804 0x200000, addr + PCI_IO_OFFSET);
2805 goto err_out;
2806 }
2807
2808 boards[board_idx].re_map_port = ioremap(addr + PCI_IO_OFFSET, 0x200000);
2809 if (!boards[board_idx].re_map_port) {
2810 printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
2811 0x200000, addr + PCI_IO_OFFSET);
2812 goto err_out_free_pciio;
2813 }
2814
2815 if (!request_mem_region (addr, 0x200000, "epca")) {
2816 printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
2817 0x200000, addr);
2818 goto err_out_free_iounmap;
2819 }
2820
2821 boards[board_idx].re_map_membase = ioremap(addr, 0x200000);
2822 if (!boards[board_idx].re_map_membase) {
2823 printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
2824 0x200000, addr + PCI_IO_OFFSET);
2825 goto err_out_free_memregion;
2826 }
2827
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002828 /*
2829 * I don't know what the below does, but the hardware guys say its
2830 * required on everything except PLX (In this case XRJ).
2831 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (info_idx != brd_xrj) {
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002833 pci_write_config_byte(pdev, 0x40, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 pci_write_config_byte(pdev, 0x46, 0);
2835 }
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 return 0;
2838
2839err_out_free_memregion:
2840 release_mem_region (addr, 0x200000);
2841err_out_free_iounmap:
2842 iounmap (boards[board_idx].re_map_port);
2843err_out_free_pciio:
2844 release_mem_region (addr + PCI_IO_OFFSET, 0x200000);
2845err_out:
2846 return -ENODEV;
2847}
2848
2849
2850static struct pci_device_id epca_pci_tbl[] = {
2851 { PCI_VENDOR_DIGI, PCI_DEVICE_XR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xr },
2852 { PCI_VENDOR_DIGI, PCI_DEVICE_XEM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xem },
2853 { PCI_VENDOR_DIGI, PCI_DEVICE_CX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_cx },
2854 { PCI_VENDOR_DIGI, PCI_DEVICE_XRJ, PCI_ANY_ID, PCI_ANY_ID, 0, 0, brd_xrj },
2855 { 0, }
2856};
2857
2858MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
2859
Harvey Harrison11fb09b2008-04-30 00:53:52 -07002860static int __init init_PCI(void)
Alexey Dobriyanae0b78d2007-10-16 23:26:37 -07002861{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 memset (&epca_driver, 0, sizeof (epca_driver));
2863 epca_driver.name = "epca";
2864 epca_driver.id_table = epca_pci_tbl;
2865 epca_driver.probe = epca_init_one;
2866
2867 return pci_register_driver(&epca_driver);
Alan Coxf2cf8e22005-09-06 15:16:44 -07002868}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870MODULE_LICENSE("GPL");