fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / char / pcmcia / synclink_cs.c
index b516e54..f108c13 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.
@@ -35,7 +35,6 @@
 
 #define MAX_DEVICE_COUNT 4
 
-#include <linux/config.h>      
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
@@ -57,7 +56,6 @@
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <asm/serial.h>
 #include <linux/delay.h>
 #include <linux/ioctl.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>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 
-#ifdef CONFIG_HDLC_MODULE
-#define CONFIG_HDLC 1
+#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE))
+#define SYNCLINK_GENERIC_HDLC 1
+#else
+#define SYNCLINK_GENERIC_HDLC 0
 #endif
 
 #define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -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;
 
@@ -238,7 +237,7 @@ typedef struct _mgslpc_info {
        int dosyncppp;
        spinlock_t netlock;
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        struct net_device *netdev;
 #endif
 
@@ -395,7 +394,7 @@ static void tx_timeout(unsigned long context);
 
 static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg);
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
 #define dev_to_port(D) (dev_to_hdlc(D)->priv)
 static void hdlcdev_tx_done(MGSLPC_INFO *info);
 static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size);
@@ -419,12 +418,12 @@ static void rx_reset_buffers(MGSLPC_INFO *info);
 static int  rx_alloc_buffers(MGSLPC_INFO *info);
 static void rx_free_buffers(MGSLPC_INFO *info);
 
-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t mgslpc_isr(int irq, void *dev_id);
 
 /*
  * Bottom half interrupt handlers
  */
-static void bh_handler(void* Context);
+static void bh_handler(struct work_struct *work);
 static void bh_transmit(MGSLPC_INFO *info);
 static void bh_status(MGSLPC_INFO *info);
 
@@ -473,7 +472,7 @@ 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;
 
@@ -485,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
@@ -540,32 +533,26 @@ 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;
-    
+
     if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_attach\n");
-       
-    info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+
+    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));
     info->magic = MGSLPC_MAGIC;
-    INIT_WORK(&info->task, bh_handler, info);
+    INIT_WORK(&info->task, bh_handler);
     info->max_frame_size = 4096;
     info->close_delay = 5*HZ/10;
-    #if HZ < 2185
     info->closing_wait = 30*HZ;
-    #else
-    info->closing_wait = 65534;
-    #endif
     init_waitqueue_head(&info->open_wait);
     init_waitqueue_head(&info->close_wait);
     init_waitqueue_head(&info->status_event_wait_q);
@@ -578,43 +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;
+    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.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.
@@ -623,48 +593,32 @@ 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;
     
     if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_config(0x%p)\n", link);
 
-    /* read CONFIG tuple to find its configuration registers */
-    tuple.DesiredTuple = CISTPL_CONFIG;
     tuple.Attributes = 0;
     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));
-    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)
@@ -685,11 +639,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;
@@ -697,9 +650,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;
@@ -707,7 +660,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);
@@ -717,13 +670,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.
@@ -732,99 +684,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)
 {
@@ -940,9 +837,9 @@ static int bh_action(MGSLPC_INFO *info)
        return rc;
 }
 
-void bh_handler(void* Context)
+static void bh_handler(struct work_struct *work)
 {
-       MGSLPC_INFO *info = (MGSLPC_INFO*)Context;
+       MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task);
        int action;
 
        if (!info)
@@ -984,7 +881,7 @@ void bh_handler(void* Context)
                        __FILE__,__LINE__,info->device_name);
 }
 
-void bh_transmit(MGSLPC_INFO *info)
+static void bh_transmit(MGSLPC_INFO *info)
 {
        struct tty_struct *tty = info->tty;
        if (debug_level >= DEBUG_LEVEL_BH)
@@ -996,7 +893,7 @@ void bh_transmit(MGSLPC_INFO *info)
        }
 }
 
-void bh_status(MGSLPC_INFO *info)
+static void bh_status(MGSLPC_INFO *info)
 {
        info->ri_chkcount = 0;
        info->dsr_chkcount = 0;
@@ -1069,8 +966,9 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
 
 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;
 
@@ -1085,20 +983,16 @@ static 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
@@ -1117,26 +1011,23 @@ static 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);
 }
 
@@ -1164,7 +1055,7 @@ static void tx_done(MGSLPC_INFO *info)
                info->drop_rts_on_tx_done = 0;
        }
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        if (info->netcount)
                hdlcdev_tx_done(info);
        else 
@@ -1275,9 +1166,13 @@ static void dcd_change(MGSLPC_INFO *info)
        }
        else
                info->input_signal_events.dcd_down++;
-#ifdef CONFIG_HDLC
-       if (info->netcount)
-               hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev);
+#if SYNCLINK_GENERIC_HDLC
+       if (info->netcount) {
+               if (info->serial_signals & SerialSignal_DCD)
+                       netif_carrier_on(info->netdev);
+               else
+                       netif_carrier_off(info->netdev);
+       }
 #endif
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
@@ -1334,9 +1229,8 @@ static void ri_change(MGSLPC_INFO *info)
  * 
  * irq     interrupt number that caused interrupt
  * dev_id  device ID supplied during interrupt registration
- * regs    interrupted processor context
  */
-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t mgslpc_isr(int irq, void *dev_id)
 {
        MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id;
        unsigned short isr;
@@ -1348,7 +1242,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);
@@ -1467,6 +1361,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;
@@ -1682,7 +1578,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
                return;
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                return;
 
        spin_lock_irqsave(&info->lock,flags);
@@ -1749,7 +1645,7 @@ static int mgslpc_write(struct tty_struct * tty,
                        __FILE__,__LINE__,info->device_name,count);
        
        if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
-           !tty || !info->tx_buf)
+               !info->tx_buf)
                goto cleanup;
 
        if (info->params.mode == MGSL_MODE_HDLC) {
@@ -1956,9 +1852,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;
 }
 
@@ -2401,7 +2301,7 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
        return ioctl_common(info, cmd, arg);
 }
 
-int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
+static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
 {
        int error;
        struct mgsl_icount cnow;        /* kernel counter temps */
@@ -2475,7 +2375,7 @@ int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
  *     tty             pointer to tty structure
  *     termios         pointer to buffer to hold returned old termios
  */
-static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
        unsigned long flags;
@@ -2973,7 +2873,7 @@ done:
        return ((count < begin+len-off) ? count : begin+len-off);
 }
 
-int rx_alloc_buffers(MGSLPC_INFO *info)
+static int rx_alloc_buffers(MGSLPC_INFO *info)
 {
        /* each buffer has header and data */
        info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size;
@@ -2996,14 +2896,13 @@ int rx_alloc_buffers(MGSLPC_INFO *info)
        return 0;
 }
 
-void rx_free_buffers(MGSLPC_INFO *info)
+static void rx_free_buffers(MGSLPC_INFO *info)
 {
-       if (info->rx_buf)
-               kfree(info->rx_buf);
+       kfree(info->rx_buf);
        info->rx_buf = NULL;
 }
 
-int claim_resources(MGSLPC_INFO *info)
+static int claim_resources(MGSLPC_INFO *info)
 {
        if (rx_alloc_buffers(info) < 0 ) {
                printk( "Cant allocate rx buffer %s\n", info->device_name);
@@ -3013,7 +2912,7 @@ int claim_resources(MGSLPC_INFO *info)
        return 0;
 }
 
-void release_resources(MGSLPC_INFO *info)
+static void release_resources(MGSLPC_INFO *info)
 {
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("release_resources(%s)\n", info->device_name);
@@ -3025,7 +2924,7 @@ void release_resources(MGSLPC_INFO *info)
  *     
  * Arguments:          info    pointer to device instance data
  */
-void mgslpc_add_device(MGSLPC_INFO *info)
+static void mgslpc_add_device(MGSLPC_INFO *info)
 {
        info->next_device = NULL;
        info->line = mgslpc_device_count;
@@ -3056,12 +2955,12 @@ void mgslpc_add_device(MGSLPC_INFO *info)
        printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n",
                info->device_name, info->io_base, info->irq_level);
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        hdlcdev_init(info);
 #endif
 }
 
-void mgslpc_remove_device(MGSLPC_INFO *remove_info)
+static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
 {
        MGSLPC_INFO *info = mgslpc_device_list;
        MGSLPC_INFO *last = NULL;
@@ -3072,7 +2971,7 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
                                last->next_device = info->next_device;
                        else
                                mgslpc_device_list = info->next_device;
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
                        hdlcdev_exit(info);
 #endif
                        release_resources(info);
@@ -3085,16 +2984,25 @@ 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 = {
+static const struct tty_operations mgslpc_ops = {
        .open = mgslpc_open,
        .close = mgslpc_close,
        .write = mgslpc_write,
@@ -3135,7 +3043,6 @@ static void synclink_cs_cleanup(void)
        }
 
        pcmcia_unregister_driver(&mgslpc_driver);
-       BUG_ON(dev_list != NULL);
 }
 
 static int __init synclink_cs_init(void)
@@ -3346,7 +3253,7 @@ static void loopback_enable(MGSLPC_INFO *info)
        write_reg(info, CHA + MODE, val);
 }
 
-void hdlc_mode(MGSLPC_INFO *info)
+static void hdlc_mode(MGSLPC_INFO *info)
 {
        unsigned char val;
        unsigned char clkmode, clksubmode;
@@ -3586,7 +3493,7 @@ void hdlc_mode(MGSLPC_INFO *info)
        rx_stop(info);
 }
 
-void rx_stop(MGSLPC_INFO *info)
+static void rx_stop(MGSLPC_INFO *info)
 {
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):rx_stop(%s)\n",
@@ -3599,7 +3506,7 @@ void rx_stop(MGSLPC_INFO *info)
        info->rx_overflow = 0;
 }
 
-void rx_start(MGSLPC_INFO *info)
+static void rx_start(MGSLPC_INFO *info)
 {
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):rx_start(%s)\n",
@@ -3615,7 +3522,7 @@ void rx_start(MGSLPC_INFO *info)
        info->rx_enabled = 1;
 }
 
-void tx_start(MGSLPC_INFO *info)
+static void tx_start(MGSLPC_INFO *info)
 {
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):tx_start(%s)\n",
@@ -3653,7 +3560,7 @@ void tx_start(MGSLPC_INFO *info)
                info->tx_enabled = 1;
 }
 
-void tx_stop(MGSLPC_INFO *info)
+static void tx_stop(MGSLPC_INFO *info)
 {
        if (debug_level >= DEBUG_LEVEL_ISR)
                printk("%s(%d):tx_stop(%s)\n",
@@ -3667,7 +3574,7 @@ void tx_stop(MGSLPC_INFO *info)
 
 /* Reset the adapter to a known state and prepare it for further use.
  */
-void reset_device(MGSLPC_INFO *info)
+static void reset_device(MGSLPC_INFO *info)
 {
        /* power up both channels (set BIT7) */ 
        write_reg(info, CHA + CCR0, 0x80);
@@ -3717,7 +3624,7 @@ void reset_device(MGSLPC_INFO *info)
        write_reg(info, IPC, 0x05);
 }
 
-void async_mode(MGSLPC_INFO *info)
+static void async_mode(MGSLPC_INFO *info)
 {
        unsigned char val;
 
@@ -3888,7 +3795,7 @@ void async_mode(MGSLPC_INFO *info)
 
 /* Set the HDLC idle mode for the transmitter.
  */
-void tx_set_idle(MGSLPC_INFO *info)
+static void tx_set_idle(MGSLPC_INFO *info)
 {
        /* Note: ESCC2 only supports flags and one idle modes */ 
        if (info->idle_mode == HDLC_TXIDLE_FLAGS)
@@ -3899,7 +3806,7 @@ void tx_set_idle(MGSLPC_INFO *info)
 
 /* get state of the V24 status (input) signals.
  */
-void get_signals(MGSLPC_INFO *info)
+static void get_signals(MGSLPC_INFO *info)
 {
        unsigned char status = 0;
        
@@ -3921,7 +3828,7 @@ void get_signals(MGSLPC_INFO *info)
 /* Set the state of DTR and RTS based on contents of
  * serial_signals member of device extension.
  */
-void set_signals(MGSLPC_INFO *info)
+static void set_signals(MGSLPC_INFO *info)
 {
        unsigned char val;
 
@@ -3945,7 +3852,7 @@ void set_signals(MGSLPC_INFO *info)
                set_reg_bits(info, CHA + PVR, PVR_DTR);
 }
 
-void rx_reset_buffers(MGSLPC_INFO *info)
+static void rx_reset_buffers(MGSLPC_INFO *info)
 {
        RXBUF *buf;
        int i;
@@ -3964,7 +3871,7 @@ void rx_reset_buffers(MGSLPC_INFO *info)
  *
  * Returns 1 if frame returned, otherwise 0
  */
-int rx_get_frame(MGSLPC_INFO *info)
+static int rx_get_frame(MGSLPC_INFO *info)
 {
        unsigned short status;
        RXBUF *buf;
@@ -3996,7 +3903,7 @@ int rx_get_frame(MGSLPC_INFO *info)
                                return_frame = 1;
                }
                framesize = 0;
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
                {
                        struct net_device_stats *stats = hdlc_stats(info->netdev);
                        stats->rx_errors++;
@@ -4030,7 +3937,7 @@ int rx_get_frame(MGSLPC_INFO *info)
                                ++framesize;
                        }
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
                        if (info->netcount)
                                hdlcdev_rx(info, buf->data, framesize);
                        else
@@ -4050,11 +3957,11 @@ int rx_get_frame(MGSLPC_INFO *info)
        return 1;
 }
 
-BOOLEAN register_test(MGSLPC_INFO *info)
+static 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;
@@ -4065,7 +3972,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;
@@ -4076,7 +3983,7 @@ BOOLEAN register_test(MGSLPC_INFO *info)
        return rc;
 }
 
-BOOLEAN irq_test(MGSLPC_INFO *info)
+static BOOLEAN irq_test(MGSLPC_INFO *info)
 {
        unsigned long end_time;
        unsigned long flags;
@@ -4111,7 +4018,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info)
        return info->irq_occurred ? TRUE : FALSE;
 }
 
-int adapter_test(MGSLPC_INFO *info)
+static int adapter_test(MGSLPC_INFO *info)
 {
        if (!register_test(info)) {
                info->init_error = DiagStatus_AddressFailure;
@@ -4133,7 +4040,7 @@ int adapter_test(MGSLPC_INFO *info)
        return 0;
 }
 
-void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
+static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
 {
        int i;
        int linecount;
@@ -4168,7 +4075,7 @@ void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
 /* HDLC frame time out
  * update stats and do tx completion processing
  */
-void tx_timeout(unsigned long context)
+static void tx_timeout(unsigned long context)
 {
        MGSLPC_INFO *info = (MGSLPC_INFO*)context;
        unsigned long flags;
@@ -4186,7 +4093,7 @@ void tx_timeout(unsigned long context)
 
        spin_unlock_irqrestore(&info->lock,flags);
        
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        if (info->netcount)
                hdlcdev_tx_done(info);
        else
@@ -4194,7 +4101,7 @@ void tx_timeout(unsigned long context)
                bh_transmit(info);
 }
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
 
 /**
  * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
@@ -4236,7 +4143,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)
@@ -4340,8 +4247,10 @@ static int hdlcdev_open(struct net_device *dev)
        spin_lock_irqsave(&info->lock, flags);
        get_signals(info);
        spin_unlock_irqrestore(&info->lock, flags);
-       hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+       if (info->serial_signals & SerialSignal_DCD)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
        return 0;
 }