int irqtype;
};
-static int stli_nrbrds;
+static unsigned int stli_nrbrds;
/* stli_lock must NOT be taken holding brd_lock */
static spinlock_t stli_lock; /* TTY logic lock */
static comstats_t stli_comstats;
static combrd_t stli_brdstats;
static struct asystats stli_cdkstats;
-static struct stlibrd stli_dummybrd;
-static struct stliport stli_dummyport;
/*****************************************************************************/
+static DEFINE_MUTEX(stli_brdslock);
static struct stlibrd *stli_brds[STL_MAXBRDS];
static int stli_shared;
*/
#define BST_FOUND 0x1
#define BST_STARTED 0x2
+#define BST_PROBED 0x4
/*
* Define the set of port state flags. These are marked for internal
module_param_array(board3, charp, NULL, 0);
MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
+#if STLI_EISAPROBE != 0
/*
* Set up a default memory address table for EISA board probing.
* The default addresses are all bellow 1Mbyte, which has to be the
};
static int stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
+#endif
/*
* Define the Stallion PCI vendor and device IDs.
*/
static int stli_parsebrd(struct stlconf *confp, char **argp);
-static int stli_init(void);
static int stli_open(struct tty_struct *tty, struct file *filp);
static void stli_close(struct tty_struct *tty, struct file *filp);
static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void stli_putchar(struct tty_struct *tty, unsigned char ch);
+static int stli_putchar(struct tty_struct *tty, unsigned char ch);
static void stli_flushchars(struct tty_struct *tty);
static int stli_writeroom(struct tty_struct *tty);
static int stli_charsinbuffer(struct tty_struct *tty);
static void stli_stop(struct tty_struct *tty);
static void stli_start(struct tty_struct *tty);
static void stli_flushbuffer(struct tty_struct *tty);
-static void stli_breakctl(struct tty_struct *tty, int state);
+static int stli_breakctl(struct tty_struct *tty, int state);
static void stli_waituntilsent(struct tty_struct *tty, int timeout);
static void stli_sendxchar(struct tty_struct *tty, char ch);
static void stli_hangup(struct tty_struct *tty);
static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait);
static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp);
-static void stli_dohangup(struct work_struct *);
static int stli_setport(struct stliport *portp);
static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback);
static void __iomem *stli_stalgetmemptr(struct stlibrd *brdp, unsigned long offset, int line);
static void stli_stalreset(struct stlibrd *brdp);
-static struct stliport *stli_getport(int brdnr, int panelnr, int portnr);
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, unsigned int portnr);
static int stli_initecp(struct stlibrd *brdp);
static int stli_initonb(struct stlibrd *brdp);
+#if STLI_EISAPROBE != 0
static int stli_eisamemprobe(struct stlibrd *brdp);
+#endif
static int stli_initports(struct stlibrd *brdp);
/*****************************************************************************/
for (j = 0; j < STL_MAXPORTS; j++) {
portp = brdp->ports[j];
if (portp != NULL) {
- if (portp->tty != NULL)
- tty_hangup(portp->tty);
+ if (portp->port.tty != NULL)
+ tty_hangup(portp->port.tty);
kfree(portp);
}
}
}
-/*
- * Loadable module initialization stuff.
- */
-
-static int __init istallion_module_init(void)
-{
- stli_init();
- return 0;
-}
-
-/*****************************************************************************/
-
-static void __exit istallion_module_exit(void)
-{
- struct stlibrd *brdp;
- int i;
-
- printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
- stli_drvversion);
-
- pci_unregister_driver(&stli_pcidriver);
- /*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts.
- */
- if (stli_timeron) {
- stli_timeron = 0;
- del_timer_sync(&stli_timerlist);
- }
-
- i = tty_unregister_driver(stli_serial);
- if (i) {
- printk("STALLION: failed to un-register tty driver, "
- "errno=%d\n", -i);
- return;
- }
- put_tty_driver(stli_serial);
- for (i = 0; i < 4; i++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- class_destroy(istallion_class);
- if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -i);
-
- kfree(stli_txcookbuf);
-
- for (i = 0; (i < stli_nrbrds); i++) {
- if ((brdp = stli_brds[i]) == NULL)
- continue;
-
- stli_cleanup_ports(brdp);
-
- iounmap(brdp->membase);
- if (brdp->iosize > 0)
- release_region(brdp->iobase, brdp->iosize);
- kfree(brdp);
- stli_brds[i] = NULL;
- }
-}
-
-module_init(istallion_module_init);
-module_exit(istallion_module_exit);
-
/*****************************************************************************/
/*
static int stli_parsebrd(struct stlconf *confp, char **argp)
{
+ unsigned int i;
char *sp;
- int i;
if (argp[0] == NULL || *argp[0] == 0)
return 0;
{
struct stlibrd *brdp;
struct stliport *portp;
- unsigned int minordev;
- int brdnr, portnr, rc;
+ unsigned int minordev, brdnr, portnr;
+ int rc;
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
if ((brdp->state & BST_STARTED) == 0)
return -ENODEV;
portnr = MINOR2PORT(minordev);
- if ((portnr < 0) || (portnr > brdp->nrports))
+ if (portnr > brdp->nrports)
return -ENODEV;
portp = brdp->ports[portnr];
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
- if (portp->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&portp->close_wait);
- if (portp->flags & ASYNC_HUP_NOTIFY)
+ if (portp->port.flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&portp->port.close_wait);
+ if (portp->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
return -ERESTARTSYS;
}
* requires several commands to the board we will need to wait for any
* other open that is already initializing the port.
*/
- portp->tty = tty;
+ portp->port.tty = tty;
tty->driver_data = portp;
- portp->refcount++;
+ portp->port.count++;
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_INITIALIZING, &portp->state));
if (signal_pending(current))
return -ERESTARTSYS;
- if ((portp->flags & ASYNC_INITIALIZED) == 0) {
+ if ((portp->port.flags & ASYNC_INITIALIZED) == 0) {
set_bit(ST_INITIALIZING, &portp->state);
if ((rc = stli_initopen(brdp, portp)) >= 0) {
- portp->flags |= ASYNC_INITIALIZED;
+ portp->port.flags |= ASYNC_INITIALIZED;
clear_bit(TTY_IO_ERROR, &tty->flags);
}
clear_bit(ST_INITIALIZING, &portp->state);
* The sleep here does not need interrupt protection since the wakeup
* for it is done with the same context.
*/
- if (portp->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&portp->close_wait);
- if (portp->flags & ASYNC_HUP_NOTIFY)
+ if (portp->port.flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&portp->port.close_wait);
+ if (portp->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
return -ERESTARTSYS;
}
if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
return rc;
}
- portp->flags |= ASYNC_NORMAL_ACTIVE;
+ portp->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
spin_unlock_irqrestore(&stli_lock, flags);
return;
}
- if ((tty->count == 1) && (portp->refcount != 1))
- portp->refcount = 1;
- if (portp->refcount-- > 1) {
+ if ((tty->count == 1) && (portp->port.count != 1))
+ portp->port.count = 1;
+ if (portp->port.count-- > 1) {
spin_unlock_irqrestore(&stli_lock, flags);
return;
}
- portp->flags |= ASYNC_CLOSING;
+ portp->port.flags |= ASYNC_CLOSING;
/*
* May want to wait for data to drain before closing. The BUSY flag
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
- portp->flags &= ~ASYNC_INITIALIZED;
+ portp->port.flags &= ~ASYNC_INITIALIZED;
brdp = stli_brds[portp->brdnr];
stli_rawclose(brdp, portp, 0, 0);
if (tty->termios->c_cflag & HUPCL) {
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
- if (tty->ldisc.flush_buffer)
- (tty->ldisc.flush_buffer)(tty);
+ tty_ldisc_flush(tty);
set_bit(ST_DOFLUSHRX, &portp->state);
stli_flushbuffer(tty);
tty->closing = 0;
- portp->tty = NULL;
+ portp->port.tty = NULL;
if (portp->openwaitcnt) {
if (portp->close_delay)
msleep_interruptible(jiffies_to_msecs(portp->close_delay));
- wake_up_interruptible(&portp->open_wait);
+ wake_up_interruptible(&portp->port.open_wait);
}
- portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&portp->close_wait);
+ portp->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&portp->port.close_wait);
}
/*****************************************************************************/
sizeof(asynotify_t), 0)) < 0)
return rc;
- tty = portp->tty;
+ tty = portp->port.tty;
if (tty == NULL)
return -ENODEV;
stli_mkasyport(portp, &aport, tty->termios);
if (portp == NULL)
return -ENODEV;
- if (portp->tty == NULL)
+ if (portp->port.tty == NULL)
return -ENODEV;
- if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return -ENODEV;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
return -ENODEV;
- stli_mkasyport(portp, &aport, portp->tty->termios);
+ stli_mkasyport(portp, &aport, portp->port.tty->termios);
return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
}
rc = 0;
doclocal = 0;
- if (portp->tty->termios->c_cflag & CLOCAL)
+ if (portp->port.tty->termios->c_cflag & CLOCAL)
doclocal++;
spin_lock_irqsave(&stli_lock, flags);
portp->openwaitcnt++;
if (! tty_hung_up_p(filp))
- portp->refcount--;
+ portp->port.count--;
spin_unlock_irqrestore(&stli_lock, flags);
for (;;) {
&portp->asig, sizeof(asysigs_t), 0)) < 0)
break;
if (tty_hung_up_p(filp) ||
- ((portp->flags & ASYNC_INITIALIZED) == 0)) {
- if (portp->flags & ASYNC_HUP_NOTIFY)
+ ((portp->port.flags & ASYNC_INITIALIZED) == 0)) {
+ if (portp->port.flags & ASYNC_HUP_NOTIFY)
rc = -EBUSY;
else
rc = -ERESTARTSYS;
break;
}
- if (((portp->flags & ASYNC_CLOSING) == 0) &&
+ if (((portp->port.flags & ASYNC_CLOSING) == 0) &&
(doclocal || (portp->sigs & TIOCM_CD))) {
break;
}
rc = -ERESTARTSYS;
break;
}
- interruptible_sleep_on(&portp->open_wait);
+ interruptible_sleep_on(&portp->port.open_wait);
}
spin_lock_irqsave(&stli_lock, flags);
if (! tty_hung_up_p(filp))
- portp->refcount++;
+ portp->port.count++;
portp->openwaitcnt--;
spin_unlock_irqrestore(&stli_lock, flags);
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
* first them do the new ports.
*/
-static void stli_putchar(struct tty_struct *tty, unsigned char ch)
+static int stli_putchar(struct tty_struct *tty, unsigned char ch)
{
if (tty != stli_txcooktty) {
if (stli_txcooktty != NULL)
}
stli_txcookbuf[stli_txcooksize++] = ch;
+ return 0;
}
/*****************************************************************************/
portp = tty->driver_data;
if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
portp = tty->driver_data;
if (portp == NULL)
return 0;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
sio.type = PORT_UNKNOWN;
sio.line = portp->portnr;
sio.irq = 0;
- sio.flags = portp->flags;
+ sio.flags = portp->port.flags;
sio.baud_base = portp->baud_base;
sio.close_delay = portp->close_delay;
sio.closing_wait = portp->closing_wait;
if ((sio.baud_base != portp->baud_base) ||
(sio.close_delay != portp->close_delay) ||
((sio.flags & ~ASYNC_USR_MASK) !=
- (portp->flags & ~ASYNC_USR_MASK)))
+ (portp->port.flags & ~ASYNC_USR_MASK)))
return -EPERM;
}
- portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
+ portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) |
(sio.flags & ASYNC_USR_MASK);
portp->baud_base = sio.baud_base;
portp->close_delay = sio.close_delay;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
{
struct stliport *portp;
struct stlibrd *brdp;
- unsigned int ival;
int rc;
void __user *argp = (void __user *)arg;
portp = tty->driver_data;
if (portp == NULL)
return -ENODEV;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return 0;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
rc = 0;
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) arg);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) arg)) == 0)
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stli_getserial(portp, argp);
break;
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
return;
tiosp = tty->termios;
- if ((tiosp->c_cflag == old->c_cflag) &&
- (tiosp->c_iflag == old->c_iflag))
- return;
stli_mkasyport(portp, &aport, tiosp);
stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0))
tty->hw_stopped = 0;
if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL))
- wake_up_interruptible(&portp->open_wait);
+ wake_up_interruptible(&portp->port.open_wait);
}
/*****************************************************************************/
/*****************************************************************************/
/*
- * Scheduler called hang up routine. This is called from the scheduler,
- * not direct from the driver "poll" routine. We can't call it there
- * since the real local hangup code will enable/disable the board and
- * other things that we can't do while handling the poll. Much easier
- * to deal with it some time later (don't really care when, hangups
- * aren't that time critical).
- */
-
-static void stli_dohangup(struct work_struct *ugly_api)
-{
- struct stliport *portp = container_of(ugly_api, struct stliport, tqhangup);
- if (portp->tty != NULL) {
- tty_hangup(portp->tty);
- }
-}
-
-/*****************************************************************************/
-
-/*
* Hangup this port. This is pretty much like closing the port, only
* a little more brutal. No waiting for data to drain. Shutdown the
* port and maybe drop signals. This is rather tricky really. We want
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
return;
- portp->flags &= ~ASYNC_INITIALIZED;
+ portp->port.flags &= ~ASYNC_INITIALIZED;
if (!test_bit(ST_CLOSING, &portp->state))
stli_rawclose(brdp, portp, 0, 0);
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
- portp->tty = NULL;
- portp->flags &= ~ASYNC_NORMAL_ACTIVE;
- portp->refcount = 0;
+ portp->port.tty = NULL;
+ portp->port.flags &= ~ASYNC_NORMAL_ACTIVE;
+ portp->port.count = 0;
spin_unlock_irqrestore(&stli_lock, flags);
- wake_up_interruptible(&portp->open_wait);
+ wake_up_interruptible(&portp->port.open_wait);
}
/*****************************************************************************/
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
/*****************************************************************************/
-static void stli_breakctl(struct tty_struct *tty, int state)
+static int stli_breakctl(struct tty_struct *tty, int state)
{
struct stlibrd *brdp;
struct stliport *portp;
portp = tty->driver_data;
if (portp == NULL)
- return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
- return;
+ return -EINVAL;
+ if (portp->brdnr >= stli_nrbrds)
+ return -EINVAL;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
- return;
+ return -EINVAL;
arg = (state == -1) ? BREAKON : BREAKOFF;
stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
+ return 0;
}
/*****************************************************************************/
portp = tty->driver_data;
if (portp == NULL)
return;
- if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ if (portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
if (brdp == NULL)
{
struct stlibrd *brdp;
struct stliport *portp;
- int brdnr, portnr, totalport;
+ unsigned int brdnr, portnr, totalport;
int curoff, maxoff;
char *pos;
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
unsigned char __iomem *bits;
- unsigned long flags;
-
- spin_lock_irqsave(&brd_lock, flags);
if (test_bit(ST_CMDING, &portp->state)) {
printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
(int) cmd);
- spin_unlock_irqrestore(&brd_lock, flags);
return;
}
writeb(readb(bits) | portp->portbit, bits);
set_bit(ST_CMDING, &portp->state);
EBRDDISABLE(brdp);
- spin_unlock_irqrestore(&brd_lock, flags);
}
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
if (test_bit(ST_RXSTOP, &portp->state))
return;
- tty = portp->tty;
+ tty = portp->port.tty;
if (tty == NULL)
return;
if (ap->notify) {
nt = ap->changed;
ap->notify = 0;
- tty = portp->tty;
+ tty = portp->port.tty;
if (nt.signal & SG_DCD) {
oldsigs = portp->sigs;
clear_bit(ST_GETSIGS, &portp->state);
if ((portp->sigs & TIOCM_CD) &&
((oldsigs & TIOCM_CD) == 0))
- wake_up_interruptible(&portp->open_wait);
+ wake_up_interruptible(&portp->port.open_wait);
if ((oldsigs & TIOCM_CD) &&
((portp->sigs & TIOCM_CD) == 0)) {
- if (portp->flags & ASYNC_CHECK_CD) {
+ if (portp->port.flags & ASYNC_CHECK_CD) {
if (tty)
- schedule_work(&portp->tqhangup);
+ tty_hangup(tty);
}
}
}
if (tty != NULL) {
tty_wakeup(tty);
EBRDENABLE(brdp);
- wake_up_interruptible(&tty->write_wait);
}
}
if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
if (tty != NULL) {
tty_insert_flip_char(tty, 0, TTY_BREAK);
- if (portp->flags & ASYNC_SAK) {
+ if (portp->port.flags & ASYNC_SAK) {
do_SAK(tty);
EBRDENABLE(brdp);
}
{
cdkhdr_t __iomem *hdrp;
struct stlibrd *brdp;
- int brdnr;
+ unsigned int brdnr;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
/*
* Check each board and do any servicing required.
/*
* Start of by setting the baud, char size, parity and stop bit info.
*/
- pp->baudout = tty_get_baud_rate(portp->tty);
+ pp->baudout = tty_get_baud_rate(portp->port.tty);
if ((tiosp->c_cflag & CBAUD) == B38400) {
- if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
pp->baudout = 57600;
- else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
pp->baudout = 115200;
- else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
pp->baudout = 230400;
- else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
pp->baudout = 460800;
- else if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+ else if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
pp->baudout = (portp->baud_base / portp->custom_divisor);
}
if (pp->baudout > STL_MAXBAUD)
* Set up clocal processing as required.
*/
if (tiosp->c_cflag & CLOCAL)
- portp->flags &= ~ASYNC_CHECK_CD;
+ portp->port.flags &= ~ASYNC_CHECK_CD;
else
- portp->flags |= ASYNC_CHECK_CD;
+ portp->port.flags |= ASYNC_CHECK_CD;
/*
* Transfer any persistent flags into the asyport structure.
static int stli_initports(struct stlibrd *brdp)
{
struct stliport *portp;
- int i, panelnr, panelport;
+ unsigned int i, panelnr, panelport;
for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
portp = kzalloc(sizeof(struct stliport), GFP_KERNEL);
portp->baud_base = STL_BAUDBASE;
portp->close_delay = STL_CLOSEDELAY;
portp->closing_wait = 30 * HZ;
- INIT_WORK(&portp->tqhangup, stli_dohangup);
- init_waitqueue_head(&portp->open_wait);
- init_waitqueue_head(&portp->close_wait);
+ init_waitqueue_head(&portp->port.open_wait);
+ init_waitqueue_head(&portp->port.close_wait);
init_waitqueue_head(&portp->raw_wait);
panelport++;
if (panelport >= brdp->panels[panelnr]) {
cdkecpsig_t __iomem *sigsp;
unsigned int status, nxtid;
char *name;
- int panelnr, nrports;
+ int retval, panelnr, nrports;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
-
- if ((brdp->iobase == 0) || (brdp->memaddr == 0))
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENODEV;
+ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) {
+ retval = -ENODEV;
+ goto err;
}
brdp->iosize = ECP_IOSIZE;
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
+ }
+
/*
* Based on the specific board type setup the common vars to access
* and enable shared memory. Set all board specific information now
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
EBRDDISABLE(brdp);
- if (sig.magic != cpu_to_le32(ECP_MAGIC))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ if (sig.magic != cpu_to_le32(ECP_MAGIC)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
cdkonbsig_t sig;
cdkonbsig_t __iomem *sigsp;
char *name;
- int i;
+ int i, retval;
/*
* Do a basic sanity check on the IO and memory addresses.
*/
- if (brdp->iobase == 0 || brdp->memaddr == 0)
- return -ENODEV;
+ if (brdp->iobase == 0 || brdp->memaddr == 0) {
+ retval = -ENODEV;
+ goto err;
+ }
brdp->iosize = ONB_IOSIZE;
- if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
- return -EIO;
+ if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
+ retval = -EIO;
+ goto err;
+ }
/*
* Based on the specific board type setup the common vars to access
break;
default:
- release_region(brdp->iobase, brdp->iosize);
- return -EINVAL;
+ retval = -EINVAL;
+ goto err_reg;
}
/*
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == NULL)
- {
- release_region(brdp->iobase, brdp->iosize);
- return -ENOMEM;
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
+ if (brdp->membase == NULL) {
+ retval = -ENOMEM;
+ goto err_reg;
}
/*
if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
- sig.magic3 != cpu_to_le16(ONB_MAGIC3))
- {
- release_region(brdp->iobase, brdp->iosize);
- iounmap(brdp->membase);
- brdp->membase = NULL;
- return -ENODEV;
+ sig.magic3 != cpu_to_le16(ONB_MAGIC3)) {
+ retval = -ENODEV;
+ goto err_unmap;
}
/*
brdp->state |= BST_FOUND;
return 0;
+err_unmap:
+ iounmap(brdp->membase);
+ brdp->membase = NULL;
+err_reg:
+ release_region(brdp->iobase, brdp->iosize);
+err:
+ return retval;
}
/*****************************************************************************/
cdkmem_t __iomem *memp;
cdkasy_t __iomem *ap;
unsigned long flags;
+ unsigned int portnr, nrdevs, i;
struct stliport *portp;
- int portnr, nrdevs, i, rc = 0;
+ int rc = 0;
u32 memoff;
spin_lock_irqsave(&brd_lock, flags);
if (! stli_timeron) {
stli_timeron++;
- stli_timerlist.expires = STLI_TIMEOUT;
- add_timer(&stli_timerlist);
+ mod_timer(&stli_timerlist, STLI_TIMEOUT);
}
return rc;
static int __devinit stli_brdinit(struct stlibrd *brdp)
{
- stli_brds[brdp->brdnr] = brdp;
+ int retval;
switch (brdp->brdtype) {
case BRD_ECP:
case BRD_ECPE:
case BRD_ECPMC:
case BRD_ECPPCI:
- stli_initecp(brdp);
+ retval = stli_initecp(brdp);
break;
case BRD_ONBOARD:
case BRD_ONBOARDE:
case BRD_ONBOARD2:
case BRD_BRUMBY4:
case BRD_STALLION:
- stli_initonb(brdp);
+ retval = stli_initonb(brdp);
break;
default:
printk(KERN_ERR "STALLION: board=%d is unknown board "
"type=%d\n", brdp->brdnr, brdp->brdtype);
- return -ENODEV;
+ retval = -ENODEV;
}
- if ((brdp->state & BST_FOUND) == 0) {
- printk(KERN_ERR "STALLION: %s board not found, board=%d "
- "io=%x mem=%x\n",
- stli_brdnames[brdp->brdtype], brdp->brdnr,
- brdp->iobase, (int) brdp->memaddr);
- return -ENODEV;
- }
+ if (retval)
+ return retval;
stli_initports(brdp);
printk(KERN_INFO "STALLION: %s found, board=%d io=%x mem=%x "
return 0;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
*/
for (i = 0; (i < stli_eisamempsize); i++) {
brdp->memaddr = stli_eisamemprobeaddrs[i];
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL)
continue;
}
return 0;
}
+#endif
static int stli_getbrdnr(void)
{
- int i;
+ unsigned int i;
for (i = 0; i < STL_MAXBRDS; i++) {
if (!stli_brds[i]) {
return -1;
}
+#if STLI_EISAPROBE != 0
/*****************************************************************************/
/*
static int stli_findeisabrds(void)
{
struct stlibrd *brdp;
- unsigned int iobase, eid;
- int i;
+ unsigned int iobase, eid, i;
+ int brdnr, found = 0;
/*
* Firstly check if this is an EISA system. If this is not an EISA system then
* Allocate a board structure and initialize it.
*/
if ((brdp = stli_allocbrd()) == NULL)
- return -ENOMEM;
- if ((brdp->brdnr = stli_getbrdnr()) < 0)
- return -ENOMEM;
+ return found ? : -ENOMEM;
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0)
+ return found ? : -ENOMEM;
+ brdp->brdnr = (unsigned int)brdnr;
eid = inb(iobase + 0xc82);
if (eid == ECP_EISAID)
brdp->brdtype = BRD_ECPE;
outb(0x1, (iobase + 0xc84));
if (stli_eisamemprobe(brdp))
outb(0, (iobase + 0xc84));
- stli_brdinit(brdp);
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
}
- return 0;
+ return found;
}
+#else
+static inline int stli_findeisabrds(void) { return 0; }
+#endif
/*****************************************************************************/
const struct pci_device_id *ent)
{
struct stlibrd *brdp;
- int retval = -EIO;
+ unsigned int i;
+ int brdnr, retval = -EIO;
retval = pci_enable_device(pdev);
if (retval)
retval = -ENOMEM;
goto err;
}
- if ((brdp->brdnr = stli_getbrdnr()) < 0) { /* TODO: locking */
+ mutex_lock(&stli_brdslock);
+ brdnr = stli_getbrdnr();
+ if (brdnr < 0) {
printk(KERN_INFO "STALLION: too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
+ mutex_unlock(&stli_brdslock);
retval = -EIO;
goto err_fr;
}
+ brdp->brdnr = (unsigned int)brdnr;
+ stli_brds[brdp->brdnr] = brdp;
+ mutex_unlock(&stli_brdslock);
brdp->brdtype = BRD_ECPPCI;
/*
* We have all resources from the board, so lets setup the actual
brdp->memaddr = pci_resource_start(pdev, 2);
retval = stli_brdinit(brdp);
if (retval)
- goto err_fr;
+ goto err_null;
+ brdp->state |= BST_PROBED;
pci_set_drvdata(pdev, brdp);
+ EBRDENABLE(brdp);
+ brdp->enable = NULL;
+ brdp->disable = NULL;
+
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial, brdp->brdnr * STL_MAXPORTS + i,
+ &pdev->dev);
+
return 0;
+err_null:
+ stli_brds[brdp->brdnr] = NULL;
err_fr:
kfree(brdp);
err:
{
struct stlibrd *brdp, *nxtbrdp;
struct stlconf conf;
- int i, j, retval;
+ unsigned int i, j, found = 0;
+ int retval;
for (stli_nrbrds = 0; stli_nrbrds < ARRAY_SIZE(stli_brdsp);
stli_nrbrds++) {
brdp->brdtype = conf.brdtype;
brdp->iobase = conf.ioaddr1;
brdp->memaddr = conf.memaddr;
- stli_brdinit(brdp);
- }
+ if (stli_brdinit(brdp) < 0) {
+ kfree(brdp);
+ continue;
+ }
+ stli_brds[brdp->brdnr] = brdp;
+ found++;
- if (STLI_EISAPROBE)
- stli_findeisabrds();
+ for (i = 0; i < brdp->nrports; i++)
+ tty_register_device(stli_serial,
+ brdp->brdnr * STL_MAXPORTS + i, NULL);
+ }
- retval = pci_register_driver(&stli_pcidriver);
- /* TODO: check retval and do something */
+ retval = stli_findeisabrds();
+ if (retval > 0)
+ found += retval;
/*
* All found boards are initialized. Now for a little optimization, if
}
}
+ retval = pci_register_driver(&stli_pcidriver);
+ if (retval && found == 0) {
+ printk(KERN_ERR "Neither isa nor eisa cards found nor pci "
+ "driver can be registered!\n");
+ goto err;
+ }
+
return 0;
+err:
+ return retval;
}
/*****************************************************************************/
unsigned long flags;
void __iomem *memptr;
struct stlibrd *brdp;
- int brdnr, size, n;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
void __iomem *memptr;
struct stlibrd *brdp;
char __user *chbuf;
- int brdnr, size, n;
+ unsigned int brdnr;
+ int size, n;
void *p;
loff_t off = *offp;
static int stli_getbrdstats(combrd_t __user *bp)
{
struct stlibrd *brdp;
- int i;
+ unsigned int i;
if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
* Resolve the referenced port number into a port struct pointer.
*/
-static struct stliport *stli_getport(int brdnr, int panelnr, int portnr)
+static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr,
+ unsigned int portnr)
{
struct stlibrd *brdp;
- int i;
+ unsigned int i;
- if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ if (brdnr >= STL_MAXBRDS)
return NULL;
brdp = stli_brds[brdnr];
if (brdp == NULL)
return NULL;
for (i = 0; (i < panelnr); i++)
portnr += brdp->panels[i];
- if ((portnr < 0) || (portnr >= brdp->nrports))
+ if (portnr >= brdp->nrports)
return NULL;
return brdp->ports[portnr];
}
stli_comstats.panel = portp->panelnr;
stli_comstats.port = portp->portnr;
stli_comstats.state = portp->state;
- stli_comstats.flags = portp->flags;
+ stli_comstats.flags = portp->port.flags;
spin_lock_irqsave(&brd_lock, flags);
- if (portp->tty != NULL) {
- if (portp->tty->driver_data == portp) {
- stli_comstats.ttystate = portp->tty->flags;
+ if (portp->port.tty != NULL) {
+ if (portp->port.tty->driver_data == portp) {
+ stli_comstats.ttystate = portp->port.tty->flags;
stli_comstats.rxbuffered = -1;
- if (portp->tty->termios != NULL) {
- stli_comstats.cflags = portp->tty->termios->c_cflag;
- stli_comstats.iflags = portp->tty->termios->c_iflag;
- stli_comstats.oflags = portp->tty->termios->c_oflag;
- stli_comstats.lflags = portp->tty->termios->c_lflag;
+ if (portp->port.tty->termios != NULL) {
+ stli_comstats.cflags = portp->port.tty->termios->c_cflag;
+ stli_comstats.iflags = portp->port.tty->termios->c_iflag;
+ stli_comstats.oflags = portp->port.tty->termios->c_oflag;
+ stli_comstats.lflags = portp->port.tty->termios->c_lflag;
}
}
}
static int stli_getportstruct(struct stliport __user *arg)
{
+ struct stliport stli_dummyport;
struct stliport *portp;
if (copy_from_user(&stli_dummyport, arg, sizeof(struct stliport)))
static int stli_getbrdstruct(struct stlibrd __user *arg)
{
+ struct stlibrd stli_dummybrd;
struct stlibrd *brdp;
if (copy_from_user(&stli_dummybrd, arg, sizeof(struct stlibrd)))
return -EFAULT;
- if ((stli_dummybrd.brdnr < 0) || (stli_dummybrd.brdnr >= STL_MAXBRDS))
+ if (stli_dummybrd.brdnr >= STL_MAXBRDS)
return -ENODEV;
brdp = stli_brds[stli_dummybrd.brdnr];
if (!brdp)
done = 0;
rc = 0;
+ lock_kernel();
+
switch (cmd) {
case COM_GETPORTSTATS:
rc = stli_getportstats(NULL, argp);
done++;
break;
}
+ unlock_kernel();
if (done)
return rc;
if (brdp->state == 0)
return -ENODEV;
+ lock_kernel();
+
switch (cmd) {
case STL_BINTR:
EBRDINTR(brdp);
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
return rc;
}
};
/*****************************************************************************/
+/*
+ * Loadable module initialization stuff.
+ */
-static int __init stli_init(void)
+static void istallion_cleanup_isa(void)
{
- int i;
+ struct stlibrd *brdp;
+ unsigned int j;
+
+ for (j = 0; (j < stli_nrbrds); j++) {
+ if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED))
+ continue;
+
+ stli_cleanup_ports(brdp);
+
+ iounmap(brdp->membase);
+ if (brdp->iosize > 0)
+ release_region(brdp->iobase, brdp->iosize);
+ kfree(brdp);
+ stli_brds[j] = NULL;
+ }
+}
+
+static int __init istallion_module_init(void)
+{
+ unsigned int i;
+ int retval;
+
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
spin_lock_init(&stli_lock);
spin_lock_init(&brd_lock);
- stli_initbrds();
-
- stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
- if (!stli_serial)
- return -ENOMEM;
-
-/*
- * Allocate a temporary write buffer.
- */
stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
- if (!stli_txcookbuf)
+ if (!stli_txcookbuf) {
printk(KERN_ERR "STALLION: failed to allocate memory "
"(size=%d)\n", STLI_TXBUFSIZE);
+ retval = -ENOMEM;
+ goto err;
+ }
-/*
- * Set up a character driver for the shared memory region. We need this
- * to down load the slave code image. Also it is a useful debugging tool.
- */
- if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem))
- printk(KERN_ERR "STALLION: failed to register serial memory "
- "device\n");
-
- istallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
+ if (!stli_serial) {
+ retval = -ENOMEM;
+ goto err_free;
+ }
-/*
- * Set up the tty driver structure and register us as a driver.
- */
stli_serial->owner = THIS_MODULE;
stli_serial->driver_name = stli_drvname;
stli_serial->name = stli_serialname;
stli_serial->type = TTY_DRIVER_TYPE_SERIAL;
stli_serial->subtype = SERIAL_TYPE_NORMAL;
stli_serial->init_termios = stli_deftermios;
- stli_serial->flags = TTY_DRIVER_REAL_RAW;
+ stli_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(stli_serial, &stli_ops);
- if (tty_register_driver(stli_serial)) {
- put_tty_driver(stli_serial);
+ retval = tty_register_driver(stli_serial);
+ if (retval) {
printk(KERN_ERR "STALLION: failed to register serial driver\n");
- return -EBUSY;
+ goto err_ttyput;
}
+
+ retval = stli_initbrds();
+ if (retval)
+ goto err_ttyunr;
+
+/*
+ * Set up a character driver for the shared memory region. We need this
+ * to down load the slave code image. Also it is a useful debugging tool.
+ */
+ retval = register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stli_fsiomem);
+ if (retval) {
+ printk(KERN_ERR "STALLION: failed to register serial memory "
+ "device\n");
+ goto err_deinit;
+ }
+
+ istallion_class = class_create(THIS_MODULE, "staliomem");
+ for (i = 0; i < 4; i++)
+ device_create_drvdata(istallion_class, NULL,
+ MKDEV(STL_SIOMEMMAJOR, i),
+ NULL, "staliomem%d", i);
+
return 0;
+err_deinit:
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+err_ttyunr:
+ tty_unregister_driver(stli_serial);
+err_ttyput:
+ put_tty_driver(stli_serial);
+err_free:
+ kfree(stli_txcookbuf);
+err:
+ return retval;
}
/*****************************************************************************/
+
+static void __exit istallion_module_exit(void)
+{
+ unsigned int j;
+
+ printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
+ stli_drvversion);
+
+ if (stli_timeron) {
+ stli_timeron = 0;
+ del_timer_sync(&stli_timerlist);
+ }
+
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
+
+ for (j = 0; j < 4; j++)
+ device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
+ class_destroy(istallion_class);
+
+ pci_unregister_driver(&stli_pcidriver);
+ istallion_cleanup_isa();
+
+ tty_unregister_driver(stli_serial);
+ put_tty_driver(stli_serial);
+
+ kfree(stli_txcookbuf);
+}
+
+module_init(istallion_module_init);
+module_exit(istallion_module_exit);