> Now, should I forget this and wait for your version?  Could I have a
> copy of what you did, and work from that instead? Did it at least manage
> to get as far as loading the firmware of the poxy thing? :)

Hi David, here's a dump of my patch with no effort to rediff, hide the gucky
stuff etc :)  It was from Sep 10 last year, how time flies!

Duncan.

diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c
--- a/drivers/usb/misc/speedtch.c       2004-09-28 09:38:41 +02:00
+++ b/drivers/usb/misc/speedtch.c       2004-09-28 09:38:41 +02:00
@@ -59,6 +59,7 @@
  *
  */
 
+#include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -66,8 +67,10 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
+#include <linux/firmware.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
+#include <linux/wait.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
@@ -77,8 +80,9 @@
 #include <linux/crc32.h>
 #include <linux/init.h>
 
-/*
+#define CONFIG_FW_LOADER
 #define DEBUG
+/*
 #define VERBOSE_DEBUG
 */
 
@@ -146,6 +150,8 @@
 
 #define UDSL_ENDPOINT_DATA_OUT         0x07
 #define UDSL_ENDPOINT_DATA_IN          0x87
+#define UDSL_ENDPOINT_FIRMWARE_OUT     0x05
+#define UDSL_ENDPOINT_FIRMWARE_IN      0x85
 
 #define ATM_CELL_HEADER                        (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
 #define UDSL_NUM_CELLS(x)              (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 
1) / ATM_CELL_PAYLOAD)
@@ -215,18 +221,28 @@
 
 /* main driver data */
 
+enum udsl_status {
+       UDSL_NO_FIRMWARE,
+       UDSL_LOADING_FIRMWARE,
+       UDSL_LOADED_FIRMWARE
+};
+
 struct udsl_instance_data {
+       atomic_t refcount;
        struct semaphore serialize;
 
        /* USB device part */
        struct usb_device *usb_dev;
        char description [64];
-       int firmware_loaded;
 
        /* ATM device part */
        struct atm_dev *atm_dev;
        struct list_head vcc_list;
 
+       /* firmware */
+       enum udsl_status status;
+       wait_queue_head_t firmware_waiters;
+
        /* receive */
        struct udsl_receiver receivers [UDSL_MAX_RCV_URBS];
        struct udsl_receive_buffer receive_buffers [UDSL_MAX_RCV_BUFS];
@@ -761,7 +777,7 @@
 
        vdbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
 
-       if (!instance || !instance->usb_dev) {
+       if (!instance) {
                dbg ("udsl_atm_send: NULL data!");
                return -ENODEV;
        }
@@ -786,25 +802,298 @@
 }
 
 
-/**********
-**  ATM  **
-**********/
+/********************
+**  bean counting  **
+********************/
 
-static void udsl_atm_dev_close (struct atm_dev *dev)
+static inline void udsl_get_instance (struct udsl_instance_data *instance)
 {
-       struct udsl_instance_data *instance = dev->dev_data;
+       atomic_inc (&instance->refcount);
+}
+
+static inline void udsl_put_instance (struct udsl_instance_data *instance)
+{
+       if (atomic_dec_and_test (&instance->refcount)) {
+               tasklet_kill (&instance->receive_tasklet);
+               tasklet_kill (&instance->send_tasklet);
+               usb_put_dev (instance->usb_dev);
+               kfree (instance);
+       }
+}
+
+
+/***************
+**  firmware  **
+***************/
+
+static void udsl_got_firmware (struct udsl_instance_data *instance, int got_it)
+{
+       int err;
+
+       down (&instance->serialize); /* vs self, udsl_firmware_start */
+       if (instance->status == UDSL_LOADED_FIRMWARE)
+               goto out;
+       if (!got_it) {
+               instance->status = UDSL_NO_FIRMWARE;
+               goto out;
+       }
+       if ((err = usb_set_interface (instance->usb_dev, 1, 1)) < 0) {
+               dbg ("udsl_set_alternate: usb_set_interface returned %d!", err);
+               instance->status = UDSL_NO_FIRMWARE;
+               goto out;
+       }
+       instance->status = UDSL_LOADED_FIRMWARE;
+       tasklet_schedule (&instance->receive_tasklet);
+out:
+       up (&instance->serialize);
+       wake_up_interruptible (&instance->firmware_waiters);
+}
+
+#ifdef CONFIG_FW_LOADER
+static void udsl_firmware_stage2 (const struct firmware *fw, void *context)
+{
+       unsigned char *buffer;
+       struct udsl_instance_data *instance = context;
+       struct usb_interface *intf;
+       int actual_length, ret;
+
+       dbg ("udsl_firmware_stage2");
+
+       ret = -1;
 
        if (!instance) {
-               dbg ("udsl_atm_dev_close: NULL instance!");
+               dbg ("udsl_firmware_stage2: NULL instance!");
+               return; /* deep doggy do */
+       }
+
+       if (!(intf = usb_ifnum_to_if (instance->usb_dev, 2))) {
+               dbg ("udsl_firmware_stage2: interface not found!");
+               goto finish;
+       }
+
+       if (!(buffer = kmalloc (0x200, GFP_KERNEL))) {
+               dbg ("udsl_firmware_stage1: no memory for buffer!");
+               goto out;
+       }
+
+       if (!fw) {
+               dbg ("udsl_firmware_stage2: no firmware!");
+               goto out;
+       }
+
+       /* URBs 12 to 139 - USB led blinking green, ADSL led off */
+       ret = usb_bulk_msg (instance->usb_dev,
+                           usb_sndbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_FIRMWARE_OUT),
+                           fw->data,
+                           fw->size,
+                           &actual_length,
+                           5 * HZ);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_stage2: write to modem failed (%d)!", ret);
+               goto out;
+       }
+
+       /* USB led static green, ADSL led static red */
+
+       /* URB 142 */
+       ret = usb_bulk_msg (instance->usb_dev,
+                           usb_rcvbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_FIRMWARE_IN),
+                           buffer,
+                           0x200,
+                           &actual_length,
+                           5 * HZ);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_stage2: read from modem failed (%d)!", ret);
+               goto out;
+       }
+
+       /* success */
+/* QQ test sequence */
+
+out:
+       kfree (buffer);
+       usb_driver_release_interface (&udsl_usb_driver, intf);
+finish:
+       udsl_got_firmware (instance, (ret < 0) ? 0 : 1);
+       udsl_put_instance (instance);
+}
+
+static void udsl_firmware_stage1 (const struct firmware *fw, void *context)
+{
+       unsigned char *buffer;
+       struct udsl_instance_data *instance = context;
+       struct usb_interface *intf;
+       int actual_length, ret;
+
+       dbg ("udsl_firmware_stage1");
+
+       ret = -1;
+
+       if (!instance) {
+               dbg ("udsl_firmware_stage1: NULL instance!");
+               return; /* deep doggy do */
+       }
+
+       if (!(intf = usb_ifnum_to_if (instance->usb_dev, 2))) {
+               dbg ("udsl_firmware_stage1: interface not found!");
+               goto finish;
+       }
+
+       if (!(buffer = kmalloc (0x200, GFP_KERNEL))) {
+               dbg ("udsl_firmware_stage1: no memory for buffer!");
+               goto fail;
+       }
+
+       if (!fw) {
+               dbg ("udsl_firmware_stage1: no firmware!");
+               goto fail;
+       }
+
+       if ((ret = usb_reset_device (instance->usb_dev)) < 0) {
+               dbg ("udsl_firmware_stage1: usb_reset_device failed (%d)!", ret);
+               goto fail;
+       }
+
+       /* URB 7 */
+       if (1) { /* some modems need a read before writing the firmware */
+               ret = usb_bulk_msg (instance->usb_dev,
+                                   usb_rcvbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_FIRMWARE_IN),
+                                   buffer,
+                                   0x200,
+                                   &actual_length,
+                                   5 * HZ);
+
+               if (ret < 0)
+                       dbg ("udsl_firmware_stage1: initial read from modem failed 
(%d)!", ret);
+       }
+
+       /* URB 8 : both leds are static green */
+       ret = usb_bulk_msg (instance->usb_dev,
+                           usb_sndbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_FIRMWARE_OUT),
+                           fw->data,
+                           fw->size,
+                           &actual_length,
+                           5 * HZ);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_stage1: write to modem failed (%d)!", ret);
+               goto fail;
+       }
+
+       /* USB led blinking green, ADSL led off */
+
+       /* URB 11 */
+       ret = usb_bulk_msg (instance->usb_dev,
+                           usb_rcvbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_FIRMWARE_IN),
+                           buffer,
+                           0x200,
+                           &actual_length,
+                           5 * HZ);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_stage1: read from modem failed (%d)!", ret);
+               goto fail;
+       }
+
+       ret = request_firmware_nowait (THIS_MODULE,
+                                      "speedtch_fw2",
+                                      &instance->usb_dev->dev,
+                                      instance,
+                                      udsl_firmware_stage2);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_stage1: request_firmware_nowait failed (%d)!", 
ret);
+               goto fail;
+       }
+
+       /* success */
+       kfree (buffer);
+       return;
+
+fail:
+       kfree (buffer);
+       usb_driver_release_interface (&udsl_usb_driver, intf);
+finish:
+       udsl_got_firmware (instance, (ret < 0) ? 0 : 1);
+       udsl_put_instance (instance);
+}
+
+#endif /* CONFIG_FW_LOADER */
+
+static void udsl_firmware_start (struct udsl_instance_data *instance)
+{
+#ifdef CONFIG_FW_LOADER
+       struct usb_interface *intf;
+       int ret;
+#endif
+
+       dbg ("udsl_firmware_start");
+
+       down (&instance->serialize); /* vs self, udsl_got_firmware */
+       if (instance->status >= UDSL_LOADING_FIRMWARE) {
+               up (&instance->serialize);
                return;
        }
+       instance->status = UDSL_LOADING_FIRMWARE;
+       up (&instance->serialize);
 
-       dbg ("udsl_atm_dev_close: queue has %u elements", instance->sndqueue.qlen);
+       udsl_get_instance (instance);
+
+#ifdef CONFIG_FW_LOADER
+       if (!(intf = usb_ifnum_to_if (instance->usb_dev, 2))) {
+               dbg ("udsl_firmware_start: interface not found!");
+               goto finish;
+       }
+
+        if ((ret = usb_driver_claim_interface (&udsl_usb_driver, intf, NULL)) < 0) {
+               dbg ("udsl_firmware_start: interface in use (%d)!", ret);
+               goto finish;
+       }
+
+       ret = request_firmware_nowait (THIS_MODULE,
+                                      "speedtch_fw1",
+                                      &instance->usb_dev->dev,
+                                      instance,
+                                      udsl_firmware_stage1);
+
+       if (ret < 0) {
+               dbg ("udsl_firmware_start: request_firmware_nowait failed (%d)!", ret);
+               goto fail;
+       }
+
+       return;
+
+fail:
+       usb_driver_release_interface (&udsl_usb_driver, intf);
+finish:
+#endif /* CONFIG_FW_LOADER */
+       udsl_got_firmware (instance, 0);
+       udsl_put_instance (instance);
+}
+
+static int udsl_firmware_wait (struct udsl_instance_data *instance)
+{
+       udsl_firmware_start (instance);
+
+       if (wait_event_interruptible (instance->firmware_waiters, instance->status != 
UDSL_LOADING_FIRMWARE) < 0)
+               return -ERESTARTSYS;
+
+       return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN;
+}
+
+
+/**********
+**  ATM  **
+**********/
+
+static void udsl_atm_dev_close (struct atm_dev *dev)
+{
+       struct udsl_instance_data *instance = dev->dev_data;
 
-       tasklet_kill (&instance->receive_tasklet);
-       tasklet_kill (&instance->send_tasklet);
-       kfree (instance);
        dev->dev_data = NULL;
+       udsl_put_instance (instance);
 }
 
 static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
@@ -846,13 +1135,16 @@
                        break;
                }
 
-               if (instance->usb_dev) {
-                       if (!instance->firmware_loaded)
-                               strcat (page, ", no firmware\n");
-                       else
-                               strcat (page, ", firmware loaded\n");
-               } else
+               if (instance->usb_dev->state == USB_STATE_NOTATTACHED)
                        strcat (page, ", disconnected\n");
+               else {
+                       if (instance->status == UDSL_LOADED_FIRMWARE)
+                               strcat (page, ", firmware loaded\n");
+                       else if (instance->status == UDSL_LOADING_FIRMWARE)
+                               strcat (page, ", firmware loading\n");
+                       else
+                               strcat (page, ", no firmware\n");
+               }
 
                return strlen (page);
        }
@@ -864,10 +1156,11 @@
 {
        struct udsl_instance_data *instance = vcc->dev->dev_data;
        struct udsl_vcc_data *new;
+       int err;
 
        dbg ("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
 
-       if (!instance || !instance->usb_dev) {
+       if (!instance) {
                dbg ("udsl_atm_open: NULL data!");
                return -ENODEV;
        }
@@ -879,9 +1172,9 @@
        if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) || 
(vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU))
                return -EINVAL;
 
-       if (!instance->firmware_loaded) {
-               dbg ("udsl_atm_open: firmware not loaded!");
-               return -EAGAIN;
+       if ((err = udsl_firmware_wait (instance)) < 0) {
+               dbg ("udsl_atm_open: firmware not loaded (%d)!", err);
+               return err;
        }
 
        down (&instance->serialize); /* vs self, udsl_atm_close */
@@ -978,26 +1271,6 @@
 **  USB  **
 **********/
 
-static int udsl_set_alternate (struct udsl_instance_data *instance)
-{
-       down (&instance->serialize); /* vs self */
-       if (!instance->firmware_loaded) {
-               int ret;
-
-               if ((ret = usb_set_interface (instance->usb_dev, 1, 1)) < 0) {
-                       dbg ("udsl_set_alternate: usb_set_interface returned %d!", 
ret);
-                       up (&instance->serialize);
-                       return ret;
-               }
-               instance->firmware_loaded = 1;
-       }
-       up (&instance->serialize);
-
-       tasklet_schedule (&instance->receive_tasklet);
-
-       return 0;
-}
-
 static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void 
*user_data)
 {
        struct udsl_instance_data *instance = usb_get_intfdata (intf);
@@ -1012,7 +1285,8 @@
        switch (code) {
        case UDSL_IOCTL_LINE_UP:
                instance->atm_dev->signal = ATM_PHY_SIG_FOUND;
-               return udsl_set_alternate (instance);
+               udsl_got_firmware (instance, 1);
+               return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO;
        case UDSL_IOCTL_LINE_DOWN:
                instance->atm_dev->signal = ATM_PHY_SIG_LOST;
                return 0;
@@ -1027,7 +1301,7 @@
        int ifnum = intf->altsetting->desc.bInterfaceNumber;
        struct udsl_instance_data *instance;
        unsigned char mac_str [13];
-       int i, length;
+       int err, i, length;
        char *buf;
 
        dbg ("udsl_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",
@@ -1040,6 +1314,9 @@
 
        dbg ("udsl_usb_probe: device accepted");
 
+       if ((err = usb_set_interface (dev, 1, 0)) < 0)
+               return err;
+
        /* instance init */
        if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
                dbg ("udsl_usb_probe: no memory for instance data!");
@@ -1048,12 +1325,17 @@
 
        memset (instance, 0, sizeof (struct udsl_instance_data));
 
+       atomic_set (&instance->refcount, 2); /* one for USB, one for ATM */
+
        init_MUTEX (&instance->serialize);
 
        instance->usb_dev = dev;
 
        INIT_LIST_HEAD (&instance->vcc_list);
 
+       instance->status = UDSL_NO_FIRMWARE;
+       init_waitqueue_head (&instance->firmware_waiters);
+
        spin_lock_init (&instance->receive_lock);
        INIT_LIST_HEAD (&instance->spare_receivers);
        INIT_LIST_HEAD (&instance->filled_receive_buffers);
@@ -1166,8 +1448,12 @@
        wmb ();
        instance->atm_dev->dev_data = instance;
 
+       usb_get_dev (dev);
+
        usb_set_intfdata (intf, instance);
 
+       udsl_firmware_start (instance);
+
        return 0;
 
 fail:
@@ -1195,9 +1481,9 @@
        unsigned int count;
        int result, i;
 
-       dbg ("udsl_usb_disconnect entered");
+/* QQ - need to handle disconnects on interface 2! */
 
-       usb_set_intfdata (intf, NULL);
+       dbg ("udsl_usb_disconnect entered");
 
        if (!instance) {
                dbg ("udsl_usb_disconnect: NULL instance!");
@@ -1279,11 +1565,12 @@
        for (i = 0; i < num_snd_bufs; i++)
                kfree (instance->send_buffers [i].base);
 
-       wmb ();
-       instance->usb_dev = NULL;
-
        /* ATM finalize */
-       shutdown_atm_dev (instance->atm_dev); /* frees instance, kills tasklets */
+       shutdown_atm_dev (instance->atm_dev);
+
+       /* clean up */
+       usb_set_intfdata (intf, NULL);
+       udsl_put_instance (instance);
 }
 
 


-------------------------------------------------------
This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170
Project Admins to receive an Apple iPod Mini FREE for your judgement on
who ports your project to Linux PPC the best. Sponsored by IBM.
Deadline: Sept. 24. Go here: http://sf.net/ppc_contest.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to