pp-by: Oleg Verych
---
 drivers/usb/serial/ti_usb_3410_5052.c |  148 +++++++++++++++++++++-------------
 drivers/usb/serial/ti_usb_3410_5052.h |   27 +++---
 2 files changed, 109 insertions(+), 66 deletions(-)

Index: linux-source-2.6.18/drivers/usb/serial/ti_usb_3410_5052.h
===================================================================
--- linux-source-2.6.18.orig/drivers/usb/serial/ti_usb_3410_5052.h      
2007-02-23 09:12:43.276763750 +0100
+++ linux-source-2.6.18/drivers/usb/serial/ti_usb_3410_5052.h   2007-02-23 
09:13:05.310140750 +0100
@@ -21,8 +21,8 @@
 #define _TI_3410_5052_H_
 
 /* Configuration ids */
-#define TI_BOOT_CONFIG                 1
-#define TI_ACTIVE_CONFIG               2
+#define TI_BOOT_CONFIG                 1 /* boot config to get firmware  */
+#define TI_ACTIVE_CONFIG               2 /* actual working device config */
 
 /* Vendor and product ids */
 #define TI_VENDOR_ID                   0x0451
@@ -206,19 +206,24 @@
 #define TI_CODE_DATA_ERROR             0x03
 #define TI_CODE_MODEM_STATUS           0x04
 
-/* Download firmware max packet size */
-#define TI_DOWNLOAD_MAX_PACKET_SIZE    64
-
-/* Firmware image header */
-struct ti_firmware_header {
-       __le16  wLength;
-       __u8    bCheckSum;
-} __attribute__((packed));
-
 /* UART addresses */
 #define TI_UART1_BASE_ADDR             0xFFA0  /* UART 1 base address */
 #define TI_UART2_BASE_ADDR             0xFFB0  /* UART 2 base address */
 #define TI_UART_OFFSET_LCR             0x0002  /* UART MCR register offset */
 #define TI_UART_OFFSET_MCR             0x0004  /* UART MCR register offset */
 
+/* Firmware */
+#define TI_FW_PACKET_SIZE              64
+#define TI_MAX_FIRMWARE_SIZE           16284
+
+#define ti_fw_file_3410                        "umpf3410.i51"
+#define ti_fw_file_5052                        "umpf5052.i51"
+
+typedef union {
+       __le32 a; /* all */
+       struct {
+               __le32 sz : 16, cs : 8;
+       } d;
+} ti_firmware_header_t;
+
 #endif /* _TI_3410_5052_H_ */
Index: linux-source-2.6.18/drivers/usb/serial/ti_usb_3410_5052.c
===================================================================
--- linux-source-2.6.18.orig/drivers/usb/serial/ti_usb_3410_5052.c      
2007-02-23 09:12:43.276763750 +0100
+++ linux-source-2.6.18/drivers/usb/serial/ti_usb_3410_5052.c   2007-02-23 
09:13:05.314141000 +0100
@@ -33,20 +33,15 @@
 #include <asm/semaphore.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
-
+#include <linux/firmware.h>
 #include "ti_usb_3410_5052.h"
-#include "ti_fw_3410.h"                /* firmware image for 3410 */
-#include "ti_fw_5052.h"                /* firmware image for 5052 */
-
 
 /* Defines */
 
-#define TI_DRIVER_VERSION      "v0.9"
+#define TI_DRIVER_VERSION      "v0.92"
 #define TI_DRIVER_AUTHOR       "Al Borchers <[EMAIL PROTECTED]>"
 #define TI_DRIVER_DESC         "TI USB 3410/5052 Serial Driver"
 
-#define TI_FIRMWARE_BUF_SIZE   16284
-
 #define TI_WRITE_BUF_SIZE      1024
 
 #define TI_TRANSFER_TIMEOUT    2
@@ -143,8 +138,7 @@
 static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
        __u8 mask, __u8 byte);
 
-static int ti_download_firmware(struct ti_device *tdev,
-       unsigned char *firmware, unsigned int firmware_size);
+static int ti_fw_change(struct ti_device *tdev, const char *filename);
 
 /* circular buffer */
 static struct circ_buf *ti_buf_alloc(void);
@@ -382,13 +376,8 @@
 
        /* if we have only 1 configuration, download firmware */
        if (dev->descriptor.bNumConfigurations == 1) {
-
-               if (tdev->td_is_3410)
-                       status = ti_download_firmware(tdev, ti_fw_3410,
-                               sizeof(ti_fw_3410));
-               else
-                       status = ti_download_firmware(tdev, ti_fw_5052,
-                               sizeof(ti_fw_5052));
+               status = ti_fw_change(tdev, tdev->td_is_3410 ?
+                                     ti_fw_file_3410 : ti_fw_file_5052);
                if (status)
                        goto free_tdev;
 
@@ -1594,57 +1583,106 @@
 }
 
 
-static int ti_download_firmware(struct ti_device *tdev,
-       unsigned char *firmware, unsigned int firmware_size)
+static int ti_fw_change(struct ti_device *tdev, const char *filename)
 {
-       int status = 0;
-       int buffer_size;
-       int pos;
-       int len;
-       int done;
-       __u8 cs = 0;
-       __u8 *buffer;
-       struct usb_device *dev = tdev->td_serial->dev;
-       struct ti_firmware_header *header;
-       unsigned int pipe = usb_sndbulkpipe(dev,
-               tdev->td_serial->port[0]->bulk_out_endpointAddress);
+#define udev           (tdev->td_serial->dev)
+#define fw_endpoint    (tdev->td_serial->port[0]->bulk_out_endpointAddress)
 
+       const struct firmware *fw_data_ptr;
+       size_t size;
+       int w;
 
-       buffer_size = TI_FIRMWARE_BUF_SIZE + sizeof(struct ti_firmware_header);
-       buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (!buffer) {
-               dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
-               return -ENOMEM;
+       dbg("%s() start; requesting firmware from userspace.",__FUNCTION__);
+
+       w = request_firmware(&fw_data_ptr, filename, &udev->dev);
+       if (w) {
+               dev_err(&udev->dev, "userspace firmware helper failed.\n");
+               return w;
        }
 
-       memcpy(buffer, firmware, firmware_size);
-       memset(buffer+firmware_size, 0xff, buffer_size-firmware_size);
+       size = fw_data_ptr->size;
 
-       for(pos = sizeof(struct ti_firmware_header); pos < buffer_size; pos++)
-               cs = (__u8)(cs + buffer[pos]);
+       if (likely(size <= TI_MAX_FIRMWARE_SIZE)) {
+               ti_firmware_header_t h;
 
-       header = (struct ti_firmware_header *)buffer;
-       header->wLength = cpu_to_le16((__u16)(buffer_size - sizeof(struct 
ti_firmware_header)));
-       header->bCheckSum = cs;
-
-       dbg("%s - downloading firmware", __FUNCTION__);
-       for (pos = 0; pos < buffer_size; pos += done) {
-               len = min(buffer_size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE);
-               status = usb_bulk_msg(dev, pipe, buffer+pos, len, &done, 1000);
-               if (status)
-                       break;
+               if (size % TI_FW_PACKET_SIZE) {
+                       dev_err(&udev->dev, "firmware size isn't %u modulo.\n"
+                               "Care to provide one.\n", TI_FW_PACKET_SIZE);
+                       return -EIO;
+               }
+
+               /* constructing header: size_LSB size_MSB CRCB */
+               h.a = 0x000000;
+               h.d.sz = cpu_to_le16(size);
+
+               /* w is zero here and used as index */
+               do {
+                       h.d.cs += fw_data_ptr->data[w++];
+               } while (w < size);
+
+               /* using `w' as buffer */
+               w = (int) h.a;
+               dbg("cs: %#x; w: %#x", h.d.cs, w);
+       } else {
+               dev_err(&udev->dev,"firmware is too big.\n");
+               return -EFBIG;
        }
 
-       kfree(buffer);
+       dbg("starting downloading %#zx bytes of firmware.", size);
 
-       if (status) {
-               dev_err(&dev->dev, "%s - error downloading firmware, %d\n", 
__FUNCTION__, status);
-               return status;
-       }
+       do {
+               u8 *fw;
+               int gone;
+               unsigned int pipe = usb_sndbulkpipe(udev, fw_endpoint);
+
+               /* XXX implement retry? */
+               w = usb_bulk_msg(udev, pipe, &w, 3, &gone, 1024);
+               if (gone != 3) {
+                       if (!w)
+                               w = -EIO;
+                       break;
+               }
 
-       dbg("%s - download successful", __FUNCTION__);
+               /*
+                * 3-4 12-bit pages, this is not much for kmalloc(),
+                * why request_firmware() doesn't allocate with it?
+                */
+               fw = kmalloc(size, GFP_KERNEL);
+               if (!fw) {
+                       w = -ENOMEM;
+                       break;
+               }
 
-       return 0;
+               memcpy(fw, fw_data_ptr->data, size);
+
+               size /= TI_FW_PACKET_SIZE;
+
+               do {
+                       w = usb_bulk_msg(udev, pipe, fw, TI_FW_PACKET_SIZE,
+                                        &gone, 1024);
+                       if (gone != TI_FW_PACKET_SIZE) {
+                       /*
+                        * unless bulk_msg can be sent partially,
+                        * `if' above can be removed
+                        */
+                               if (!w)
+                                       w = -EIO;
+                               break;
+                       } else {
+                               fw += TI_FW_PACKET_SIZE;
+                       }
+               } while (--size);
+
+               kfree(fw);
+       } while (0);
+
+       release_firmware(fw_data_ptr);
+
+       dbg("%s() done with result %#x.\n",__FUNCTION__, w);
+
+       return w;
+#undef fw_endpoint
+#undef dev
 }
 
 

--


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to