Freezer: make kernel threads nonfreezable by default
[safe/jmp/linux-2.6] / drivers / usb / atm / ueagle-atm.c
index 465961a..8f04665 100644 (file)
 #include <linux/usb.h>
 #include <linux/firmware.h>
 #include <linux/ctype.h>
+#include <linux/sched.h>
 #include <linux/kthread.h>
 #include <linux/version.h>
 #include <linux/mutex.h>
+#include <linux/freezer.h>
+
 #include <asm/unaligned.h>
 
 #include "usbatm.h"
 
-#define EAGLEUSBVERSION "ueagle 1.3"
+#define EAGLEUSBVERSION "ueagle 1.4"
 
 
 /*
                        dev_dbg(&(usb_dev)->dev, \
                                "[ueagle-atm dbg] %s: " format, \
                                        __FUNCTION__, ##args); \
-       } while (0)
+       } while (0)
 
 #define uea_vdbg(usb_dev, format, args...)     \
        do { \
                if (debug >= 2) \
                        dev_dbg(&(usb_dev)->dev, \
                                "[ueagle-atm vdbg]  " format, ##args); \
-       } while (0)
+       } while (0)
 
 #define uea_enters(usb_dev) \
        uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
@@ -218,8 +221,8 @@ enum {
 #define UEA_CHIP_VERSION(x) \
        ((x)->driver_info & 0xf)
 
-#define IS_ISDN(sc) \
-       (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(usb_dev) \
+       (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
@@ -401,9 +404,8 @@ static int uea_send_modem_cmd(struct usb_device *usb,
        int ret = -ENOMEM;
        u8 *xfer_buff;
 
-       xfer_buff = kmalloc(size, GFP_KERNEL);
+       xfer_buff = kmemdup(buff, size, GFP_KERNEL);
        if (xfer_buff) {
-               memcpy(xfer_buff, buff, size);
                ret = usb_control_msg(usb,
                                      usb_sndctrlpipe(usb, 0),
                                      LOAD_INTERNAL,
@@ -595,14 +597,12 @@ static int uea_idma_write(struct uea_softc *sc, void *data, u32 size)
        u8 *xfer_buff;
        int bytes_read;
 
-       xfer_buff = kmalloc(size, GFP_KERNEL);
+       xfer_buff = kmemdup(data, size, GFP_KERNEL);
        if (!xfer_buff) {
                uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n");
                return ret;
        }
 
-       memcpy(xfer_buff, data, size);
-
        ret = usb_bulk_msg(sc->usb_dev,
                         usb_sndbulkpipe(sc->usb_dev, UEA_IDMA_PIPE),
                         xfer_buff, size, &bytes_read, BULK_TIMEOUT);
@@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc)
        char *dsp_name;
 
        if (UEA_CHIP_VERSION(sc) == ADI930) {
-               if (IS_ISDN(sc))
+               if (IS_ISDN(sc->usb_dev))
                        dsp_name = FW_DIR "DSP9i.bin";
                else
                        dsp_name = FW_DIR "DSP9p.bin";
        } else {
-               if (IS_ISDN(sc))
+               if (IS_ISDN(sc->usb_dev))
                        dsp_name = FW_DIR "DSPei.bin";
                else
                        dsp_name = FW_DIR "DSPep.bin";
@@ -658,9 +658,9 @@ static int request_dsp(struct uea_softc *sc)
 /*
  * The uea_load_page() function must be called within a process context
  */
-static void uea_load_page(void *xsc)
+static void uea_load_page(struct work_struct *work)
 {
-       struct uea_softc *sc = xsc;
+       struct uea_softc *sc = container_of(work, struct uea_softc, task);
        u16 pageno = sc->pageno;
        u16 ovl = sc->ovl;
        struct block_info bi;
@@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc)
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-       int ret = wait_event_timeout(sc->cmv_ack_wait,
+       int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
                                                   sc->cmv_ack, ACK_TIMEOUT);
        sc->cmv_ack = 0;
 
@@ -765,12 +765,11 @@ static int uea_request(struct uea_softc *sc,
        u8 *xfer_buff;
        int ret = -ENOMEM;
 
-       xfer_buff = kmalloc(size, GFP_KERNEL);
+       xfer_buff = kmemdup(data, size, GFP_KERNEL);
        if (!xfer_buff) {
                uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n");
                return ret;
        }
-       memcpy(xfer_buff, data, size);
 
        ret = usb_control_msg(sc->usb_dev, usb_sndctrlpipe(sc->usb_dev, 0),
                              UCDC_SEND_ENCAPSULATED_COMMAND,
@@ -885,7 +884,8 @@ static int uea_stat(struct uea_softc *sc)
                break;
 
        case 3:         /* fail ... */
-               uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n");
+               uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+                               " (may be try other cmv/dsp)\n");
                return -EAGAIN;
 
        case 4 ... 6:   /* test state */
@@ -913,12 +913,6 @@ static int uea_stat(struct uea_softc *sc)
                        release_firmware(sc->dsp_firm);
                        sc->dsp_firm = NULL;
                }
-
-               ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
-               if (ret < 0)
-                       return ret;
-               uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-                               sc->stats.phy.firmid);
        }
 
        /* always update it as atm layer could not be init when we switch to
@@ -1033,9 +1027,9 @@ static int request_cmvs(struct uea_softc *sc,
 
        if (cmv_file[sc->modem_index] == NULL) {
                if (UEA_CHIP_VERSION(sc) == ADI930)
-                       file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin";
+                       file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
                else
-                       file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin";
+                       file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
        } else
                file = cmv_file[sc->modem_index];
 
@@ -1131,6 +1125,13 @@ static int uea_start_reset(struct uea_softc *sc)
        if (ret < 0)
                return ret;
 
+       /* Dump firmware version */
+       ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+       if (ret < 0)
+               return ret;
+       uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+                       sc->stats.phy.firmid);
+
        /* get options */
        ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
        if (ret < 0)
@@ -1147,6 +1148,8 @@ static int uea_start_reset(struct uea_softc *sc)
        /* Enter in R-ACT-REQ */
        ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
        uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+       uea_info(INS_TO_USBDEV(sc), "Modem started, "
+               "waiting synchronization\n");
 out:
        release_firmware(cmvs_fw);
        sc->reset = 0;
@@ -1165,6 +1168,7 @@ static int uea_kthread(void *data)
        struct uea_softc *sc = data;
        int ret = -EAGAIN;
 
+       set_freezable();
        uea_enters(INS_TO_USBDEV(sc));
        while (!kthread_should_stop()) {
                if (ret < 0 || sc->reset)
@@ -1172,7 +1176,10 @@ static int uea_kthread(void *data)
                if (!ret)
                        ret = uea_stat(sc);
                if (ret != -EAGAIN)
-                       msleep(1000);
+                       msleep_interruptible(1000);
+               if (try_to_freeze())
+                       uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
+                               "please unplug/replug your modem\n");
        }
        uea_leaves(INS_TO_USBDEV(sc));
        return ret;
@@ -1297,7 +1304,7 @@ bad1:
 /*
  * interrupt handler
  */
-static void uea_intr(struct urb *urb, struct pt_regs *regs)
+static void uea_intr(struct urb *urb)
 {
        struct uea_softc *sc = urb->context;
        struct intr_pkt *intr = urb->transfer_buffer;
@@ -1345,7 +1352,7 @@ static int uea_boot(struct uea_softc *sc)
 
        uea_enters(INS_TO_USBDEV(sc));
 
-       INIT_WORK(&sc->task, uea_load_page, sc);
+       INIT_WORK(&sc->task, uea_load_page);
        init_waitqueue_head(&sc->sync_q);
        init_waitqueue_head(&sc->cmv_ack_wait);
 
@@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0);
 UEA_ATTR(dscorr, 0);
 UEA_ATTR(usunc, 0);
 UEA_ATTR(dsunc, 0);
+UEA_ATTR(firmid, 0);
 
 /* Retrieve the device End System Identifier (MAC) */
 
@@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
        struct uea_softc *sc = usbatm->driver_data;
 
-       wait_event(sc->sync_q, IS_OPERATIONAL(sc));
+       wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc));
 
        return 0;
 
@@ -1639,16 +1647,13 @@ static struct attribute *attrs[] = {
        &dev_attr_stat_dscorr.attr,
        &dev_attr_stat_usunc.attr,
        &dev_attr_stat_dsunc.attr,
+       &dev_attr_stat_firmid.attr,
+       NULL,
 };
 static struct attribute_group attr_grp = {
        .attrs = attrs,
 };
 
-static int create_fs_entries(struct usb_interface *intf)
-{
-       return sysfs_create_group(&intf->dev.kobj, &attr_grp);
-}
-
 static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
                   const struct usb_device_id *id)
 {
@@ -1708,31 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
                }
        }
 
+       ret = sysfs_create_group(&intf->dev.kobj, &attr_grp);
+       if (ret < 0)
+               goto error;
+
        ret = uea_boot(sc);
-       if (ret < 0) {
-               kfree(sc);
-               return ret;
-       }
+       if (ret < 0)
+               goto error;
 
-       ret = create_fs_entries(intf);
-       if (ret) {
-               uea_stop(sc);
-               kfree(sc);
-               return ret;
-       }
        return 0;
-}
-
-static void destroy_fs_entries(struct usb_interface *intf)
-{
-       sysfs_remove_group(&intf->dev.kobj, &attr_grp);
+error:
+       kfree(sc);
+       return ret;
 }
 
 static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
 {
        struct uea_softc *sc = usbatm->driver_data;
 
-       destroy_fs_entries(intf);
+       sysfs_remove_group(&intf->dev.kobj, &attr_grp);
        uea_stop(sc);
        kfree(sc);
 }
@@ -1753,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *usb = interface_to_usbdev(intf);
 
        uea_enters(usb);
-       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n",
+       uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
               le16_to_cpu(usb->descriptor.idVendor),
               le16_to_cpu(usb->descriptor.idProduct),
-              chip_name[UEA_CHIP_VERSION(id)]);
+              chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
 
        usb_reset_device(usb);