specialix: Switch to int put_char method
[linux-2.6.git] / drivers / char / specialix.c
index 5343e9f..dfb7cd7 100644 (file)
@@ -75,7 +75,6 @@
  * Documentation/specialix.txt
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/io.h>
@@ -179,16 +178,7 @@ static int sx_poll = HZ;
         ASYNC_SPD_HI       | ASYNC_SPEED_VHI    | ASYNC_SESSION_LOCKOUT | \
         ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP)
 
-#undef RS_EVENT_WRITE_WAKEUP
-#define RS_EVENT_WRITE_WAKEUP  0
-
 static struct tty_driver *specialix_driver;
-static unsigned char * tmp_buf;
-
-static unsigned long baud_table[] =  {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 0,
-};
 
 static struct specialix_board sx_board[SX_NBOARD] =  {
        { 0, SX_IOBASE1,  9, },
@@ -202,7 +192,7 @@ static struct specialix_port sx_port[SX_NBOARD * SX_NPORT];
 
 #ifdef SPECIALIX_TIMER
 static struct timer_list missed_irq_timer;
-static irqreturn_t sx_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t sx_interrupt(int irq, void * dev_id);
 #endif
 
 
@@ -352,18 +342,6 @@ static inline void sx_release_io_range(struct specialix_board * bp)
 }
 
 
-/* Must be called with enabled interrupts */
-/* Ugly. Very ugly. Don't use this for anything else than initialization
-   code */
-static inline void sx_long_delay(unsigned long delay)
-{
-       unsigned long i;
-
-       for (i = jiffies + delay; time_after(i, jiffies); ) ;
-}
-
-
-
 /* Set the IRQ using the RTS lines that run to the PAL on the board.... */
 static int sx_set_irq ( struct specialix_board *bp)
 {
@@ -404,7 +382,7 @@ static int sx_init_CD186x(struct specialix_board  * bp)
        spin_lock_irqsave(&bp->lock, flags);
        sx_out_off(bp, CD186x_CCR, CCR_HARDRESET);      /* Reset CD186x chip          */
        spin_unlock_irqrestore(&bp->lock, flags);
-       sx_long_delay(HZ/20);                      /* Delay 0.05 sec            */
+       msleep(50);                                     /* Delay 0.05 sec            */
        spin_lock_irqsave(&bp->lock, flags);
        sx_out_off(bp, CD186x_GIVR, SX_ID);             /* Set ID for this chip      */
        sx_out_off(bp, CD186x_GICR, 0);                 /* Clear all bits            */
@@ -465,11 +443,9 @@ void missed_irq (unsigned long data)
        spin_unlock_irqrestore(&bp->lock, flags);
        if (irq) {
                printk (KERN_INFO "Missed interrupt... Calling int from timer. \n");
-               sx_interrupt (((struct specialix_board *)data)->irq,
-                             (void*)data, NULL);
+               sx_interrupt (-1, bp);
        }
-       missed_irq_timer.expires = jiffies + sx_poll;
-       add_timer (&missed_irq_timer);
+       mod_timer(&missed_irq_timer, jiffies + sx_poll);
 }
 #endif
 
@@ -541,7 +517,7 @@ static int sx_probe(struct specialix_board *bp)
                sx_wait_CCR(bp);
                sx_out(bp, CD186x_CCR, CCR_TXEN);        /* Enable transmitter     */
                sx_out(bp, CD186x_IER, IER_TXRDY);       /* Enable tx empty intr   */
-               sx_long_delay(HZ/20);
+               msleep(50);
                irqs = probe_irq_off(irqs);
 
                dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
@@ -604,11 +580,8 @@ static int sx_probe(struct specialix_board *bp)
        dprintk (SX_DEBUG_INIT, " GFCR = 0x%02x\n", sx_in_off(bp, CD186x_GFRCR) );
 
 #ifdef SPECIALIX_TIMER
-       init_timer (&missed_irq_timer);
-       missed_irq_timer.function = missed_irq;
-       missed_irq_timer.data = (unsigned long) bp;
-       missed_irq_timer.expires = jiffies + sx_poll;
-       add_timer (&missed_irq_timer);
+       setup_timer(&missed_irq_timer, missed_irq, (unsigned long)bp);
+       mod_timer(&missed_irq_timer, jiffies + sx_poll);
 #endif
 
        printk(KERN_INFO"sx%d: specialix IO8+ board detected at 0x%03x, IRQ %d, CD%d Rev. %c.\n",
@@ -625,17 +598,6 @@ static int sx_probe(struct specialix_board *bp)
  *  Interrupt processing routines.
  * */
 
-static inline void sx_mark_event(struct specialix_port * port, int event)
-{
-       func_enter();
-
-       set_bit(event, &port->event);
-       schedule_work(&port->tqueue);
-
-       func_exit();
-}
-
-
 static inline struct specialix_port * sx_get_port(struct specialix_board * bp,
                                               unsigned char const * what)
 {
@@ -832,7 +794,7 @@ static inline void sx_transmit(struct specialix_board * bp)
                sx_out(bp, CD186x_IER, port->IER);
        }
        if (port->xmit_cnt <= port->wakeup_chars)
-               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+               tty_wakeup(tty);
 
        func_exit();
 }
@@ -862,7 +824,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        wake_up_interruptible(&port->open_wait);
                } else {
                        dprintk (SX_DEBUG_SIGNALS, "Sending HUP.\n");
-                       schedule_work(&port->tqueue_hangup);
+                       tty_hangup(tty);
                }
        }
 
@@ -872,7 +834,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -884,7 +846,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
                        tty->hw_stopped = 0;
                        port->IER |= IER_TXRDY;
                        if (port->xmit_cnt <= port->wakeup_chars)
-                               sx_mark_event(port, RS_EVENT_WRITE_WAKEUP);
+                               tty_wakeup(tty);
                } else {
                        tty->hw_stopped = 1;
                        port->IER &= ~IER_TXRDY;
@@ -899,23 +861,22 @@ static inline void sx_check_modem(struct specialix_board * bp)
 
 
 /* The main interrupt processing routine */
-static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sx_interrupt(int dummy, void *dev_id)
 {
        unsigned char status;
        unsigned char ack;
-       struct specialix_board *bp;
+       struct specialix_board *bp = dev_id;
        unsigned long loop = 0;
        int saved_reg;
        unsigned long flags;
 
        func_enter();
 
-       bp = dev_id;
        spin_lock_irqsave(&bp->lock, flags);
 
        dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
-       if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
-               dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
+       if (!(bp->flags & SX_BOARD_ACTIVE)) {
+               dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq);
                spin_unlock_irqrestore(&bp->lock, flags);
                func_exit();
                return IRQ_NONE;
@@ -1016,9 +977,9 @@ static inline int sx_setup_board(struct specialix_board * bp)
                return 0;
 
        if (bp->flags & SX_BOARD_IS_PCI)
-               error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT | SA_SHIRQ, "specialix IO8+", bp);
+               error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);
        else
-               error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
+               error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED, "specialix IO8+", bp);
 
        if (error)
                return error;
@@ -1088,24 +1049,16 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
                port->MSVR =  (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
        spin_unlock_irqrestore(&bp->lock, flags);
        dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
-       baud = C_BAUD(tty);
+       baud = tty_get_baud_rate(tty);
 
-       if (baud & CBAUDEX) {
-               baud &= ~CBAUDEX;
-               if (baud < 1 || baud > 2)
-                       port->tty->termios->c_cflag &= ~CBAUDEX;
-               else
-                       baud += 15;
-       }
-       if (baud == 15) {
+       if (baud == 38400) {
                if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-                       baud ++;
+                       baud = 57600;
                if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-                       baud += 2;
+                       baud = 115200;
        }
 
-
-       if (!baud_table[baud]) {
+       if (!baud) {
                /* Drop DTR & exit */
                dprintk (SX_DEBUG_TERMIOS, "Dropping DTR...  Hmm....\n");
                if (!SX_CRTSCTS (tty)) {
@@ -1135,7 +1088,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
                                  "This is an untested option, please be carefull.\n",
                                  port_No (port), tmp);
        else
-               tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
+               tmp = (((SX_OSCFREQ + baud/2) / baud +
                         CD186x_TPC/2) / CD186x_TPC);
 
        if ((tmp < 0x10) && time_before(again, jiffies)) {
@@ -1160,11 +1113,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
        sx_out(bp, CD186x_RBPRL, tmp & 0xff);
        sx_out(bp, CD186x_TBPRL, tmp & 0xff);
        spin_unlock_irqrestore(&bp->lock, flags);
-       if (port->custom_divisor) {
+       if (port->custom_divisor)
                baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
-               baud = ( baud + 5 ) / 10;
-       } else
-               baud = (baud_table[baud] + 5) / 10;   /* Estimated CPS */
+       baud = (baud + 5) / 10;         /* Estimated CPS */
 
        /* Two timer ticks seems enough to wakeup something like SLIP driver */
        tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO;
@@ -1553,6 +1504,27 @@ static int sx_open(struct tty_struct * tty, struct file * filp)
        return 0;
 }
 
+static void sx_flush_buffer(struct tty_struct *tty)
+{
+       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+       unsigned long flags;
+       struct specialix_board  * bp;
+
+       func_enter();
+
+       if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+               func_exit();
+               return;
+       }
+
+       bp = port_Board(port);
+       spin_lock_irqsave(&port->lock, flags);
+       port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+       tty_wakeup(tty);
+
+       func_exit();
+}
 
 static void sx_close(struct tty_struct * tty, struct file * filp)
 {
@@ -1646,12 +1618,10 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
        }
 
        sx_shutdown_port(bp, port);
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
+       sx_flush_buffer(tty);
        tty_ldisc_flush(tty);
        spin_lock_irqsave(&port->lock, flags);
        tty->closing = 0;
-       port->event = 0;
        port->tty = NULL;
        spin_unlock_irqrestore(&port->lock, flags);
        if (port->blocked_open) {
@@ -1683,7 +1653,7 @@ static int sx_write(struct tty_struct * tty,
 
        bp = port_Board(port);
 
-       if (!tty || !port->xmit_buf || !tmp_buf) {
+       if (!port->xmit_buf) {
                func_exit();
                return 0;
        }
@@ -1720,7 +1690,7 @@ static int sx_write(struct tty_struct * tty,
 }
 
 
-static void sx_put_char(struct tty_struct * tty, unsigned char ch)
+static int sx_put_char(struct tty_struct * tty, unsigned char ch)
 {
        struct specialix_port *port = (struct specialix_port *)tty->driver_data;
        unsigned long flags;
@@ -1730,12 +1700,12 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
 
        if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
                func_exit();
-               return;
+               return 0;
        }
        dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
-       if (!tty || !port->xmit_buf) {
+       if (!port->xmit_buf) {
                func_exit();
-               return;
+               return 0;
        }
        bp = port_Board(port);
        spin_lock_irqsave(&port->lock, flags);
@@ -1745,7 +1715,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
                spin_unlock_irqrestore(&port->lock, flags);
                dprintk (SX_DEBUG_TX, "Exit size\n");
                func_exit();
-               return;
+               return 0;
        }
        dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
        port->xmit_buf[port->xmit_head++] = ch;
@@ -1754,6 +1724,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
        spin_unlock_irqrestore(&port->lock, flags);
 
        func_exit();
+       return 1;
 }
 
 
@@ -1820,28 +1791,6 @@ static int sx_chars_in_buffer(struct tty_struct *tty)
 }
 
 
-static void sx_flush_buffer(struct tty_struct *tty)
-{
-       struct specialix_port *port = (struct specialix_port *)tty->driver_data;
-       unsigned long flags;
-       struct specialix_board  * bp;
-
-       func_enter();
-
-       if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
-               func_exit();
-               return;
-       }
-
-       bp = port_Board(port);
-       spin_lock_irqsave(&port->lock, flags);
-       port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-       spin_unlock_irqrestore(&port->lock, flags);
-       tty_wakeup(tty);
-
-       func_exit();
-}
-
 
 static int sx_tiocmget(struct tty_struct *tty, struct file *file)
 {
@@ -1972,29 +1921,13 @@ static inline int sx_set_serial_info(struct specialix_port * port,
        int change_speed;
 
        func_enter();
-       /*
-       if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
-               func_exit();
-               return -EFAULT;
-       }
-       */
+
        if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
                func_enter();
                return -EFAULT;
        }
 
-#if 0
-       if ((tmp.irq != bp->irq) ||
-           (tmp.port != bp->base) ||
-           (tmp.type != PORT_CIRRUS) ||
-           (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
-           (tmp.custom_divisor != 0) ||
-           (tmp.xmit_fifo_size != CD186x_NFIFO) ||
-           (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
-               func_exit();
-               return -EINVAL;
-       }
-#endif
+       lock_kernel();
 
        change_speed = ((port->flags & ASYNC_SPD_MASK) !=
                        (tmp.flags & ASYNC_SPD_MASK));
@@ -2006,6 +1939,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
                    ((tmp.flags & ~ASYNC_USR_MASK) !=
                     (port->flags & ~ASYNC_USR_MASK))) {
                        func_exit();
+                       unlock_kernel();
                        return -EPERM;
                }
                port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -2022,6 +1956,7 @@ static inline int sx_set_serial_info(struct specialix_port * port,
                sx_change_speed(bp, port);
        }
        func_exit();
+       unlock_kernel();
        return 0;
 }
 
@@ -2034,12 +1969,8 @@ static inline int sx_get_serial_info(struct specialix_port * port,
 
        func_enter();
 
-       /*
-       if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
-               return -EFAULT;
-       */
-
        memset(&tmp, 0, sizeof(tmp));
+       lock_kernel();
        tmp.type = PORT_CIRRUS;
        tmp.line = port - sx_port;
        tmp.port = bp->base;
@@ -2050,6 +1981,7 @@ static inline int sx_get_serial_info(struct specialix_port * port,
        tmp.closing_wait = port->closing_wait * HZ/100;
        tmp.custom_divisor =  port->custom_divisor;
        tmp.xmit_fifo_size = CD186x_NFIFO;
+       unlock_kernel();
        if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
                func_exit();
                return -EFAULT;
@@ -2095,23 +2027,6 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp,
                sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
                func_exit();
                return 0;
-        case TIOCGSOFTCAR:
-                if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
-                        func_exit();
-                        return -EFAULT;
-                }
-                func_exit();
-               return 0;
-        case TIOCSSOFTCAR:
-                if (get_user(arg, (unsigned long __user *) argp)) {
-                        func_exit();
-                        return -EFAULT;
-                }
-               tty->termios->c_cflag =
-                       ((tty->termios->c_cflag & ~CLOCAL) |
-                       (arg ? CLOCAL : 0));
-               func_exit();
-               return 0;
         case TIOCGSERIAL:
                 func_exit();
                return sx_get_serial_info(port, argp);
@@ -2157,7 +2072,6 @@ static void sx_throttle(struct tty_struct * tty)
        sx_out(bp, CD186x_CAR, port_No(port));
        spin_unlock_irqrestore(&bp->lock, flags);
        if (I_IXOFF(tty)) {
-               spin_unlock_irqrestore(&bp->lock, flags);
                sx_wait_CCR(bp);
                spin_lock_irqsave(&bp->lock, flags);
                sx_out(bp, CD186x_CCR, CCR_SSCH2);
@@ -2268,31 +2182,6 @@ static void sx_start(struct tty_struct * tty)
        func_exit();
 }
 
-
-/*
- * This routine is called from the work-queue when the interrupt
- * routine has signalled that a hangup has occurred.  The path of
- * hangup processing is:
- *
- *     serial interrupt routine -> (workqueue) ->
- *     do_sx_hangup() -> tty->hangup() -> sx_hangup()
- *
- */
-static void do_sx_hangup(void *private_)
-{
-       struct specialix_port   *port = (struct specialix_port *) private_;
-       struct tty_struct       *tty;
-
-       func_enter();
-
-       tty = port->tty;
-       if (tty)
-               tty_hangup(tty);        /* FIXME: module removal race here */
-
-       func_exit();
-}
-
-
 static void sx_hangup(struct tty_struct * tty)
 {
        struct specialix_port *port = (struct specialix_port *)tty->driver_data;
@@ -2310,7 +2199,6 @@ static void sx_hangup(struct tty_struct * tty)
 
        sx_shutdown_port(bp, port);
        spin_lock_irqsave(&port->lock, flags);
-       port->event = 0;
        bp->count -= port->count;
        if (bp->count < 0) {
                printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",
@@ -2327,7 +2215,7 @@ static void sx_hangup(struct tty_struct * tty)
 }
 
 
-static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios)
+static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
 {
        struct specialix_port *port = (struct specialix_port *)tty->driver_data;
        unsigned long flags;
@@ -2352,28 +2240,7 @@ static void sx_set_termios(struct tty_struct * tty, struct termios * old_termios
        }
 }
 
-
-static void do_softint(void *private_)
-{
-       struct specialix_port   *port = (struct specialix_port *) private_;
-       struct tty_struct       *tty;
-
-       func_enter();
-
-       if(!(tty = port->tty)) {
-               func_exit();
-               return;
-       }
-
-       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {
-               tty_wakeup(tty);
-               //wake_up_interruptible(&tty->write_wait);
-       }
-
-       func_exit();
-}
-
-static struct tty_operations sx_ops = {
+static const struct tty_operations sx_ops = {
        .open  = sx_open,
        .close = sx_close,
        .write = sx_write,
@@ -2407,12 +2274,6 @@ static int sx_init_drivers(void)
                return 1;
        }
 
-       if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
-               printk(KERN_ERR "sx: Couldn't get free page.\n");
-               put_tty_driver(specialix_driver);
-               func_exit();
-               return 1;
-       }
        specialix_driver->owner = THIS_MODULE;
        specialix_driver->name = "ttyW";
        specialix_driver->major = SPECIALIX_NORMAL_MAJOR;
@@ -2421,12 +2282,13 @@ static int sx_init_drivers(void)
        specialix_driver->init_termios = tty_std_termios;
        specialix_driver->init_termios.c_cflag =
                B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       specialix_driver->init_termios.c_ispeed = 9600;
+       specialix_driver->init_termios.c_ospeed = 9600;
        specialix_driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(specialix_driver, &sx_ops);
 
        if ((error = tty_register_driver(specialix_driver))) {
                put_tty_driver(specialix_driver);
-               free_page((unsigned long)tmp_buf);
                printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
                       error);
                func_exit();
@@ -2435,8 +2297,6 @@ static int sx_init_drivers(void)
        memset(sx_port, 0, sizeof(sx_port));
        for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
                sx_port[i].magic = SPECIALIX_MAGIC;
-               INIT_WORK(&sx_port[i].tqueue, do_softint, &sx_port[i]);
-               INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup, &sx_port[i]);
                sx_port[i].close_delay = 50 * HZ/100;
                sx_port[i].closing_wait = 3000 * HZ/100;
                init_waitqueue_head(&sx_port[i].open_wait);
@@ -2452,7 +2312,6 @@ static void sx_release_drivers(void)
 {
        func_enter();
 
-       free_page((unsigned long)tmp_buf);
        tty_unregister_driver(specialix_driver);
        put_tty_driver(specialix_driver);
        func_exit();
@@ -2477,7 +2336,7 @@ static int __init specialix_init(void)
 #endif
 
        for (i = 0; i < SX_NBOARD; i++)
-               sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+               spin_lock_init(&sx_board[i].lock);
 
        if (sx_init_drivers()) {
                func_exit();
@@ -2498,7 +2357,7 @@ static int __init specialix_init(void)
                                i++;
                                continue;
                        }
-                       pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+                       pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
                                                PCI_DEVICE_ID_SPECIALIX_IO8,
                                                pdev);
                        if (!pdev) break;
@@ -2514,6 +2373,9 @@ static int __init specialix_init(void)
                        if (!sx_probe(&sx_board[i]))
                                found ++;
                }
+               /* May exit pci_get sequence early with lots of boards */
+               if (pdev != NULL)
+                       pci_dev_put(pdev);
        }
 #endif
 
@@ -2579,12 +2441,18 @@ static void __exit specialix_exit_module(void)
                if (sx_board[i].flags & SX_BOARD_PRESENT)
                        sx_release_io_range(&sx_board[i]);
 #ifdef SPECIALIX_TIMER
-       del_timer (&missed_irq_timer);
+       del_timer_sync(&missed_irq_timer);
 #endif
 
        func_exit();
 }
 
+static struct pci_device_id specialx_pci_tbl[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, specialx_pci_tbl);
+
 module_init(specialix_init_module);
 module_exit(specialix_exit_module);