Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / char / pcmcia / synclink_cs.c
index 5d7f215..0721345 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/pcmcia/synclink_cs.c
  *
- * $Id: synclink_cs.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $
  *
  * Device driver for Microgate SyncLink PC Card
  * multiprotocol serial adapter.
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
 #include <asm/types.h>
 #include <linux/termios.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
 
-#include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -229,7 +228,7 @@ typedef struct _mgslpc_info {
        struct  _input_signal_events    input_signal_events;
 
        /* PCMCIA support */
-       dev_link_t            link;
+       struct pcmcia_device    *p_dev;
        dev_node_t            node;
        int                   stop;
 
@@ -464,26 +463,16 @@ static int debug_level = 0;
 static int maxframe[MAX_DEVICE_COUNT] = {0,};
 static int dosyncppp[MAX_DEVICE_COUNT] = {1,1,1,1};
 
-/* The old way: bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
-static u_int irq_mask = 0xdeb8;
-
-/* Newer, simpler way of listing specific interrupts */
-static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-
-MODULE_PARM(break_on_load,"i");
-MODULE_PARM(ttymajor,"i");
-MODULE_PARM(debug_level,"i");
-MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
-MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
+module_param(break_on_load, bool, 0);
+module_param(ttymajor, int, 0);
+module_param(debug_level, int, 0);
+module_param_array(maxframe, int, NULL, 0);
+module_param_array(dosyncppp, int, NULL, 0);
 
 MODULE_LICENSE("GPL");
 
 static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.26 $";
+static char *driver_version = "$Revision: 4.34 $";
 
 static struct tty_driver *serial_driver;
 
@@ -495,15 +484,9 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout);
 
 /* PCMCIA prototypes */
 
-static void mgslpc_config(dev_link_t *link);
+static int mgslpc_config(struct pcmcia_device *link);
 static void mgslpc_release(u_long arg);
-static int  mgslpc_event(event_t event, int priority,
-                        event_callback_args_t *args);
-static dev_link_t *mgslpc_attach(void);
-static void mgslpc_detach(dev_link_t *);
-
-static dev_info_t dev_info = "synclink_cs";
-static dev_link_t *dev_list = NULL;
+static void mgslpc_detach(struct pcmcia_device *p_dev);
 
 /*
  * 1st function defined in .text section. Calling this function in
@@ -550,20 +533,18 @@ static void ldisc_receive_buf(struct tty_struct *tty,
        }
 }
 
-static dev_link_t *mgslpc_attach(void)
+static int mgslpc_probe(struct pcmcia_device *link)
 {
     MGSLPC_INFO *info;
-    dev_link_t *link;
-    client_reg_t client_reg;
-    int ret, i;
-    
+    int ret;
+
     if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_attach\n");
-       
+
     info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
     if (!info) {
            printk("Error can't allocate device instance data\n");
-           return NULL;
+           return -ENOMEM;
     }
 
     memset(info, 0, sizeof(MGSLPC_INFO));
@@ -584,49 +565,26 @@ static dev_link_t *mgslpc_attach(void)
     info->imrb_value = 0xffff;
     info->pim_value = 0xff;
 
-    link = &info->link;
+    info->p_dev = link;
     link->priv = info;
-    
-    /* Initialize the dev_link_t structure */
+
+    /* Initialize the struct pcmcia_device structure */
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-    link->irq.IRQInfo1   = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-    if (irq_list[0] == -1)
-           link->irq.IRQInfo2 = irq_mask;
-    else
-           for (i = 0; i < 4; i++)
-                   link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.IRQInfo1   = IRQ_LEVEL_ID;
     link->irq.Handler = NULL;
-    
+
     link->conf.Attributes = 0;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    /* Register with Card Services */
-    link->next = dev_list;
-    dev_list = link;
-
-    client_reg.dev_info = &dev_info;
-    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-    client_reg.EventMask =
-           CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-           CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-           CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-    client_reg.event_handler = &mgslpc_event;
-    client_reg.Version = 0x0210;
-    client_reg.event_callback_args.client_data = link;
-
-    ret = pcmcia_register_client(&link->handle, &client_reg);
-    if (ret != CS_SUCCESS) {
-           cs_error(link->handle, RegisterClient, ret);
-           mgslpc_detach(link);
-           return NULL;
-    }
+    ret = mgslpc_config(link);
+    if (ret)
+           return ret;
 
     mgslpc_add_device(info);
 
-    return link;
+    return 0;
 }
 
 /* Card has been inserted.
@@ -635,15 +593,13 @@ static dev_link_t *mgslpc_attach(void)
 #define CS_CHECK(fn, ret) \
 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 
-static void mgslpc_config(dev_link_t *link)
+static int mgslpc_config(struct pcmcia_device *link)
 {
-    client_handle_t handle = link->handle;
     MGSLPC_INFO *info = link->priv;
     tuple_t tuple;
     cisparse_t parse;
     int last_fn, last_ret;
     u_char buf[64];
-    config_info_t conf;
     cistpl_cftable_entry_t dflt = { 0 };
     cistpl_cftable_entry_t *cfg;
     
@@ -656,27 +612,20 @@ static void mgslpc_config(dev_link_t *link)
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
-    /* Configure card */
-    link->state |= DEV_CONFIG;
-
-    /* Look up the current Vcc */
-    CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
-    link->conf.Vcc = conf.Vcc;
 
     /* get CIS configuration entry */
 
     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
 
     cfg = &(parse.cftable_entry);
-    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
 
     if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
     if (cfg->index == 0)
@@ -697,11 +646,10 @@ static void mgslpc_config(dev_link_t *link)
            link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
            link->io.BasePort1 = io->win[0].base;
            link->io.NumPorts1 = io->win[0].len;
-           CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
+           CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io));
     }
 
     link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.Vcc = 50;
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 8;
     link->conf.Present = PRESENT_OPTION;
@@ -709,9 +657,9 @@ static void mgslpc_config(dev_link_t *link)
     link->irq.Attributes |= IRQ_HANDLE_PRESENT;
     link->irq.Handler     = mgslpc_isr;
     link->irq.Instance    = info;
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
 
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
 
     info->io_base = link->io.BasePort1;
     info->irq_level = link->irq.AssignedIRQ;
@@ -719,7 +667,7 @@ static void mgslpc_config(dev_link_t *link)
     /* add to linked list of devices */
     sprintf(info->node.dev_name, "mgslpc0");
     info->node.major = info->node.minor = 0;
-    link->dev = &info->node;
+    link->dev_node = &info->node;
 
     printk(KERN_INFO "%s: index 0x%02x:",
           info->node.dev_name, link->conf.ConfigIndex);
@@ -729,13 +677,12 @@ static void mgslpc_config(dev_link_t *link)
            printk(", io 0x%04x-0x%04x", link->io.BasePort1,
                   link->io.BasePort1+link->io.NumPorts1-1);
     printk("\n");
-    
-    link->state &= ~DEV_CONFIG_PENDING;
-    return;
+    return 0;
 
 cs_failed:
-    cs_error(link->handle, last_fn, last_ret);
+    cs_error(link, last_fn, last_ret);
     mgslpc_release((u_long)link);
+    return -ENODEV;
 }
 
 /* Card has been removed.
@@ -744,99 +691,44 @@ cs_failed:
  */
 static void mgslpc_release(u_long arg)
 {
-    dev_link_t *link = (dev_link_t *)arg;
+       struct pcmcia_device *link = (struct pcmcia_device *)arg;
 
-    if (debug_level >= DEBUG_LEVEL_INFO)
-           printk("mgslpc_release(0x%p)\n", link);
+       if (debug_level >= DEBUG_LEVEL_INFO)
+               printk("mgslpc_release(0x%p)\n", link);
 
-    /* Unlink the device chain */
-    link->dev = NULL;
-    link->state &= ~DEV_CONFIG;
+       pcmcia_disable_device(link);
+}
 
-    pcmcia_release_configuration(link->handle);
-    if (link->io.NumPorts1)
-           pcmcia_release_io(link->handle, &link->io);
-    if (link->irq.AssignedIRQ)
-           pcmcia_release_irq(link->handle, &link->irq);
-    if (link->state & DEV_STALE_LINK)
-           mgslpc_detach(link);
+static void mgslpc_detach(struct pcmcia_device *link)
+{
+       if (debug_level >= DEBUG_LEVEL_INFO)
+               printk("mgslpc_detach(0x%p)\n", link);
+
+       ((MGSLPC_INFO *)link->priv)->stop = 1;
+       mgslpc_release((u_long)link);
+
+       mgslpc_remove_device((MGSLPC_INFO *)link->priv);
 }
 
-static void mgslpc_detach(dev_link_t *link)
+static int mgslpc_suspend(struct pcmcia_device *link)
 {
-    dev_link_t **linkp;
+       MGSLPC_INFO *info = link->priv;
 
-    if (debug_level >= DEBUG_LEVEL_INFO)
-           printk("mgslpc_detach(0x%p)\n", link);
-    
-    /* find device */
-    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-           if (*linkp == link) break;
-    if (*linkp == NULL)
-           return;
-
-    if (link->state & DEV_CONFIG) {
-           /* device is configured/active, mark it so when
-            * release() is called a proper detach() occurs.
-            */
-           if (debug_level >= DEBUG_LEVEL_INFO)
-                   printk(KERN_DEBUG "synclinkpc: detach postponed, '%s' "
-                          "still locked\n", link->dev->dev_name);
-           link->state |= DEV_STALE_LINK;
-           return;
-    }
+       info->stop = 1;
 
-    /* Break the link with Card Services */
-    if (link->handle)
-           pcmcia_deregister_client(link->handle);
-    
-    /* Unlink device structure, and free it */
-    *linkp = link->next;
-    mgslpc_remove_device((MGSLPC_INFO *)link->priv);
+       return 0;
 }
 
-static int mgslpc_event(event_t event, int priority,
-                       event_callback_args_t *args)
+static int mgslpc_resume(struct pcmcia_device *link)
 {
-    dev_link_t *link = args->client_data;
-    MGSLPC_INFO *info = link->priv;
-    
-    if (debug_level >= DEBUG_LEVEL_INFO)
-           printk("mgslpc_event(0x%06x)\n", event);
-    
-    switch (event) {
-    case CS_EVENT_CARD_REMOVAL:
-           link->state &= ~DEV_PRESENT;
-           if (link->state & DEV_CONFIG) {
-                   ((MGSLPC_INFO *)link->priv)->stop = 1;
-                   mgslpc_release((u_long)link);
-           }
-           break;
-    case CS_EVENT_CARD_INSERTION:
-           link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-           mgslpc_config(link);
-           break;
-    case CS_EVENT_PM_SUSPEND:
-           link->state |= DEV_SUSPEND;
-           /* Fall through... */
-    case CS_EVENT_RESET_PHYSICAL:
-           /* Mark the device as stopped, to block IO until later */
-           info->stop = 1;
-           if (link->state & DEV_CONFIG)
-                   pcmcia_release_configuration(link->handle);
-           break;
-    case CS_EVENT_PM_RESUME:
-           link->state &= ~DEV_SUSPEND;
-           /* Fall through... */
-    case CS_EVENT_CARD_RESET:
-           if (link->state & DEV_CONFIG)
-                   pcmcia_request_configuration(link->handle, &link->conf);
-           info->stop = 0;
-           break;
-    }
-    return 0;
+       MGSLPC_INFO *info = link->priv;
+
+       info->stop = 0;
+
+       return 0;
 }
 
+
 static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
                                        char *name, const char *routine)
 {
@@ -923,7 +815,7 @@ static void tx_release(struct tty_struct *tty)
 /* Return next bottom half action to perform.
  * or 0 if nothing to do.
  */
-int bh_action(MGSLPC_INFO *info)
+static int bh_action(MGSLPC_INFO *info)
 {
        unsigned long flags;
        int rc = 0;
@@ -1017,7 +909,7 @@ void bh_status(MGSLPC_INFO *info)
 }
 
 /* eom: non-zero = end of frame */ 
-void rx_ready_hdlc(MGSLPC_INFO *info, int eom) 
+static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
 {
        unsigned char data[2];
        unsigned char fifo_count, read_count, i;
@@ -1079,10 +971,11 @@ void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
        issue_command(info, CHA, CMD_RXFIFO);
 }
 
-void rx_ready_async(MGSLPC_INFO *info, int tcd) 
+static void rx_ready_async(MGSLPC_INFO *info, int tcd)
 {
-       unsigned char data, status;
+       unsigned char data, status, flag;
        int fifo_count;
+       int work = 0;
        struct tty_struct *tty = info->tty;
        struct mgsl_icount *icount = &info->icount;
 
@@ -1097,20 +990,16 @@ void rx_ready_async(MGSLPC_INFO *info, int tcd)
                        fifo_count = 32;
        } else
                fifo_count = 32;
-       
+
+       tty_buffer_request_room(tty, fifo_count);
        /* Flush received async data to receive data buffer. */ 
        while (fifo_count) {
                data   = read_reg(info, CHA + RXFIFO);
                status = read_reg(info, CHA + RXFIFO);
                fifo_count -= 2;
 
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                       break;
-                       
-               *tty->flip.char_buf_ptr = data;
                icount->rx++;
-               
-               *tty->flip.flag_buf_ptr = 0;
+               flag = TTY_NORMAL;
 
                // if no frameing/crc error then save data
                // BIT7:parity error
@@ -1129,31 +1018,28 @@ void rx_ready_async(MGSLPC_INFO *info, int tcd)
                        status &= info->read_status_mask;
 
                        if (status & BIT7)
-                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                               flag = TTY_PARITY;
                        else if (status & BIT6)
-                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                               flag = TTY_FRAME;
                }
-               
-               tty->flip.flag_buf_ptr++;
-               tty->flip.char_buf_ptr++;
-               tty->flip.count++;
+               work += tty_insert_flip_char(tty, data, flag);
        }
        issue_command(info, CHA, CMD_RXFIFO);
 
        if (debug_level >= DEBUG_LEVEL_ISR) {
-               printk("%s(%d):rx_ready_async count=%d\n",
-                       __FILE__,__LINE__,tty->flip.count);
+               printk("%s(%d):rx_ready_async",
+                       __FILE__,__LINE__);
                printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n",
                        __FILE__,__LINE__,icount->rx,icount->brk,
                        icount->parity,icount->frame,icount->overrun);
        }
                        
-       if (tty->flip.count)
+       if (work)
                tty_flip_buffer_push(tty);
 }
 
 
-void tx_done(MGSLPC_INFO *info) 
+static void tx_done(MGSLPC_INFO *info)
 {
        if (!info->tx_active)
                return;
@@ -1190,7 +1076,7 @@ void tx_done(MGSLPC_INFO *info)
        }
 }
 
-void tx_ready(MGSLPC_INFO *info) 
+static void tx_ready(MGSLPC_INFO *info)
 {
        unsigned char fifo_count = 32;
        int c;
@@ -1239,7 +1125,7 @@ void tx_ready(MGSLPC_INFO *info)
        }
 }
 
-void cts_change(MGSLPC_INFO *info) 
+static void cts_change(MGSLPC_INFO *info)
 {
        get_signals(info);
        if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1276,7 +1162,7 @@ void cts_change(MGSLPC_INFO *info)
        info->pending_bh |= BH_STATUS;
 }
 
-void dcd_change(MGSLPC_INFO *info) 
+static void dcd_change(MGSLPC_INFO *info)
 {
        get_signals(info);
        if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1310,7 +1196,7 @@ void dcd_change(MGSLPC_INFO *info)
        info->pending_bh |= BH_STATUS;
 }
 
-void dsr_change(MGSLPC_INFO *info) 
+static void dsr_change(MGSLPC_INFO *info)
 {
        get_signals(info);
        if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1325,7 +1211,7 @@ void dsr_change(MGSLPC_INFO *info)
        info->pending_bh |= BH_STATUS;
 }
 
-void ri_change(MGSLPC_INFO *info) 
+static void ri_change(MGSLPC_INFO *info)
 {
        get_signals(info);
        if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
@@ -1360,7 +1246,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
        if (!info)
                return IRQ_NONE;
                
-       if (!(info->link.state & DEV_CONFIG))
+       if (!(info->p_dev->_locked))
                return IRQ_HANDLED;
 
        spin_lock(&info->lock);
@@ -1479,6 +1365,8 @@ static int startup(MGSLPC_INFO * info)
 
        info->pending_bh = 0;
        
+       memset(&info->icount, 0, sizeof(info->icount));
+
        init_timer(&info->tx_timer);
        info->tx_timer.data = (unsigned long)info;
        info->tx_timer.function = tx_timeout;
@@ -1744,16 +1632,15 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
  * Arguments:
  * 
  * tty        pointer to tty information structure
- * from_user  flag: 1 = from user process
  * buf       pointer to buffer containing send data
  * count      size of send data in bytes
  *     
  * Returns: number of characters written
  */
-static int mgslpc_write(struct tty_struct * tty, int from_user,
+static int mgslpc_write(struct tty_struct * tty,
                        const unsigned char *buf, int count)
 {
-       int c, ret = 0, err;
+       int c, ret = 0;
        MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
        unsigned long flags;
        
@@ -1783,15 +1670,7 @@ static int mgslpc_write(struct tty_struct * tty, int from_user,
                if (c <= 0)
                        break;
                        
-               if (from_user) {
-                       COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c);
-                       if (err) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-               } else
-                       memcpy(info->tx_buf + info->tx_put, buf, c);
+               memcpy(info->tx_buf + info->tx_put, buf, c);
 
                spin_lock_irqsave(&info->lock,flags);
                info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1);
@@ -1977,9 +1856,13 @@ static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount)
        int err;
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("get_params(%s)\n", info->device_name);
-       COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount));
-       if (err)
-               return -EFAULT;
+       if (!user_icount) {
+               memset(&info->icount, 0, sizeof(info->icount));
+       } else {
+               COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount));
+               if (err)
+                       return -EFAULT;
+       }
        return 0;
 }
 
@@ -2609,8 +2492,7 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
        
        if (info->blocked_open) {
                if (info->close_delay) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(info->close_delay);
+                       msleep_interruptible(jiffies_to_msecs(info->close_delay));
                }
                wake_up_interruptible(&info->open_wait);
        }
@@ -2665,8 +2547,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
                
        if (info->params.mode == MGSL_MODE_HDLC) {
                while (info->tx_active) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(char_time);
+                       msleep_interruptible(jiffies_to_msecs(char_time));
                        if (signal_pending(current))
                                break;
                        if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -2675,8 +2556,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
        } else {
                while ((info->tx_count || info->tx_active) &&
                        info->tx_enabled) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(char_time);
+                       msleep_interruptible(jiffies_to_msecs(char_time));
                        if (signal_pending(current))
                                break;
                        if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -2967,7 +2847,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
 
 /* Called to print information about devices
  */
-int mgslpc_read_proc(char *page, char **start, off_t off, int count,
+static int mgslpc_read_proc(char *page, char **start, off_t off, int count,
                 int *eof, void *data)
 {
        int len = 0, l;
@@ -3022,8 +2902,7 @@ int rx_alloc_buffers(MGSLPC_INFO *info)
 
 void rx_free_buffers(MGSLPC_INFO *info)
 {
-       if (info->rx_buf)
-               kfree(info->rx_buf);
+       kfree(info->rx_buf);
        info->rx_buf = NULL;
 }
 
@@ -3109,13 +2988,22 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
        }
 }
 
+static struct pcmcia_device_id mgslpc_ids[] = {
+       PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
+       PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
+
 static struct pcmcia_driver mgslpc_driver = {
        .owner          = THIS_MODULE,
        .drv            = {
                .name   = "synclink_cs",
        },
-       .attach         = mgslpc_attach,
-       .detach         = mgslpc_detach,
+       .probe          = mgslpc_probe,
+       .remove         = mgslpc_detach,
+       .id_table       = mgslpc_ids,
+       .suspend        = mgslpc_suspend,
+       .resume         = mgslpc_resume,
 };
 
 static struct tty_operations mgslpc_ops = {
@@ -3159,13 +3047,6 @@ static void synclink_cs_cleanup(void)
        }
 
        pcmcia_unregister_driver(&mgslpc_driver);
-
-       /* XXX: this really needs to move into generic code.. */
-       while (dev_list != NULL) {
-               if (dev_list->state & DEV_CONFIG)
-                       mgslpc_release((u_long)dev_list);
-               mgslpc_detach(dev_list);
-       }
 }
 
 static int __init synclink_cs_init(void)
@@ -3230,7 +3111,7 @@ static void __exit synclink_cs_exit(void)
 module_init(synclink_cs_init);
 module_exit(synclink_cs_exit);
 
-void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) 
+static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate)
 {
        unsigned int M, N;
        unsigned char val;
@@ -3266,7 +3147,7 @@ void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate
 
 /* Enabled the AUX clock output at the specified frequency.
  */
-void enable_auxclk(MGSLPC_INFO *info)
+static void enable_auxclk(MGSLPC_INFO *info)
 {
        unsigned char val;
        
@@ -4084,7 +3965,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
 {
        static unsigned char patterns[] = 
            { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
-       static unsigned int count = sizeof(patterns) / sizeof(patterns[0]);
+       static unsigned int count = ARRAY_SIZE(patterns);
        unsigned int i;
        BOOLEAN rc = TRUE;
        unsigned long flags;
@@ -4095,7 +3976,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
        for (i = 0; i < count; i++) {
                write_reg(info, XAD1, patterns[i]);
                write_reg(info, XAD2, patterns[(i + 1) % count]);
-               if ((read_reg(info, XAD1) != patterns[i]) || 
+               if ((read_reg(info, XAD1) != patterns[i]) ||
                    (read_reg(info, XAD2) != patterns[(i + 1) % count])) {
                        rc = FALSE;
                        break;
@@ -4129,8 +4010,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info)
 
        end_time=100;
        while(end_time-- && !info->irq_occurred) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(msecs_to_jiffies(10));
+               msleep_interruptible(10);
        }
        
        info->testing_irq = FALSE;
@@ -4267,7 +4147,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
        }
 
        info->params.encoding = new_encoding;
-       info->params.crc_type = new_crctype;;
+       info->params.crc_type = new_crctype;
 
        /* if network interface up, reprogram hardware */
        if (info->netcount)
@@ -4570,9 +4450,7 @@ static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
 
        memcpy(skb_put(skb, size),buf,size);
 
-       skb->dev      = info->netdev;
-       skb->mac.raw  = skb->data;
-       skb->protocol = hdlc_type_trans(skb, skb->dev);
+       skb->protocol = hdlc_type_trans(skb, info->netdev);
 
        stats->rx_packets++;
        stats->rx_bytes += size;