Commit ae0b78d0 authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by Linus Torvalds

epca.c: reformat comments and coding style improvements

* Remove stupid comments, like, at the beginning of every function that
  function begins (twice per function) and at the end (once)
* Remove trailing or otherwise broken whitespace as per let c_space_errors=1
* Reformat comments to fit it into 80 columns and remove stupid ------------'s.
* Indent case labels on the same column where switch begins
* other minor CS tweaks not worth mentioning
Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Cc: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 32321137
/* /*
Copyright (C) 1996 Digi International. Copyright (C) 1996 Digi International.
For technical support please email digiLinux@dgii.com or For technical support please email digiLinux@dgii.com or
...@@ -25,11 +23,9 @@ ...@@ -25,11 +23,9 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
--------------------------------------------------------------------------- */
/* See README.epca for change history --DAT*/ /* See README.epca for change history --DAT*/
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -54,12 +50,9 @@ ...@@ -54,12 +50,9 @@
#include "epca.h" #include "epca.h"
#include "epcaconfig.h" #include "epcaconfig.h"
/* ---------------------- Begin defines ------------------------ */
#define VERSION "1.3.0.1-LK2.6" #define VERSION "1.3.0.1-LK2.6"
/* This major needs to be submitted to Linux to join the majors list */ /* This major needs to be submitted to Linux to join the majors list */
#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */ #define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
...@@ -68,60 +61,48 @@ ...@@ -68,60 +61,48 @@
#define PFX "epca: " #define PFX "epca: "
/* ----------------- Begin global definitions ------------------- */
static int nbdevs, num_cards, liloconfig; static int nbdevs, num_cards, liloconfig;
static int digi_poller_inhibited = 1 ; static int digi_poller_inhibited = 1 ;
static int setup_error_code; static int setup_error_code;
static int invalid_lilo_config; static int invalid_lilo_config;
/* The ISA boards do window flipping into the same spaces so its only sane /*
with a single lock. It's still pretty efficient */ * The ISA boards do window flipping into the same spaces so its only sane with
* a single lock. It's still pretty efficient.
*/
static DEFINE_SPINLOCK(epca_lock); static DEFINE_SPINLOCK(epca_lock);
/* ----------------------------------------------------------------------- /* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
7 below.
--------------------------------------------------------------------------*/
static struct board_info boards[MAXBOARDS]; static struct board_info boards[MAXBOARDS];
/* ------------- Begin structures used for driver registeration ---------- */
static struct tty_driver *pc_driver; static struct tty_driver *pc_driver;
static struct tty_driver *pc_info; static struct tty_driver *pc_info;
/* ------------------ Begin Digi specific structures -------------------- */ /* ------------------ Begin Digi specific structures -------------------- */
/* ------------------------------------------------------------------------ /*
digi_channels represents an array of structures that keep track of * digi_channels represents an array of structures that keep track of each
each channel of the Digi product. Information such as transmit and * channel of the Digi product. Information such as transmit and receive
receive pointers, termio data, and signal definitions (DTR, CTS, etc ...) * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
are stored here. This structure is NOT used to overlay the cards * here. This structure is NOT used to overlay the cards physical channel
physical channel structure. * structure.
-------------------------------------------------------------------------- */ */
static struct channel digi_channels[MAX_ALLOC]; static struct channel digi_channels[MAX_ALLOC];
/* ------------------------------------------------------------------------ /*
card_ptr is an array used to hold the address of the * card_ptr is an array used to hold the address of the first channel structure
first channel structure of each card. This array will hold * of each card. This array will hold the addresses of various channels located
the addresses of various channels located in digi_channels. * in digi_channels.
-------------------------------------------------------------------------- */ */
static struct channel *card_ptr[MAXCARDS]; static struct channel *card_ptr[MAXCARDS];
static struct timer_list epca_timer; static struct timer_list epca_timer;
/* ---------------------- Begin function prototypes --------------------- */ /*
* Begin generic memory functions. These functions will be alias (point at)
/* ---------------------------------------------------------------------- * more specific functions dependent on the board being configured.
Begin generic memory functions. These functions will be alias */
(point at) more specific functions dependent on the board being
configured.
----------------------------------------------------------------------- */
static void memwinon(struct board_info *b, unsigned int win); static void memwinon(struct board_info *b, unsigned int win);
static void memwinoff(struct board_info *b, unsigned int win); static void memwinoff(struct board_info *b, unsigned int win);
static void globalwinon(struct channel *ch); static void globalwinon(struct channel *ch);
...@@ -170,8 +151,6 @@ static void dummy_memoff(struct channel *ch); ...@@ -170,8 +151,6 @@ static void dummy_memoff(struct channel *ch);
static void dummy_assertgwinon(struct channel *ch); static void dummy_assertgwinon(struct channel *ch);
static void dummy_assertmemoff(struct channel *ch); static void dummy_assertmemoff(struct channel *ch);
/* ------------------- Begin declare functions ----------------------- */
static struct channel *verifyChannel(struct tty_struct *); static struct channel *verifyChannel(struct tty_struct *);
static void pc_sched_event(struct channel *, int); static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *); static void epca_error(int, char *);
...@@ -213,62 +192,55 @@ static int pc_write(struct tty_struct *, const unsigned char *, int); ...@@ -213,62 +192,55 @@ static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void); static int pc_init(void);
static int init_PCI(void); static int init_PCI(void);
/*
/* ------------------------------------------------------------------ * Table of functions for each board to handle memory. Mantaining parallelism
Table of functions for each board to handle memory. Mantaining * is a *very* good idea here. The idea is for the runtime code to blindly call
parallelism is a *very* good idea here. The idea is for the * these functions, not knowing/caring about the underlying hardware. This
runtime code to blindly call these functions, not knowing/caring * stuff should contain no conditionals; if more functionality is needed a
about the underlying hardware. This stuff should contain no * different entry should be established. These calls are the interface calls
conditionals; if more functionality is needed a different entry * and are the only functions that should be accessed. Anyone caught making
should be established. These calls are the interface calls and * direct calls deserves what they get.
are the only functions that should be accessed. Anyone caught */
making direct calls deserves what they get.
-------------------------------------------------------------------- */
static void memwinon(struct board_info *b, unsigned int win) static void memwinon(struct board_info *b, unsigned int win)
{ {
(b->memwinon)(b, win); b->memwinon(b, win);
} }
static void memwinoff(struct board_info *b, unsigned int win) static void memwinoff(struct board_info *b, unsigned int win)
{ {
(b->memwinoff)(b, win); b->memwinoff(b, win);
} }
static void globalwinon(struct channel *ch) static void globalwinon(struct channel *ch)
{ {
(ch->board->globalwinon)(ch); ch->board->globalwinon(ch);
} }
static void rxwinon(struct channel *ch) static void rxwinon(struct channel *ch)
{ {
(ch->board->rxwinon)(ch); ch->board->rxwinon(ch);
} }
static void txwinon(struct channel *ch) static void txwinon(struct channel *ch)
{ {
(ch->board->txwinon)(ch); ch->board->txwinon(ch);
} }
static void memoff(struct channel *ch) static void memoff(struct channel *ch)
{ {
(ch->board->memoff)(ch); ch->board->memoff(ch);
} }
static void assertgwinon(struct channel *ch) static void assertgwinon(struct channel *ch)
{ {
(ch->board->assertgwinon)(ch); ch->board->assertgwinon(ch);
} }
static void assertmemoff(struct channel *ch) static void assertmemoff(struct channel *ch)
{ {
(ch->board->assertmemoff)(ch); ch->board->assertmemoff(ch);
} }
/* --------------------------------------------------------- /* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
PCXEM windowing is the same as that used in the PCXR
and CX series cards.
------------------------------------------------------------ */
static void pcxem_memwinon(struct board_info *b, unsigned int win) static void pcxem_memwinon(struct board_info *b, unsigned int win)
{ {
outb_p(FEPWIN|win, b->port + 1); outb_p(FEPWIN|win, b->port + 1);
...@@ -300,7 +272,6 @@ static void pcxem_memoff(struct channel *ch) ...@@ -300,7 +272,6 @@ static void pcxem_memoff(struct channel *ch)
} }
/* ----------------- Begin pcxe memory window stuff ------------------ */ /* ----------------- Begin pcxe memory window stuff ------------------ */
static void pcxe_memwinon(struct board_info *b, unsigned int win) static void pcxe_memwinon(struct board_info *b, unsigned int win)
{ {
outb_p(FEPWIN | win, b->port + 1); outb_p(FEPWIN | win, b->port + 1);
...@@ -308,14 +279,13 @@ static void pcxe_memwinon(struct board_info *b, unsigned int win) ...@@ -308,14 +279,13 @@ static void pcxe_memwinon(struct board_info *b, unsigned int win)
static void pcxe_memwinoff(struct board_info *b, unsigned int win) static void pcxe_memwinoff(struct board_info *b, unsigned int win)
{ {
outb_p(inb(b->port) & ~FEPMEM, outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
b->port + 1);
outb_p(0, b->port + 1); outb_p(0, b->port + 1);
} }
static void pcxe_globalwinon(struct channel *ch) static void pcxe_globalwinon(struct channel *ch)
{ {
outb_p( FEPWIN, (int)ch->board->port + 1); outb_p(FEPWIN, (int)ch->board->port + 1);
} }
static void pcxe_rxwinon(struct channel *ch) static void pcxe_rxwinon(struct channel *ch)
...@@ -335,7 +305,6 @@ static void pcxe_memoff(struct channel *ch) ...@@ -335,7 +305,6 @@ static void pcxe_memoff(struct channel *ch)
} }
/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */ /* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
static void pcxi_memwinon(struct board_info *b, unsigned int win) static void pcxi_memwinon(struct board_info *b, unsigned int win)
{ {
outb_p(inb(b->port) | FEPMEM, b->port); outb_p(inb(b->port) | FEPMEM, b->port);
...@@ -376,16 +345,13 @@ static void pcxi_assertmemoff(struct channel *ch) ...@@ -376,16 +345,13 @@ static void pcxi_assertmemoff(struct channel *ch)
epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on"); epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
} }
/*
/* ---------------------------------------------------------------------- * Not all of the cards need specific memory windowing routines. Some cards
Not all of the cards need specific memory windowing routines. Some * (Such as PCI) needs no windowing routines at all. We provide these do
cards (Such as PCI) needs no windowing routines at all. We provide * nothing routines so that the same code base can be used. The driver will
these do nothing routines so that the same code base can be used. * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
The driver will ALWAYS call a windowing routine if it thinks it needs * card. However, dependent on the card the routine may or may not do anything.
to; regardless of the card. However, dependent on the card the routine */
may or may not do anything.
---------------------------------------------------------------------------*/
static void dummy_memwinon(struct board_info *b, unsigned int win) static void dummy_memwinon(struct board_info *b, unsigned int win)
{ {
} }
...@@ -418,15 +384,14 @@ static void dummy_assertmemoff(struct channel *ch) ...@@ -418,15 +384,14 @@ static void dummy_assertmemoff(struct channel *ch)
{ {
} }
/* ----------------- Begin verifyChannel function ----------------------- */
static struct channel *verifyChannel(struct tty_struct *tty) static struct channel *verifyChannel(struct tty_struct *tty)
{ /* Begin verifyChannel */ {
/* -------------------------------------------------------------------- /*
This routine basically provides a sanity check. It insures that * This routine basically provides a sanity check. It insures that the
the channel returned is within the proper range of addresses as * channel returned is within the proper range of addresses as well as
well as properly initialized. If some bogus info gets passed in * properly initialized. If some bogus info gets passed in
through tty->driver_data this should catch it. * through tty->driver_data this should catch it.
--------------------------------------------------------------------- */ */
if (tty) { if (tty) {
struct channel *ch = (struct channel *)tty->driver_data; struct channel *ch = (struct channel *)tty->driver_data;
if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) { if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
...@@ -435,62 +400,55 @@ static struct channel *verifyChannel(struct tty_struct *tty) ...@@ -435,62 +400,55 @@ static struct channel *verifyChannel(struct tty_struct *tty)
} }
} }
return NULL; return NULL;
}
} /* End verifyChannel */
/* ------------------ Begin pc_sched_event ------------------------- */
static void pc_sched_event(struct channel *ch, int event) static void pc_sched_event(struct channel *ch, int event)
{ {
/* ---------------------------------------------------------------------- /*
We call this to schedule interrupt processing on some event. The * We call this to schedule interrupt processing on some event. The
kernel sees our request and calls the related routine in OUR driver. * kernel sees our request and calls the related routine in OUR driver.
-------------------------------------------------------------------------*/ */
ch->event |= 1 << event; ch->event |= 1 << event;
schedule_work(&ch->tqueue); schedule_work(&ch->tqueue);
} /* End pc_sched_event */ }
/* ------------------ Begin epca_error ------------------------- */
static void epca_error(int line, char *msg) static void epca_error(int line, char *msg)
{ {
printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg); printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
} }
/* ------------------ Begin pc_close ------------------------- */ static void pc_close(struct tty_struct *tty, struct file *filp)
static void pc_close(struct tty_struct * tty, struct file * filp)
{ {
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) { if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
return; return;
} }
/* Check to see if the channel is open more than once */
if (ch->count-- > 1) { if (ch->count-- > 1) {
/* Begin channel is open more than once */ /* Begin channel is open more than once */
/* ------------------------------------------------------------- /*
Return without doing anything. Someone might still be using * Return without doing anything. Someone might still
the channel. * be using the channel.
---------------------------------------------------------------- */ */
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
return; return;
} /* End channel is open more than once */ }
/* Port open only once go ahead with shutdown & reset */ /* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->count < 0); BUG_ON(ch->count < 0);
/* --------------------------------------------------------------- /*
Let the rest of the driver know the channel is being closed. * Let the rest of the driver know the channel is being closed.
This becomes important if an open is attempted before close * This becomes important if an open is attempted before close
is finished. * is finished.
------------------------------------------------------------------ */ */
ch->asyncflags |= ASYNC_CLOSING; ch->asyncflags |= ASYNC_CLOSING;
tty->closing = 1; tty->closing = 1;
...@@ -513,22 +471,19 @@ static void pc_close(struct tty_struct * tty, struct file * filp) ...@@ -513,22 +471,19 @@ static void pc_close(struct tty_struct * tty, struct file * filp)
ch->tty = NULL; ch->tty = NULL;
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
if (ch->blocked_open) { /* Begin if blocked_open */ if (ch->blocked_open) {
if (ch->close_delay) if (ch->close_delay)
msleep_interruptible(jiffies_to_msecs(ch->close_delay)); msleep_interruptible(jiffies_to_msecs(ch->close_delay));
wake_up_interruptible(&ch->open_wait); wake_up_interruptible(&ch->open_wait);
} /* End if blocked_open */ }
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING); ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait); wake_up_interruptible(&ch->close_wait);
} /* End if ch != NULL */ }
} /* End pc_close */ }
/* ------------------ Begin shutdown ------------------------- */
static void shutdown(struct channel *ch) static void shutdown(struct channel *ch)
{ /* Begin shutdown */ {
unsigned long flags; unsigned long flags;
struct tty_struct *tty; struct tty_struct *tty;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
...@@ -541,50 +496,40 @@ static void shutdown(struct channel *ch) ...@@ -541,50 +496,40 @@ static void shutdown(struct channel *ch)
globalwinon(ch); globalwinon(ch);
bc = ch->brdchan; bc = ch->brdchan;
/* ------------------------------------------------------------------ /*
In order for an event to be generated on the receipt of data the * In order for an event to be generated on the receipt of data the
idata flag must be set. Since we are shutting down, this is not * idata flag must be set. Since we are shutting down, this is not
necessary clear this flag. * necessary clear this flag.
--------------------------------------------------------------------- */ */
if (bc) if (bc)
writeb(0, &bc->idata); writeb(0, &bc->idata);
tty = ch->tty; tty = ch->tty;
/* ---------------------------------------------------------------- /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
If we're a modem control device and HUPCL is on, drop RTS & DTR.
------------------------------------------------------------------ */
if (tty->termios->c_cflag & HUPCL) { if (tty->termios->c_cflag & HUPCL) {
ch->omodem &= ~(ch->m_rts | ch->m_dtr); ch->omodem &= ~(ch->m_rts | ch->m_dtr);
fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1); fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
} }
memoff(ch); memoff(ch);
/* ------------------------------------------------------------------ /*
The channel has officialy been closed. The next time it is opened * The channel has officialy been closed. The next time it is opened it
it will have to reinitialized. Set a flag to indicate this. * will have to reinitialized. Set a flag to indicate this.
---------------------------------------------------------------------- */ */
/* Prevent future Digi programmed interrupts from coming active */ /* Prevent future Digi programmed interrupts from coming active */
ch->asyncflags &= ~ASYNC_INITIALIZED; ch->asyncflags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
}
} /* End shutdown */
/* ------------------ Begin pc_hangup ------------------------- */
static void pc_hangup(struct tty_struct *tty) static void pc_hangup(struct tty_struct *tty)
{ /* Begin pc_hangup */ {
struct channel *ch; struct channel *ch;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) {
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
unsigned long flags; unsigned long flags;
if (tty->driver->flush_buffer) if (tty->driver->flush_buffer)
...@@ -599,15 +544,12 @@ static void pc_hangup(struct tty_struct *tty) ...@@ -599,15 +544,12 @@ static void pc_hangup(struct tty_struct *tty)
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->open_wait); wake_up_interruptible(&ch->open_wait);
} /* End if ch != NULL */ }
}
} /* End pc_hangup */
/* ------------------ Begin pc_write ------------------------- */
static int pc_write(struct tty_struct * tty, static int pc_write(struct tty_struct *tty,
const unsigned char *buf, int bytesAvailable) const unsigned char *buf, int bytesAvailable)
{ /* Begin pc_write */ {
unsigned int head, tail; unsigned int head, tail;
int dataLen; int dataLen;
int size; int size;
...@@ -617,25 +559,23 @@ static int pc_write(struct tty_struct * tty, ...@@ -617,25 +559,23 @@ static int pc_write(struct tty_struct * tty,
int remain; int remain;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
/* ---------------------------------------------------------------- /*
pc_write is primarily called directly by the kernel routine * pc_write is primarily called directly by the kernel routine
tty_write (Though it can also be called by put_char) found in * tty_write (Though it can also be called by put_char) found in
tty_io.c. pc_write is passed a line discipline buffer where * tty_io.c. pc_write is passed a line discipline buffer where the data
the data to be written out is stored. The line discipline * to be written out is stored. The line discipline implementation
implementation itself is done at the kernel level and is not * itself is done at the kernel level and is not brought into the
brought into the driver. * driver.
------------------------------------------------------------------- */ */
/* ---------------------------------------------------------
verifyChannel returns the channel from the tty struct
if it is valid. This serves as a sanity check.
------------------------------------------------------------- */
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
if ((ch = verifyChannel(tty)) == NULL) if ((ch = verifyChannel(tty)) == NULL)
return 0; return 0;
/* Make a pointer to the channel data structure found on the board. */ /* Make a pointer to the channel data structure found on the board. */
bc = ch->brdchan; bc = ch->brdchan;
size = ch->txbufsize; size = ch->txbufsize;
amountCopied = 0; amountCopied = 0;
...@@ -650,37 +590,36 @@ static int pc_write(struct tty_struct * tty, ...@@ -650,37 +590,36 @@ static int pc_write(struct tty_struct * tty,
tail = readw(&bc->tout); tail = readw(&bc->tout);
tail &= (size - 1); tail &= (size - 1);
/* If head >= tail, head has not wrapped around. */ if (head >= tail) {
if (head >= tail) { /* Begin head has not wrapped */ /* head has not wrapped */
/* --------------------------------------------------------------- /*
remain (much like dataLen above) represents the total amount of * remain (much like dataLen above) represents the total amount
space available on the card for data. Here dataLen represents * of space available on the card for data. Here dataLen
the space existing between the head pointer and the end of * represents the space existing between the head pointer and
buffer. This is important because a memcpy cannot be told to * the end of buffer. This is important because a memcpy cannot
automatically wrap around when it hits the buffer end. * be told to automatically wrap around when it hits the buffer
------------------------------------------------------------------ */ * end.
*/
dataLen = size - head; dataLen = size - head;
remain = size - (head - tail) - 1; remain = size - (head - tail) - 1;
} else { /* Begin head has wrapped around */ } else {
/* head has wrapped around */
remain = tail - head - 1; remain = tail - head - 1;
dataLen = remain; dataLen = remain;
}
} /* End head has wrapped around */ /*
/* ------------------------------------------------------------------- * Check the space on the card. If we have more data than space; reduce
Check the space on the card. If we have more data than * the amount of data to fit the space.
space; reduce the amount of data to fit the space. */
---------------------------------------------------------------------- */
bytesAvailable = min(remain, bytesAvailable); bytesAvailable = min(remain, bytesAvailable);
txwinon(ch); txwinon(ch);
while (bytesAvailable > 0) while (bytesAvailable > 0) {
{ /* Begin while there is data to copy onto card */ /* there is data to copy onto card */
/* -----------------------------------------------------------------
If head is not wrapped, the below will make sure the first
data copy fills to the end of card buffer.
------------------------------------------------------------------- */
/*
* If head is not wrapped, the below will make sure the first
* data copy fills to the end of card buffer.
*/
dataLen = min(bytesAvailable, dataLen); dataLen = min(bytesAvailable, dataLen);
memcpy_toio(ch->txptr + head, buf, dataLen); memcpy_toio(ch->txptr + head, buf, dataLen);
buf += dataLen; buf += dataLen;
...@@ -692,7 +631,7 @@ static int pc_write(struct tty_struct * tty, ...@@ -692,7 +631,7 @@ static int pc_write(struct tty_struct * tty,
head = 0; head = 0;
dataLen = tail; dataLen = tail;
} }
} /* End while there is data to copy onto card */ }
ch->statusflags |= TXBUSY; ch->statusflags |= TXBUSY;
globalwinon(ch); globalwinon(ch);
writew(head, &bc->tin); writew(head, &bc->tin);
...@@ -703,22 +642,16 @@ static int pc_write(struct tty_struct * tty, ...@@ -703,22 +642,16 @@ static int pc_write(struct tty_struct * tty,
} }
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
return(amountCopied); return amountCopied;
}
} /* End pc_write */
/* ------------------ Begin pc_put_char ------------------------- */
static void pc_put_char(struct tty_struct *tty, unsigned char c) static void pc_put_char(struct tty_struct *tty, unsigned char c)
{ /* Begin pc_put_char */ {
pc_write(tty, &c, 1); pc_write(tty, &c, 1);
} /* End pc_put_char */ }
/* ------------------ Begin pc_write_room ------------------------- */
static int pc_write_room(struct tty_struct *tty) static int pc_write_room(struct tty_struct *tty)
{ /* Begin pc_write_room */ {
int remain; int remain;
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
...@@ -727,11 +660,10 @@ static int pc_write_room(struct tty_struct *tty) ...@@ -727,11 +660,10 @@ static int pc_write_room(struct tty_struct *tty)
remain = 0; remain = 0;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch); globalwinon(ch);
...@@ -757,14 +689,10 @@ static int pc_write_room(struct tty_struct *tty) ...@@ -757,14 +689,10 @@ static int pc_write_room(struct tty_struct *tty)
} }
/* Return how much room is left on card */ /* Return how much room is left on card */
return remain; return remain;
}
} /* End pc_write_room */
/* ------------------ Begin pc_chars_in_buffer ---------------------- */
static int pc_chars_in_buffer(struct tty_struct *tty) static int pc_chars_in_buffer(struct tty_struct *tty)
{ /* Begin pc_chars_in_buffer */ {
int chars; int chars;
unsigned int ctail, head, tail; unsigned int ctail, head, tail;
int remain; int remain;
...@@ -772,13 +700,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty) ...@@ -772,13 +700,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
struct channel *ch; struct channel *ch;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) == NULL) if ((ch = verifyChannel(tty)) == NULL)
return(0); return 0;
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch); globalwinon(ch);
...@@ -793,45 +720,40 @@ static int pc_chars_in_buffer(struct tty_struct *tty) ...@@ -793,45 +720,40 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
else { /* Begin if some space on the card has been used */ else { /* Begin if some space on the card has been used */
head = readw(&bc->tin) & (ch->txbufsize - 1); head = readw(&bc->tin) & (ch->txbufsize - 1);
tail &= (ch->txbufsize - 1); tail &= (ch->txbufsize - 1);
/* -------------------------------------------------------------- /*
The logic here is basically opposite of the above pc_write_room * The logic here is basically opposite of the above
here we are finding the amount of bytes in the buffer filled. * pc_write_room here we are finding the amount of bytes in the
Not the amount of bytes empty. * buffer filled. Not the amount of bytes empty.
------------------------------------------------------------------- */ */
if ((remain = tail - head - 1) < 0 ) if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize; remain += ch->txbufsize;
chars = (int)(ch->txbufsize - remain); chars = (int)(ch->txbufsize - remain);
/* ------------------------------------------------------------- /*
Make it possible to wakeup anything waiting for output * Make it possible to wakeup anything waiting for output in
in tty_ioctl.c, etc. * tty_ioctl.c, etc.
*
If not already set. Setup an event to indicate when the * If not already set. Setup an event to indicate when the
transmit buffer empties * transmit buffer empties.
----------------------------------------------------------------- */ */
if (!(ch->statusflags & EMPTYWAIT)) if (!(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch); setup_empty_event(tty,ch);
} /* End if some space on the card has been used */ } /* End if some space on the card has been used */
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
/* Return number of characters residing on card. */ /* Return number of characters residing on card. */
return(chars); return chars;
}
} /* End pc_chars_in_buffer */
/* ------------------ Begin pc_flush_buffer ---------------------- */
static void pc_flush_buffer(struct tty_struct *tty) static void pc_flush_buffer(struct tty_struct *tty)
{ /* Begin pc_flush_buffer */ {
unsigned int tail; unsigned int tail;
unsigned long flags; unsigned long flags;
struct channel *ch; struct channel *ch;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) == NULL) if ((ch = verifyChannel(tty)) == NULL)
return; return;
...@@ -844,35 +766,31 @@ static void pc_flush_buffer(struct tty_struct *tty) ...@@ -844,35 +766,31 @@ static void pc_flush_buffer(struct tty_struct *tty)
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
tty_wakeup(tty); tty_wakeup(tty);
} /* End pc_flush_buffer */ }
/* ------------------ Begin pc_flush_chars ---------------------- */
static void pc_flush_chars(struct tty_struct *tty) static void pc_flush_chars(struct tty_struct *tty)
{ /* Begin pc_flush_chars */ {
struct channel * ch; struct channel *ch;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
/* ---------------------------------------------------------------- /*
If not already set and the transmitter is busy setup an event * If not already set and the transmitter is busy setup an
to indicate when the transmit empties. * event to indicate when the transmit empties.
------------------------------------------------------------------- */ */
if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch); setup_empty_event(tty,ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} }
} /* End pc_flush_chars */ }
/* ------------------ Begin block_til_ready ---------------------- */
static int block_til_ready(struct tty_struct *tty, static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch) struct file *filp, struct channel *ch)
{ /* Begin block_til_ready */ {
DECLARE_WAITQUEUE(wait,current); DECLARE_WAITQUEUE(wait,current);
int retval, do_clocal = 0; int retval, do_clocal = 0;
unsigned long flags; unsigned long flags;
...@@ -882,13 +800,13 @@ static int block_til_ready(struct tty_struct *tty, ...@@ -882,13 +800,13 @@ static int block_til_ready(struct tty_struct *tty,
retval = -EAGAIN; retval = -EAGAIN;
else else
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
return(retval); return retval;
} }
/* ----------------------------------------------------------------- /*
If the device is in the middle of being closed, then block * If the device is in the middle of being closed, then block until
until it's done, and then try again. * it's done, and then try again.
-------------------------------------------------------------------- */ */
if (ch->asyncflags & ASYNC_CLOSING) { if (ch->asyncflags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->close_wait); interruptible_sleep_on(&ch->close_wait);
...@@ -899,10 +817,10 @@ static int block_til_ready(struct tty_struct *tty, ...@@ -899,10 +817,10 @@ static int block_til_ready(struct tty_struct *tty,
} }
if (filp->f_flags & O_NONBLOCK) { if (filp->f_flags & O_NONBLOCK) {
/* ----------------------------------------------------------------- /*
If non-blocking mode is set, then make the check up front * If non-blocking mode is set, then make the check up front
and then exit. * and then exit.
-------------------------------------------------------------------- */ */
ch->asyncflags |= ASYNC_NORMAL_ACTIVE; ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
return 0; return 0;
} }
...@@ -918,8 +836,7 @@ static int block_til_ready(struct tty_struct *tty, ...@@ -918,8 +836,7 @@ static int block_til_ready(struct tty_struct *tty,
if (!tty_hung_up_p(filp)) if (!tty_hung_up_p(filp))
ch->count--; ch->count--;
ch->blocked_open++; ch->blocked_open++;
while(1) while (1) {
{ /* Begin forever while */
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || if (tty_hung_up_p(filp) ||
!(ch->asyncflags & ASYNC_INITIALIZED)) !(ch->asyncflags & ASYNC_INITIALIZED))
...@@ -938,16 +855,15 @@ static int block_til_ready(struct tty_struct *tty, ...@@ -938,16 +855,15 @@ static int block_til_ready(struct tty_struct *tty,
break; break;
} }
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
/* --------------------------------------------------------------- /*
Allow someone else to be scheduled. We will occasionally go * Allow someone else to be scheduled. We will occasionally go
through this loop until one of the above conditions change. * through this loop until one of the above conditions change.
The below schedule call will allow other processes to enter and * The below schedule call will allow other processes to enter
prevent this loop from hogging the cpu. * and prevent this loop from hogging the cpu.
------------------------------------------------------------------ */ */
schedule(); schedule();
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
}
} /* End forever while */
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->open_wait, &wait); remove_wait_queue(&ch->open_wait, &wait);
...@@ -962,13 +878,10 @@ static int block_til_ready(struct tty_struct *tty, ...@@ -962,13 +878,10 @@ static int block_til_ready(struct tty_struct *tty,
ch->asyncflags |= ASYNC_NORMAL_ACTIVE; ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
return 0; return 0;
} /* End block_til_ready */ }
/* ------------------ Begin pc_open ---------------------- */
static int pc_open(struct tty_struct *tty, struct file * filp) static int pc_open(struct tty_struct *tty, struct file * filp)
{ /* Begin pc_open */ {
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
int line, retval, boardnum; int line, retval, boardnum;
...@@ -984,12 +897,11 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ...@@ -984,12 +897,11 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
/* Check status of board configured in system. */ /* Check status of board configured in system. */
/* ----------------------------------------------------------------- /*
I check to see if the epca_setup routine detected an user error. * I check to see if the epca_setup routine detected an user error. It
It might be better to put this in pc_init, but for the moment it * might be better to put this in pc_init, but for the moment it goes
goes here. * here.
---------------------------------------------------------------------- */ */
if (invalid_lilo_config) { if (invalid_lilo_config) {
if (setup_error_code & INVALID_BOARD_TYPE) if (setup_error_code & INVALID_BOARD_TYPE)
printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n"); printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
...@@ -1017,42 +929,41 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ...@@ -1017,42 +929,41 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
} }
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
/* ------------------------------------------------------------------ /*
Every time a channel is opened, increment a counter. This is * Every time a channel is opened, increment a counter. This is
necessary because we do not wish to flush and shutdown the channel * necessary because we do not wish to flush and shutdown the channel
until the last app holding the channel open, closes it. * until the last app holding the channel open, closes it.
--------------------------------------------------------------------- */ */
ch->count++; ch->count++;
/* ---------------------------------------------------------------- /*
Set a kernel structures pointer to our local channel * Set a kernel structures pointer to our local channel structure. This
structure. This way we can get to it when passed only * way we can get to it when passed only a tty struct.
a tty struct. */
------------------------------------------------------------------ */
tty->driver_data = ch; tty->driver_data = ch;
/* ---------------------------------------------------------------- /*
If this is the first time the channel has been opened, initialize * If this is the first time the channel has been opened, initialize
the tty->termios struct otherwise let pc_close handle it. * the tty->termios struct otherwise let pc_close handle it.
-------------------------------------------------------------------- */ */
globalwinon(ch); globalwinon(ch);
ch->statusflags = 0; ch->statusflags = 0;
/* Save boards current modem status */ /* Save boards current modem status */
ch->imodem = readb(&bc->mstat); ch->imodem = readb(&bc->mstat);
/* ---------------------------------------------------------------- /*
Set receive head and tail ptrs to each other. This indicates * Set receive head and tail ptrs to each other. This indicates no data
no data available to read. * available to read.
----------------------------------------------------------------- */ */
head = readw(&bc->rin); head = readw(&bc->rin);
writew(head, &bc->rout); writew(head, &bc->rout);
/* Set the channels associated tty structure */ /* Set the channels associated tty structure */
ch->tty = tty; ch->tty = tty;
/* ----------------------------------------------------------------- /*
The below routine generally sets up parity, baud, flow control * The below routine generally sets up parity, baud, flow control
issues, etc.... It effect both control flags and input flags. * issues, etc.... It effect both control flags and input flags.
-------------------------------------------------------------------- */ */
epcaparam(tty,ch); epcaparam(tty,ch);
ch->asyncflags |= ASYNC_INITIALIZED; ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch); memoff(ch);
...@@ -1061,10 +972,10 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ...@@ -1061,10 +972,10 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
retval = block_til_ready(tty, filp, ch); retval = block_til_ready(tty, filp, ch);
if (retval) if (retval)
return retval; return retval;
/* ------------------------------------------------------------- /*
Set this again in case a hangup set it to zero while this * Set this again in case a hangup set it to zero while this open() was
open() was waiting for the line... * waiting for the line...
--------------------------------------------------------------- */ */
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
ch->tty = tty; ch->tty = tty;
globalwinon(ch); globalwinon(ch);
...@@ -1073,13 +984,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ...@@ -1073,13 +984,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
return 0; return 0;
} /* End pc_open */ }
static int __init epca_module_init(void) static int __init epca_module_init(void)
{ /* Begin init_module */ {
return pc_init(); return pc_init();
} }
module_init(epca_module_init); module_init(epca_module_init);
static struct pci_driver epca_driver; static struct pci_driver epca_driver;
...@@ -1092,8 +1002,7 @@ static void __exit epca_module_exit(void) ...@@ -1092,8 +1002,7 @@ static void __exit epca_module_exit(void)
del_timer_sync(&epca_timer); del_timer_sync(&epca_timer);
if ((tty_unregister_driver(pc_driver)) || if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
(tty_unregister_driver(pc_info)))
{ {
printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n"); printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return; return;
...@@ -1101,23 +1010,20 @@ static void __exit epca_module_exit(void) ...@@ -1101,23 +1010,20 @@ static void __exit epca_module_exit(void)
put_tty_driver(pc_driver); put_tty_driver(pc_driver);
put_tty_driver(pc_info); put_tty_driver(pc_info);
for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */ for (crd = 0; crd < num_cards; crd++) {
bd = &boards[crd]; bd = &boards[crd];
if (!bd) if (!bd) { /* sanity check */
{ /* Begin sanity check */
printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n"); printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
return; return;
} /* End sanity check */ }
ch = card_ptr[crd]; ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++) for (count = 0; count < bd->numports; count++, ch++) {
{ /* Begin for each port */
if (ch && ch->tty) if (ch && ch->tty)
tty_hangup(ch->tty); tty_hangup(ch->tty);
} /* End for each port */ }
} /* End for each card */ }
pci_unregister_driver (&epca_driver); pci_unregister_driver(&epca_driver);
} }
module_exit(epca_module_exit); module_exit(epca_module_exit);
static const struct tty_operations pc_ops = { static const struct tty_operations pc_ops = {
...@@ -1148,10 +1054,8 @@ static struct tty_operations info_ops = { ...@@ -1148,10 +1054,8 @@ static struct tty_operations info_ops = {
.ioctl = info_ioctl, .ioctl = info_ioctl,
}; };
/* ------------------ Begin pc_init ---------------------- */
static int __init pc_init(void) static int __init pc_init(void)
{ /* Begin pc_init */ {
int crd; int crd;
struct board_info *bd; struct board_info *bd;
unsigned char board_id = 0; unsigned char board_id = 0;
...@@ -1169,57 +1073,51 @@ static int __init pc_init(void) ...@@ -1169,57 +1073,51 @@ static int __init pc_init(void)
if (!pc_info) if (!pc_info)
goto out2; goto out2;
/* ----------------------------------------------------------------------- /*
If epca_setup has not been ran by LILO set num_cards to defaults; copy * If epca_setup has not been ran by LILO set num_cards to defaults;
board structure defined by digiConfig into drivers board structure. * copy board structure defined by digiConfig into drivers board
Note : If LILO has ran epca_setup then epca_setup will handle defining * structure. Note : If LILO has ran epca_setup then epca_setup will
num_cards as well as copying the data into the board structure. * handle defining num_cards as well as copying the data into the board
-------------------------------------------------------------------------- */ * structure.
if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */ */
if (!liloconfig) {
/* driver has been configured via. epcaconfig */
nbdevs = NBDEVS; nbdevs = NBDEVS;
num_cards = NUMCARDS; num_cards = NUMCARDS;
memcpy((void *)&boards, (void *)&static_boards, memcpy(&boards, &static_boards,
(sizeof(struct board_info) * NUMCARDS)); sizeof(struct board_info) * NUMCARDS);
} /* End driver has been configured via. epcaconfig */ }
/* -----------------------------------------------------------------
Note : If lilo was used to configure the driver and the
ignore epcaconfig option was choosen (digiepca=2) then
nbdevs and num_cards will equal 0 at this point. This is
okay; PCI cards will still be picked up if detected.
--------------------------------------------------------------------- */
/* -----------------------------------------------------------
Set up interrupt, we will worry about memory allocation in
post_fep_init.
--------------------------------------------------------------- */
/*
* Note : If lilo was used to configure the driver and the ignore
* epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
* will equal 0 at this point. This is okay; PCI cards will still be
* picked up if detected.
*/
/*
* Set up interrupt, we will worry about memory allocation in
* post_fep_init.
*/
printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
/* ------------------------------------------------------------------ /*
NOTE : This code assumes that the number of ports found in * NOTE : This code assumes that the number of ports found in the
the boards array is correct. This could be wrong if * boards array is correct. This could be wrong if the card in question
the card in question is PCI (And therefore has no ports * is PCI (And therefore has no ports entry in the boards structure.)
entry in the boards structure.) The rest of the * The rest of the information will be valid for PCI because the
information will be valid for PCI because the beginning * beginning of pc_init scans for PCI and determines i/o and base
of pc_init scans for PCI and determines i/o and base * memory addresses. I am not sure if it is possible to read the number
memory addresses. I am not sure if it is possible to * of ports supported by the card prior to it being booted (Since that
read the number of ports supported by the card prior to * is the state it is in when pc_init is run). Because it is not
it being booted (Since that is the state it is in when * possible to query the number of supported ports until after the card
pc_init is run). Because it is not possible to query the * has booted; we are required to calculate the card_ptrs as the card
number of supported ports until after the card has booted; * is initialized (Inside post_fep_init). The negative thing about this
we are required to calculate the card_ptrs as the card is * approach is that digiDload's call to GET_INFO will have a bad port
is initialized (Inside post_fep_init). The negative thing * value. (Since this is called prior to post_fep_init.)
about this approach is that digiDload's call to GET_INFO */
will have a bad port value. (Since this is called prior
to post_fep_init.)
--------------------------------------------------------------------- */
pci_boards_found = 0; pci_boards_found = 0;
if(num_cards < MAXBOARDS) if (num_cards < MAXBOARDS)
pci_boards_found += init_PCI(); pci_boards_found += init_PCI();
num_cards += pci_boards_found; num_cards += pci_boards_found;
...@@ -1256,27 +1154,25 @@ static int __init pc_init(void) ...@@ -1256,27 +1154,25 @@ static int __init pc_init(void)
tty_set_operations(pc_info, &info_ops); tty_set_operations(pc_info, &info_ops);
for (crd = 0; crd < num_cards; crd++) for (crd = 0; crd < num_cards; crd++) {
{ /* Begin for each card */ /*
* This is where the appropriate memory handlers for the
/* ------------------------------------------------------------------ * hardware is set. Everything at runtime blindly jumps through
This is where the appropriate memory handlers for the hardware is * these vectors.
set. Everything at runtime blindly jumps through these vectors. */
---------------------------------------------------------------------- */
/* defined in epcaconfig.h */ /* defined in epcaconfig.h */
bd = &boards[crd]; bd = &boards[crd];
switch (bd->type) switch (bd->type) {
{ /* Begin switch on bd->type {board type} */
case PCXEM: case PCXEM:
case EISAXEM: case EISAXEM:
bd->memwinon = pcxem_memwinon ; bd->memwinon = pcxem_memwinon;
bd->memwinoff = pcxem_memwinoff ; bd->memwinoff = pcxem_memwinoff;
bd->globalwinon = pcxem_globalwinon ; bd->globalwinon = pcxem_globalwinon;
bd->txwinon = pcxem_txwinon ; bd->txwinon = pcxem_txwinon;
bd->rxwinon = pcxem_rxwinon ; bd->rxwinon = pcxem_rxwinon;
bd->memoff = pcxem_memoff ; bd->memoff = pcxem_memoff;
bd->assertgwinon = dummy_assertgwinon; bd->assertgwinon = dummy_assertgwinon;
bd->assertmemoff = dummy_assertmemoff; bd->assertmemoff = dummy_assertmemoff;
break; break;
...@@ -1296,7 +1192,6 @@ static int __init pc_init(void) ...@@ -1296,7 +1192,6 @@ static int __init pc_init(void)
case PCXE: case PCXE:
case PCXEVE: case PCXEVE:
bd->memwinon = pcxe_memwinon; bd->memwinon = pcxe_memwinon;
bd->memwinoff = pcxe_memwinoff; bd->memwinoff = pcxe_memwinoff;
bd->globalwinon = pcxe_globalwinon; bd->globalwinon = pcxe_globalwinon;
...@@ -1309,7 +1204,6 @@ static int __init pc_init(void) ...@@ -1309,7 +1204,6 @@ static int __init pc_init(void)
case PCXI: case PCXI:
case PC64XE: case PC64XE:
bd->memwinon = pcxi_memwinon; bd->memwinon = pcxi_memwinon;
bd->memwinoff = pcxi_memwinoff; bd->memwinoff = pcxi_memwinoff;
bd->globalwinon = pcxi_globalwinon; bd->globalwinon = pcxi_globalwinon;
...@@ -1322,21 +1216,16 @@ static int __init pc_init(void) ...@@ -1322,21 +1216,16 @@ static int __init pc_init(void)
default: default:
break; break;
}
} /* End switch on bd->type */ /*
* Some cards need a memory segment to be defined for use in
/* --------------------------------------------------------------- * transmit and receive windowing operations. These boards are
Some cards need a memory segment to be defined for use in * listed in the below switch. In the case of the XI the amount
transmit and receive windowing operations. These boards * of memory on the board is variable so the memory_seg is also
are listed in the below switch. In the case of the XI the * variable. This code determines what they segment should be.
amount of memory on the board is variable so the memory_seg */
is also variable. This code determines what they segment switch (bd->type) {
should be.
----------------------------------------------------------------- */
switch (bd->type)
{ /* Begin switch on bd->type {board type} */
case PCXE: case PCXE:
case PCXEVE: case PCXEVE:
case PC64XE: case PC64XE:
...@@ -1345,9 +1234,8 @@ static int __init pc_init(void) ...@@ -1345,9 +1234,8 @@ static int __init pc_init(void)
case PCXI: case PCXI:
board_id = inb((int)bd->port); board_id = inb((int)bd->port);
if ((board_id & 0x1) == 0x1) if ((board_id & 0x1) == 0x1) {
{ /* Begin it's an XI card */ /* it's an XI card */
/* Is it a 64K board */ /* Is it a 64K board */
if ((board_id & 0x30) == 0) if ((board_id & 0x30) == 0)
bd->memory_seg = 0xf000; bd->memory_seg = 0xf000;
...@@ -1363,13 +1251,11 @@ static int __init pc_init(void) ...@@ -1363,13 +1251,11 @@ static int __init pc_init(void)
/* Is it a 512K board */ /* Is it a 512K board */
if ((board_id & 0x30) == 0x30) if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000; bd->memory_seg = 0x8000;
} else
} else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
break; break;
}
} /* End switch on bd->type */ }
} /* End for each card */
err = tty_register_driver(pc_driver); err = tty_register_driver(pc_driver);
if (err) { if (err) {
...@@ -1383,10 +1269,7 @@ static int __init pc_init(void) ...@@ -1383,10 +1269,7 @@ static int __init pc_init(void)
goto out4; goto out4;
} }
/* ------------------------------------------------------------------- /* Start up the poller to check for events on all enabled boards */
Start up the poller to check for events on all enabled boards
---------------------------------------------------------------------- */
init_timer(&epca_timer); init_timer(&epca_timer);
epca_timer.function = epcapoll; epca_timer.function = epcapoll;
mod_timer(&epca_timer, jiffies + HZ/25); mod_timer(&epca_timer, jiffies + HZ/25);
...@@ -1400,51 +1283,47 @@ static int __init pc_init(void) ...@@ -1400,51 +1283,47 @@ static int __init pc_init(void)
put_tty_driver(pc_driver); put_tty_driver(pc_driver);
out1: out1:
return err; return err;
}
} /* End pc_init */
/* ------------------ Begin post_fep_init ---------------------- */
static void post_fep_init(unsigned int crd) static void post_fep_init(unsigned int crd)
{ /* Begin post_fep_init */ {
int i; int i;
void __iomem *memaddr; void __iomem *memaddr;
struct global_data __iomem *gd; struct global_data __iomem *gd;
struct board_info *bd; struct board_info *bd;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
struct channel *ch; struct channel *ch;
int shrinkmem = 0, lowwater ; int shrinkmem = 0, lowwater;
/* ------------------------------------------------------------- /*
This call is made by the user via. the ioctl call DIGI_INIT. * This call is made by the user via. the ioctl call DIGI_INIT. It is
It is responsible for setting up all the card specific stuff. * responsible for setting up all the card specific stuff.
---------------------------------------------------------------- */ */
bd = &boards[crd]; bd = &boards[crd];
/* ----------------------------------------------------------------- /*
If this is a PCI board, get the port info. Remember PCI cards * If this is a PCI board, get the port info. Remember PCI cards do not
do not have entries into the epcaconfig.h file, so we can't get * have entries into the epcaconfig.h file, so we can't get the number
the number of ports from it. Unfortunetly, this means that anyone * of ports from it. Unfortunetly, this means that anyone doing a
doing a DIGI_GETINFO before the board has booted will get an invalid * DIGI_GETINFO before the board has booted will get an invalid number
number of ports returned (It should return 0). Calls to DIGI_GETINFO * of ports returned (It should return 0). Calls to DIGI_GETINFO after
after DIGI_INIT has been called will return the proper values. * DIGI_INIT has been called will return the proper values.
------------------------------------------------------------------- */ */
if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */ if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
/* -------------------------------------------------------------------- /*
Below we use XEMPORTS as a memory offset regardless of which PCI * Below we use XEMPORTS as a memory offset regardless of which
card it is. This is because all of the supported PCI cards have * PCI card it is. This is because all of the supported PCI
the same memory offset for the channel data. This will have to be * cards have the same memory offset for the channel data. This
changed if we ever develop a PCI/XE card. NOTE : The FEP manual * will have to be changed if we ever develop a PCI/XE card.
states that the port offset is 0xC22 as opposed to 0xC02. This is * NOTE : The FEP manual states that the port offset is 0xC22
only true for PC/XE, and PC/XI cards; not for the XEM, or CX series. * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
On the PCI cards the number of ports is determined by reading a * cards; not for the XEM, or CX series. On the PCI cards the
ID PROM located in the box attached to the card. The card can then * number of ports is determined by reading a ID PROM located
determine the index the id to determine the number of ports available. * in the box attached to the card. The card can then determine
(FYI - The id should be located at 0x1ac (And may use up to 4 bytes * the index the id to determine the number of ports available.
if the box in question is a XEM or CX)). * (FYI - The id should be located at 0x1ac (And may use up to
------------------------------------------------------------------------ */ * 4 bytes if the box in question is a XEM or CX)).
*/
/* PCI cards are already remapped at this point ISA are not */ /* PCI cards are already remapped at this point ISA are not */
bd->numports = readw(bd->re_map_membase + XEMPORTS); bd->numports = readw(bd->re_map_membase + XEMPORTS);
epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
...@@ -1465,28 +1344,24 @@ static void post_fep_init(unsigned int crd) ...@@ -1465,28 +1344,24 @@ static void post_fep_init(unsigned int crd)
memaddr = bd->re_map_membase; memaddr = bd->re_map_membase;
/* ----------------------------------------------------------------- /*
The below assignment will set bc to point at the BEGINING of * The below assignment will set bc to point at the BEGINING of the
the cards channel structures. For 1 card there will be between * cards channel structures. For 1 card there will be between 8 and 64
8 and 64 of these structures. * of these structures.
-------------------------------------------------------------------- */ */
bc = memaddr + CHANSTRUCT; bc = memaddr + CHANSTRUCT;
/* ------------------------------------------------------------------- /*
The below assignment will set gd to point at the BEGINING of * The below assignment will set gd to point at the BEGINING of global
global memory address 0xc00. The first data in that global * memory address 0xc00. The first data in that global memory actually
memory actually starts at address 0xc1a. The command in * starts at address 0xc1a. The command in pointer begins at 0xd10.
pointer begins at 0xd10. */
---------------------------------------------------------------------- */
gd = memaddr + GLOBAL; gd = memaddr + GLOBAL;
/* -------------------------------------------------------------------- /*
XEPORTS (address 0xc22) points at the number of channels the * XEPORTS (address 0xc22) points at the number of channels the card
card supports. (For 64XE, XI, XEM, and XR use 0xc02) * supports. (For 64XE, XI, XEM, and XR use 0xc02)
----------------------------------------------------------------------- */ */
if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3)) if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1; shrinkmem = 1;
if (bd->type < PCIXEM) if (bd->type < PCIXEM)
...@@ -1494,14 +1369,11 @@ static void post_fep_init(unsigned int crd) ...@@ -1494,14 +1369,11 @@ static void post_fep_init(unsigned int crd)
return; return;
memwinon(bd, 0); memwinon(bd, 0);
/* -------------------------------------------------------------------- /*
Remember ch is the main drivers channels structure, while bc is * Remember ch is the main drivers channels structure, while bc is the
the cards channel structure. * cards channel structure.
------------------------------------------------------------------------ */ */
for (i = 0; i < bd->numports; i++, ch++, bc++) {
/* For every port on the card do ..... */
for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */
unsigned long flags; unsigned long flags;
u16 tseg, rseg; u16 tseg, rseg;
...@@ -1512,44 +1384,43 @@ static void post_fep_init(unsigned int crd) ...@@ -1512,44 +1384,43 @@ static void post_fep_init(unsigned int crd)
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
switch (bd->type) { switch (bd->type) {
/* ---------------------------------------------------------------- /*
Since some of the boards use different bitmaps for their * Since some of the boards use different bitmaps for
control signals we cannot hard code these values and retain * their control signals we cannot hard code these
portability. We virtualize this data here. * values and retain portability. We virtualize this
------------------------------------------------------------------- */ * data here.
*/
case EISAXEM: case EISAXEM:
case PCXEM: case PCXEM:
case PCIXEM: case PCIXEM:
case PCIXRJ: case PCIXRJ:
case PCIXR: case PCIXR:
ch->m_rts = 0x02 ; ch->m_rts = 0x02;
ch->m_dcd = 0x80 ; ch->m_dcd = 0x80;
ch->m_dsr = 0x20 ; ch->m_dsr = 0x20;
ch->m_cts = 0x10 ; ch->m_cts = 0x10;
ch->m_ri = 0x40 ; ch->m_ri = 0x40;
ch->m_dtr = 0x01 ; ch->m_dtr = 0x01;
break; break;
case PCXE: case PCXE:
case PCXEVE: case PCXEVE:
case PCXI: case PCXI:
case PC64XE: case PC64XE:
ch->m_rts = 0x02 ; ch->m_rts = 0x02;
ch->m_dcd = 0x08 ; ch->m_dcd = 0x08;
ch->m_dsr = 0x10 ; ch->m_dsr = 0x10;
ch->m_cts = 0x20 ; ch->m_cts = 0x20;
ch->m_ri = 0x40 ; ch->m_ri = 0x40;
ch->m_dtr = 0x80 ; ch->m_dtr = 0x80;
break; break;
}
} /* End switch bd->type */
if (boards[crd].altpin) { if (boards[crd].altpin) {
ch->dsr = ch->m_dcd; ch->dsr = ch->m_dcd;
ch->dcd = ch->m_dsr; ch->dcd = ch->m_dsr;
ch->digiext.digi_flags |= DIGI_ALTPIN; ch->digiext.digi_flags |= DIGI_ALTPIN;
} } else {
else {
ch->dcd = ch->m_dcd; ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr; ch->dsr = ch->m_dsr;
} }
...@@ -1568,7 +1439,6 @@ static void post_fep_init(unsigned int crd) ...@@ -1568,7 +1439,6 @@ static void post_fep_init(unsigned int crd)
rseg = readw(&bc->rseg); rseg = readw(&bc->rseg);
switch (bd->type) { switch (bd->type) {
case PCIXEM: case PCIXEM:
case PCIXRJ: case PCIXRJ:
case PCIXR: case PCIXR:
...@@ -1603,8 +1473,7 @@ static void post_fep_init(unsigned int crd) ...@@ -1603,8 +1473,7 @@ static void post_fep_init(unsigned int crd)
ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4); ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
ch->txwin = ch->rxwin = 0; ch->txwin = ch->rxwin = 0;
break; break;
}
} /* End switch bd->type */
ch->txbufhead = 0; ch->txbufhead = 0;
ch->txbufsize = readw(&bc->tmax) + 1; ch->txbufsize = readw(&bc->tmax) + 1;
...@@ -1618,11 +1487,9 @@ static void post_fep_init(unsigned int crd) ...@@ -1618,11 +1487,9 @@ static void post_fep_init(unsigned int crd)
fepcmd(ch, STXLWATER, lowwater, 0, 10, 0); fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
/* Set receiver low water mark */ /* Set receiver low water mark */
fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0); fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
/* Set receiver high water mark */ /* Set receiver high water mark */
fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0); fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
writew(100, &bc->edelay); writew(100, &bc->edelay);
...@@ -1648,80 +1515,66 @@ static void post_fep_init(unsigned int crd) ...@@ -1648,80 +1515,66 @@ static void post_fep_init(unsigned int crd)
init_waitqueue_head(&ch->close_wait); init_waitqueue_head(&ch->close_wait);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End for each port */ }
printk(KERN_INFO printk(KERN_INFO
"Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
memwinoff(bd, 0); memwinoff(bd, 0);
}
} /* End post_fep_init */
/* --------------------- Begin epcapoll ------------------------ */
static void epcapoll(unsigned long ignored) static void epcapoll(unsigned long ignored)
{ /* Begin epcapoll */ {
unsigned long flags; unsigned long flags;
int crd; int crd;
volatile unsigned int head, tail; volatile unsigned int head, tail;
struct channel *ch; struct channel *ch;
struct board_info *bd; struct board_info *bd;
/* ------------------------------------------------------------------- /*
This routine is called upon every timer interrupt. Even though * This routine is called upon every timer interrupt. Even though the
the Digi series cards are capable of generating interrupts this * Digi series cards are capable of generating interrupts this method
method of non-looping polling is more efficient. This routine * of non-looping polling is more efficient. This routine checks for
checks for card generated events (Such as receive data, are transmit * card generated events (Such as receive data, are transmit buffer
buffer empty) and acts on those events. * empty) and acts on those events.
----------------------------------------------------------------------- */ */
for (crd = 0; crd < num_cards; crd++) {
for (crd = 0; crd < num_cards; crd++)
{ /* Begin for each card */
bd = &boards[crd]; bd = &boards[crd];
ch = card_ptr[crd]; ch = card_ptr[crd];
if ((bd->status == DISABLED) || digi_poller_inhibited) if ((bd->status == DISABLED) || digi_poller_inhibited)
continue; /* Begin loop next interation */ continue;
/* -----------------------------------------------------------
assertmemoff is not needed here; indeed it is an empty subroutine.
It is being kept because future boards may need this as well as
some legacy boards.
---------------------------------------------------------------- */
/*
* assertmemoff is not needed here; indeed it is an empty
* subroutine. It is being kept because future boards may need
* this as well as some legacy boards.
*/
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
assertmemoff(ch); assertmemoff(ch);
globalwinon(ch); globalwinon(ch);
/* --------------------------------------------------------------- /*
In this case head and tail actually refer to the event queue not * In this case head and tail actually refer to the event queue
the transmit or receive queue. * not the transmit or receive queue.
------------------------------------------------------------------- */ */
head = readw(&ch->mailbox->ein); head = readw(&ch->mailbox->ein);
tail = readw(&ch->mailbox->eout); tail = readw(&ch->mailbox->eout);
/* If head isn't equal to tail we have an event */ /* If head isn't equal to tail we have an event */
if (head != tail) if (head != tail)
doevent(crd); doevent(crd);
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End for each card */ } /* End for each card */
mod_timer(&epca_timer, jiffies + (HZ / 25)); mod_timer(&epca_timer, jiffies + (HZ / 25));
} /* End epcapoll */ }
/* --------------------- Begin doevent ------------------------ */
static void doevent(int crd) static void doevent(int crd)
{ /* Begin doevent */ {
void __iomem *eventbuf; void __iomem *eventbuf;
struct channel *ch, *chan0; struct channel *ch, *chan0;
static struct tty_struct *tty; static struct tty_struct *tty;
...@@ -1731,28 +1584,28 @@ static void doevent(int crd) ...@@ -1731,28 +1584,28 @@ static void doevent(int crd)
int event, channel; int event, channel;
int mstat, lstat; int mstat, lstat;
/* ------------------------------------------------------------------- /*
This subroutine is called by epcapoll when an event is detected * This subroutine is called by epcapoll when an event is detected
in the event queue. This routine responds to those events. * in the event queue. This routine responds to those events.
--------------------------------------------------------------------- */ */
bd = &boards[crd]; bd = &boards[crd];
chan0 = card_ptr[crd]; chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range"); epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
assertgwinon(chan0); assertgwinon(chan0);
while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
{ /* Begin while something in event queue */
assertgwinon(chan0); assertgwinon(chan0);
eventbuf = bd->re_map_membase + tail + ISTART; eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */ /* Get the channel the event occurred on */
channel = readb(eventbuf); channel = readb(eventbuf);
/* Get the actual event code that occurred */ /* Get the actual event code that occurred */
event = readb(eventbuf + 1); event = readb(eventbuf + 1);
/* ---------------------------------------------------------------- /*
The two assignments below get the current modem status (mstat) * The two assignments below get the current modem status
and the previous modem status (lstat). These are useful becuase * (mstat) and the previous modem status (lstat). These are
an event could signal a change in modem signals itself. * useful becuase an event could signal a change in modem
------------------------------------------------------------------- */ * signals itself.
*/
mstat = readb(eventbuf + 2); mstat = readb(eventbuf + 2);
lstat = readb(eventbuf + 3); lstat = readb(eventbuf + 3);
...@@ -1772,7 +1625,7 @@ static void doevent(int crd) ...@@ -1772,7 +1625,7 @@ static void doevent(int crd)
assertgwinon(ch); assertgwinon(ch);
} /* End DATA_IND */ } /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */ /* else *//* Fix for DCD transition missed bug */
if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */ if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */ /* A modem signal change has been indicated */
ch->imodem = mstat; ch->imodem = mstat;
if (ch->asyncflags & ASYNC_CHECK_CD) { if (ch->asyncflags & ASYNC_CHECK_CD) {
...@@ -1781,28 +1634,27 @@ static void doevent(int crd) ...@@ -1781,28 +1634,27 @@ static void doevent(int crd)
else else
pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */ pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
} }
} /* End MODEMCHG_IND */ }
tty = ch->tty; tty = ch->tty;
if (tty) { /* Begin if valid tty */ if (tty) {
if (event & BREAK_IND) { /* Begin if BREAK_IND */ if (event & BREAK_IND) {
/* A break has been indicated */ /* A break has been indicated */
tty_insert_flip_char(tty, 0, TTY_BREAK); tty_insert_flip_char(tty, 0, TTY_BREAK);
tty_schedule_flip(tty); tty_schedule_flip(tty);
} else if (event & LOWTX_IND) { /* Begin LOWTX_IND */ } else if (event & LOWTX_IND) {
if (ch->statusflags & LOWWAIT) if (ch->statusflags & LOWWAIT) {
{ /* Begin if LOWWAIT */
ch->statusflags &= ~LOWWAIT; ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty); tty_wakeup(tty);
} /* End if LOWWAIT */ }
} else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */ } else if (event & EMPTYTX_IND) {
/* This event is generated by setup_empty_event */ /* This event is generated by setup_empty_event */
ch->statusflags &= ~TXBUSY; ch->statusflags &= ~TXBUSY;
if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */ if (ch->statusflags & EMPTYWAIT) {
ch->statusflags &= ~EMPTYWAIT; ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty); tty_wakeup(tty);
} /* End if EMPTYWAIT */ }
} /* End EMPTYTX_IND */ }
} /* End if valid tty */ }
next: next:
globalwinon(ch); globalwinon(ch);
BUG_ON(!bc); BUG_ON(!bc);
...@@ -1810,13 +1662,11 @@ static void doevent(int crd) ...@@ -1810,13 +1662,11 @@ static void doevent(int crd)
writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout); writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
globalwinon(chan0); globalwinon(chan0);
} /* End while something in event queue */ } /* End while something in event queue */
} /* End doevent */ }
/* --------------------- Begin fepcmd ------------------------ */
static void fepcmd(struct channel *ch, int cmd, int word_or_byte, static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
int byte2, int ncmds, int bytecmd) int byte2, int ncmds, int bytecmd)
{ /* Begin fepcmd */ {
unchar __iomem *memaddr; unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax; unsigned int head, cmdTail, cmdStart, cmdMax;
long count; long count;
...@@ -1831,11 +1681,11 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, ...@@ -1831,11 +1681,11 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
head = readw(&ch->mailbox->cin); head = readw(&ch->mailbox->cin);
/* cmdStart is a base address */ /* cmdStart is a base address */
cmdStart = readw(&ch->mailbox->cstart); cmdStart = readw(&ch->mailbox->cstart);
/* ------------------------------------------------------------------ /*
We do the addition below because we do not want a max pointer * We do the addition below because we do not want a max pointer
relative to cmdStart. We want a max pointer that points at the * relative to cmdStart. We want a max pointer that points at the
physical end of the command queue. * physical end of the command queue.
-------------------------------------------------------------------- */ */
cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax)); cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
memaddr = ch->board->re_map_membase; memaddr = ch->board->re_map_membase;
...@@ -1860,7 +1710,7 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, ...@@ -1860,7 +1710,7 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
writew(head, &ch->mailbox->cin); writew(head, &ch->mailbox->cin);
count = FEPTIMEOUT; count = FEPTIMEOUT;
for (;;) { /* Begin forever loop */ for (;;) {
count--; count--;
if (count == 0) { if (count == 0) {
printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n"); printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
...@@ -1869,26 +1719,23 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, ...@@ -1869,26 +1719,23 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
head = readw(&ch->mailbox->cin); head = readw(&ch->mailbox->cin);
cmdTail = readw(&ch->mailbox->cout); cmdTail = readw(&ch->mailbox->cout);
n = (head - cmdTail) & (cmdMax - cmdStart - 4); n = (head - cmdTail) & (cmdMax - cmdStart - 4);
/* ---------------------------------------------------------- /*
Basically this will break when the FEP acknowledges the * Basically this will break when the FEP acknowledges the
command by incrementing cmdTail (Making it equal to head). * command by incrementing cmdTail (Making it equal to head).
------------------------------------------------------------- */ */
if (n <= ncmds * (sizeof(short) * 4)) if (n <= ncmds * (sizeof(short) * 4))
break; /* Well nearly forever :-) */ break;
} /* End forever loop */ }
} /* End fepcmd */ }
/* ---------------------------------------------------------------------
Digi products use fields in their channels structures that are very
similar to the c_cflag and c_iflag fields typically found in UNIX
termios structures. The below three routines allow mappings
between these hardware "flags" and their respective Linux flags.
------------------------------------------------------------------------- */
/* --------------------- Begin termios2digi_h -------------------- */
/*
* Digi products use fields in their channels structures that are very similar
* to the c_cflag and c_iflag fields typically found in UNIX termios
* structures. The below three routines allow mappings between these hardware
* "flags" and their respective Linux flags.
*/
static unsigned termios2digi_h(struct channel *ch, unsigned cflag) static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_h */ {
unsigned res = 0; unsigned res = 0;
if (cflag & CRTSCTS) { if (cflag & CRTSCTS) {
...@@ -1918,86 +1765,73 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag) ...@@ -1918,86 +1765,73 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
ch->digiext.digi_flags |= CTSPACE; ch->digiext.digi_flags |= CTSPACE;
return res; return res;
}
} /* End termios2digi_h */
/* --------------------- Begin termios2digi_i -------------------- */
static unsigned termios2digi_i(struct channel *ch, unsigned iflag) static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
{ /* Begin termios2digi_i */ {
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
INPCK | ISTRIP|IXON|IXANY|IXOFF); INPCK | ISTRIP|IXON|IXANY|IXOFF);
if (ch->digiext.digi_flags & DIGI_AIXON) if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON; res |= IAIXON;
return res; return res;
}
} /* End termios2digi_i */
/* --------------------- Begin termios2digi_c -------------------- */
static unsigned termios2digi_c(struct channel *ch, unsigned cflag) static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
{ /* Begin termios2digi_c */ {
unsigned res = 0; unsigned res = 0;
if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */ if (cflag & CBAUDEX) {
ch->digiext.digi_flags |= DIGI_FAST; ch->digiext.digi_flags |= DIGI_FAST;
/* ------------------------------------------------------------- /*
HUPCL bit is used by FEP to indicate fast baud * HUPCL bit is used by FEP to indicate fast baud table is to
table is to be used. * be used.
----------------------------------------------------------------- */ */
res |= FEP_HUPCL; res |= FEP_HUPCL;
} /* End detected CBAUDEX */ } else
else ch->digiext.digi_flags &= ~DIGI_FAST; ch->digiext.digi_flags &= ~DIGI_FAST;
/* ------------------------------------------------------------------- /*
CBAUD has bit position 0x1000 set these days to indicate Linux * CBAUD has bit position 0x1000 set these days to indicate Linux
baud rate remap. Digi hardware can't handle the bit assignment. * baud rate remap. Digi hardware can't handle the bit assignment.
(We use a different bit assignment for high speed.). Clear this * (We use a different bit assignment for high speed.). Clear this
bit out. * bit out.
---------------------------------------------------------------------- */ */
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
/* ------------------------------------------------------------- /*
This gets a little confusing. The Digi cards have their own * This gets a little confusing. The Digi cards have their own
representation of c_cflags controling baud rate. For the most * representation of c_cflags controling baud rate. For the most part
part this is identical to the Linux implementation. However; * this is identical to the Linux implementation. However; Digi
Digi supports one rate (76800) that Linux doesn't. This means * supports one rate (76800) that Linux doesn't. This means that the
that the c_cflag entry that would normally mean 76800 for Digi * c_cflag entry that would normally mean 76800 for Digi actually means
actually means 115200 under Linux. Without the below mapping, * 115200 under Linux. Without the below mapping, a stty 115200 would
a stty 115200 would only drive the board at 76800. Since * only drive the board at 76800. Since the rate 230400 is also found
the rate 230400 is also found after 76800, the same problem afflicts * after 76800, the same problem afflicts us when we choose a rate of
us when we choose a rate of 230400. Without the below modificiation * 230400. Without the below modificiation stty 230400 would actually
stty 230400 would actually give us 115200. * give us 115200.
*
There are two additional differences. The Linux value for CLOCAL * There are two additional differences. The Linux value for CLOCAL
(0x800; 0004000) has no meaning to the Digi hardware. Also in * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
later releases of Linux; the CBAUD define has CBAUDEX (0x1000; * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
should be checked for a screened out prior to termios2digi_c * checked for a screened out prior to termios2digi_c returning. Since
returning. Since CLOCAL isn't used by the board this can be * CLOCAL isn't used by the board this can be ignored as long as the
ignored as long as the returned value is used only by Digi hardware. * returned value is used only by Digi hardware.
----------------------------------------------------------------- */ */
if (cflag & CBAUDEX) { if (cflag & CBAUDEX) {
/* ------------------------------------------------------------- /*
The below code is trying to guarantee that only baud rates * The below code is trying to guarantee that only baud rates
115200 and 230400 are remapped. We use exclusive or because * 115200 and 230400 are remapped. We use exclusive or because
the various baud rates share common bit positions and therefore * the various baud rates share common bit positions and
can't be tested for easily. * therefore can't be tested for easily.
----------------------------------------------------------------- */ */
if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) || if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
(!((cflag & 0x7) ^ (B230400 & ~CBAUDEX)))) (!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
res += 1; res += 1;
} }
return res; return res;
}
} /* End termios2digi_c */
/* --------------------- Begin epcaparam ----------------------- */
/* Caller must hold the locks */ /* Caller must hold the locks */
static void epcaparam(struct tty_struct *tty, struct channel *ch) static void epcaparam(struct tty_struct *tty, struct channel *ch)
{ /* Begin epcaparam */ {
unsigned int cmdHead; unsigned int cmdHead;
struct ktermios *ts; struct ktermios *ts;
struct board_chan __iomem *bc; struct board_chan __iomem *bc;
...@@ -2013,28 +1847,29 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ...@@ -2013,28 +1847,29 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
writew(cmdHead, &bc->rout); writew(cmdHead, &bc->rout);
cmdHead = readw(&bc->tin); cmdHead = readw(&bc->tin);
/* Changing baud in mid-stream transmission can be wonderful */ /* Changing baud in mid-stream transmission can be wonderful */
/* --------------------------------------------------------------- /*
Flush current transmit buffer by setting cmdTail pointer (tout) * Flush current transmit buffer by setting cmdTail pointer
to cmdHead pointer (tin). Hopefully the transmit buffer is empty. * (tout) to cmdHead pointer (tin). Hopefully the transmit
----------------------------------------------------------------- */ * buffer is empty.
*/
fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0); fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
mval = 0; mval = 0;
} else { /* Begin CBAUD not detected */ } else { /* Begin CBAUD not detected */
/* ------------------------------------------------------------------- /*
c_cflags have changed but that change had nothing to do with BAUD. * c_cflags have changed but that change had nothing to do with
Propagate the change to the card. * BAUD. Propagate the change to the card.
---------------------------------------------------------------------- */ */
cflag = termios2digi_c(ch, ts->c_cflag); cflag = termios2digi_c(ch, ts->c_cflag);
if (cflag != ch->fepcflag) { if (cflag != ch->fepcflag) {
ch->fepcflag = cflag; ch->fepcflag = cflag;
/* Set baud rate, char size, stop bits, parity */ /* Set baud rate, char size, stop bits, parity */
fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0); fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
} }
/* ---------------------------------------------------------------- /*
If the user has not forced CLOCAL and if the device is not a * If the user has not forced CLOCAL and if the device is not a
CALLOUT device (Which is always CLOCAL) we set flags such that * CALLOUT device (Which is always CLOCAL) we set flags such
the driver will wait on carrier detect. * that the driver will wait on carrier detect.
------------------------------------------------------------------- */ */
if (ts->c_cflag & CLOCAL) if (ts->c_cflag & CLOCAL)
ch->asyncflags &= ~ASYNC_CHECK_CD; ch->asyncflags &= ~ASYNC_CHECK_CD;
else else
...@@ -2045,19 +1880,19 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ...@@ -2045,19 +1880,19 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
/* Check input mode flags */ /* Check input mode flags */
if (iflag != ch->fepiflag) { if (iflag != ch->fepiflag) {
ch->fepiflag = iflag; ch->fepiflag = iflag;
/* --------------------------------------------------------------- /*
Command sets channels iflag structure on the board. Such things * Command sets channels iflag structure on the board. Such
as input soft flow control, handling of parity errors, and * things as input soft flow control, handling of parity
break handling are all set here. * errors, and break handling are all set here.
------------------------------------------------------------------- */ */
/* break handling, parity handling, input stripping, flow control chars */ /* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0); fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
} }
/* --------------------------------------------------------------- /*
Set the board mint value for this channel. This will cause hardware * Set the board mint value for this channel. This will cause hardware
events to be generated each time the DCD signal (Described in mint) * events to be generated each time the DCD signal (Described in mint)
changes. * changes.
------------------------------------------------------------------- */ */
writeb(ch->dcd, &bc->mint); writeb(ch->dcd, &bc->mint);
if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD)) if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
if (ch->digiext.digi_flags & DIGI_FORCEDCD) if (ch->digiext.digi_flags & DIGI_FORCEDCD)
...@@ -2066,23 +1901,23 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ...@@ -2066,23 +1901,23 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
hflow = termios2digi_h(ch, ts->c_cflag); hflow = termios2digi_h(ch, ts->c_cflag);
if (hflow != ch->hflow) { if (hflow != ch->hflow) {
ch->hflow = hflow; ch->hflow = hflow;
/* -------------------------------------------------------------- /*
Hard flow control has been selected but the board is not * Hard flow control has been selected but the board is not
using it. Activate hard flow control now. * using it. Activate hard flow control now.
----------------------------------------------------------------- */ */
fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1); fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
} }
mval ^= ch->modemfake & (mval ^ ch->modem); mval ^= ch->modemfake & (mval ^ ch->modem);
if (ch->omodem ^ mval) { if (ch->omodem ^ mval) {
ch->omodem = mval; ch->omodem = mval;
/* -------------------------------------------------------------- /*
The below command sets the DTR and RTS mstat structure. If * The below command sets the DTR and RTS mstat structure. If
hard flow control is NOT active these changes will drive the * hard flow control is NOT active these changes will drive the
output of the actual DTR and RTS lines. If hard flow control * output of the actual DTR and RTS lines. If hard flow control
is active, the changes will be saved in the mstat structure and * is active, the changes will be saved in the mstat structure
only asserted when hard flow control is turned off. * and only asserted when hard flow control is turned off.
----------------------------------------------------------------- */ */
/* First reset DTR & RTS; then set them */ /* First reset DTR & RTS; then set them */
fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1); fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
...@@ -2091,28 +1926,26 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ...@@ -2091,28 +1926,26 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) { if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
ch->fepstartc = ch->startc; ch->fepstartc = ch->startc;
ch->fepstopc = ch->stopc; ch->fepstopc = ch->stopc;
/* ------------------------------------------------------------ /*
The XON / XOFF characters have changed; propagate these * The XON / XOFF characters have changed; propagate these
changes to the card. * changes to the card.
--------------------------------------------------------------- */ */
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
} }
if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) { if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
ch->fepstartca = ch->startca; ch->fepstartca = ch->startca;
ch->fepstopca = ch->stopca; ch->fepstopca = ch->stopca;
/* --------------------------------------------------------------- /*
Similar to the above, this time the auxilarly XON / XOFF * Similar to the above, this time the auxilarly XON / XOFF
characters have changed; propagate these changes to the card. * characters have changed; propagate these changes to the card.
------------------------------------------------------------------ */ */
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
} }
} /* End epcaparam */ }
/* --------------------- Begin receive_data ----------------------- */
/* Caller holds lock */ /* Caller holds lock */
static void receive_data(struct channel *ch) static void receive_data(struct channel *ch)
{ /* Begin receive_data */ {
unchar *rptr; unchar *rptr;
struct ktermios *ts = NULL; struct ktermios *ts = NULL;
struct tty_struct *tty; struct tty_struct *tty;
...@@ -2121,11 +1954,10 @@ static void receive_data(struct channel *ch) ...@@ -2121,11 +1954,10 @@ static void receive_data(struct channel *ch)
unsigned int tail, head; unsigned int tail, head;
unsigned int wrapmask; unsigned int wrapmask;
/* --------------------------------------------------------------- /*
This routine is called by doint when a receive data event * This routine is called by doint when a receive data event has taken
has taken place. * place.
------------------------------------------------------------------- */ */
globalwinon(ch); globalwinon(ch);
if (ch->statusflags & RXSTOPPED) if (ch->statusflags & RXSTOPPED)
return; return;
...@@ -2136,10 +1968,10 @@ static void receive_data(struct channel *ch) ...@@ -2136,10 +1968,10 @@ static void receive_data(struct channel *ch)
BUG_ON(!bc); BUG_ON(!bc);
wrapmask = ch->rxbufsize - 1; wrapmask = ch->rxbufsize - 1;
/* --------------------------------------------------------------------- /*
Get the head and tail pointers to the receiver queue. Wrap the * Get the head and tail pointers to the receiver queue. Wrap the head
head pointer if it has reached the end of the buffer. * pointer if it has reached the end of the buffer.
------------------------------------------------------------------------ */ */
head = readw(&bc->rin); head = readw(&bc->rin);
head &= wrapmask; head &= wrapmask;
tail = readw(&bc->rout) & wrapmask; tail = readw(&bc->rout) & wrapmask;
...@@ -2148,10 +1980,7 @@ static void receive_data(struct channel *ch) ...@@ -2148,10 +1980,7 @@ static void receive_data(struct channel *ch)
if (bytesAvailable == 0) if (bytesAvailable == 0)
return; return;
/* ------------------------------------------------------------------ /* If CREAD bit is off or device not open, set TX tail to head */
If CREAD bit is off or device not open, set TX tail to head
--------------------------------------------------------------------- */
if (!tty || !ts || !(ts->c_cflag & CREAD)) { if (!tty || !ts || !(ts->c_cflag & CREAD)) {
writew(head, &bc->rout); writew(head, &bc->rout);
return; return;
...@@ -2168,22 +1997,20 @@ static void receive_data(struct channel *ch) ...@@ -2168,22 +1997,20 @@ static void receive_data(struct channel *ch)
rxwinon(ch); rxwinon(ch);
while (bytesAvailable > 0) { /* Begin while there is data on the card */ while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
/* --------------------------------------------------------------- /*
Even if head has wrapped around only report the amount of * Even if head has wrapped around only report the amount of
data to be equal to the size - tail. Remember memcpy can't * data to be equal to the size - tail. Remember memcpy can't
automaticly wrap around the receive buffer. * automaticly wrap around the receive buffer.
----------------------------------------------------------------- */ */
dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
/* -------------------------------------------------------------- /* Make sure we don't overflow the buffer */
Make sure we don't overflow the buffer
----------------------------------------------------------------- */
dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead); dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0) if (dataToRead == 0)
break; break;
/* --------------------------------------------------------------- /*
Move data read from our card into the line disciplines buffer * Move data read from our card into the line disciplines
for translation if necessary. * buffer for translation if necessary.
------------------------------------------------------------------ */ */
memcpy_fromio(rptr, ch->rxptr + tail, dataToRead); memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
tail = (tail + dataToRead) & wrapmask; tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead; bytesAvailable -= dataToRead;
...@@ -2192,27 +2019,25 @@ static void receive_data(struct channel *ch) ...@@ -2192,27 +2019,25 @@ static void receive_data(struct channel *ch)
writew(tail, &bc->rout); writew(tail, &bc->rout);
/* Must be called with global data */ /* Must be called with global data */
tty_schedule_flip(ch->tty); tty_schedule_flip(ch->tty);
return; }
} /* End receive_data */
static int info_ioctl(struct tty_struct *tty, struct file * file, static int info_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
switch (cmd) switch (cmd) {
{ /* Begin switch cmd */
case DIGI_GETINFO: case DIGI_GETINFO:
{ /* Begin case DIGI_GETINFO */ {
struct digi_info di ; struct digi_info di;
int brd; int brd;
if(get_user(brd, (unsigned int __user *)arg)) if (get_user(brd, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if (brd < 0 || brd >= num_cards || num_cards == 0) if (brd < 0 || brd >= num_cards || num_cards == 0)
return -ENODEV; return -ENODEV;
memset(&di, 0, sizeof(di)); memset(&di, 0, sizeof(di));
di.board = brd ; di.board = brd;
di.status = boards[brd].status; di.status = boards[brd].status;
di.type = boards[brd].type ; di.type = boards[brd].type ;
di.numports = boards[brd].numports ; di.numports = boards[brd].numports ;
...@@ -2220,45 +2045,44 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, ...@@ -2220,45 +2045,44 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
di.port = (unsigned char *)boards[brd].port ; di.port = (unsigned char *)boards[brd].port ;
di.membase = (unsigned char *)boards[brd].membase ; di.membase = (unsigned char *)boards[brd].membase ;
if (copy_to_user((void __user *)arg, &di, sizeof (di))) if (copy_to_user((void __user *)arg, &di, sizeof(di)))
return -EFAULT; return -EFAULT;
break; break;
} /* End case DIGI_GETINFO */ }
case DIGI_POLLER: case DIGI_POLLER:
{ /* Begin case DIGI_POLLER */ {
int brd = arg & 0xff000000 >> 16;
int brd = arg & 0xff000000 >> 16 ; unsigned char state = arg & 0xff;
unsigned char state = arg & 0xff ;
if (brd < 0 || brd >= num_cards) { if (brd < 0 || brd >= num_cards) {
printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n"); printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
return (-ENODEV); return -ENODEV;
}
digi_poller_inhibited = state;
break;
} }
digi_poller_inhibited = state ;
break ;
} /* End case DIGI_POLLER */
case DIGI_INIT: case DIGI_INIT:
{ /* Begin case DIGI_INIT */ {
/* ------------------------------------------------------------ /*
This call is made by the apps to complete the initilization * This call is made by the apps to complete the
of the board(s). This routine is responsible for setting * initilization of the board(s). This routine is
the card to its initial state and setting the drivers control * responsible for setting the card to its initial
fields to the sutianle settings for the card in question. * state and setting the drivers control fields to the
---------------------------------------------------------------- */ * sutianle settings for the card in question.
int crd ; */
int crd;
for (crd = 0; crd < num_cards; crd++) for (crd = 0; crd < num_cards; crd++)
post_fep_init (crd); post_fep_init(crd);
break ; break;
} /* End case DIGI_INIT */ }
default: default:
return -ENOTTY; return -ENOTTY;
} /* End switch cmd */ }
return (0) ; return 0;
} }
/* --------------------- Begin pc_ioctl ----------------------- */
static int pc_tiocmget(struct tty_struct *tty, struct file *file) static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{ {
...@@ -2304,9 +2128,9 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -2304,9 +2128,9 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
/* /*
* I think this modemfake stuff is broken. It doesn't * I think this modemfake stuff is broken. It doesn't correctly reflect
* correctly reflect the behaviour desired by the TIOCM* * the behaviour desired by the TIOCM* ioctls. Therefore this is
* ioctls. Therefore this is probably broken. * probably broken.
*/ */
if (set & TIOCM_RTS) { if (set & TIOCM_RTS) {
ch->modemfake |= ch->m_rts; ch->modemfake |= ch->m_rts;
...@@ -2325,10 +2149,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -2325,10 +2149,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
ch->modem &= ~ch->m_dtr; ch->modem &= ~ch->m_dtr;
} }
globalwinon(ch); globalwinon(ch);
/* -------------------------------------------------------------- /*
The below routine generally sets up parity, baud, flow control * The below routine generally sets up parity, baud, flow control
issues, etc.... It effect both control flags and input flags. * issues, etc.... It effect both control flags and input flags.
------------------------------------------------------------------ */ */
epcaparam(tty,ch); epcaparam(tty,ch);
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
...@@ -2337,8 +2161,7 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -2337,8 +2161,7 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
static int pc_ioctl(struct tty_struct *tty, struct file * file, static int pc_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ /* Begin pc_ioctl */ {
digiflow_t dflow; digiflow_t dflow;
int retval; int retval;
unsigned long flags; unsigned long flags;
...@@ -2353,14 +2176,12 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, ...@@ -2353,14 +2176,12 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
else else
return -EINVAL; return -EINVAL;
/* ------------------------------------------------------------------- /*
For POSIX compliance we need to add more ioctls. See tty_ioctl.c * For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
in /usr/src/linux/drivers/char for a good example. In particular * /usr/src/linux/drivers/char for a good example. In particular think
think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS. * about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
---------------------------------------------------------------------- */ */
switch (cmd) {
switch (cmd)
{ /* Begin switch cmd */
case TCSBRK: /* SVID version: non-zero arg --> no break */ case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty); retval = tty_check_change(tty);
if (retval) if (retval)
...@@ -2371,7 +2192,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, ...@@ -2371,7 +2192,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0); tty_wait_until_sent(tty, 0);
if (!arg) if (!arg)
digi_send_break(ch, HZ/4); /* 1/4 second */ digi_send_break(ch, HZ / 4); /* 1/4 second */
return 0; return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */ case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty); retval = tty_check_change(tty);
...@@ -2459,11 +2280,11 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, ...@@ -2459,11 +2280,11 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch); globalwinon(ch);
/* ----------------------------------------------------------------- /*
The below routine generally sets up parity, baud, flow control * The below routine generally sets up parity, baud, flow
issues, etc.... It effect both control flags and input flags. * control issues, etc.... It effect both control flags and
------------------------------------------------------------------- */ * input flags.
*/
epcaparam(tty,ch); epcaparam(tty,ch);
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
...@@ -2523,21 +2344,18 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, ...@@ -2523,21 +2344,18 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
break; break;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} /* End switch cmd */ }
return 0; return 0;
} /* End pc_ioctl */ }
/* --------------------- Begin pc_set_termios ----------------------- */
static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{ /* Begin pc_set_termios */ {
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch); globalwinon(ch);
...@@ -2554,45 +2372,38 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) ...@@ -2554,45 +2372,38 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
wake_up_interruptible(&ch->open_wait); wake_up_interruptible(&ch->open_wait);
} /* End if channel valid */ } /* End if channel valid */
}
} /* End pc_set_termios */
/* --------------------- Begin do_softint ----------------------- */
static void do_softint(struct work_struct *work) static void do_softint(struct work_struct *work)
{ /* Begin do_softint */ {
struct channel *ch = container_of(work, struct channel, tqueue); struct channel *ch = container_of(work, struct channel, tqueue);
/* Called in response to a modem change event */ /* Called in response to a modem change event */
if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */ if (ch && ch->magic == EPCA_MAGIC) {
struct tty_struct *tty = ch->tty; struct tty_struct *tty = ch->tty;
if (tty && tty->driver_data) { if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty); /* FIXME: module removal race here - AKPM */ tty_hangup(tty); /* FIXME: module removal race here - AKPM */
wake_up_interruptible(&ch->open_wait); wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
} /* End if clear_bit */
} }
} /* End EPCA_MAGIC */ }
} /* End do_softint */ }
}
/* ------------------------------------------------------------
pc_stop and pc_start provide software flow control to the
routine and the pc_ioctl routine.
---------------------------------------------------------------- */
/* --------------------- Begin pc_stop ----------------------- */
/*
* pc_stop and pc_start provide software flow control to the routine and the
* pc_ioctl routine.
*/
static void pc_stop(struct tty_struct *tty) static void pc_stop(struct tty_struct *tty)
{ /* Begin pc_stop */ {
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */ if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
globalwinon(ch); globalwinon(ch);
...@@ -2602,19 +2413,17 @@ static void pc_stop(struct tty_struct *tty) ...@@ -2602,19 +2413,17 @@ static void pc_stop(struct tty_struct *tty)
memoff(ch); memoff(ch);
} /* End if transmit stop requested */ } /* End if transmit stop requested */
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End if valid channel */ }
} /* End pc_stop */ }
/* --------------------- Begin pc_start ----------------------- */
static void pc_start(struct tty_struct *tty) static void pc_start(struct tty_struct *tty)
{ /* Begin pc_start */ {
struct channel *ch; struct channel *ch;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
/* Just in case output was resumed because of a change in Digi-flow */ /* Just in case output was resumed because of a change in Digi-flow */
...@@ -2630,28 +2439,25 @@ static void pc_start(struct tty_struct *tty) ...@@ -2630,28 +2439,25 @@ static void pc_start(struct tty_struct *tty)
memoff(ch); memoff(ch);
} /* End transmit resume requested */ } /* End transmit resume requested */
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */ }
} /* End pc_start */ }
/* ------------------------------------------------------------------ /*
The below routines pc_throttle and pc_unthrottle are used * The below routines pc_throttle and pc_unthrottle are used to slow (And
to slow (And resume) the receipt of data into the kernels * resume) the receipt of data into the kernels receive buffers. The exact
receive buffers. The exact occurrence of this depends on the * occurrence of this depends on the size of the kernels receive buffer and
size of the kernels receive buffer and what the 'watermarks' * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
are set to for that buffer. See the n_ttys.c file for more * more details.
details. */
______________________________________________________________________ */ static void pc_throttle(struct tty_struct *tty)
/* --------------------- Begin throttle ----------------------- */ {
static void pc_throttle(struct tty_struct * tty)
{ /* Begin pc_throttle */
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & RXSTOPPED) == 0) { if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch); globalwinon(ch);
...@@ -2660,20 +2466,18 @@ static void pc_throttle(struct tty_struct * tty) ...@@ -2660,20 +2466,18 @@ static void pc_throttle(struct tty_struct * tty)
memoff(ch); memoff(ch);
} }
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */ }
} /* End pc_throttle */ }
/* --------------------- Begin unthrottle ----------------------- */
static void pc_unthrottle(struct tty_struct *tty) static void pc_unthrottle(struct tty_struct *tty)
{ /* Begin pc_unthrottle */ {
struct channel *ch; struct channel *ch;
unsigned long flags; unsigned long flags;
/* --------------------------------------------------------- /*
verifyChannel returns the channel from the tty struct * verifyChannel returns the channel from the tty struct if it is
if it is valid. This serves as a sanity check. * valid. This serves as a sanity check.
------------------------------------------------------------- */ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ if ((ch = verifyChannel(tty)) != NULL) {
/* Just in case output was resumed because of a change in Digi-flow */ /* Just in case output was resumed because of a change in Digi-flow */
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
if (ch->statusflags & RXSTOPPED) { if (ch->statusflags & RXSTOPPED) {
...@@ -2683,62 +2487,55 @@ static void pc_unthrottle(struct tty_struct *tty) ...@@ -2683,62 +2487,55 @@ static void pc_unthrottle(struct tty_struct *tty)
memoff(ch); memoff(ch);
} }
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End if channel valid */ }
} /* End pc_unthrottle */ }
/* --------------------- Begin digi_send_break ----------------------- */
void digi_send_break(struct channel *ch, int msec) void digi_send_break(struct channel *ch, int msec)
{ /* Begin digi_send_break */ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&epca_lock, flags); spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch); globalwinon(ch);
/* -------------------------------------------------------------------- /*
Maybe I should send an infinite break here, schedule() for * Maybe I should send an infinite break here, schedule() for msec
msec amount of time, and then stop the break. This way, * amount of time, and then stop the break. This way, the user can't
the user can't screw up the FEP by causing digi_send_break() * screw up the FEP by causing digi_send_break() to be called (i.e. via
to be called (i.e. via an ioctl()) more than once in msec amount * an ioctl()) more than once in msec amount of time.
of time. Try this for now... * Try this for now...
------------------------------------------------------------------------ */ */
fepcmd(ch, SENDBREAK, msec, 0, 10, 0); fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch); memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags); spin_unlock_irqrestore(&epca_lock, flags);
} /* End digi_send_break */ }
/* --------------------- Begin setup_empty_event ----------------------- */
/* Caller MUST hold the lock */ /* Caller MUST hold the lock */
static void setup_empty_event(struct tty_struct *tty, struct channel *ch) static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
{ /* Begin setup_empty_event */ {
struct board_chan __iomem *bc = ch->brdchan; struct board_chan __iomem *bc = ch->brdchan;
globalwinon(ch); globalwinon(ch);
ch->statusflags |= EMPTYWAIT; ch->statusflags |= EMPTYWAIT;
/* ------------------------------------------------------------------ /*
When set the iempty flag request a event to be generated when the * When set the iempty flag request a event to be generated when the
transmit buffer is empty (If there is no BREAK in progress). * transmit buffer is empty (If there is no BREAK in progress).
--------------------------------------------------------------------- */ */
writeb(1, &bc->iempty); writeb(1, &bc->iempty);
memoff(ch); memoff(ch);
} /* End setup_empty_event */ }
/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints) void epca_setup(char *str, int *ints)
{ /* Begin epca_setup */ {
struct board_info board; struct board_info board;
int index, loop, last; int index, loop, last;
char *temp, *t2; char *temp, *t2;
unsigned len; unsigned len;
/* ---------------------------------------------------------------------- /*
If this routine looks a little strange it is because it is only called * If this routine looks a little strange it is because it is only
if a LILO append command is given to boot the kernel with parameters. * called if a LILO append command is given to boot the kernel with
In this way, we can provide the user a method of changing his board * parameters. In this way, we can provide the user a method of
configuration without rebuilding the kernel. * changing his board configuration without rebuilding the kernel.
----------------------------------------------------------------------- */ */
if (!liloconfig) if (!liloconfig)
liloconfig = 1; liloconfig = 1;
...@@ -2747,15 +2544,14 @@ void epca_setup(char *str, int *ints) ...@@ -2747,15 +2544,14 @@ void epca_setup(char *str, int *ints)
/* Assume the data is int first, later we can change it */ /* Assume the data is int first, later we can change it */
/* I think that array position 0 of ints holds the number of args */ /* I think that array position 0 of ints holds the number of args */
for (last = 0, index = 1; index <= ints[0]; index++) for (last = 0, index = 1; index <= ints[0]; index++)
switch(index) switch (index) { /* Begin parse switch */
{ /* Begin parse switch */
case 1: case 1:
board.status = ints[index]; board.status = ints[index];
/* --------------------------------------------------------- /*
We check for 2 (As opposed to 1; because 2 is a flag * We check for 2 (As opposed to 1; because 2 is a flag
instructing the driver to ignore epcaconfig.) For this * instructing the driver to ignore epcaconfig.) For
reason we check for 2. * this reason we check for 2.
------------------------------------------------------------ */ */
if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */ if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
nbdevs = 0; nbdevs = 0;
num_cards = 0; num_cards = 0;
...@@ -2844,8 +2640,7 @@ void epca_setup(char *str, int *ints) ...@@ -2844,8 +2640,7 @@ void epca_setup(char *str, int *ints)
/* Set index to the number of args + 1 */ /* Set index to the number of args + 1 */
index = last + 1; index = last + 1;
switch(index) switch (index) {
{
case 1: case 1:
len = strlen(str); len = strlen(str);
if (strncmp("Disable", str, len) == 0) if (strncmp("Disable", str, len) == 0)
...@@ -2862,13 +2657,13 @@ void epca_setup(char *str, int *ints) ...@@ -2862,13 +2657,13 @@ void epca_setup(char *str, int *ints)
break; break;
case 2: case 2:
for(loop = 0; loop < EPCA_NUM_TYPES; loop++) for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
if (strcmp(board_desc[loop], str) == 0) if (strcmp(board_desc[loop], str) == 0)
break; break;
/* --------------------------------------------------------------- /*
If the index incremented above refers to a legitamate board * If the index incremented above refers to a
type set it here. * legitamate board type set it here.
------------------------------------------------------------------*/ */
if (index < EPCA_NUM_TYPES) if (index < EPCA_NUM_TYPES)
board.type = loop; board.type = loop;
else { else {
...@@ -2907,19 +2702,21 @@ void epca_setup(char *str, int *ints) ...@@ -2907,19 +2702,21 @@ void epca_setup(char *str, int *ints)
return; return;
} }
/* ------------------------------------------------------------ /*
There is not a man page for simple_strtoul but the code can be * There is not a man page for simple_strtoul but the
found in vsprintf.c. The first argument is the string to * code can be found in vsprintf.c. The first argument
translate (To an unsigned long obviously), the second argument * is the string to translate (To an unsigned long
can be the address of any character variable or a NULL. If a * obviously), the second argument can be the address
variable is given, the end pointer of the string will be stored * of any character variable or a NULL. If a variable
in that variable; if a NULL is given the end pointer will * is given, the end pointer of the string will be
not be returned. The last argument is the base to use. If * stored in that variable; if a NULL is given the end
a 0 is indicated, the routine will attempt to determine the * pointer will not be returned. The last argument is
proper base by looking at the values prefix (A '0' for octal, * the base to use. If a 0 is indicated, the routine
a 'x' for hex, etc ... If a value is given it will use that * will attempt to determine the proper base by looking
value as the base. * at the values prefix (A '0' for octal, a 'x' for
---------------------------------------------------------------- */ * hex, etc ... If a value is given it will use that
* value as the base.
*/
board.numports = simple_strtoul(str, NULL, 0); board.numports = simple_strtoul(str, NULL, 0);
nbdevs += board.numports; nbdevs += board.numports;
last = index; last = index;
...@@ -2975,10 +2772,7 @@ void epca_setup(char *str, int *ints) ...@@ -2975,10 +2772,7 @@ void epca_setup(char *str, int *ints)
num_cards, board_desc[board.type], num_cards, board_desc[board.type],
board.numports, (int)board.port, (unsigned int) board.membase); board.numports, (int)board.port, (unsigned int) board.membase);
num_cards++; num_cards++;
} /* End epca_setup */ }
/* ------------------------ Begin init_PCI --------------------------- */
enum epic_board_types { enum epic_board_types {
brd_xr = 0, brd_xr = 0,
...@@ -2987,7 +2781,6 @@ enum epic_board_types { ...@@ -2987,7 +2781,6 @@ enum epic_board_types {
brd_xrj, brd_xrj,
}; };
/* indexed directly by epic_board_types enum */ /* indexed directly by epic_board_types enum */
static struct { static struct {
unsigned char board_type; unsigned char board_type;
...@@ -2999,7 +2792,7 @@ static struct { ...@@ -2999,7 +2792,7 @@ static struct {
{ PCIXRJ, 2, }, { PCIXRJ, 2, },
}; };
static int __devinit epca_init_one (struct pci_dev *pdev, static int __devinit epca_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent) const struct pci_device_id *ent)
{ {
static int board_num = -1; static int board_num = -1;
...@@ -3053,10 +2846,10 @@ static int __devinit epca_init_one (struct pci_dev *pdev, ...@@ -3053,10 +2846,10 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
goto err_out_free_memregion; goto err_out_free_memregion;
} }
/* -------------------------------------------------------------- /*
I don't know what the below does, but the hardware guys say * I don't know what the below does, but the hardware guys say its
its required on everything except PLX (In this case XRJ). * required on everything except PLX (In this case XRJ).
---------------------------------------------------------------- */ */
if (info_idx != brd_xrj) { if (info_idx != brd_xrj) {
pci_write_config_byte(pdev, 0x40, 0); pci_write_config_byte(pdev, 0x40, 0);
pci_write_config_byte(pdev, 0x46, 0); pci_write_config_byte(pdev, 0x46, 0);
...@@ -3086,7 +2879,7 @@ static struct pci_device_id epca_pci_tbl[] = { ...@@ -3086,7 +2879,7 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl); MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
int __init init_PCI (void) int __init init_PCI (void)
{ /* Begin init_PCI */ {
memset (&epca_driver, 0, sizeof (epca_driver)); memset (&epca_driver, 0, sizeof (epca_driver));
epca_driver.name = "epca"; epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl; epca_driver.id_table = epca_pci_tbl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment