]> git.neil.brown.name Git - history.git/commitdiff
- Stephen Rothwell: APM updates 2.4.0-test12pre8
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:41 +0000 (15:40 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:40:41 +0000 (15:40 -0500)
- Johannes Erdfelt: USB updates
- Linus: call_usermodehelper(/sbin/hotplug) cleanup and deadlock fix
- Leonard Zubkoff: DAC960 Driver Update
- Martin Diehl: fix PCI PM callback ordering
- Andrew Morton: call_usermodehelper() fixes
- Urban Widmark: clean up and enable shared mmap on smbfs.
- Trond Myklebust: fix NFS path revalidation.

56 files changed:
Documentation/Configure.help
Documentation/README.DAC960
Documentation/usb/error-codes.txt
Documentation/usb/usb-serial.txt
arch/i386/kernel/apm.c
arch/i386/kernel/i386_ksyms.c
arch/i386/kernel/setup.c
arch/mips64/Makefile
drivers/acpi/driver.c
drivers/block/DAC960.c
drivers/block/ll_rw_blk.c
drivers/char/tty_io.c
drivers/pci/pci.c
drivers/sound/ac97_codec.c
drivers/sound/cs4281.c
drivers/sound/cs46xx.c
drivers/usb/hub.h
drivers/usb/scanner.c
drivers/usb/serial/Config.in
drivers/usb/serial/Makefile
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_usa26msg.h
drivers/usb/serial/keyspan_usa28msg.h
drivers/usb/serial/keyspan_usa49msg.h [new file with mode: 0644]
drivers/usb/serial/keyspan_usa49w_fw.h [new file with mode: 0644]
drivers/usb/serial/mct_u232.c [new file with mode: 0644]
drivers/usb/serial/mct_u232.h [new file with mode: 0644]
drivers/usb/uhci.c
drivers/usb/usb-uhci.c
drivers/usb/usb.c
fs/buffer.c
fs/hpfs/buffer.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/smbfs/dir.c
fs/smbfs/file.c
fs/smbfs/inode.c
fs/smbfs/proc.c
include/linux/apm_bios.h
include/linux/fs.h
include/linux/kernel.h
include/linux/nfs_fs.h
include/linux/sched.h
include/linux/smb_fs.h
include/linux/smb_fs_sb.h
include/linux/tqueue.h
include/linux/usb.h
init/main.c
kernel/context.c
kernel/exit.c
kernel/kmod.c
kernel/ksyms.c
kernel/timer.c
net/core/dev.c
net/ipv4/devinet.c

index 7e813107d15a7c8e64a93950d0db7e2fa8357253..135426b104f3b4b0a4559e20bc5c1d0fee49422c 100644 (file)
@@ -10392,6 +10392,16 @@ CONFIG_USB_SERIAL_EMPEG
   The module will be called empeg.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+USB MCT Single Port Serial Driver
+CONFIG_USB_SERIAL_MCT_U232
+  Say Y here if you want to use a USB Serial single port adapter from
+  Magic Control Technology Corp. (U232 is one of the model numbers).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called mct_u232.o.  If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
 USB Serial Converter verbose debug
 CONFIG_USB_SERIAL_DEBUG
   Say Y here if you want verbose debug messages from the USB Serial
index 88f52364b647b01caafade73db3b7b475cae48e2..4c0832e79e1526074a1c9e7856e70da9d83ad984 100644 (file)
@@ -1,11 +1,11 @@
    Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-                       Version 2.2.8 for Linux 2.2.16
-                       Version 2.4.8 for Linux 2.4.0
+                       Version 2.2.9 for Linux 2.2.17
+                       Version 2.4.9 for Linux 2.4.0
 
                              PRODUCTION RELEASE
 
-                               19 August 2000
+                              7 September 2000
 
                               Leonard N. Zubkoff
                               Dandelion Digital
@@ -203,13 +203,13 @@ ftp://ftp.mylex.com/pub/dac960/diskcomp.html.
 
                              DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.16 or 2.4.0.
+This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0.
 
 To install the DAC960 RAID driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf DAC960-2.2.8.tar.gz (or DAC960-2.4.8.tar.gz)
+  tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
   patch -p0 < DAC960.patch (if DAC960.patch is included)
index e42ab36e07c6fd4cf1c6290bb2b87a6015b1ff06..964af3033decf28c953935415cd6f0935f0a7c94 100644 (file)
@@ -26,9 +26,9 @@ USB-specific:
 -ENODEV                specified USB-device or bus doesn't exist
 
 USB_ST_REQUEST_ERROR
--ENXIO         a) specified endpoint doesn't exist on the device
-               b) an URB is already queued to this endpoint and
-                  USB_QUEUE_BULK wasn't used (UHCI HCDs only)
+-ENXIO         a control or interrupt URB is already queued to this endpoint; or
+                 a bulk URB is already queued to this endpoint and
+                 USB_QUEUE_BULK wasn't used (UHCI HCDs only)
 
 USB_ST_URB_INVALID_ERROR
 -EINVAL                a) Invalid transfer type specified (or not supported)
index d4740c4048e4ddfef44e8ae816608b4eaaa6cd85..2fc5ac8eb9414f7a0f5e67ae4029902eafbfa9b4 100644 (file)
@@ -200,6 +200,18 @@ Empeg empeg-car Mark I/II Driver (empeg.c)
   helpful. :)
 
 
+MCT USB Single Port Serial Adapter U232
+
+ This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
+ U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+ Model No. U232-P9). More information about this device can be found
+ at the manufacture's web-site: http://www.mct.com.tw.
+
+ The driver is generally working, though it still needs some more
+ testing. It is derived from the Belkin USB Serial Adapter F5U103
+ driver and its TODO list is valid for this driver as well.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
index dc47528cd1c763a07e8119b2145c7bb689f22fba..9703e33044c49e87d0da0179a7b0e92b49018ede 100644 (file)
@@ -37,6 +37,7 @@
  * Nov 1999, Version 1.11
  * Jan 2000, Version 1.12
  * Feb 2000, Version 1.13
+ * Nov 2000, Version 1.14
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
  *         <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
  *         Remove CONFIG_APM_SUSPEND_BOUNCE.  The bounce ignore
  *         interval is now configurable.
+ *   1.14: Make connection version persist across module unload/load.
+ *         Enable and engage power management earlier.
+ *         Disengage power management on module unload.
  *
  * APM 1.1 Reference:
  *
@@ -344,9 +348,9 @@ static int                  kapmd_running;
 
 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user *       user_list = NULL;
+static struct apm_user *       user_list;
 
-static char                    driver_version[] = "1.13";      /* no spaces */
+static char                    driver_version[] = "1.14";      /* no spaces */
 
 static char *  apm_event_name[] = {
        "system standby",
@@ -527,7 +531,7 @@ static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
                        &dummy, &dummy))
                return (eax >> 8) & 0xff;
        *event = ebx;
-       if (apm_bios_info.version < 0x0102)
+       if (apm_info.connection_version < 0x0102)
                *info = ~0; /* indicate info not valid */
        else
                *info = ecx;
@@ -559,7 +563,7 @@ static int apm_do_idle(void)
 #ifdef ALWAYS_CALL_BUSY
        clock_slowed = 1;
 #else
-       clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+       clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
 #endif
        return 1;
 }
@@ -670,15 +674,15 @@ static int apm_enable_power_management(int enable)
 {
        u32     eax;
 
-       if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+       if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
                return APM_NOT_ENGAGED;
        if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
                        enable, &eax))
                return (eax >> 8) & 0xff;
        if (enable)
-               apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+               apm_info.bios.flags &= ~APM_BIOS_DISABLED;
        else
-               apm_bios_info.flags |= APM_BIOS_DISABLED;
+               apm_info.bios.flags |= APM_BIOS_DISABLED;
        return APM_SUCCESS;
 }
 #endif
@@ -691,6 +695,8 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
        u32     edx;
        u32     dummy;
 
+       if (apm_info.get_power_status_broken)
+               return APM_32_UNSUPPORTED;
        if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
                        &eax, &ebx, &ecx, &edx, &dummy))
                return (eax >> 8) & 0xff;
@@ -710,7 +716,7 @@ static int apm_get_battery_status(u_short which, u_short *status,
        u32     edx;
        u32     esi;
 
-       if (apm_bios_info.version < 0x0102) {
+       if (apm_info.connection_version < 0x0102) {
                /* pretend we only have one battery. */
                if (which != 1)
                        return APM_BAD_DEVICE;
@@ -734,15 +740,15 @@ static int apm_engage_power_management(u_short device, int enable)
        u32     eax;
 
        if ((enable == 0) && (device == APM_DEVICE_ALL)
-           && (apm_bios_info.flags & APM_BIOS_DISABLED))
+           && (apm_info.bios.flags & APM_BIOS_DISABLED))
                return APM_DISABLED;
        if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
                return (eax >> 8) & 0xff;
        if (device == APM_DEVICE_ALL) {
                if (enable)
-                       apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+                       apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
                else
-                       apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+                       apm_info.bios.flags |= APM_BIOS_DISENGAGED;
        }
        return APM_SUCCESS;
 }
@@ -890,7 +896,7 @@ static int send_event(apm_event_t event)
                                printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );
                                return 0;
                        }
-                       if (apm_bios_info.version > 0x100)
+                       if (apm_info.connection_version > 0x100)
                                apm_set_power_state(APM_STATE_REJECT);
                        return 0;
                }
@@ -993,13 +999,13 @@ static void check_events(void)
 
                case APM_USER_SUSPEND:
 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
-                       if (apm_bios_info.version > 0x100)
+                       if (apm_info.connection_version > 0x100)
                                apm_set_power_state(APM_STATE_REJECT);
                        break;
 #endif
                case APM_SYS_SUSPEND:
                        if (ignore_bounce) {
-                               if (apm_bios_info.version > 0x100)
+                               if (apm_info.connection_version > 0x100)
                                        apm_set_power_state(APM_STATE_REJECT);
                                break;
                        }
@@ -1064,7 +1070,7 @@ static void apm_event_handler(void)
        int             err;
 
        if ((standbys_pending > 0) || (suspends_pending > 0)) {
-               if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+               if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
                        pending_count = 4;
                        if (debug)
                                printk(KERN_DEBUG "apm: setting state busy\n");
@@ -1334,7 +1340,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
        unsigned short  bx;
        unsigned short  cx;
        unsigned short  dx;
-       unsigned short  error;
+       int             error;
        unsigned short  ac_line_status = 0xff;
        unsigned short  battery_status = 0xff;
        unsigned short  battery_flag   = 0xff;
@@ -1351,7 +1357,7 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
                if ((cx & 0xff) != 0xff)
                        percentage = cx & 0xff;
 
-               if (apm_bios_info.version > 0x100) {
+               if (apm_info.connection_version > 0x100) {
                        battery_flag = (cx >> 8) & 0xff;
                        if (dx != 0xffff) {
                                units = (dx & 0x8000) ? "min" : "sec";
@@ -1399,9 +1405,9 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
 
        p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
                     driver_version,
-                    (apm_bios_info.version >> 8) & 0xff,
-                    apm_bios_info.version & 0xff,
-                    apm_bios_info.flags,
+                    (apm_info.bios.version >> 8) & 0xff,
+                    apm_info.bios.version & 0xff,
+                    apm_info.bios.flags,
                     ac_line_status,
                     battery_status,
                     battery_flag,
@@ -1417,7 +1423,7 @@ static int apm(void *unused)
        unsigned short  bx;
        unsigned short  cx;
        unsigned short  dx;
-       unsigned short  error;
+       int             error;
        char *          power_stat;
        char *          bat_stat;
 
@@ -1429,22 +1435,53 @@ static int apm(void *unused)
        sigfillset(&current->blocked);
        current->tty = NULL;    /* get rid of controlling tty */
 
-       if (apm_bios_info.version > 0x100) {
+       if (apm_info.connection_version == 0) {
+               apm_info.connection_version = apm_info.bios.version;
+               if (apm_info.connection_version > 0x100) {
+                       /*
+                        * We only support BIOSs up to version 1.2
+                        */
+                       if (apm_info.connection_version > 0x0102)
+                               apm_info.connection_version = 0x0102;
+                       error = apm_driver_version(&apm_info.connection_version);
+                       if (error != APM_SUCCESS) {
+                               apm_error("driver version", error);
+                               /* Fall back to an APM 1.0 connection. */
+                               apm_info.connection_version = 0x100;
+                       }
+               }
+       }
+
+       if (debug)
+               printk(KERN_INFO "apm: Connection version %d.%d\n",
+                       (apm_info.connection_version >> 8) & 0xff,
+                       apm_info.connection_version & 0xff);
+
+#ifdef CONFIG_APM_DO_ENABLE
+       if (apm_info.bios.flags & APM_BIOS_DISABLED) {
                /*
-                * We only support BIOSs up to version 1.2
+                * This call causes my NEC UltraLite Versa 33/C to hang if it
+                * is booted with PM disabled but not in the docking station.
+                * Unfortunate ...
                 */
-               if (apm_bios_info.version > 0x0102)
-                       apm_bios_info.version = 0x0102;
-               if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
-                       /* Fall back to an APM 1.0 connection. */
-                       apm_bios_info.version = 0x100;
+               error = apm_enable_power_management(1);
+               if (error) {
+                       apm_error("enable power management", error);
+                       return -1;
+               }
+       }
+#endif
+
+       if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
+           && (apm_info.connection_version > 0x0100)) {
+               error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+               if (error) {
+                       apm_error("engage power management", error);
+                       return -1;
                }
        }
-       if (debug && (smp_num_cpus == 1)) {
-               printk(KERN_INFO "apm: Connection version %d.%d\n",
-                       (apm_bios_info.version >> 8) & 0xff,
-                       apm_bios_info.version & 0xff);
 
+       if (debug && (smp_num_cpus == 1)) {
                error = apm_get_power_status(&bx, &cx, &dx);
                if (error)
                        printk(KERN_INFO "apm: power status not available\n");
@@ -1469,7 +1506,7 @@ static int apm(void *unused)
                                printk("unknown\n");
                        else
                                printk("%d%%\n", cx & 0xff);
-                       if (apm_bios_info.version > 0x100) {
+                       if (apm_info.connection_version > 0x100) {
                                printk(KERN_INFO
                                       "apm: battery flag 0x%02x, battery life ",
                                       (cx >> 8) & 0xff);
@@ -1483,29 +1520,6 @@ static int apm(void *unused)
                }
        }
 
-#ifdef CONFIG_APM_DO_ENABLE
-       if (apm_bios_info.flags & APM_BIOS_DISABLED) {
-               /*
-                * This call causes my NEC UltraLite Versa 33/C to hang if it
-                * is booted with PM disabled but not in the docking station.
-                * Unfortunate ...
-                */
-               error = apm_enable_power_management(1);
-               if (error) {
-                       apm_error("enable power management", error);
-                       return -1;
-               }
-       }
-#endif
-       if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
-           && (apm_bios_info.version > 0x0100)) {
-               error = apm_engage_power_management(APM_DEVICE_ALL, 1);
-               if (error) {
-                       apm_error("engage power management", error);
-                       return -1;
-               }
-       }
-
        /* Install our power off handler.. */
        if (power_off)
                pm_power_off = apm_power_off;
@@ -1584,17 +1598,19 @@ static struct miscdevice apm_device = {
  */
 static int __init apm_init(void)
 {
-       if (apm_bios_info.version == 0) {
+       struct proc_dir_entry *apm_proc;
+
+       if (apm_info.bios.version == 0) {
                printk(KERN_INFO "apm: BIOS not found.\n");
                return -ENODEV;
        }
        printk(KERN_INFO
                "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
-               ((apm_bios_info.version >> 8) & 0xff),
-               (apm_bios_info.version & 0xff),
-               apm_bios_info.flags,
+               ((apm_info.bios.version >> 8) & 0xff),
+               (apm_info.bios.version & 0xff),
+               apm_info.bios.flags,
                driver_version);
-       if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+       if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
                printk(KERN_INFO "apm: no 32 bit BIOS support\n");
                return -ENODEV;
        }
@@ -1603,23 +1619,23 @@ static int __init apm_init(void)
         * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
         * but is reportedly a 1.0 BIOS.
         */
-       if (apm_bios_info.version == 0x001)
-               apm_bios_info.version = 0x100;
+       if (apm_info.bios.version == 0x001)
+               apm_info.bios.version = 0x100;
 
        /* BIOS < 1.2 doesn't set cseg_16_len */
-       if (apm_bios_info.version < 0x102)
-               apm_bios_info.cseg_16_len = 0; /* 64k */
+       if (apm_info.bios.version < 0x102)
+               apm_info.bios.cseg_16_len = 0; /* 64k */
 
        if (debug) {
                printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
-                       apm_bios_info.cseg, apm_bios_info.offset,
-                       apm_bios_info.cseg_16, apm_bios_info.dseg);
-               if (apm_bios_info.version > 0x100)
+                       apm_info.bios.cseg, apm_info.bios.offset,
+                       apm_info.bios.cseg_16, apm_info.bios.dseg);
+               if (apm_info.bios.version > 0x100)
                        printk(" cseg len %x, dseg len %x",
-                               apm_bios_info.cseg_len,
-                               apm_bios_info.dseg_len);
-               if (apm_bios_info.version > 0x101)
-                       printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
+                               apm_info.bios.cseg_len,
+                               apm_info.bios.dseg_len);
+               if (apm_info.bios.version > 0x101)
+                       printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
                printk("\n");
        }
 
@@ -1647,16 +1663,16 @@ static int __init apm_init(void)
                 __va((unsigned long)0x40 << 4));
        _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
 
-       apm_bios_entry.offset = apm_bios_info.offset;
+       apm_bios_entry.offset = apm_info.bios.offset;
        apm_bios_entry.segment = APM_CS;
        set_base(gdt[APM_CS >> 3],
-                __va((unsigned long)apm_bios_info.cseg << 4));
+                __va((unsigned long)apm_info.bios.cseg << 4));
        set_base(gdt[APM_CS_16 >> 3],
-                __va((unsigned long)apm_bios_info.cseg_16 << 4));
+                __va((unsigned long)apm_info.bios.cseg_16 << 4));
        set_base(gdt[APM_DS >> 3],
-                __va((unsigned long)apm_bios_info.dseg << 4));
+                __va((unsigned long)apm_info.bios.dseg << 4));
 #ifndef APM_RELAX_SEGMENTS
-       if (apm_bios_info.version == 0x100) {
+       if (apm_info.bios.version == 0x100) {
 #endif
                /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
                _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
@@ -1667,15 +1683,17 @@ static int __init apm_init(void)
 #ifndef APM_RELAX_SEGMENTS
        } else {
                _set_limit((char *)&gdt[APM_CS >> 3],
-                       (apm_bios_info.cseg_len - 1) & 0xffff);
+                       (apm_info.bios.cseg_len - 1) & 0xffff);
                _set_limit((char *)&gdt[APM_CS_16 >> 3],
-                       (apm_bios_info.cseg_16_len - 1) & 0xffff);
+                       (apm_info.bios.cseg_16_len - 1) & 0xffff);
                _set_limit((char *)&gdt[APM_DS >> 3],
-                       (apm_bios_info.dseg_len - 1) & 0xffff);
+                       (apm_info.bios.dseg_len - 1) & 0xffff);
        }
 #endif
 
-       create_proc_info_entry("apm", 0, NULL, apm_get_info);
+       apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
+       if (apm_proc)
+               SET_MODULE_OWNER(apm_proc);
 
        kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
@@ -1692,6 +1710,14 @@ static int __init apm_init(void)
 
 static void __exit apm_exit(void)
 {
+       int     error;
+
+       if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
+           && (apm_info.connection_version > 0x0100)) {
+               error = apm_engage_power_management(APM_DEVICE_ALL, 0);
+               if (error)
+                       apm_error("disengage power management", error);
+       }
        misc_deregister(&apm_device);
        remove_proc_entry("apm", NULL);
 #ifdef CONFIG_MAGIC_SYSRQ
index 3de4a76d1b988adaac8d3842744f93366bcf01b3..071b3991a988c91c7a7cee0763c1eed39b91f025 100644 (file)
@@ -68,7 +68,7 @@ EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
 EXPORT_SYMBOL(get_cmos_time);
-EXPORT_SYMBOL(apm_bios_info);
+EXPORT_SYMBOL(apm_info);
 EXPORT_SYMBOL(gdt);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
index b0bbdb759c85e18d6c26d9d10dfaab5f2c3ddb51..fffe11398481d6df0e5beb5d9a2ca7dcc7e031c5 100644 (file)
@@ -126,7 +126,7 @@ unsigned int mca_pentium_flag;
  */
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
-struct apm_bios_info apm_bios_info;
+struct apm_info apm_info;
 struct sys_desc_table_struct {
        unsigned short length;
        unsigned char table[0];
@@ -608,7 +608,7 @@ void __init setup_arch(char **cmdline_p)
        ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
        drive_info = DRIVE_INFO;
        screen_info = SCREEN_INFO;
-       apm_bios_info = APM_BIOS_INFO;
+       apm_info.bios = APM_BIOS_INFO;
        if( SYS_DESC_TABLE.length != 0 ) {
                MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
                machine_id = SYS_DESC_TABLE.table[0];
index f52468efe5c566de797e9ba036ade1b35d546d80..917229bfde30b855d11e005adb9706e92e832631 100644 (file)
@@ -33,6 +33,7 @@ endif
 # machines may also.  Since BFD is incredibly buggy with respect to
 # crossformat linking we rely on the elf2ecoff tool for format conversion.
 #
+CFLAGS         += -I $(TOPDIR)/include/asm $(CFLAGS)
 CFLAGS         += -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe
 LINKFLAGS      += -G 0 -static # -N
 MODFLAGS       += -mlong-calls
@@ -154,7 +155,7 @@ archclean:
        @$(MAKEBOOT) clean
        $(MAKE) -C arch/$(ARCH)/kernel clean
        $(MAKE) -C arch/$(ARCH)/tools clean
-       rm -f vmlinux.64 arch/($ARCH)/ld.script.elf32
+       rm -f vmlinux.64 arch/$(ARCH)/ld.script.elf32
 
 archmrproper:
        @$(MAKEBOOT) mrproper
index 411e07fcbbba7aba2bb7d1ab615e514d2cfb26c2..5015551eb59412f55c9f832cc8bc872564f40d97 100644 (file)
@@ -336,9 +336,7 @@ acpi_thread(void *context)
                interruptible_sleep_on(&acpi_thread_wait);
                if (signal_pending(current))
                        break;
-               do {
-                       run_task_queue(&acpi_thread_run);
-               } while (acpi_thread_run);
+               run_task_queue(&acpi_thread_run);
        }
 
        /*
index dba6b5adfdb4567fb9674d63112bed93a1ee4321..5e8dc19f9feeb1d3ec7ee0b98eba95e093e8ee9a 100644 (file)
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion                   "2.4.8"
-#define DAC960_DriverDate                      "19 August 2000"
+#define DAC960_DriverVersion                   "2.4.9"
+#define DAC960_DriverDate                      "7 September 2000"
 
 
 #include <linux/version.h>
@@ -300,13 +300,8 @@ static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command)
 
 static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
 {
-  DECLARE_WAITQUEUE(WaitQueueEntry, current);
-  add_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
-  current->state = TASK_UNINTERRUPTIBLE;
-  spin_unlock(&io_request_lock);
-  schedule();
-  current->state = TASK_RUNNING;
-  remove_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
+  spin_unlock_irq(&io_request_lock);
+  __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
   spin_lock_irq(&io_request_lock);
 }
 
@@ -4957,7 +4952,8 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File,
        }
       Geometry.start =
        Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect;
-      return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T));
+      return (copy_to_user(UserGeometry, &Geometry,
+                          sizeof(DiskGeometry_T)) ? -EFAULT : 0);
     case BLKGETSIZE:
       /* Get Device Size. */
       if ((long *) Argument == NULL) return -EINVAL;
@@ -5078,8 +5074,8 @@ static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File,
        ControllerInfo.PCI_Address = Controller->PCI_Address;
        strcpy(ControllerInfo.ModelName, Controller->ModelName);
        strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
-       return copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
-                           sizeof(DAC960_ControllerInfo_T));
+       return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
+                            sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
       }
     case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
@@ -6401,7 +6397,7 @@ static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer,
   unsigned char CommandBuffer[80];
   int Length;
   if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
-  copy_from_user(CommandBuffer, Buffer, Count);
+  if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
   CommandBuffer[Count] = '\0';
   Length = strlen(CommandBuffer);
   if (CommandBuffer[Length-1] == '\n')
index 96c5b2b3961bbd368a834609e900c78a62075d31..a228034de4d70fa83d178a98992f22279df815a0 100644 (file)
@@ -885,6 +885,36 @@ void generic_make_request (int rw, struct buffer_head * bh)
        while (q->make_request_fn(q, rw, bh));
 }
 
+
+/*
+ * Submit a buffer head for IO.
+ */
+void submit_bh(int rw, struct buffer_head * bh)
+{
+       if (!test_bit(BH_Lock, &bh->b_state))
+               BUG();
+
+       set_bit(BH_Req, &bh->b_state);
+
+       /*
+        * First step, 'identity mapping' - RAID or LVM might
+        * further remap this.
+        */
+       bh->b_rdev = bh->b_dev;
+       bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);
+
+       generic_make_request(rw, bh);
+}
+
+/*
+ * Default IO end handler, used by "ll_rw_block()".
+ */
+static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+       mark_buffer_uptodate(bh, uptodate);
+       unlock_buffer(bh);
+}
+
 /* This function can be used to request a number of buffers from a block
    device. Currently the only restriction is that all buffers must belong to
    the same device */
@@ -931,7 +961,8 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
                if (test_and_set_bit(BH_Lock, &bh->b_state))
                        continue;
 
-               set_bit(BH_Req, &bh->b_state);
+               /* We have the buffer lock */
+               bh->b_end_io = end_buffer_io_sync;
 
                switch(rw) {
                case WRITE:
@@ -954,17 +985,9 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
        end_io:
                        bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
                        continue;
-                       
                }
 
-               /*
-                * First step, 'identity mapping' - RAID or LVM might
-                * further remap this.
-                */
-               bh->b_rdev = bh->b_dev;
-               bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);
-
-               generic_make_request(rw, bh);
+               submit_bh(rw, bh);
        }
        return;
 
@@ -973,7 +996,6 @@ sorry:
                buffer_IO_error(bhs[i]);
 }
 
-
 #ifdef CONFIG_STRAM_SWAP
 extern int stram_device_init (void);
 #endif
index 33f5bc879af259dfe27e702a57b594510efb8f6b..92569a777ac9619bfcc76a2632b3cd4208606986 100644 (file)
@@ -1262,7 +1262,7 @@ static void release_dev(struct file * filp)
         * Make sure that the tty's task queue isn't activated. 
         */
        run_task_queue(&tq_timer);
-       run_schedule_tasks();
+       flush_scheduled_tasks();
 
        /* 
         * The release_mem function takes care of the details of clearing
index 72a8ec211b2e2fc41a3519bde3389c9348f7bacf..afcc00a892c375ae9ed1dd448cbc954a6042ca32 100644 (file)
@@ -300,18 +300,25 @@ static int
 pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
 {
        const struct pci_device_id *id;
+       int ret = 0;
 
        if (drv->id_table) {
                id = pci_match_device(drv->id_table, dev);
-               if (!id)
-                       return 0;
+               if (!id) {
+                       ret = 0;
+                       goto out;
+               }
        } else
                id = NULL;
+
+       dev_probe_lock();
        if (drv->probe(dev, id) >= 0) {
                dev->driver = drv;
-               return 1;
+               ret = 1;
        }
-       return 0;
+       dev_probe_unlock();
+out:
+       return ret;
 }
 
 int
@@ -360,9 +367,9 @@ run_sbin_hotplug(struct pci_dev *pdev, int insert)
        if (!hotplug_path[0])
                return;
 
-       sprintf(class_id, "PCI_CLASS=%X", pdev->class);
-       sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
-       sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
+       sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+       sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+       sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
        sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
 
        i = 0;
@@ -704,6 +711,7 @@ static struct pci_bus * __init pci_alloc_bus(void)
 static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
 {
        struct pci_bus *child;
+       int i;
 
        /*
         * Allocate a new bus, and inherit stuff from the parent..
@@ -725,6 +733,10 @@ static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pc
        child->primary = parent->secondary;
        child->subordinate = 0xff;
 
+       /* Set up default resource pointers.. */
+       for (i = 0; i < 4; i++)
+               child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
        return child;
 }
 
@@ -765,10 +777,7 @@ static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int
                        unsigned int cmax = pci_do_scan_bus(child);
                        if (cmax > max) max = cmax;
                } else {
-                       int i;
                        unsigned int cmax = child->subordinate;
-                       for (i = 0; i < 4; i++)
-                               child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
                        if (cmax > max) max = cmax;
                }
        } else {
@@ -782,6 +791,7 @@ static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int
                pci_read_config_word(dev, PCI_COMMAND, &cr);
                pci_write_config_word(dev, PCI_COMMAND, 0x0000);
                pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
                child = pci_add_new_bus(bus, dev, ++max);
                buses = (buses & 0xff000000)
                      | ((unsigned int)(child->primary)     <<  0)
@@ -795,15 +805,12 @@ static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int
                        /* Now we can scan all subordinate buses... */
                        max = pci_do_scan_bus(child);
                } else {
-                       int i;
                        /*
                         * For CardBus bridges, we leave 4 bus numbers
                         * as cards with a PCI-to-PCI bridge can be
                         * inserted later.
                         */
                        max += 3;
-                       for (i = 0; i < 4; i++)
-                               child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
                }
                /*
                 * Set the subordinate bus number to its real value.
@@ -1082,6 +1089,9 @@ static int pci_pm_resume_device(struct pci_dev *dev)
        return 0;
 }
 
+
+/* take care to suspend/resume bridges only once */
+
 static int pci_pm_suspend_bus(struct pci_bus *bus)
 {
        struct list_head *list;
@@ -1093,9 +1103,6 @@ static int pci_pm_suspend_bus(struct pci_bus *bus)
        /* Walk the device children list */
        list_for_each(list, &bus->devices)
                pci_pm_suspend_device(pci_dev_b(list));
-
-       /* Suspend the bus controller.. */
-       pci_pm_suspend_device(bus->self);
        return 0;
 }
 
@@ -1103,8 +1110,6 @@ static int pci_pm_resume_bus(struct pci_bus *bus)
 {
        struct list_head *list;
 
-       pci_pm_resume_device(bus->self);
-
        /* Walk the device children list */
        list_for_each(list, &bus->devices)
                pci_pm_resume_device(pci_dev_b(list));
@@ -1118,18 +1123,26 @@ static int pci_pm_resume_bus(struct pci_bus *bus)
 static int pci_pm_suspend(void)
 {
        struct list_head *list;
+       struct pci_bus *bus;
 
-       list_for_each(list, &pci_root_buses)
-               pci_pm_suspend_bus(pci_bus_b(list));
+       list_for_each(list, &pci_root_buses) {
+               bus = pci_bus_b(list);
+               pci_pm_suspend_bus(bus);
+               pci_pm_suspend_device(bus->self);
+       }
        return 0;
 }
 
 static int pci_pm_resume(void)
 {
        struct list_head *list;
+       struct pci_bus *bus;
 
-       list_for_each(list, &pci_root_buses)
-               pci_pm_resume_bus(pci_bus_b(list));
+       list_for_each(list, &pci_root_buses) {
+               bus = pci_bus_b(list);
+               pci_pm_resume_device(bus->self);
+               pci_pm_resume_bus(bus);
+       }
        return 0;
 }
 
index 558161d28ea6da3e298a7f3a19319b13c855f0de..e489fbd018723da80153b91851fa7633f8a784e9 100644 (file)
@@ -134,7 +134,7 @@ static struct mixer_defaults {
        {SOUND_MIXER_PCM,       0x4343},
        {SOUND_MIXER_SPEAKER,   0x4343},
        {SOUND_MIXER_LINE,      0x4343},
-       {SOUND_MIXER_MIC,       0x4343},
+       {SOUND_MIXER_MIC,       0x0000},
        {SOUND_MIXER_CD,        0x4343},
        {SOUND_MIXER_ALTPCM,    0x4343},
        {SOUND_MIXER_IGAIN,     0x4343},
index 3fcb068d1c31715ea67400bec3de42db7de7ea09..661caa2144ab15fbae7fae4ecf4eb1950daace53 100644 (file)
@@ -258,7 +258,7 @@ struct cs4281_state {
 #define SNDCTL_DSP_CS_GETDBGMASK       _SIOWR('P', 52, int)
 #define SNDCTL_DSP_CS_SETDBGMASK       _SIOWR('P', 53, int)
 
-void printioctl(unsigned int x)
+static void printioctl(unsigned int x)
 {
        unsigned int i;
        unsigned char vidx;
index c0bf7c382864caff59d7489a024d75406d3aeee0..d3ff7d71fe48887acac60199d107253884578827 100644 (file)
@@ -359,7 +359,7 @@ extern __inline__ unsigned ld2(unsigned int x)
 #define SNDCTL_DSP_CS_GETDBGMASK       _SIOWR('P', 52, int)
 #define SNDCTL_DSP_CS_SETDBGMASK       _SIOWR('P', 53, int)
 
-void printioctl(unsigned int x)
+static void printioctl(unsigned int x)
 {
     unsigned int i;
     unsigned char vidx;
index 626869736116980253c5ca358d91bc049281c305..422533b444df2da575cd19cf9496b20fa01db9d5 100644 (file)
@@ -95,8 +95,8 @@ struct usb_hub {
 
        struct urb *urb;                /* Interrupt polling pipe */
 
-       char buffer[USB_MAXCHILDREN / 8];
-
+       char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
+                                       /* and add 7 bits to round up to byte boundary */
        int error;
        int nerrors;
 
index 2ee4ba127d767c9b07dbe6a0c420e36566133180..2a7e887d9396f5862df082f352362d365f79210d 100644 (file)
@@ -252,6 +252,7 @@ static struct usb_device_id scanner_device_ids [] = {
     { idVendor: 0x04a5, idProduct: 0x2022 },/* Vuego Scan Brisa 340U */
        /* Agfa */
     { idVendor: 0x06bd, idProduct: 0x0001 },   /* SnapScan 1212U */
+    { idVendor: 0x06bd, idProduct: 0x0002 },   /* SnapScan 1236U */
     { idVendor: 0x06bd, idProduct: 0x2061 },   /* Another SnapScan 1212U (?)*/
     { idVendor: 0x06bd, idProduct: 0x0100 },   /* SnapScan Touch */
        /* Colorado -- See Primax/Colorado below */
@@ -300,10 +301,10 @@ static struct usb_device_id scanner_device_ids [] = {
     { idVendor: 0x04b8, idProduct: 0x0101 },/* Perfection 636U and 636Photo */
     { idVendor: 0x04b8, idProduct: 0x0103 },/* Perfection 610 */
     { idVendor: 0x04b8, idProduct: 0x0104 },/* Perfection 1200U and 1200Photo*/
+    { idVendor: 0x04b8, idProduct: 0x0106 },/* Stylus Scan 2500 */
     { idVendor: 0x04b8, idProduct: 0x0107 },/* Expression 1600 */
        /* Umax */
     { idVendor: 0x1606, idProduct: 0x0010 },   /* Astra 1220U */
-    { idVendor: 0x1606, idProduct: 0x0002 },   /* Astra 1236U */
     { idVendor: 0x1606, idProduct: 0x0030 },   /* Astra 2000U */
     { idVendor: 0x1606, idProduct: 0x0230 },   /* Astra 2200U */
        /* Visioneer */
index db77957a97820802ca0fd8615cf72cc254da7487..6d949bc0ba79eb8b9525a6dce897fdf0bbc84ca2 100644 (file)
@@ -23,6 +23,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
      bool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
      bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
   fi
+  dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
 
index 0fc7143045e9b494121fb08d7485c6eea9b7d355..97b5516aab29387288eb17330c4a394ec4418efa 100644 (file)
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_OMNINET)              += omninet.o
 obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT)       += digi_acceleport.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)                        += belkin_sa.o
 obj-$(CONFIG_USB_SERIAL_EMPEG)                 += empeg.o
+obj-$(CONFIG_USB_SERIAL_MCT_U232)              += mct_u232.o
  
 # Objects that export symbols.
 export-objs    := usbserial.o
index 885108cd0819fdecd3ba1f91f7ee4c349e62e8b3..b4ee5fdc111d12dd64c136fa126dbde8a2ab76a1 100644 (file)
   and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
   Thanks Guys :)
   
+  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+  of much nicer and/or completely new code and (perhaps most uniquely)
+  having the patience to sit down and explain why and where he'd changed
+  stuff. 
+  
   Tip 'o the hat to Linuxcare for supporting staff in their work on
   open source projects.
 
- (11/01/2000) Adam J. Richter
+  Change History
+   (11/01/2000) Adam J. Richter
        usb_device_id table support.
+   
+    Tue Oct 10 23:15:33 EST 2000 Hugh
+      Merged Paul's changes with my USA-49W mods.  Work in progress
+      still...
+  
+    Wed Jul 19 14:00:42 EST 2000 gkh
+      Added module_init and module_exit functions to handle the fact that
+      this driver is a loadable module now.
  
- (10/05/2000) gkh
-       Fixed bug with urb->dev not being set properly, now that the usb
-       core needs it.
-
-  Wed Jul 19 14:00:42 EST 2000 gkh
-       Added module_init and module_exit functions to handle the fact that this
-       driver is a loadable module now.
-
-  Tue Jul 18 16:14:52 EST 2000 Hugh
-    Basic character input/output for USA-19 now mostly works,
-    fixed at 9600 baud for the moment.
+    Tue Jul 18 16:14:52 EST 2000 Hugh
+      Basic character input/output for USA-19 now mostly works,
+      fixed at 9600 baud for the moment.
 
+    Sat Jul  8 11:11:48 EST 2000 Hugh
+      First public release - nothing works except the firmware upload.
+      Tested on PPC and x86 architectures, seems to behave...
 */
 
 
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
-#ifdef CONFIG_USB_SERIAL_DEBUG
+#define DEBUG
+/*  #ifdef CONFIG_USB_SERIAL_DEBUG */
        #define DEBUG
-#else
-       #undef DEBUG
-#endif
+/*  #endif */
 #include <linux/usb.h>
 
 #include "usb-serial.h"
 #include "keyspan.h"
 
+#define INSTAT_BUFLEN  32
+#define GLOCONT_BUFLEN 64
+
        /* Per device and per port private data */
 struct keyspan_serial_private {
-       struct urb      *in_urbs[8];
-       struct urb      *out_urbs[8];
-       char            out_buffer[64];
-       char            in_buffer[64];
+       /* number of active ports */
+       atomic_t        active_count;
+
+       const keyspan_device_details    *device_details;
+
+       urb_t           *instat_urb;
+       char            instat_buf[INSTAT_BUFLEN];
+
+       /* XXX this one probably will need a lock */
+       urb_t           *glocont_urb;
+       char            glocont_buf[GLOCONT_BUFLEN];
 };
 
 struct keyspan_port_private {
-               /* Keep track of which output endpoint to use */
+       /* Keep track of which input & output endpoints to use */
+       int             in_flip;
        int             out_flip;
 
-               /* Settings for the port */
+       /* Keep duplicate of device details in each port
+          structure as well - simplifies some of the
+          callback functions etc. */
+       const keyspan_device_details    *device_details;
+
+       /* Input endpoints and buffer for this port */
+       urb_t           *in_urbs[2];
+       char            in_buffer[2][64];
+       /* Output endpoints and buffer for this port */
+       urb_t           *out_urbs[2];
+       char            out_buffer[2][64];
+
+       /* Input ack endpoint */
+       urb_t           *inack_urb;
+       char            inack_buffer[1];
+
+       /* Output control endpoint */
+       urb_t           *outcont_urb;
+       char            outcont_buffer[64];
+
+       /* Settings for the port */
        int             baud;
        int             old_baud;
-       enum            {parity_none, parity_odd, parity_even} parity;
+       unsigned int    cflag;
        enum            {flow_none, flow_cts, flow_xon} flow_control;
-       int             rts_state;
+       int             rts_state;      /* Handshaking pins (outputs) */
        int             dtr_state;
+       int             cts_state;      /* Handshaking pins (inputs) */
+       int             dsr_state;
+       int             dcd_state;
+       int             ri_state;
 
+       unsigned long   tx_start_time[2];
+       int             resend_cont;    /* need to resend control packet */
 };
 
-
-       /* FIXME this will break if multiple physical interfaces used */
-static wait_queue_head_t       out_wait;
        
-       /* Include Keyspan message headers (not both yet, need some tweaks
-          to get clean build) */
-/*#include "keyspan_usa26msg.h"*/
+/* Include Keyspan message headers.  All current Keyspan Adapters
+   make use of one of three message formats which are referred
+   to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */
+#include "keyspan_usa26msg.h"
 #include "keyspan_usa28msg.h"
+#include "keyspan_usa49msg.h"
        
-       /* If you don't get debugging output, uncomment the following
-          two lines to enable cheat. */
-#undef         dbg
-#define        dbg     printk
+/* If you don't get debugging output, uncomment the following
+   two lines to enable cheat. */
+#if 0
+  #undef       dbg 
+  #define      dbg     printk 
+#endif
+
+static void keyspan_send_setup(struct usb_serial_port *port);
+
+/* Functions used by new usb-serial code. */
+int keyspan_init (void)
+{
+       usb_serial_register (&keyspan_usa18x_pre_device);
+       usb_serial_register (&keyspan_usa19_pre_device);
+       usb_serial_register (&keyspan_usa19w_pre_device);
+       usb_serial_register (&keyspan_usa28_pre_device);
+       usb_serial_register (&keyspan_usa28x_pre_device);
+       usb_serial_register (&keyspan_usa49w_pre_device);
+
+       usb_serial_register (&keyspan_usa18x_device);
+       usb_serial_register (&keyspan_usa19_device);
+       usb_serial_register (&keyspan_usa19w_device);
+       usb_serial_register (&keyspan_usa28_device);
+       usb_serial_register (&keyspan_usa28x_device);
+       usb_serial_register (&keyspan_usa49w_device);
+       return 0;
+}
+
+void keyspan_exit (void)
+{
+       usb_serial_deregister (&keyspan_usa18x_pre_device);
+       usb_serial_deregister (&keyspan_usa19_pre_device);
+       usb_serial_deregister (&keyspan_usa19w_pre_device);
+       usb_serial_deregister (&keyspan_usa28_pre_device);
+       usb_serial_deregister (&keyspan_usa28x_pre_device);
+       usb_serial_deregister (&keyspan_usa49w_pre_device);
+
+       usb_serial_deregister (&keyspan_usa18x_device);
+       usb_serial_deregister (&keyspan_usa19_device);
+       usb_serial_deregister (&keyspan_usa19w_device);
+       usb_serial_deregister (&keyspan_usa28_device);
+       usb_serial_deregister (&keyspan_usa28x_device);
+       usb_serial_deregister (&keyspan_usa49w_device);
+}
+
+module_init(keyspan_init);
+module_exit(keyspan_exit);
 
-       /* Functions - mostly stubs for now */
 static void keyspan_rx_throttle (struct usb_serial_port *port)
 {
        dbg("keyspan_rx_throttle port %d", port->number);
@@ -123,194 +209,597 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state)
 static void keyspan_set_termios (struct usb_serial_port *port, 
                                     struct termios *old_termios)
 {
-       dbg("keyspan_set_termios");
+       int                             baud_rate;
+       struct keyspan_port_private     *p_priv;
+       const keyspan_device_details    *d_details;
+       unsigned int                    cflag;
+
+       /*  dbg(__FUNCTION__ "."); */
+
+       p_priv = (struct keyspan_port_private *)(port->private);
+       d_details = p_priv->device_details;
+       cflag = port->tty->termios->c_cflag;
+
+       /* Baud rate calculation takes baud rate as an integer
+          so other rates can be generated if desired. */
+       baud_rate = tty_get_baud_rate(port->tty);
+       /* If no match or invalid, don't change */              
+       if (baud_rate >= 0
+           && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+                               NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) {
+               /* FIXME - more to do here to ensure rate changes cleanly */
+               p_priv->baud = baud_rate;
+       }
+
+       /* set CTS/RTS handshake etc. */
+       p_priv->cflag = cflag;
+       p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
+
+       keyspan_send_setup(port);
 }
 
 static int keyspan_ioctl(struct usb_serial_port *port, struct file *file,
                             unsigned int cmd, unsigned long arg)
 {
-       unsigned int            value;
+       unsigned int                    value, set;
+       struct keyspan_port_private     *p_priv;
 
-       dbg("keyspan_ioctl_info");
+       p_priv = (struct keyspan_port_private *)(port->private);
        
        switch (cmd) {
        case TIOCMGET:
-               value = TIOCM_DTR | TIOCM_RNG;
-               if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) {
+               value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
+                       ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
+                       ((p_priv->cts_state) ? TIOCM_CTS : 0) |
+                       ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
+                       ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
+                       ((p_priv->ri_state) ? TIOCM_RNG : 0); 
+
+               if (put_user(value, (unsigned int *) arg))
                        return -EFAULT;
-               }
-               else {
-                       return 0;
-               }
-               
-       default:
-               return -ENOIOCTLCMD;
+               return 0;
+       
+       case TIOCMSET:
+               if (get_user(value, (unsigned int *) arg))
+                       return -EFAULT;
+               p_priv->rts_state = ((value & TIOCM_RTS) ? 1 : 0);
+               p_priv->dtr_state = ((value & TIOCM_DTR) ? 1 : 0);
+               keyspan_send_setup(port);
+               return 0;
+
+       case TIOCMBIS:
+       case TIOCMBIC:
+               if (get_user(value, (unsigned int *) arg))
+                       return -EFAULT;
+               set = (cmd == TIOCMBIS);
+               if (value & TIOCM_RTS)
+                       p_priv->rts_state = set;
+               if (value & TIOCM_DTR)
+                       p_priv->dtr_state = set;
+               keyspan_send_setup(port);
+               return 0;
        }
 
        return -ENOIOCTLCMD;
 }
 
+       /* Write function is generic for the three protocols used
+          with only a minor change for usa49 required */
 static int keyspan_write(struct usb_serial_port *port, int from_user, 
-                            const unsigned char *buf, int count)
+                        const unsigned char *buf, int count)
 {
-       struct usb_serial               *serial = port->serial;
-       struct keyspan_serial_private   *s_priv;
        struct keyspan_port_private     *p_priv;
-       int                             current_urb;
-       int                             i;
+       const keyspan_device_details    *d_details;
+       int                             flip;
+       int left, todo;
+       urb_t *this_urb;
+       int err;
 
-       s_priv = (struct keyspan_serial_private *)(serial->private);
        p_priv = (struct keyspan_port_private *)(port->private);
-       
-       if (p_priv->out_flip == 0) {
-               current_urb = 0;
-               p_priv->out_flip = 1;
-       }
-       else {
-               current_urb = 1;
-               p_priv->out_flip = 0;
-       }
+       d_details = p_priv->device_details;
 
-       dbg("keyspan_write called for port %d (%d) chars {", port->number, count);
-       for (i = 0; i < count ; i++) {
-               dbg("%02x ", buf[i]);
-       }
-       dbg("}\n");
+#if 0
+       dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d",
+           port->number, count, buf[0], p_priv->out_flip);
+#endif
 
-       if (count == 0) {
-               dbg("write request of 0 bytes");
-               return (0);
-       }
+       for (left = count; left > 0; left -= todo) {
+               todo = left;
+               if (todo > 63)
+                       todo = 63;
 
-               /* only send data if we have a bulk out endpoint */
-       if (s_priv->out_urbs[current_urb]) {
-               while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
-                       dbg (__FUNCTION__ " INPROGRES\n");
-                       interruptible_sleep_on(&out_wait);
-                       if (signal_pending(current)) {
-                               dbg (__FUNCTION__ " signal\n");
-                               return (-ERESTARTSYS);
-                       }
+               flip = p_priv->out_flip;
+       
+               /* Check we have a valid urb/endpoint before we use it... */
+               if ((this_urb = p_priv->out_urbs[flip]) == 0) {
+                       /* no bulk out, so return 0 bytes written */
+                       dbg(__FUNCTION__ " no output urb :(");
+                       return count;
+               }
+
+               if (this_urb->status == -EINPROGRESS) {
+                       if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
+                               break;
+                       if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)
+                               break;
+                       this_urb->transfer_flags |= USB_ASYNC_UNLINK;
+                       usb_unlink_urb(this_urb);
+                       break;
                }
-               /*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
-                       dbg ("already writing");
-                       return (-EAGAIN);
-               }*/
-                       /* First byte in buffer is "last flag" - unused so
-                          for now so set to zero */
-               memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1);
+
+               /* First byte in buffer is "last flag" - unused so
+                  for now so set to zero */
+               ((char *)this_urb->transfer_buffer)[0] = 0;
 
                if (from_user) {
-                       copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
+                       copy_from_user(this_urb->transfer_buffer + 1, buf, todo);
+               } else {
+                       memcpy (this_urb->transfer_buffer + 1, buf, todo);
                }
-               else {
-                       memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
-               }  
+               buf += todo;
 
                /* send the data out the bulk port */
-               s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1;
-               s_priv->out_urbs[current_urb]->dev = serial->dev;
+               this_urb->transfer_buffer_length = todo + 1;
 
-               if (usb_submit_urb(s_priv->out_urbs[current_urb])) {
-                       dbg("usb_submit_urb(write bulk) failed");
+               this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+               this_urb->dev = port->serial->dev;
+               if ((err = usb_submit_urb(this_urb)) != 0) {
+                       dbg("usb_submit_urb(write bulk) failed (%d)", err);
                }
+               p_priv->tx_start_time[flip] = jiffies;
 
-               return (count);
+               /* Flip for next time if usa26 or usa28 interface
+                  (not used on usa49) */
+               p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
        }
-       
-       /* no bulk out, so return 0 bytes written */
-       return (0);
-}
 
+       return count - left;
+}
 
-static void keyspan_write_bulk_callback (struct urb *urb)
+static void    usa26_indat_callback(struct urb *urb)
 {
-       int             endpoint;
-       
+       int                     i, err;
+       int                     endpoint;
+       struct usb_serial_port  *port;
+       struct tty_struct       *tty;
+       unsigned char           *data = urb->transfer_buffer;
+
+       /*  dbg (__FUNCTION__); */
+
        endpoint = usb_pipeendpoint(urb->pipe);
 
-       dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint);
+       if (urb->status) {
+               dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
+                                       urb->status, endpoint);
+               return;
+       }
+
+       port = (struct usb_serial_port *) urb->context;
+       tty = port->tty;
+       if (urb->actual_length) {
+               if (data[0] == 0) {
+                       /* no error on any byte */
+                       for (i = 1; i < urb->actual_length ; ++i) {
+                               tty_insert_flip_char(tty, data[i], 0);
+                       }
+               } else {
+                       /* some bytes had errors, every byte has status */
+                       for (i = 0; i + 1 < urb->actual_length; i += 2) {
+                               int stat = data[i], flag = 0;
+                               if (stat & RXERROR_OVERRUN)
+                                       flag |= TTY_OVERRUN;
+                               if (stat & RXERROR_FRAMING)
+                                       flag |= TTY_FRAME;
+                               if (stat & RXERROR_PARITY)
+                                       flag |= TTY_PARITY;
+                               /* XXX should handle break (0x10) */
+                               tty_insert_flip_char(tty, data[i+1], flag);
+                       }
+               }
+               tty_flip_buffer_push(tty);
+       }
+                               
+               /* Resubmit urb so we continue receiving */
+       urb->dev = port->serial->dev;
+       if ((err = usb_submit_urb(urb)) != 0) {
+               dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+       }
+       return;
+}
 
-               /* Only do wakeup if this callback is from one of the data
-                  endpoints.  */
-       if (endpoint == 2 || endpoint == 3) {
-               wake_up_interruptible(&out_wait);
+       /* Outdat handling is common for usa26, usa28 and usa49 messages */
+static void    usa2x_outdat_callback(struct urb *urb)
+{
+       struct usb_serial_port *port;
+       struct keyspan_port_private *p_priv;
+
+       port = (struct usb_serial_port *) urb->context;
+       p_priv = (struct keyspan_port_private *)(port->private);
+       /*  dbg (__FUNCTION__ " urb %d", urb == p_priv->out_urbs[1]); */
+
+       if (port->active) {
+               queue_task(&port->tqueue, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
        }
+}
 
+static void    usa26_inack_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+       
 }
 
+static void    usa26_outcont_callback(struct urb *urb)
+{
+       struct usb_serial_port *port;
+       struct keyspan_port_private *p_priv;
 
-static void keyspan_read_bulk_callback (struct urb *urb)
+       port = (struct usb_serial_port *) urb->context;
+       p_priv = (struct keyspan_port_private *)(port->private);
+
+       if (p_priv->resend_cont) {
+               /*  dbg (__FUNCTION__ " sending setup"); */
+               keyspan_usa26_send_setup(port->serial, port);
+       }
+}
+
+static void    usa26_instat_callback(struct urb *urb)
 {
-       struct usb_serial       *serial = (struct usb_serial *)urb->context;
-       struct usb_serial_port  *port;
-       int                     i;
-       int                     endpoint;
-       struct tty_struct       *tty;
-       unsigned char           *data = urb->transfer_buffer;
+       unsigned char                           *data = urb->transfer_buffer;
+       keyspan_usa26_portStatusMessage         *msg;
+       struct usb_serial                       *serial;
+       struct usb_serial_port                  *port;
+       struct keyspan_port_private             *p_priv;
+       int old_dcd_state, err;
 
-       if (serial_paranoia_check (serial, __FUNCTION__))
+       serial = (struct usb_serial *) urb->context;
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " nonzero status: %x", urb->status);
                return;
-       port = &serial->port[0];
-       if (port_paranoia_check (port, __FUNCTION__))
+       }
+       if (urb->actual_length != 9) {
+               dbg(__FUNCTION__ " %d byte report??", urb->actual_length);
+               goto exit;
+       }
+
+       msg = (keyspan_usa26_portStatusMessage *)data;
+
+#if 0
+       dbg(__FUNCTION__ " port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
+           msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
+           msg->_txXoff, msg->rxEnabled, msg->controlResponse);
+#endif
+
+       /* Now do something useful with the data */
+
+
+       /* Check port number from message and retrieve private data */  
+       if (msg->port >= serial->num_ports) {
+               dbg ("Unexpected port number %d", msg->port);
+               goto exit;
+       }
+       port = &serial->port[msg->port];
+       p_priv = (struct keyspan_port_private *)(port->private);
+       
+       /* Update handshaking pin state information */
+       old_dcd_state = p_priv->dcd_state;
+       p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
+       p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+       p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
+       p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+       if (port->tty && !C_CLOCAL(port->tty)
+           && old_dcd_state != p_priv->dcd_state) {
+               if (old_dcd_state)
+                       tty_hangup(port->tty);
+               /*  else */
+               /*      wake_up_interruptible(&p_priv->open_wait); */
+       }
+       
+exit:
+       /* Resubmit urb so we continue receiving */
+       urb->dev = serial->dev;
+       if ((err = usb_submit_urb(urb)) != 0) {
+               dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+       }
+}
+
+static void    usa26_glocont_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+       
+}
+
+
+static void     usa28_indat_callback(struct urb *urb)
+{
+       int                     i, err;
+       struct usb_serial_port  *port;
+       struct tty_struct       *tty;
+       unsigned char           *data;
+       struct keyspan_port_private             *p_priv;
+
+       /*  dbg (__FUNCTION__); */
+
+       port = (struct usb_serial_port *) urb->context;
+       p_priv = (struct keyspan_port_private *)(port->private);
+       data = urb->transfer_buffer;
+
+       if (urb != p_priv->in_urbs[p_priv->in_flip])
                return;
 
+       do {
+               if (urb->status) {
+                       dbg(__FUNCTION__ "nonzero status: %x on endpoint
+%d.",
+                           urb->status, usb_pipeendpoint(urb->pipe));
+                       return;
+               }
+
+               port = (struct usb_serial_port *) urb->context;
+               p_priv = (struct keyspan_port_private *)(port->private);
+               data = urb->transfer_buffer;
+
+               tty = port->tty;
+               if (urb->actual_length) {
+                       for (i = 0; i < urb->actual_length ; ++i) {
+                               tty_insert_flip_char(tty, data[i], 0);
+                       }
+                       tty_flip_buffer_push(tty);
+               }
+
+               /* Resubmit urb so we continue receiving */
+               urb->dev = port->serial->dev;
+               if ((err = usb_submit_urb(urb)) != 0) {
+                       dbg(__FUNCTION__ "resubmit read urb failed. (%d)",
+err);
+               }
+               p_priv->in_flip ^= 1;
+
+               urb = p_priv->in_urbs[p_priv->in_flip];
+       } while (urb->status != -EINPROGRESS);
+}
+
+static void    usa28_inack_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+}
+
+static void    usa28_outcont_callback(struct urb *urb)
+{
+       struct usb_serial_port *port;
+       struct keyspan_port_private *p_priv;
+
+       port = (struct usb_serial_port *) urb->context;
+       p_priv = (struct keyspan_port_private *)(port->private);
+
+       if (p_priv->resend_cont) {
+               dbg (__FUNCTION__ " sending setup");
+               keyspan_usa28_send_setup(port->serial, port);
+       }
+}
+
+static void    usa28_instat_callback(struct urb *urb)
+{
+       int                                     err;
+       unsigned char                           *data = urb->transfer_buffer;
+       keyspan_usa28_portStatusMessage         *msg;
+       struct usb_serial                       *serial;
+       struct usb_serial_port                  *port;
+       struct keyspan_port_private             *p_priv;
+       int old_dcd_state;
+
+       serial = (struct usb_serial *) urb->context;
+
        if (urb->status) {
-               dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+               dbg(__FUNCTION__ " nonzero status: %x", urb->status);
                return;
        }
 
-       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+       if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
+               dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+               goto exit;
+       }
 
-       endpoint = usb_pipeendpoint(urb->pipe);
+       /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x %x",
+           data[0], data[1], data[2], data[3], data[4], data[5],
+           data[6], data[7], data[8], data[9], data[10], data[11]);*/
+       
+               /* Now do something useful with the data */
+       msg = (keyspan_usa28_portStatusMessage *)data;
+
+
+               /* Check port number from message and retrieve private data */  
+       if (msg->port >= serial->num_ports) {
+               dbg ("Unexpected port number %d", msg->port);
+               goto exit;
+       }
+       port = &serial->port[msg->port];
+       p_priv = (struct keyspan_port_private *)(port->private);
+       
+       /* Update handshaking pin state information */
+       old_dcd_state = p_priv->dcd_state;
+       p_priv->cts_state = ((msg->cts) ? 1 : 0);
+       p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+       p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+       p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+       if (port->tty && !C_CLOCAL(port->tty)
+           && old_dcd_state != p_priv->dcd_state) {
+               if (old_dcd_state)
+                       tty_hangup(port->tty);
+               /*  else */
+               /*      wake_up_interruptible(&p_priv->open_wait); */
+       }
+
+exit:  
+               /* Resubmit urb so we continue receiving */
+       urb->dev = serial->dev;
+       if ((err = usb_submit_urb(urb)) != 0) {
+               dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+       }
+}
+
+static void    usa28_glocont_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+}
+
+
+static void    usa49_glocont_callback(struct urb *urb)
+{
+       struct usb_serial *serial;
+       struct usb_serial_port *port;
+       struct keyspan_port_private *p_priv;
+       int i;
+
+       /*  dbg (__FUNCTION__); */
 
+       serial = (struct usb_serial *) urb->context;
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = &serial->port[i];
+               p_priv = (struct keyspan_port_private *)(port->private);
+
+               if (p_priv->resend_cont) {
+                       /*  dbg (__FUNCTION__ " sending setup"); */
+                       keyspan_usa49_send_setup(serial, port);
+                       break;
+               }
+       }
+}
+
+       /* This is actually called glostat in the Keyspan
+          doco */
+static void    usa49_instat_callback(struct urb *urb)
+{
+       int                                     err;
+       unsigned char                           *data = urb->transfer_buffer;
+       keyspan_usa49_portStatusMessage         *msg;
+       struct usb_serial                       *serial;
+       struct usb_serial_port                  *port;
+       struct keyspan_port_private             *p_priv;
+       int old_dcd_state;
+
+       /*  dbg (__FUNCTION__); */
+
+       serial = (struct usb_serial *) urb->context;
 
        if (urb->status) {
-               dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
-                                       urb->status, endpoint);
+               dbg(__FUNCTION__ " nonzero status: %x", urb->status);
                return;
        }
 
-       switch (endpoint) {
+       if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) {
+               dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+               goto exit;
+       }
 
-                       /* If this is one of the data endpoints, stuff it's
-                          contents into the tty flip_buffer. */
-               case 1:
-               case 2:
-                       tty = port->tty;
-                       if (urb->actual_length) {
-                               for (i = 0; i < urb->actual_length ; ++i) {
-                                        tty_insert_flip_char(tty, data[i], 0);
-                               }
-                               tty_flip_buffer_push(tty);
-                       }
-                       break;
+       /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x",
+           data[0], data[1], data[2], data[3], data[4], data[5],
+           data[6], data[7], data[8], data[9], data[10]);*/
+       
+               /* Now do something useful with the data */
+       msg = (keyspan_usa49_portStatusMessage *)data;
 
-                       /* INACK endpoint */    
-               case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n");
-                       break;
+               /* Check port number from message and retrieve private data */  
+       if (msg->portNumber >= serial->num_ports) {
+               dbg ("Unexpected port number %d", msg->portNumber);
+               goto exit;
+       }
+       port = &serial->port[msg->portNumber];
+       p_priv = (struct keyspan_port_private *)(port->private);
+       
+       /* Update handshaking pin state information */
+       old_dcd_state = p_priv->dcd_state;
+       p_priv->cts_state = ((msg->cts) ? 1 : 0);
+       p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+       p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+       p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+       if (port->tty && !C_CLOCAL(port->tty)
+           && old_dcd_state != p_priv->dcd_state) {
+               if (old_dcd_state)
+                       tty_hangup(port->tty);
+               /*  else */
+               /*      wake_up_interruptible(&p_priv->open_wait); */
+       }
 
-                       /* INSTAT endpoint */
-               case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n");
-                       break;
-               
-               default:
-                       dbg(__FUNCTION__ " callback for unknown endpoint!\n");
-                       break;
+exit:  
+               /* Resubmit urb so we continue receiving */
+       urb->dev = serial->dev;
+
+       if ((err = usb_submit_urb(urb)) != 0) {
+               dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+       }
+}
+
+static void    usa49_inack_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+}
+
+static void    usa49_indat_callback(struct urb *urb)
+{
+       int                     i, err;
+       int                     endpoint;
+       struct usb_serial_port  *port;
+       struct tty_struct       *tty;
+       unsigned char           *data = urb->transfer_buffer;
+
+       /*  dbg (__FUNCTION__); */
+
+       endpoint = usb_pipeendpoint(urb->pipe);
+
+       if (urb->status) {
+               dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
+                                       urb->status, endpoint);
+               return;
+       }
+
+       port = (struct usb_serial_port *) urb->context;
+       tty = port->tty;
+       if (urb->actual_length) {
+               if (data[0] == 0) {
+                       /* no error on any byte */
+                       for (i = 1; i < urb->actual_length ; ++i) {
+                               tty_insert_flip_char(tty, data[i], 0);
+                       }
+               } else {
+                       /* some bytes had errors, every byte has status */
+                       for (i = 0; i + 1 < urb->actual_length; i += 2) {
+                               int stat = data[i], flag = 0;
+                               if (stat & RXERROR_OVERRUN)
+                                       flag |= TTY_OVERRUN;
+                               if (stat & RXERROR_FRAMING)
+                                       flag |= TTY_FRAME;
+                               if (stat & RXERROR_PARITY)
+                                       flag |= TTY_PARITY;
+                               /* XXX should handle break (0x10) */
+                               tty_insert_flip_char(tty, data[i+1], flag);
+                       }
+               }
+               tty_flip_buffer_push(tty);
        }
                                
-       /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
-       if (usb_submit_urb(urb)) {
-               dbg(__FUNCTION__ "resubmit read urb failed.\n");
+               /* Resubmit urb so we continue receiving */
+       urb->dev = port->serial->dev;
+       if ((err = usb_submit_urb(urb)) != 0) {
+               dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
        }
-       return;
-       
 }
 
+/* not used, usa-49 doesn't have per-port control endpoints */
+static void    usa49_outcont_callback(struct urb *urb)
+{
+       dbg (__FUNCTION__);
+}
+
+
+
 static int keyspan_write_room (struct usb_serial_port *port)
 {
-//     dbg("keyspan_write_room called\n");
+//     dbg("keyspan_write_room called");
        return (32);
 
 }
@@ -327,63 +816,103 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
        struct keyspan_port_private     *p_priv;
        struct keyspan_serial_private   *s_priv;
        struct usb_serial               *serial = port->serial;
-       int                             i;
-
-       s_priv = (struct keyspan_serial_private *)(serial->private);
-       p_priv = (struct keyspan_port_private *)(port->private);
-       
-       dbg("keyspan_open called.\n");
-       
-       if (port->active) {
-               dbg(__FUNCTION__ "port->active already true!\n");
-               return (-EINVAL);
-       }
+       const keyspan_device_details    *d_details;
+       int                             i, already_active, err;
+       unsigned long flags;
+       urb_t *urb;
 
+       s_priv = (struct keyspan_serial_private *)(serial->private);
        p_priv = (struct keyspan_port_private *)(port->private);
+       d_details = s_priv->device_details;
        
-       p_priv->out_flip = 0;
+       /*  dbg("keyspan_open called."); */
+       MOD_INC_USE_COUNT;
+
+       spin_lock_irqsave (&port->port_lock, flags);
+       ++port->open_count;
+       already_active = port->active;
        port->active = 1;
+       spin_unlock_irqrestore (&port->port_lock, flags);
 
-               /* Start reading from port */
-       for (i = 0; i < 4; i++) {
-               if (s_priv->in_urbs[i]) {
-                       s_priv->in_urbs[i]->dev = serial->dev;
-                       if (usb_submit_urb(s_priv->in_urbs[i])) {
-                               dbg(__FUNCTION__ " submit in urb %d failed", i);
-                       }
-               }
+       if (already_active)
+               return 0;
 
+       p_priv = (struct keyspan_port_private *)(port->private);
+
+       /* Set some sane defaults */
+       p_priv->baud = 9600;
+       p_priv->cflag = CREAD | CLOCAL;
+       p_priv->flow_control = flow_none;
+       p_priv->rts_state = 1;
+       p_priv->dtr_state = 1;
+
+       /* Start reading from endpoints */
+       for (i = 0; i < 2; i++) {
+               if ((urb = p_priv->in_urbs[i]) == NULL)
+                       continue;
+               urb->dev = serial->dev;
+               if ((err = usb_submit_urb(urb)) != 0) {
+                       dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
+               }
        }
-       
-       keyspan_usa19_send_setup(serial, port);
+/*    Now done in startup routine
+       if (atomic_inc_return(&s_priv->active_count) == 1) {
+               s_priv->instat_urb->dev = serial->dev;
+               if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+                       dbg(__FUNCTION__ " submit instat urb failed %d", err);
+               }
+       }
+*/
+
+       keyspan_send_setup(port);
 
        return (0);
 }
 
+static inline void stop_urb(urb_t *urb)
+{
+       if (urb && urb->status == -EINPROGRESS) {
+               urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+               usb_unlink_urb(urb);
+       }
+}
 
 static void keyspan_close(struct usb_serial_port *port, struct file *filp)
 {
        int                     i;
        struct usb_serial       *serial = port->serial; /* FIXME should so sanity check */
        struct keyspan_serial_private   *s_priv;
+       struct keyspan_port_private     *p_priv;
+       unsigned long flags;
 
+       /*  dbg("keyspan_close called"); */
        s_priv = (struct keyspan_serial_private *)(serial->private);
-       
-               /* Stop reading/writing urbs */
-       for (i = 0; i < 4; i++) {
-               if (s_priv->in_urbs[i]) {
-                       usb_unlink_urb(s_priv->in_urbs[i]);
-               }
+       p_priv = (struct keyspan_port_private *)(port->private);
 
-       }
-       for (i = 0; i < 3; i++) {
-               if (s_priv->out_urbs[i]) {
-                       usb_unlink_urb(s_priv->out_urbs[i]);
-               }
+       spin_lock_irqsave (&port->port_lock, flags);
 
+       if (--port->open_count <= 0) {
+               if (port->active) {
+                       /* Stop reading/writing urbs */
+                       stop_urb(p_priv->inack_urb);
+                       stop_urb(p_priv->outcont_urb);
+                       for (i = 0; i < 2; i++) {
+                               stop_urb(p_priv->in_urbs[i]);
+                               stop_urb(p_priv->out_urbs[i]);
+                       }
+                       /* Now done in shutdown 
+                       if (atomic_dec_return(&s_priv->active_count) <= 0) {
+                               stop_urb(s_priv->instat_urb);
+                               stop_urb(s_priv->glocont_urb);
+                       } */
+               }
+               port->active = 0;
+               port->open_count = 0;
+               port->tty = 0;
        }
-       port->active = 0;
-       dbg("keyspan_close called\n");
+       spin_unlock_irqrestore (&port->port_lock, flags);
+
+       MOD_DEC_USE_COUNT;
 }
 
 
@@ -394,47 +923,59 @@ static int keyspan_fake_startup (struct usb_serial *serial)
        const struct ezusb_hex_record   *record;
        char                            *fw_name;
 
-       dbg("Keyspan startup version %04x product %04x\n", serial->dev->descriptor.bcdDevice,
-                                                       serial->dev->descriptor.idProduct); 
+       dbg("Keyspan startup version %04x product %04x",
+           serial->dev->descriptor.bcdDevice,
+           serial->dev->descriptor.idProduct); 
        
        if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
-               dbg("Firmware already loaded.  Quitting.\n");
+               dbg("Firmware already loaded.  Quitting.");
                return(1);
        }
 
                /* Select firmware image on the basis of idProduct */
        switch (serial->dev->descriptor.idProduct) {
-               case 0x0101: record = &keyspan_usa28_firmware[0];
-                            fw_name = "USA28";
-                            break;
+       case 0x0101:
+               record = &keyspan_usa28_firmware[0];
+               fw_name = "USA28";
+               break;
+
+       case 0x0102:
+               record = &keyspan_usa28x_firmware[0];
+               fw_name = "USA28X";
+               break;
+
+       case 0x0103:
+               record = &keyspan_usa19_firmware[0];
+               fw_name = "USA19";
+               break;
                             
-               case 0x0102: record = &keyspan_usa28x_firmware[0];
-                            fw_name = "USA28X";
-                            break;
-
-               case 0x0103: record = &keyspan_usa19_firmware[0];
-                            fw_name = "USA19";
-                            break;
-                            
-               case 0x0105: record = &keyspan_usa18x_firmware[0];
-                            fw_name = "USA18X";
-                            break;
+       case 0x0105:
+               record = &keyspan_usa18x_firmware[0];
+               fw_name = "USA18X";
+               break;
                             
-               case 0x0106: record = &keyspan_usa19w_firmware[0];
-                            fw_name = "USA19W";
-                            break;
+       case 0x0106:
+               record = &keyspan_usa19w_firmware[0];
+               fw_name = "USA19W";
+               break;
                
-               default:     record = NULL;
-                            fw_name = "Unknown";
-                            break;
+       case 0x0109:
+               record = &keyspan_usa49w_firmware[0];
+               fw_name = "USA49W";
+               break;
+
+       default:
+               record = NULL;
+               fw_name = "Unknown";
+               break;
        }
 
        if (record == NULL) {
-               err("Required keyspan firmware image (%s) unavailable.\n", fw_name);
+               err("Required keyspan firmware image (%s) unavailable.", fw_name);
                return(1);
        }
 
-       dbg("Uploading Keyspan %s firmware.\n", fw_name);
+       dbg("Uploading Keyspan %s firmware.", fw_name);
 
                /* download the firmware image */
        response = ezusb_set_reset(serial, 1);
@@ -456,72 +997,165 @@ static int keyspan_fake_startup (struct usb_serial *serial)
                   moment and the new device will bind to the real driver */
        response = ezusb_set_reset(serial, 0);
 
-               /* we don't want this device to have a driver assigned to it. */
+       /* we don't want this device to have a driver assigned to it. */
        return (1);
 }
 
-       /* USA-19 uses three output endpoints and four input
-          endpoints.  First two output endpoints are for
-          data (used in an alternating fashion), the third is
-          output control.  First two input endpoints are for
-          data (again alternating), the third is the ACK
-          endpoint, the fourth is input status. */
-static void keyspan_usa19_setup_urbs(struct usb_serial *serial)
+/* Helper functions used by keyspan_setup_urbs */
+static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+                               int dir, void *ctx, char *buf, int len,
+                               void (*callback)(urb_t *))
 {
-       struct keyspan_serial_private   *s_priv;
-       int                     i;
+       urb_t *urb;
 
-       s_priv = (struct keyspan_serial_private *)(serial->private);
+       if (endpoint == -1)
+               return NULL;            /* endpoint not needed */
+
+       /*  dbg (__FUNCTION__ " alloc for endpoint %d.", endpoint); */
+       urb = usb_alloc_urb(0);         /* No ISO */
+       if (urb == NULL) {
+               dbg (__FUNCTION__ " alloc for endpoint %d failed.", endpoint);
+               return NULL;
+       }
 
-               /* Output urbs first */
-       dbg(__FUNCTION__ "Allocating output urbs.\n");
-       for (i = 0; i < 3; i++) {
+               /* Fill URB using supplied data. */
+       FILL_BULK_URB(urb, serial->dev,
+                     usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                     buf, len, callback, ctx);
 
-               s_priv->out_urbs[i] = usb_alloc_urb (0);        /* No ISO */
-               if (!s_priv->out_urbs[i]) {
-                       dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i);
-                       return;
-               }
+       return urb;
+}
 
-               FILL_BULK_URB(s_priv->out_urbs[i], serial->dev, 
-                             usb_sndbulkpipe(serial->dev, i + 1),
-                             &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]),
-                             keyspan_write_bulk_callback, 
-                             serial);
+struct callbacks {
+       void    (*instat_callback)(urb_t *);
+       void    (*glocont_callback)(urb_t *);
+       void    (*indat_callback)(urb_t *);
+       void    (*outdat_callback)(urb_t *);
+       void    (*inack_callback)(urb_t *);
+       void    (*outcont_callback)(urb_t *);
+} keyspan_callbacks[] = {
+       {
+               /* msg_usa26 callbacks */
+               instat_callback: usa26_instat_callback,
+               glocont_callback: usa26_glocont_callback,
+               indat_callback: usa26_indat_callback,
+               outdat_callback: usa2x_outdat_callback,
+               inack_callback: usa26_inack_callback,
+               outcont_callback: usa26_outcont_callback,
+       }, {
+               /* msg_usa28 callbacks */
+               instat_callback: usa28_instat_callback,
+               glocont_callback: usa28_glocont_callback,
+               indat_callback: usa28_indat_callback,
+               outdat_callback: usa2x_outdat_callback,
+               inack_callback: usa28_inack_callback,
+               outcont_callback: usa28_outcont_callback,
+       }, {
+               /* msg_usa49 callbacks */
+               instat_callback: usa49_instat_callback,
+               glocont_callback: usa49_glocont_callback,
+               indat_callback: usa49_indat_callback,
+               outdat_callback: usa2x_outdat_callback,
+               inack_callback: usa49_inack_callback,
+               outcont_callback: usa49_outcont_callback,
        }
+};
+
+       /* Generic setup urbs function that uses
+          data in device_details */
+static void keyspan_setup_urbs(struct usb_serial *serial)
+{
+       int                             i, j;
+       struct keyspan_serial_private   *s_priv;
+       const keyspan_device_details    *d_details;
+       struct usb_serial_port          *port;
+       struct keyspan_port_private     *p_priv;
+       struct callbacks                *cback;
+       int                             endp;
 
-               /* Now input urbs */
-       dbg(__FUNCTION__ "Allocating input urbs.\n");
-       for (i = 0; i < 4; i++) {
+       /*  dbg (__FUNCTION__); */
 
-               s_priv->in_urbs[i] = usb_alloc_urb (0); /* No ISO */
-               if (!s_priv->in_urbs[i]) {
-                       dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i);
-                       return;
+       s_priv = (struct keyspan_serial_private *)(serial->private);
+       d_details = s_priv->device_details;
+
+               /* Setup values for the various callback routines */
+       cback = &keyspan_callbacks[d_details->msg_format];
+
+               /* Allocate and set up urbs for each one that is in use, 
+                  starting with instat endpoints */
+       s_priv->instat_urb = keyspan_setup_urb
+               (serial, d_details->instat_endpoint, USB_DIR_IN,
+                serial, s_priv->instat_buf, INSTAT_BUFLEN,
+                cback->instat_callback);
+
+       s_priv->glocont_urb = keyspan_setup_urb
+               (serial, d_details->glocont_endpoint, USB_DIR_OUT,
+                serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
+                cback->glocont_callback);
+
+               /* Setup endpoints for each port specific thing */
+       for (i = 0; i < d_details->num_ports; i ++) {
+               port = &serial->port[i];
+               p_priv = (struct keyspan_port_private *)(port->private);
+
+               /* Do indat endpoints first, once for each flip */
+               endp = d_details->indat_endpoints[i];
+               for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
+                       p_priv->in_urbs[j] = keyspan_setup_urb
+                               (serial, endp, USB_DIR_IN, port,
+                                p_priv->in_buffer[j], 64,
+                                cback->indat_callback);
                }
+               for (; j < 2; ++j)
+                       p_priv->in_urbs[j] = NULL;
+
+               /* outdat endpoints also have flip */
+               endp = d_details->outdat_endpoints[i];
+               for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
+                       p_priv->out_urbs[j] = keyspan_setup_urb
+                               (serial, endp, USB_DIR_OUT, port,
+                                p_priv->out_buffer[j], 64,
+                                cback->outdat_callback);
+               }
+               for (; j < 2; ++j)
+                       p_priv->out_urbs[j] = NULL;
+
+               /* inack endpoint */
+               p_priv->inack_urb = keyspan_setup_urb
+                       (serial, d_details->inack_endpoints[i], USB_DIR_IN,
+                        port, p_priv->inack_buffer, 1, cback->inack_callback);
+
+               /* outcont endpoint */
+               p_priv->outcont_urb = keyspan_setup_urb
+                       (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
+                        port, p_priv->outcont_buffer, 64,
+                        cback->outcont_callback);
+       }       
 
-               FILL_BULK_URB(s_priv->in_urbs[i], serial->dev, 
-                             usb_rcvbulkpipe(serial->dev, i + 0x81),
-                             &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]),
-                             keyspan_read_bulk_callback, 
-                             serial);
-       }
-       
 }
 
-static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low)
+/* usa19 function doesn't require prescaler */
+static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk,
+                                  u8 *rate_hi, u8 *rate_low, u8 *prescaler)
 {
-       u32 b16,        /* baud rate times 16 (actual rate used internally) */
+       u32     b16,    /* baud rate times 16 (actual rate used internally) */
                div,    /* divisor */   
                cnt;    /* inverse of divisor (programmed into 8051) */
+               
 
                /* prevent divide by zero...  */
        if( (b16 = (baud_rate * 16L)) == 0) {
                return (KEYSPAN_INVALID_BAUD_RATE);
        }
 
+               /* Any "standard" rate over 57k6 is marginal on the USA-19
+                  as we run out of divisor resolution. */
+       if (baud_rate > 57600) {
+               return (KEYSPAN_INVALID_BAUD_RATE);
+       }
+
                /* calculate the divisor and the counter (its inverse) */
-       if( (div = (USA19_BAUDCLK / b16)) == 0) {
+       if( (div = (baudclk / b16)) == 0) {
                return (KEYSPAN_INVALID_BAUD_RATE);
        }
        else {
@@ -532,217 +1166,520 @@ static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low)
                return (KEYSPAN_INVALID_BAUD_RATE);
        }
 
-               /* return the counter values */
-       *rate_low = (u8) (cnt & 0xff);
-       *rate_hi = (u8) ((cnt >> 8) & 0xff);
+               /* return the counter values if non-null */
+       if (rate_low) {
+               *rate_low = (u8) (cnt & 0xff);
+       }
+       if (rate_hi) {
+               *rate_hi = (u8) ((cnt >> 8) & 0xff);
+       }
+       if (rate_low && rate_hi) {
+               dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low);
+       }
        
-       dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low);
+       return (KEYSPAN_BAUD_RATE_OK);
+}
+
+static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk,
+                                   u8 *rate_hi, u8 *rate_low, u8 *prescaler)
+{
+       u32     b16,    /* baud rate times 16 (actual rate used internally) */
+               clk,    /* clock with 13/8 prescaler */
+               div,    /* divisor using 13/8 prescaler */      
+               res,    /* resulting baud rate using 13/8 prescaler */
+               diff,   /* error using 13/8 prescaler */
+               smallest_diff;
+       u8      best_prescaler;
+       int     i;
+
+       /*  dbg (__FUNCTION__ " %d.", baud_rate); */
+
+               /* prevent divide by zero */
+       if( (b16 = baud_rate * 16L) == 0) {
+               return (KEYSPAN_INVALID_BAUD_RATE);
+       }
+
+               /* Calculate prescaler by trying them all and looking
+                  for best fit */
+               
+               /* start with largest possible difference */
+       smallest_diff = 0xffffffff;
+
+               /* 0 is an invalid prescaler, used as a flag */
+       best_prescaler = 0;
+
+       for(i = 8; i <= 0xff; ++i)
+       {
+               clk = (baudclk * 8) / (u32) i;
+               
+               if( (div = clk / b16) == 0) {
+                       continue;
+               }
+
+               res = clk / div;
+               diff= (res > b16) ? (res-b16) : (b16-res);
+
+               if(diff < smallest_diff)
+               {
+                       best_prescaler = i;
+                       smallest_diff = diff;
+               }
+       }
+
+       if(best_prescaler == 0) {
+               return (KEYSPAN_INVALID_BAUD_RATE);
+       }
+
+       clk = (baudclk * 8) / (u32) best_prescaler;
+       div = clk / b16;
 
+               /* return the divisor and prescaler if non-null */
+       if (rate_low) {
+               *rate_low = (u8) (div & 0xff);
+       }
+       if (rate_hi) {
+               *rate_hi = (u8) ((div >> 8) & 0xff);
+       }
+       if (prescaler) {
+               *prescaler = best_prescaler;
+               /*  dbg(__FUNCTION__ " %d %d", *prescaler, div); */
+       }
        return (KEYSPAN_BAUD_RATE_OK);
 }
 
-static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port)
+static int keyspan_usa26_send_setup(struct usb_serial *serial,
+                                   struct usb_serial_port *port)
 {
-       struct portControlMessage       msg;            
-       struct keyspan_serial_private   *s_priv;
-       struct keyspan_port_private     *p_priv;
+       struct keyspan_usa26_portControlMessage msg;            
+       struct keyspan_serial_private           *s_priv;
+       struct keyspan_port_private             *p_priv;
+       const  keyspan_device_details           *d_details;
+       int                                     outcont_urb;
+       urb_t *this_urb;
+       int err;
+
+       /*  dbg (__FUNCTION__); */
 
        s_priv = (struct keyspan_serial_private *)(serial->private);
        p_priv = (struct keyspan_port_private *)(port->private);
+       d_details = s_priv->device_details;
+
+       outcont_urb = d_details->outcont_endpoints[port->number];
+       this_urb = p_priv->outcont_urb;
+
+               /* Make sure we have an urb then send the message */
+       if (this_urb == NULL) {
+               dbg(__FUNCTION__ " oops no urb.");
+               return -1;
+       }
+
+       p_priv->resend_cont = 1;
+       if (this_urb->status == -EINPROGRESS) {
+               /*  dbg (__FUNCTION__ " already writing"); */
+               return(-1);
+       }
+
+       memset(&msg, 0, sizeof (struct keyspan_usa26_portControlMessage));
+       
+               /* Only set baud rate if it's changed */        
+       if (p_priv->old_baud != p_priv->baud) {
+               p_priv->old_baud = p_priv->baud;
+               msg.setClocking = 0xff;
+               if (d_details->calculate_baud_rate
+                   (p_priv->baud, d_details->baudclk, &msg.baudHi,
+                    &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+                       dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+                           p_priv->baud);
+                       msg.baudLo = 0;
+                       msg.baudHi = 125;       /* Values for 9600 baud */
+                       msg.prescaler = 10;
+               }
+               msg.setPrescaler = 0xff;
+       }
+
+       msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+       if (p_priv->cflag & PARENB) {
+               /* note USA_PARITY_NONE == 0 */
+               msg.lcr |= (p_priv->cflag & PARODD)?
+                       USA_PARITY_ODD: USA_PARITY_EVEN;
+       }
+       msg.setLcr = 0xff;
+
+       msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+       msg.xonFlowControl = 0;
+       msg.setFlowControl = 0xff;
+       
+       msg.forwardingLength = 1;
+       msg.xonChar = 17;
+       msg.xoffChar = 19;
+       
+       msg._txOn = 1;
+       msg._txOff = 0;
+       msg.txFlush = 0;
+       msg.txBreak = 0;
+       msg.rxOn = 1;
+       msg.rxOff = 0;
+       msg.rxFlush = 0;
+       msg.rxForward = 0;
+       /*msg.returnStatus = 1;
+       msg.resetDataToggle = 0xff;*/
 
-       //memset(msg, 0, sizeof (struct portControlMessage));
+               /* Do handshaking outputs */    
+       msg.setTxTriState_setRts = 0xff;
+       msg.txTriState_rts = p_priv->rts_state;
+
+       msg.setHskoa_setDtr = 0xff;
+       msg.hskoa_dtr = p_priv->dtr_state;
                
+       p_priv->resend_cont = 0;
+       memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+       
+       /* send the data out the device on control endpoint */
+       this_urb->transfer_buffer_length = sizeof(msg);
+
+       this_urb->dev = serial->dev;
+       if ((err = usb_submit_urb(this_urb)) != 0) {
+               dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
+       }
+#if 0
+       else {
+               dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+                   outcont_urb, this_urb->transfer_buffer_length,
+                   usb_pipeendpoint(this_urb->pipe));
+       }
+#endif
+
+       return (0);
+}
+
+static int keyspan_usa28_send_setup(struct usb_serial *serial,
+                                   struct usb_serial_port *port)
+{
+       struct keyspan_usa28_portControlMessage msg;            
+       struct keyspan_serial_private           *s_priv;
+       struct keyspan_port_private             *p_priv;
+       const  keyspan_device_details           *d_details;
+       urb_t *this_urb;
+       int err;
+
+       s_priv = (struct keyspan_serial_private *)(serial->private);
+       p_priv = (struct keyspan_port_private *)(port->private);
+       d_details = s_priv->device_details;
+
+       /* only do something if we have a bulk out endpoint */
+       if ((this_urb = p_priv->outcont_urb) == NULL) {
+               dbg(__FUNCTION__ " oops no urb.");
+               return -1;
+       }
+
+       p_priv->resend_cont = 1;
+       if (this_urb->status == -EINPROGRESS) {
+               dbg (__FUNCTION__ " already writing");
+               return(-1);
+       }
+
+       memset(&msg, 0, sizeof (struct keyspan_usa28_portControlMessage));
+
        msg.setBaudRate = 1;
-       if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) ==
-               KEYSPAN_INVALID_BAUD_RATE ) {
-               dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600);
+       if (keyspan_usa19_calc_baud(p_priv->baud, d_details->baudclk,
+               &msg.baudHi, &msg.baudLo, NULL) == KEYSPAN_INVALID_BAUD_RATE ) {
+               dbg(__FUNCTION__ "Invalid baud rate requested %d.", 9600);
                msg.baudLo = 0xff;
                msg.baudHi = 0xb2;      /* Values for 9600 baud */
        }
 
-               /* If parity is enabled, we must calculate it ourselves. */
-       if (p_priv->parity) {
-               msg.parity = 1;
+       /* If parity is enabled, we must calculate it ourselves. */
+       msg.parity = 0;         /* XXX for now */
+
+       msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+       msg.xonFlowControl = 0;
+
+       /* Do handshaking outputs, DTR is inverted relative to RTS */   
+       msg.rts = p_priv->rts_state;
+       msg.dtr = p_priv->dtr_state;
+
+       msg.forwardingLength = 1;
+       msg.forwardMs = 10;
+       msg.breakThreshold = 45;
+       msg.xonChar = 17;
+       msg.xoffChar = 19;
+
+       msg._txOn = 1;
+       msg._txOff = 0;
+       msg.txFlush = 0;
+       msg.txForceXoff = 0;
+       msg.txBreak = 0;
+       msg.rxOn = 1;
+       msg.rxOff = 0;
+       msg.rxFlush = 0;
+       msg.rxForward = 0;
+       /*msg.returnStatus = 1;
+       msg.resetDataToggle = 0xff;*/
+
+       p_priv->resend_cont = 0;
+       memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+       /* send the data out the device on control endpoint */
+       this_urb->transfer_buffer_length = sizeof(msg);
+
+       this_urb->dev = serial->dev;
+       if ((err = usb_submit_urb(this_urb)) != 0) {
+               dbg(__FUNCTION__ " usb_submit_urb(setup) failed");
        }
+#if 0
        else {
-               msg.parity = 0;
+               dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes",
+                   this_urb->transfer_buffer_length);
+       }
+#endif
+
+       return (0);
+}
+
+static int keyspan_usa49_send_setup(struct usb_serial *serial,
+                                   struct usb_serial_port *port)
+{
+       struct keyspan_usa49_portControlMessage msg;            
+       struct keyspan_serial_private           *s_priv;
+       struct keyspan_port_private             *p_priv;
+       const  keyspan_device_details           *d_details;
+       int                                     glocont_urb;
+       urb_t *this_urb;
+       int err;
+
+       /*  dbg (__FUNCTION__); */
+
+       s_priv = (struct keyspan_serial_private *)(serial->private);
+       p_priv = (struct keyspan_port_private *)(port->private);
+       d_details = s_priv->device_details;
+
+       glocont_urb = d_details->glocont_endpoint;
+       this_urb = s_priv->glocont_urb;
+
+       /*  dbg(__FUNCTION__ " port %d\n", port->number); */
+
+               /* Make sure we have an urb then send the message */
+       if (this_urb == NULL) {
+               dbg(__FUNCTION__ " oops no urb for port %d.", port->number);
+               return -1;
+       }
+
+       p_priv->resend_cont = 1;
+       if (this_urb->status == -EINPROGRESS) {
+               /*  dbg (__FUNCTION__ " already writing"); */
+               return(-1);
+       }
+
+       memset(&msg, 0, sizeof (struct keyspan_usa49_portControlMessage));
+
+       msg.portNumber = port->number;
+       
+               /* Only set baud rate if it's changed */        
+       if (p_priv->old_baud != p_priv->baud) {
+               p_priv->old_baud = p_priv->baud;
+               msg.setClocking = 0xff;
+               if (d_details->calculate_baud_rate
+                   (p_priv->baud, d_details->baudclk, &msg.baudHi,
+                    &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+                       dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+                           p_priv->baud);
+                       msg.baudLo = 0;
+                       msg.baudHi = 125;       /* Values for 9600 baud */
+                       msg.prescaler = 10;
+               }
+               //msg.setPrescaler = 0xff;
+       }
+
+       msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+       if (p_priv->cflag & PARENB) {
+               /* note USA_PARITY_NONE == 0 */
+               msg.lcr |= (p_priv->cflag & PARODD)?
+                       USA_PARITY_ODD: USA_PARITY_EVEN;
        }
+       msg.setLcr = 0xff;
 
-       msg.ctsFlowControl = 0;
+       msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
        msg.xonFlowControl = 0;
-       msg.rts = 1;
-       msg.dtr = 0;
+       msg.setFlowControl = 0xff;
        
        msg.forwardingLength = 1;
-       msg.forwardMs = 10;
-       msg.breakThreshold = 45;
        msg.xonChar = 17;
        msg.xoffChar = 19;
        
        msg._txOn = 1;
        msg._txOff = 0;
        msg.txFlush = 0;
-       msg.txForceXoff = 0;
        msg.txBreak = 0;
        msg.rxOn = 1;
        msg.rxOff = 0;
        msg.rxFlush = 0;
        msg.rxForward = 0;
-       msg.returnStatus = 1;
-       msg.resetDataToggle = 1;
+       msg.enablePort = 0xff;
+       msg.disablePort = 0;
 
+               /* Do handshaking outputs */    
+       msg.setRts = 0xff;
+       msg.rts = p_priv->rts_state;
+
+       msg.setDtr = 0xff;
+       msg.dtr = p_priv->dtr_state;
                
-       /* only do something if we have a bulk out endpoint */
-       if (s_priv->out_urbs[2]) {
-               if (s_priv->out_urbs[2]->status == -EINPROGRESS) {
-                       dbg (__FUNCTION__ " already writing");
-                       return(-1);
-               }
-               memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg));
+       p_priv->resend_cont = 0;
+       memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
        
-               /* send the data out the device on control endpoint */
-               s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg);
-               s_priv->out_urbs[2]->dev = serial->dev;
+       /* send the data out the device on control endpoint */
+       this_urb->transfer_buffer_length = sizeof(msg);
 
-               if (usb_submit_urb(s_priv->out_urbs[2])) {
-                       dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
-               }
-               else {
-                       dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length);
-               }
-       
+       this_urb->dev = serial->dev;
+       if ((err = usb_submit_urb(this_urb)) != 0) {
+               dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
        }
+#if 0
+       else {
+               dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+                   outcont_urb, this_urb->transfer_buffer_length,
+                   usb_pipeendpoint(this_urb->pipe));
+       }
+#endif
+
        return (0);
 }
 
+static void keyspan_send_setup(struct usb_serial_port *port)
+{
+       struct usb_serial *serial = port->serial;
+       struct keyspan_serial_private   *s_priv;
+       const keyspan_device_details    *d_details;
+
+       s_priv = (struct keyspan_serial_private *)(serial->private);
+       d_details = s_priv->device_details;
+
+       switch (d_details->msg_format) {
+       case msg_usa26:
+               keyspan_usa26_send_setup(serial, port);
+               break;
+       case msg_usa28:
+               keyspan_usa28_send_setup(serial, port);
+               break;
+       case msg_usa49:
+               keyspan_usa49_send_setup(serial, port);
+               break;
+       }
+}
 
-       /* Gets called by the "real" driver (ie once firmware is loaded
-          and renumeration has taken place. */
+/* Gets called by the "real" driver (ie once firmware is loaded
+   and renumeration has taken place. */
 static int keyspan_startup (struct usb_serial *serial)
 {
-       int                     i;
-       struct usb_serial_port  *port;
+       int                             i, err;
+       struct usb_serial_port          *port;
+       struct keyspan_serial_private   *s_priv;
+       struct keyspan_port_private     *p_priv;
+       const keyspan_device_details    *d_details;
 
-       dbg("keyspan_startup called.\n");
+       /*  dbg("keyspan_startup called."); */
+
+       for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
+               if (d_details->product_id == serial->dev->descriptor.idProduct)
+                       break;
+       if (d_details == NULL) {
+               printk(KERN_ERR __FUNCTION__ ": unknown product id %x\n",
+                      serial->dev->descriptor.idProduct);
+               return 1;
+       }
 
-               /* Setup private data for serial driver */
-       serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+       /* Setup private data for serial driver */
+       serial->private = kmalloc(sizeof(struct keyspan_serial_private),
+                                 GFP_KERNEL);
        if (!serial->private) {
-               dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n");
+               dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed.");
                return (1);
        }
        memset(serial->private, 0, sizeof(struct keyspan_serial_private));
+
+       s_priv = (struct keyspan_serial_private *)(serial->private);
+       s_priv->device_details = d_details;
                
-       init_waitqueue_head(&out_wait);
-       
-               /* Now setup per port private data */
+       /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = &serial->port[i];
-               port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+               port->private = kmalloc(sizeof(struct keyspan_port_private),
+                                       GFP_KERNEL);
                if (!port->private) {
-                       dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i);
+                       dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.", i);
                        return (1);
                }
                memset(port->private, 0, sizeof(struct keyspan_port_private));
+               p_priv = (struct keyspan_port_private *)(port->private);
+               p_priv->device_details = d_details;
        }
 
-       
-
-       switch (serial->dev->descriptor.idProduct) {
-               case 0x0107:    keyspan_usa19_setup_urbs(serial);
-                               //keyspan_send_usa19_setup(serial);
-                               break;
+       keyspan_setup_urbs(serial);
 
-               default:        break;
+       s_priv->instat_urb->dev = serial->dev;
+       if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+               dbg(__FUNCTION__ " submit instat urb failed %d", err);
        }
-
                        
        return (0);
 }
 
 static void keyspan_shutdown (struct usb_serial *serial)
 {
-       int                             i;
+       int                             i, j;
        struct usb_serial_port          *port;
        struct keyspan_serial_private   *s_priv;
+       struct keyspan_port_private     *p_priv;
 
-       dbg("keyspan_shutdown called freeing ");
+       /*  dbg("keyspan_shutdown called"); */
 
        s_priv = (struct keyspan_serial_private *)(serial->private);
 
-               /* Stop reading/writing urbs */
-       for (i = 0; i < 4; i++) {
-               if (s_priv->in_urbs[i]) {
-                       usb_unlink_urb(s_priv->in_urbs[i]);
+       /* Stop reading/writing urbs */
+       stop_urb(s_priv->instat_urb);
+       stop_urb(s_priv->glocont_urb);
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = &serial->port[i];
+               p_priv = (struct keyspan_port_private *)(port->private);
+               stop_urb(p_priv->inack_urb);
+               stop_urb(p_priv->outcont_urb);
+               for (j = 0; j < 2; j++) {
+                       stop_urb(p_priv->in_urbs[j]);
+                       stop_urb(p_priv->out_urbs[j]);
                }
-
        }
-       for (i = 0; i < 3; i++) {
-               if (s_priv->out_urbs[i]) {
-                       usb_unlink_urb(s_priv->out_urbs[i]);
-               }
 
-       }
-               /* Now free them */
-       for (i = 0; i < 7; i ++) {
-               if (s_priv->in_urbs[i] != NULL) {
-                       dbg("in%d ", i);
-                       usb_free_urb(s_priv->in_urbs[i]);
-               }
-               
-               if (s_priv->out_urbs[i] != NULL) {
-                       dbg("out%d ", i);
-                       usb_free_urb(s_priv->out_urbs[i]);
+       /* Now free them */
+       if (s_priv->instat_urb)
+               usb_free_urb(s_priv->instat_urb);
+       if (s_priv->glocont_urb)
+               usb_free_urb(s_priv->glocont_urb);
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = &serial->port[i];
+               p_priv = (struct keyspan_port_private *)(port->private);
+               if (p_priv->inack_urb)
+                       usb_free_urb(p_priv->inack_urb);
+               if (p_priv->outcont_urb)
+                       usb_free_urb(p_priv->outcont_urb);
+               for (j = 0; j < 2; j++) {
+                       if (p_priv->in_urbs[j])
+                               usb_free_urb(p_priv->in_urbs[j]);
+                       if (p_priv->out_urbs[j])
+                               usb_free_urb(p_priv->out_urbs[j]);
                }
        }
-       dbg("urbs.\n");
 
-       dbg("Freeing serial->private.\n");      
+       /*  dbg("Freeing serial->private."); */
        kfree(serial->private);
 
-       dbg("Freeing port->private.\n");        
-               /* Now free per port private data */
+       /*  dbg("Freeing port->private."); */
+       /* Now free per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = &serial->port[i];
+               while (port->open_count > 0) {
+                       --port->open_count;
+                       MOD_DEC_USE_COUNT;
+               }
                kfree(port->private);
        }
-       
-}
-
-
-static int __init keyspan_init (void)
-{
-       usb_serial_register (&keyspan_usa18x_pre_device);
-       usb_serial_register (&keyspan_usa19_pre_device);
-       usb_serial_register (&keyspan_usa19w_pre_device);
-       usb_serial_register (&keyspan_usa28_pre_device);
-       usb_serial_register (&keyspan_usa28x_pre_device);
-       usb_serial_register (&keyspan_usa18x_device);
-       usb_serial_register (&keyspan_usa19_device);
-       usb_serial_register (&keyspan_usa19w_device);
-       usb_serial_register (&keyspan_usa28_device);
-       usb_serial_register (&keyspan_usa28x_device);
-       return 0;
-}
-
-
-static void __exit keyspan_exit (void)
-{
-       usb_serial_deregister (&keyspan_usa18x_pre_device);
-       usb_serial_deregister (&keyspan_usa19_pre_device);
-       usb_serial_deregister (&keyspan_usa19w_pre_device);
-       usb_serial_deregister (&keyspan_usa28_pre_device);
-       usb_serial_deregister (&keyspan_usa28x_pre_device);
-       usb_serial_deregister (&keyspan_usa18x_device);
-       usb_serial_deregister (&keyspan_usa19_device);
-       usb_serial_deregister (&keyspan_usa19w_device);
-       usb_serial_deregister (&keyspan_usa28_device);
-       usb_serial_deregister (&keyspan_usa28x_device);
 }
-
-
-module_init(keyspan_init);
-module_exit(keyspan_exit);
-
-MODULE_AUTHOR("Hugh Blemings <hugh@linuxcare.com>");
-MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver");
index 8d249916c2e0acb99fb53bbce76601c9a2b84270..0d7b4545ae324f24f3e46494c106d9125e7e0ffd 100644 (file)
   and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
   Thanks Guys :)
   
+  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+  of much nicer and/or completely new code and (perhaps most uniquely)
+  having the patience to sit down and explain why and where he'd changed
+  stuff.
+
   Tip 'o the hat to Linuxcare for supporting staff in their work on
   open source projects.
   
@@ -29,7 +34,6 @@
 #ifndef __LINUX_USB_SERIAL_KEYSPAN_H
 #define __LINUX_USB_SERIAL_KEYSPAN_H
 
-#include <linux/config.h>
 
        /* Function prototypes for Keyspan serial converter */
 static int  keyspan_open               (struct usb_serial_port *port,
@@ -41,12 +45,18 @@ static void keyspan_shutdown                (struct usb_serial *serial);
 static void keyspan_rx_throttle                (struct usb_serial_port *port);
 static void keyspan_rx_unthrottle      (struct usb_serial_port *port);
 static int  keyspan_write_room         (struct usb_serial_port *port);
+
 static int  keyspan_write              (struct usb_serial_port *port,
                                         int from_user,
                                         const unsigned char *buf,
                                         int count);
+
+#if 0
 static void keyspan_write_bulk_callback (struct urb *urb);
-static void keyspan_read_bulk_callback  (struct urb *urb);
+#endif
+
+//static void keyspan_usa26_read_int_callback  (struct urb *urb);
+//static void keyspan_usa28_read_int_callback  (struct urb *urb);
 static int  keyspan_chars_in_buffer    (struct usb_serial_port *port);
 static int  keyspan_ioctl              (struct usb_serial_port *port,
                                         struct file *file,
@@ -58,12 +68,20 @@ static void keyspan_break_ctl               (struct usb_serial_port *port,
                                         int break_state);
 static int  keyspan_fake_startup       (struct usb_serial *serial);
 
-static int  keyspan_usa19_calc_baud    (u32 baud_rate, u8 *rate_hi, 
-                                        u8 *rate_low);
-static void keyspan_usa19_setup_urbs   (struct usb_serial *serial);
-static int  keyspan_usa19_send_setup   (struct usb_serial *serial,
-                                        struct usb_serial_port *port);
+static int  keyspan_usa19_calc_baud    (u32 baud_rate, u32 baudclk, 
+                                        u8 *rate_hi, u8 *rate_low, u8 *prescaler);
 
+static int  keyspan_usa19w_calc_baud   (u32 baud_rate, u32 baudclk,
+                                        u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+
+//static void keyspan_usa19_setup_urbs (struct usb_serial *serial);
+
+static int  keyspan_usa28_send_setup   (struct usb_serial *serial,
+                                        struct usb_serial_port *port);
+static int  keyspan_usa26_send_setup   (struct usb_serial *serial,
+                                        struct usb_serial_port *port);
+static int  keyspan_usa49_send_setup   (struct usb_serial *serial,
+                                        struct usb_serial_port *port);
 
        /* Functions from usbserial.c for ezusb firmware handling */
 extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
@@ -109,13 +127,162 @@ struct ezusb_hex_record {
        static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL;
 #endif
 
-
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49W
+        #include "keyspan_usa49w_fw.h"
+#else
+       static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL;
+#endif
+       
        /* Values used for baud rate calculation - device specific */
 #define        KEYSPAN_INVALID_BAUD_RATE               (-1)
 #define        KEYSPAN_BAUD_RATE_OK                    (0)
-#define        USA19_BAUDCLK                           (12000000L)
+#define        KEYSPAN_USA18X_BAUDCLK                  (12000000L)     /* a guess */
+#define        KEYSPAN_USA19_BAUDCLK                   (12000000L)
+#define        KEYSPAN_USA19W_BAUDCLK                  (24000000L)
+#define        KEYSPAN_USA28X_BAUDCLK                  (12000000L)
+#define        KEYSPAN_USA49W_BAUDCLK                  (48000000L)
+
+       /* Some constants used to characterise each device. 
+          There is a four port device due later in the year,
+          we allow for it now in the following */
+#define                KEYSPAN_MAX_NUM_PORTS           (4)
+#define                KEYSPAN_MAX_FLIPS               (2)
+       
+typedef struct {
+       /* product ID value */
+       int     product_id;
+       
+       enum    {msg_usa26, msg_usa28, msg_usa49} msg_format;
+
+               /* Number of physical ports */
+       int     num_ports;
+
+               /* 1 if endpoint flipping used on input, 0 if not */
+       int     indat_endp_flip;
+
+               /* 1 if endpoint flipping used on output, 0 if not */
+       int     outdat_endp_flip;
+
+               /* Table mapping input data endpoint IDs to physical
+                  port number and flip if used */
+       int     indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+               /* Same for output endpoints */
+       int     outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+               /* Input acknowledge endpoints */
+       int     inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+               /* Output control endpoints */  
+       int     outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+               /* Endpoint used for input status */
+       int     instat_endpoint;
+
+               /* Endpoint used for global control functions */
+       int     glocont_endpoint;       
+       
+       int     (*calculate_baud_rate) (u32 baud_rate, u32 baudclk,
+                       u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+       u32     baudclk;
+
+} keyspan_device_details; 
+
+       /* Now for each device type we setup the device detail
+          structure with the appropriate information (provided
+          in Keyspan's documentation) */
+
+static const keyspan_device_details usa18x_device_details = {
+       0x112,                          /* product ID */
+               msg_usa26,                      /* msg type*/
+       1,                              /* num ports */
+       0,                              /* indat endpoint flip */
+       1,                              /* outdat endpoint flip */
+       {0x81},                         /* per port indat */
+       {0x01},                         /* per port outdat */
+       {0x85},                         /* per port inack */
+       {0x05},                         /* per port outcont */
+       0x87,                           /* instat endpoint */
+       0x07,                           /* glocont endpoint */
+       keyspan_usa19w_calc_baud,       /* calc baud rate */
+       KEYSPAN_USA18X_BAUDCLK          /* base baud clock */
+};
+
+static const keyspan_device_details usa19_device_details = {
+       0x107,                          /* product ID */
+               msg_usa28,                      /* msg type*/
+       1,                              /* num ports */
+       1,                              /* indat endpoint flip */
+       1,                              /* outdat endpoint flip */
+       {0x81},                         /* per port indat */
+       {0x01},                         /* per port outdat */
+       {0x83},                         /* per port inack */
+       {0x03},                         /* per port outcont */
+       0x84,                           /* instat endpoint */
+       -1,                             /* glocont endpoint */
+       keyspan_usa19_calc_baud,        /* calc baud rate */
+       KEYSPAN_USA19_BAUDCLK           /* base baud clock */
+};
+
+static const keyspan_device_details usa19w_device_details = {
+       0x108,                          /* product ID */
+               msg_usa26,                      /* msg type*/
+       1,                              /* num ports */
+       0,                              /* indat endpoint flip */
+       1,                              /* outdat endpoint flip */
+       {0x81},                         /* per port indat */
+       {0x01},                         /* per port outdat */
+       {0x85},                         /* per port inack */
+       {0x05},                         /* per port outcont */
+       0x87,                           /* instat endpoint */
+       0x07,                           /* glocont endpoint */
+       keyspan_usa19w_calc_baud,       /* calc baud rate */
+       KEYSPAN_USA19W_BAUDCLK          /* base baud clock */
+};
+
+static const keyspan_device_details usa28x_device_details = {
+       0x110,                          /* product ID */
+               msg_usa26,                      /* msg type*/
+       2,                              /* num ports */
+       0,                              /* indat endpoint flip */
+       1,                              /* outdat endpoint flip */
+       {0x81, 0x83},                   /* per port indat */
+       {0x01, 0x03},                   /* per port outdat */
+       {0x85, 0x86},                   /* per port inack */
+       {0x05, 0x06},                   /* per port outcont */
+       0x87,                           /* instat endpoint */
+       0x07,                           /* glocont endpoint */
+       keyspan_usa19w_calc_baud,       /* calc baud rate */
+       KEYSPAN_USA28X_BAUDCLK
+};
+
+static const keyspan_device_details usa49w_device_details = {
+       0x010a,                         /* product ID */
+               msg_usa49,                      /* msg type*/
+       4,                              /* num ports */
+       0,                              /* indat endpoint flip */
+       0,                              /* outdat endpoint flip */
+       { 0x81, 0x82, 0x83, 0x84},      /* per port indat */
+       { 0x01, 0x02, 0x03, 0x04},      /* per port outdat */
+       {-1, -1, -1, -1},               /* per port inack */
+       {-1, -1, -1, -1},               /* per port outcont */
+       0x87,                           /* instat endpoint */
+       0x07,                           /* glocont endpoint */
+       keyspan_usa19w_calc_baud,       /* calc baud rate */
+       KEYSPAN_USA49W_BAUDCLK
+};
 
-       /* Device info for the Keyspan serial converter */
+static const keyspan_device_details *keyspan_devices[] = {
+       &usa18x_device_details,
+       &usa19_device_details,
+       &usa19w_device_details,
+       &usa28x_device_details,
+       &usa49w_device_details,
+       NULL
+};
+
+       /* Device info for the Keyspan serial converter, used
+          by the overall usb-serial probe function */
 #define KEYSPAN_VENDOR_ID                      (0x06cd)
 
     /* Product IDs for the five products supported, pre-renumeration */
@@ -124,6 +291,7 @@ struct ezusb_hex_record {
 #define        keyspan_usa19w_pre_product_id   0x0106
 #define        keyspan_usa28_pre_product_id    0x0101
 #define        keyspan_usa28x_pre_product_id   0x0102
+#define        keyspan_usa49w_pre_product_id   0x0109
 
     /* Product IDs post-renumeration */
 #define        keyspan_usa18x_product_id       0x0112
@@ -131,6 +299,7 @@ struct ezusb_hex_record {
 #define        keyspan_usa19w_product_id       0x0108
 #define        keyspan_usa28_product_id        0x010f
 #define        keyspan_usa28x_product_id       0x0110
+#define        keyspan_usa49w_product_id       0x010a
 
 static __devinitdata struct usb_device_id keyspan_ids_combined[] = {
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id},
@@ -138,11 +307,13 @@ static __devinitdata struct usb_device_id keyspan_ids_combined[] = {
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id},
+    {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_pre_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id},
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id},
+    {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_product_id},
     { } /* Terminating entry */
 };
 
@@ -177,6 +348,11 @@ static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
     { } /* Terminating entry */
 };
 
+static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
+    {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_pre_product_id},
+    { } /* Terminating entry */
+};
+
 static __devinitdata struct usb_device_id keyspan_usa18x_ids[] = {
     {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
     { } /* Terminating entry */
@@ -202,10 +378,15 @@ static __devinitdata struct usb_device_id keyspan_usa28x_ids[] = {
     { } /* Terminating entry */
 };
 
+static __devinitdata struct usb_device_id keyspan_usa49w_ids[] = {
+    {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_product_id},
+    { } /* Terminating entry */
+};
+
     /* Structs for the devices, pre and post renumeration.
        These are incomplete at present - HAB 20000708  */
 struct usb_serial_device_type keyspan_usa18x_pre_device = {
-       name:                   "Keyspan USA18X - (prerenumeration)",
+       name:                   "Keyspan USA18X - (without firmware)",
        id_table:               keyspan_usa18x_pre_ids,
        needs_interrupt_in:     DONT_CARE,
        needs_bulk_in:          DONT_CARE,
@@ -218,7 +399,7 @@ struct usb_serial_device_type keyspan_usa18x_pre_device = {
 };
 
 struct usb_serial_device_type keyspan_usa19_pre_device = {
-       name:                   "Keyspan USA19 - (prerenumeration)",
+       name:                   "Keyspan USA19 - (without firmware)",
        id_table:               keyspan_usa19_pre_ids,
        needs_interrupt_in:     DONT_CARE,
        needs_bulk_in:          DONT_CARE,
@@ -232,7 +413,7 @@ struct usb_serial_device_type keyspan_usa19_pre_device = {
 
 
 struct usb_serial_device_type keyspan_usa19w_pre_device = {
-       name:                   "Keyspan USA19W - (prerenumeration)",
+       name:                   "Keyspan USA19W - (without firmware)",
        id_table:               keyspan_usa19w_pre_ids,
        needs_interrupt_in:     DONT_CARE,
        needs_bulk_in:          DONT_CARE,
@@ -246,7 +427,7 @@ struct usb_serial_device_type keyspan_usa19w_pre_device = {
 
 
 struct usb_serial_device_type keyspan_usa28_pre_device = {
-       name:                   "Keyspan USA28 - (prerenumeration)",
+       name:                   "Keyspan USA28 - (without firmware)",
        id_table:               keyspan_usa28_pre_ids,
        needs_interrupt_in:     DONT_CARE,
        needs_bulk_in:          DONT_CARE,
@@ -259,7 +440,7 @@ struct usb_serial_device_type keyspan_usa28_pre_device = {
 };
 
 struct usb_serial_device_type keyspan_usa28x_pre_device = {
-       name:                   "Keyspan USA28X - (prerenumeration)",
+       name:                   "Keyspan USA28X - (without firmware)",
        id_table:               keyspan_usa28x_pre_ids,
        needs_interrupt_in:     DONT_CARE,
        needs_bulk_in:          DONT_CARE,
@@ -271,22 +452,43 @@ struct usb_serial_device_type keyspan_usa28x_pre_device = {
        startup:                keyspan_fake_startup    
 };
 
+struct usb_serial_device_type keyspan_usa49w_pre_device = {
+       name:                   "Keyspan USA49W - (without firmware)",
+       id_table:               keyspan_usa49w_pre_ids,
+       needs_interrupt_in:     DONT_CARE,
+       needs_bulk_in:          DONT_CARE,
+       needs_bulk_out:         DONT_CARE,
+       num_interrupt_in:       NUM_DONT_CARE,
+       num_bulk_in:            NUM_DONT_CARE,
+       num_bulk_out:           NUM_DONT_CARE,
+       num_ports:              4,
+       startup:                keyspan_fake_startup    
+};
 
 struct usb_serial_device_type keyspan_usa18x_device = {
        name:                   "Keyspan USA18X",
        id_table:               keyspan_usa18x_ids,
        needs_interrupt_in:     DONT_CARE,      
-       needs_bulk_in:          DONT_CARE,
-       needs_bulk_out:         DONT_CARE,
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
        num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
+       num_bulk_in:            3,
+       num_bulk_out:           4,
        num_ports:              1,
        open:                   keyspan_open,
        close:                  keyspan_close,
+       write:                  keyspan_write,
+       write_room:             keyspan_write_room,
+       //write_bulk_callback:  Not used - we define our own herbs
+       //read_int_callback:    keyspan_usa26_read_int_callback,
+       chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
+       ioctl:                  keyspan_ioctl,
        set_termios:            keyspan_set_termios,
+       break_ctl:              keyspan_break_ctl,
+       startup:                keyspan_startup,
+       shutdown:               keyspan_shutdown,
 };
 
 struct usb_serial_device_type keyspan_usa19_device = {
@@ -303,8 +505,8 @@ struct usb_serial_device_type keyspan_usa19_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-       write_bulk_callback:    keyspan_write_bulk_callback,
-       read_int_callback:      keyspan_read_bulk_callback,
+//     write_bulk_callback:    keyspan_write_bulk_callback,
+//     read_int_callback:      keyspan_usa28_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -320,17 +522,26 @@ struct usb_serial_device_type keyspan_usa19w_device = {
        name:                   "Keyspan USA19W",
        id_table:               keyspan_usa19w_ids,
        needs_interrupt_in:     DONT_CARE,      
-       needs_bulk_in:          DONT_CARE,
-       needs_bulk_out:         DONT_CARE,
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
        num_interrupt_in:       NUM_DONT_CARE,
-       num_bulk_in:            NUM_DONT_CARE,
-       num_bulk_out:           NUM_DONT_CARE,
+       num_bulk_in:            3,
+       num_bulk_out:           4,
        num_ports:              1,
        open:                   keyspan_open,
        close:                  keyspan_close,
+       write:                  keyspan_write,
+       write_room:             keyspan_write_room,
+       //write_bulk_callback:  Not used - we define our own herbs
+       //read_int_callback:    keyspan_usa26_read_int_callback,
+       chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
+       ioctl:                  keyspan_ioctl,
        set_termios:            keyspan_set_termios,
+       break_ctl:              keyspan_break_ctl,
+       startup:                keyspan_startup,
+       shutdown:               keyspan_shutdown,
 };
 
 
@@ -366,8 +577,8 @@ struct usb_serial_device_type keyspan_usa28x_device = {
        close:                  keyspan_close,
        write:                  keyspan_write,
        write_room:             keyspan_write_room,
-       write_bulk_callback:    keyspan_write_bulk_callback,
-       read_int_callback:      keyspan_read_bulk_callback,
+//     write_bulk_callback:    keyspan_write_bulk_callback,
+//     read_int_callback:      keyspan_usa26_read_int_callback,
        chars_in_buffer:        keyspan_chars_in_buffer,
        throttle:               keyspan_rx_throttle,
        unthrottle:             keyspan_rx_unthrottle,
@@ -377,10 +588,34 @@ struct usb_serial_device_type keyspan_usa28x_device = {
        startup:                keyspan_startup,
        shutdown:               keyspan_shutdown,
 
+};
                                
 
+struct usb_serial_device_type keyspan_usa49w_device = {
+       name:                   "Keyspan USA49W",
+       id_table:               keyspan_usa49w_ids,
+       needs_interrupt_in:     DONT_CARE,      
+       needs_bulk_in:          MUST_HAVE,
+       needs_bulk_out:         MUST_HAVE,
+       num_interrupt_in:       NUM_DONT_CARE,
+       num_bulk_in:            5,
+       num_bulk_out:           5,
+       num_ports:              4,
+       open:                   keyspan_open,
+       close:                  keyspan_close,
+       write:                  keyspan_write,
+       write_room:             keyspan_write_room,
+       //write_bulk_callback:  Not used - we define our own herbs
+       //read_int_callback:    keyspan_usa26_read_int_callback,
+       chars_in_buffer:        keyspan_chars_in_buffer,
+       throttle:               keyspan_rx_throttle,
+       unthrottle:             keyspan_rx_unthrottle,
+       ioctl:                  keyspan_ioctl,
+       set_termios:            keyspan_set_termios,
+       break_ctl:              keyspan_break_ctl,
+       startup:                keyspan_startup,
+       shutdown:               keyspan_shutdown,
 };
 
 
-
 #endif
index 8f53c96e8158f47b87a21e8c5ab85b6a20edb7f9..403fd47adc29c7baa30ff3600a80b1e3fecf015a 100644 (file)
 #ifndef        __USA26MSG__
 #define        __USA26MSG__
 
-#ifndef __stubs__
-#include "datadefs.h"
-#endif
-
-typedef struct txAckMessage
-{
-       u8      dummy;
-} txAckMessage;
 
-typedef struct portControlMessage
+typedef struct keyspan_usa26_portControlMessage
 {
        /*
                there are three types of "commands" sent in the control message:
@@ -172,7 +164,7 @@ typedef struct portControlMessage
                returnStatus,   // BOTH: return current status (even if it hasn't changed)
                resetDataToggle;// BOTH: reset data toggle state to DATA0
        
-} portControlMessage;
+} keyspan_usa26_portControlMessage;
 
 // defines for bits in lcr
 #define        USA_DATABITS_5          0x00
@@ -190,7 +182,7 @@ typedef struct portControlMessage
 
 // all things called "StatusMessage" are sent on the status endpoint
 
-typedef struct portStatusMessage       // one for each port
+typedef struct keyspan_usa26_portStatusMessage // one for each port
 {
        u8      port,                   // BOTH: 0=first, 1=second, other=see below
                hskia_cts,              // USA26: reports HSKIA pin
@@ -203,7 +195,7 @@ typedef struct portStatusMessage    // one for each port
                _txXoff,                // port is in XOFF state (either host or RX XOFF)
                rxEnabled,              // as configured by rxOn/rxOff 1=on, 0=off
                controlResponse;// 1=a control message has been processed
-} portStatusMessage;
+} keyspan_usa26_portStatusMessage;
 
 // bits in RX data message when STAT byte is included
 #define        RXERROR_OVERRUN 0x02
@@ -211,28 +203,28 @@ typedef struct portStatusMessage  // one for each port
 #define        RXERROR_FRAMING 0x08
 #define        RXERROR_BREAK   0x10
 
-typedef struct globalControlMessage
+typedef struct keyspan_usa26_globalControlMessage
 {
        u8      sendGlobalStatus,       // 2=request for two status responses
                resetStatusToggle,      // 1=reset global status toggle
                resetStatusCount;       // a cycling value
-} globalControlMessage;
+} keyspan_usa26_globalControlMessage;
 
-typedef struct globalStatusMessage
+typedef struct keyspan_usa26_globalStatusMessage
 {
        u8      port,                           // 3
                sendGlobalStatus,       // from request, decremented
                resetStatusCount;       // as in request
-} globalStatusMessage;
+} keyspan_usa26_globalStatusMessage;
 
-typedef struct globalDebugMessage
+typedef struct keyspan_usa26_globalDebugMessage
 {
        u8      port,                           // 2
                a,
                b,
                c,
                d;
-} globalDebugMessage;
+} keyspan_usa26_globalDebugMessage;
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define        MAX_DATA_LEN                    64
index 6378bc5b03f17e607c9dfdb106ab1a85fa491380..ad03c9c44e62dbec26916103ee99c8a718d32a07 100644 (file)
 #ifndef        __USA28MSG__
 #define        __USA28MSG__
 
-/*#ifndef STUBS
-#include "datadefs.h"
-#endif*/
 
-typedef struct txAckMessage
-{
-       u8      dummy;
-} txAckMessage;
-
-typedef struct portControlMessage
+typedef struct keyspan_usa28_portControlMessage
 {
        /*
                there are four types of "commands" sent in the control message:
@@ -153,9 +145,9 @@ typedef struct portControlMessage
                returnStatus,   // return current status n times (1 or 2)
                resetDataToggle;// reset data toggle state to DATA0
        
-} portControlMessage;
+} keyspan_usa28_portControlMessage;
 
-typedef struct portStatusMessage
+typedef struct keyspan_usa28_portStatusMessage
 {
        u8      port,                   // 0=first, 1=second, 2=global (see below)
                cts,
@@ -171,32 +163,32 @@ typedef struct portStatusMessage
                rxBreak,                // 1=we're in break state
                rs232invalid,   // 1=no valid signals on rs-232 inputs
                controlResponse;// 1=a control messages has been processed
-} portStatusMessage;
+} keyspan_usa28_portStatusMessage;
 
 // bit defines in txState
 #define        TX_OFF                  0x01    // requested by host txOff command
 #define        TX_XOFF                 0x02    // either real, or simulated by host
 
-typedef struct globalControlMessage
+typedef struct keyspan_usa28_globalControlMessage
 {
        u8      sendGlobalStatus,       // 2=request for two status responses
                resetStatusToggle,      // 1=reset global status toggle
                resetStatusCount;       // a cycling value
-} globalControlMessage;
+} keyspan_usa28_globalControlMessage;
 
-typedef struct globalStatusMessage
+typedef struct keyspan_usa28_globalStatusMessage
 {
        u8      port,                           // 3
                sendGlobalStatus,       // from request, decremented
                resetStatusCount;       // as in request
-} globalStatusMessage;
+} keyspan_usa28_globalStatusMessage;
 
-typedef struct globalDebugMessage
+typedef struct keyspan_usa28_globalDebugMessage
 {
        u8      port,                           // 2
                n,                                      // typically a count/status byte
                b;                                      // typically a data byte
-} globalDebugMessage;
+} keyspan_usa28_globalDebugMessage;
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define        MAX_DATA_LEN                    64
diff --git a/drivers/usb/serial/keyspan_usa49msg.h b/drivers/usb/serial/keyspan_usa49msg.h
new file mode 100644 (file)
index 0000000..16ef105
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+       usa49msg.h
+
+       Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+       This file is available under a BSD-style copyright
+
+       Keyspan USB Async Firmware to run on Anchor EZ-USB
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+
+       1. Redistributions of source code must retain this licence text
+       without modification, this list of conditions, and the following
+       disclaimer.  The following copyright notice must appear immediately at
+       the beginning of all source files:
+
+               Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+
+               This file is available under a BSD-style copyright
+
+       2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+
+       3. The name of InnoSys Incorprated may not be used to endorse or promote
+       products derived from this software without specific prior written
+       permission.
+
+       THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR
+       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+       OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+       NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+       INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+       (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+       SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+       CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+       LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+       OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+       SUCH DAMAGE.    
+
+       4th revision: USA49W version
+
+       See usa26msg.h for description of message formats
+
+       Third revision: USA28X version (aka USA26)
+
+       Buffer formats for RX/TX data messages are not defined by
+       a structure, but are described here:
+
+       USB OUT (host -> USA26, transmit) messages contain a 
+       REQUEST_ACK indicator (set to 0xff to request an ACK at the 
+       completion of transmit; 0x00 otherwise), followed by data:
+
+               RQSTACK DAT DAT DAT ...
+
+       with a total data length of 63.
+
+       USB IN (USA26 -> host, receive) messages contain either a zero
+       flag (indicating no error in any data bytes):
+
+               00 DAT DAT DAT ...
+
+       for a total of 63 data bytes, or a non-zero status flag (indicating 
+       that all data bytes will be preceded by status flag):
+
+               STAT DAT STAT DAT STAT DAT ...
+
+       for a total of 32 data bytes.  The valid bits in the STAT bytes are:
+
+               OVERRUN 0x02
+               PARITY  0x04
+               FRAMING 0x08
+               BREAK   0x10
+
+       Notes:
+       
+       1.      a "no status" RX data message (first byte zero) can serve as
+               a "break off" indicator.
+       2.      a control message specifying disablePort will be answered
+               with a status message, but no further status will be sent
+               until a control messages with enablePort is sent
+
+       revision history:
+
+       1999feb10       add reportHskiaChanges to allow us to ignore them
+       1999feb10       add txAckThreshold for fast+loose throughput enhancement
+       1999mar30       beef up support for RX error reporting
+       1999apr14       add resetDataToggle to control message
+       2000jan04       merge with usa17msg.h
+       2000mar08       clone from usa26msg.h -> usa49msg.h
+       2000mar09       change to support 4 ports
+       2000may03       change external clocking to match USA-49W hardware
+       2000jun01       add extended BSD-style copyright text
+*/
+
+#ifndef        __USA49MSG__
+#define        __USA49MSG__
+
+
+/*
+       Host->device messages sent on the global control endpoint:
+
+       portNumber      message
+       ----------      --------------------
+       0,1,2,3         portControlMessage
+       0x80            globalControlMessage
+*/
+
+typedef struct keyspan_usa49_portControlMessage
+{
+       /*
+               0.      0/1/2/3         port control message follows
+                       0x80 set        non-port control message follows
+       */
+       u8      portNumber,
+
+       /*
+               there are three types of "commands" sent in the control message:
+
+               1.      configuration changes which must be requested by setting
+                       the corresponding "set" flag (and should only be requested
+                       when necessary, to reduce overhead on the USA26):
+       */
+               setClocking,    // host requests baud rate be set
+               baudLo,                 // host does baud divisor calculation
+               baudHi,                 // baudHi is only used for first port (gives lower rates)
+               prescaler,              // specified as N/8; values 8-ff are valid
+                                               // must be set any time internal baud rate is set;
+               txClocking,             // 0=internal, 1=external/DSR
+               rxClocking,             // 0=internal, 1=external/DSR
+
+               setLcr,                 // host requests lcr be set
+               lcr,                    // use PARITY, STOPBITS, DATABITS below
+
+               setFlowControl, // host requests flow control be set
+               ctsFlowControl, // 1=use CTS flow control, 0=don't
+               xonFlowControl, // 1=use XON/XOFF flow control, 0=don't
+               xonChar,                // specified in current character format
+               xoffChar,               // specified in current character format
+
+               setRts,                 // host requests RTS output be set
+               rts,                    // 1=active, 0=inactive
+
+               setDtr,                 // host requests DTR output be set
+               dtr;                    // 1=on, 0=off
+
+
+       /*
+               3.      configuration data which is simply used as is (no overhead,
+                       but must be specified correctly in every host message).
+       */
+       u8      forwardingLength,  // forward when this number of chars available
+               dsrFlowControl, // 1=use DSR flow control, 0=don't
+               txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster
+               loopbackMode;   // 0=no loopback, 1=loopback enabled
+
+       /*
+               4.      commands which are flags only; these are processed in order
+                       (so that, e.g., if both _txOn and _txOff flags are set, the
+                       port ends in a TX_OFF state); any non-zero value is respected
+       */
+       u8      _txOn,                  // enable transmitting (and continue if there's data)
+               _txOff,                 // stop transmitting
+               txFlush,                // toss outbound data
+               txBreak,                // turn on break (cleared by _txOn)
+               rxOn,                   // turn on receiver
+               rxOff,                  // turn off receiver
+               rxFlush,                // toss inbound data
+               rxForward,              // forward all inbound data, NOW (as if fwdLen==1)
+               returnStatus,   // return current status (even if it hasn't changed)
+               resetDataToggle,// reset data toggle state to DATA0
+               enablePort,             // start servicing port (move data, check status)
+               disablePort;    // stop servicing port (does implicit tx/rx flush/off)
+       
+} keyspan_usa49_portControlMessage;
+
+// defines for bits in lcr
+#define        USA_DATABITS_5          0x00
+#define        USA_DATABITS_6          0x01
+#define        USA_DATABITS_7          0x02
+#define        USA_DATABITS_8          0x03
+#define        STOPBITS_5678_1         0x00    // 1 stop bit for all byte sizes
+#define        STOPBITS_5_1p5          0x04    // 1.5 stop bits for 5-bit byte
+#define        STOPBITS_678_2          0x04    // 2 stop bits for 6/7/8-bit byte
+#define        USA_PARITY_NONE         0x00
+#define        USA_PARITY_ODD          0x08
+#define        USA_PARITY_EVEN         0x18
+#define        PARITY_1                        0x28
+#define        PARITY_0                        0x38
+
+typedef struct keyspan_usa49_globalControlMessage
+{
+       u8      portNumber,                     // 0x80
+               sendGlobalStatus,       // 1/2=number of status responses requested
+               resetStatusToggle,      // 1=reset global status toggle
+               resetStatusCount,       // a cycling value
+               remoteWakeupEnable;     // 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P3
+} keyspan_usa49_globalControlMessage;
+
+/*
+       Device->host messages send on the global status endpoint
+
+       portNumber                      message
+       ----------                      --------------------
+       0x00,0x01,0x02,0x03     portStatusMessage
+       0x80                            globalStatusMessage
+       0x81                            globalDebugMessage
+*/
+
+typedef struct keyspan_usa49_portStatusMessage // one for each port
+{
+       u8      portNumber,             // 0,1,2,3
+               cts,                    // reports CTS pin
+               dcd,                    // reports DCD pin
+               dsr,                    // reports DSR pin
+               ri,                             // reports RI pin
+               _txOff,                 // transmit has been disabled (by host)
+               _txXoff,                // transmit is in XOFF state (either host or RX XOFF)
+               rxEnabled,              // as configured by rxOn/rxOff 1=on, 0=off
+               controlResponse,// 1=a control message has been processed
+               txAck,                  // ACK (data TX complete)
+               rs232valid;             // RS-232 signal valid
+} keyspan_usa49_portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define        RXERROR_OVERRUN 0x02
+#define        RXERROR_PARITY  0x04
+#define        RXERROR_FRAMING 0x08
+#define        RXERROR_BREAK   0x10
+
+typedef struct keyspan_usa49_globalStatusMessage
+{
+       u8      portNumber,                     // 0x80=globalStatusMessage
+               sendGlobalStatus,       // from request, decremented
+               resetStatusCount;       // as in request
+} keyspan_usa49_globalStatusMessage;
+
+typedef struct keyspan_usa49_globalDebugMessage
+{
+       u8      portNumber,                     // 0x81=globalDebugMessage
+               n,                                      // typically a count/status byte
+               b;                                      // typically a data byte
+} keyspan_usa49_globalDebugMessage;
+
+// ie: the maximum length of an EZUSB endpoint buffer
+#define        MAX_DATA_LEN                    64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define        STATUS_UPDATE_INTERVAL  16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define        STATUS_RATION   10
+
+#endif
diff --git a/drivers/usb/serial/keyspan_usa49w_fw.h b/drivers/usb/serial/keyspan_usa49w_fw.h
new file mode 100644 (file)
index 0000000..4e01712
--- /dev/null
@@ -0,0 +1,457 @@
+/* keyspan_usa49w_fw.h
+  
+   Generated from Keyspan firmware image Thu Sep 28 09:13:26 2000 EST
+   This firmware is for the Keyspan USA-49W Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa49w_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-49W Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa49w_firmware[] = {
+{ 0x0000,      3,      {0x02, 0x10, 0x36} },
+{ 0x0003,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x0013,      16,     {0x01, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x0023,      16,     {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0033,      3,      {0x02, 0x17, 0xf0} },
+{ 0x0036,      12,     {0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043,      3,      {0x02, 0x18, 0x00} },
+{ 0x0046,      16,     {0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x27} },
+{ 0x0056,      16,     {0x24, 0x04, 0xfd, 0xe4, 0x35, 0x26, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9} },
+{ 0x0066,      16,     {0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0x90, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x27, 0x24, 0x05, 0xf5} },
+{ 0x0076,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x4f, 0x7f, 0x01, 0xe5, 0x27} },
+{ 0x0086,      16,     {0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27} },
+{ 0x0096,      16,     {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0x6c, 0xe5, 0x27} },
+{ 0x00a6,      16,     {0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03, 0xe5, 0x27} },
+{ 0x00b6,      16,     {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x30, 0xf0, 0x7d, 0x04, 0x44} },
+{ 0x00c6,      16,     {0x20, 0xf0, 0xe5, 0x27, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x12} },
+{ 0x00d6,      16,     {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x00e6,      16,     {0x05, 0xc0, 0xe5, 0x27, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x14} },
+{ 0x00f6,      16,     {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x0106,      16,     {0x05, 0x0b, 0x80, 0x03, 0x43, 0x05, 0x02, 0x7f, 0x03, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x39} },
+{ 0x0116,      16,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04} },
+{ 0x0126,      16,     {0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00} },
+{ 0x0136,      16,     {0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0146,      16,     {0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0b, 0xf5, 0x82, 0xe4} },
+{ 0x0156,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x32, 0xe5, 0x27, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0166,      16,     {0xf5, 0x83, 0xe0, 0x54, 0x3f, 0xff, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0176,      16,     {0x83, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4} },
+{ 0x0186,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0d, 0xf5, 0x82, 0xe4} },
+{ 0x0196,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x02, 0x6a, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82} },
+{ 0x01a6,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01b6,      16,     {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4} },
+{ 0x01c6,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82} },
+{ 0x01d6,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x0e, 0xf5, 0x82} },
+{ 0x01e6,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01f6,      16,     {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4} },
+{ 0x0206,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0216,      16,     {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x27, 0x24, 0x0f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0226,      16,     {0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0236,      16,     {0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0246,      16,     {0xff, 0x12, 0x14, 0xdd, 0xe5, 0x27, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0256,      16,     {0xff, 0x12, 0x15, 0x0d, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0266,      16,     {0xff, 0x12, 0x14, 0xad, 0xe5, 0x27, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0276,      16,     {0x60, 0x44, 0xe5, 0x27, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11} },
+{ 0x0286,      16,     {0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0296,      16,     {0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x02a6,      16,     {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02b6,      16,     {0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x12, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02c6,      16,     {0x83, 0xe0, 0x60, 0x44, 0xe5, 0x27, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x02d6,      16,     {0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x02} },
+{ 0x02e6,      16,     {0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54} },
+{ 0x02f6,      16,     {0xfd, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0306,      16,     {0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x16, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0316,      16,     {0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0326,      16,     {0xef, 0xf0, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe0} },
+{ 0x0336,      16,     {0x11, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x0346,      16,     {0x80, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf} },
+{ 0x0356,      16,     {0xf0, 0xe5, 0x27, 0x24, 0x18, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27} },
+{ 0x0366,      16,     {0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x27, 0x24, 0x19, 0xf5} },
+{ 0x0376,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4} },
+{ 0x0386,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82} },
+{ 0x0396,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5} },
+{ 0x03a6,      16,     {0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5} },
+{ 0x03b6,      16,     {0x27, 0x24, 0x1a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x6b, 0xe5, 0x27, 0x24} },
+{ 0x03c6,      16,     {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x03d6,      16,     {0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f} },
+{ 0x03e6,      16,     {0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0xfe} },
+{ 0x03f6,      16,     {0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0406,      16,     {0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0416,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0426,      16,     {0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0436,      16,     {0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0446,      16,     {0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0456,      16,     {0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82} },
+{ 0x0466,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1c} },
+{ 0x0476,      16,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0486,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x2c, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27} },
+{ 0x0496,      16,     {0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0} },
+{ 0x04a6,      16,     {0xe4, 0xff, 0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x04b6,      16,     {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x1d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x04c6,      16,     {0x60, 0x27, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40} },
+{ 0x04d6,      16,     {0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x04e6,      16,     {0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x1e, 0xf5, 0x82, 0xe4} },
+{ 0x04f6,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0506,      16,     {0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24} },
+{ 0x0516,      16,     {0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5} },
+{ 0x0526,      16,     {0x27, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24} },
+{ 0x0536,      16,     {0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x27, 0x24, 0x32, 0xf5} },
+{ 0x0546,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15} },
+{ 0x0556,      16,     {0x3d, 0xe5, 0x27, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28} },
+{ 0x0566,      16,     {0x42, 0x25, 0xe5, 0x27, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e} },
+{ 0x0576,      16,     {0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x90, 0x78} },
+{ 0x0586,      16,     {0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0596,      16,     {0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x21, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x05a6,      16,     {0x83, 0xe0, 0x60, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x05b6,      16,     {0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x22, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60} },
+{ 0x05c6,      16,     {0x1f, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5} },
+{ 0x05d6,      16,     {0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x05e6,      16,     {0xe5, 0x27, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x12, 0x17} },
+{ 0x05f6,      16,     {0x4e, 0xe5, 0x27, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x1b, 0xe5} },
+{ 0x0606,      16,     {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f} },
+{ 0x0616,      16,     {0x98, 0xe0, 0xff, 0xe5, 0x28, 0xf4, 0xfe, 0xef, 0x5e, 0xf0, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0626,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x16, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0636,      14,     {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0} },
+{ 0x0644,      1,      {0x22} },
+{ 0x0645,      16,     {0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x11, 0xa2, 0x07, 0x42, 0x00, 0x07, 0xb6, 0x01, 0x08, 0x22, 0x03} },
+{ 0x0655,      16,     {0x06, 0x68, 0x06, 0x07, 0x35, 0x08, 0x07, 0x2f, 0x09, 0x07, 0x17, 0x0a, 0x07, 0x26, 0x0b, 0x00} },
+{ 0x0665,      16,     {0x00, 0x08, 0x71, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x77, 0x24, 0x02} },
+{ 0x0675,      16,     {0x60, 0x03, 0x02, 0x07, 0x0d, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x0685,      16,     {0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0} },
+{ 0x0695,      16,     {0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe0, 0x04, 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x02, 0x75, 0x82, 0x82} },
+{ 0x06a5,      16,     {0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x6d, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75} },
+{ 0x06b5,      16,     {0x83, 0x19, 0xf0, 0x75, 0x82, 0x5f, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19} },
+{ 0x06c5,      16,     {0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe1, 0x04, 0x7f, 0x64, 0x80, 0x02, 0x7f, 0x32, 0x75, 0x82} },
+{ 0x06d5,      16,     {0x1a, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f} },
+{ 0x06e5,      16,     {0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x13, 0x54, 0xea, 0x49, 0x60} },
+{ 0x06f5,      16,     {0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f} },
+{ 0x0705,      16,     {0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02} },
+{ 0x0715,      16,     {0x08, 0x78, 0x90, 0x7f, 0x00, 0xe5, 0x0a, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x0725,      16,     {0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0a, 0x02, 0x08, 0x78, 0x12, 0x0a, 0x6a, 0x02, 0x08, 0x78} },
+{ 0x0735,      16,     {0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xe8} },
+{ 0x0745,      16,     {0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33} },
+{ 0x0755,      16,     {0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0} },
+{ 0x0765,      16,     {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0} },
+{ 0x0775,      16,     {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80} },
+{ 0x0785,      16,     {0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4} },
+{ 0x0795,      16,     {0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f} },
+{ 0x07a5,      16,     {0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x07b5,      16,     {0x78, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x08, 0x78} },
+{ 0x07c5,      16,     {0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x07d5,      16,     {0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x07e5,      16,     {0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x07f5,      16,     {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff} },
+{ 0x0805,      16,     {0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44} },
+{ 0x0815,      16,     {0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8} },
+{ 0x0825,      16,     {0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x0835,      16,     {0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea} },
+{ 0x0845,      16,     {0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x0855,      16,     {0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x0865,      16,     {0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0875,      10,     {0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x087f,      1,      {0x22} },
+{ 0x0880,      16,     {0xe5, 0x23, 0x54, 0x0f, 0x70, 0x03, 0x02, 0x09, 0x5f, 0x12, 0x15, 0x9b, 0xef, 0x20, 0xe1, 0x63} },
+{ 0x0890,      16,     {0x12, 0x15, 0xf9, 0xef, 0x14, 0xf5, 0x1a, 0x12, 0x17, 0xc1, 0xef, 0x25, 0x1a, 0xff, 0xe4, 0x33} },
+{ 0x08a0,      16,     {0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee, 0x64, 0x80, 0x94, 0x80, 0x50, 0x47, 0x85, 0x27, 0x82, 0x85} },
+{ 0x08b0,      16,     {0x26, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5} },
+{ 0x08c0,      16,     {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f} },
+{ 0x08d0,      16,     {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x85} },
+{ 0x08e0,      16,     {0x1a, 0x08, 0xef, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12, 0x13, 0xd6, 0xe4, 0xff} },
+{ 0x08f0,      16,     {0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30} },
+{ 0x0900,      16,     {0xe7, 0x5d, 0x12, 0x17, 0xc1, 0xe5, 0x27, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0910,      16,     {0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x48, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0920,      16,     {0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0930,      16,     {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4} },
+{ 0x0940,      16,     {0xf0, 0xe5, 0x28, 0x42, 0x25, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0950,      16,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xf5, 0x09, 0x80, 0x03, 0x12, 0x12, 0x3d, 0x12} },
+{ 0x0960,      16,     {0x15, 0xca, 0xef, 0x30, 0xe1, 0x03, 0x02, 0x0a, 0x69, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4} },
+{ 0x0970,      16,     {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x80, 0xf0, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0980,      16,     {0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x17, 0xcd, 0xee, 0x4f, 0xd0, 0x82} },
+{ 0x0990,      16,     {0xd0, 0x83, 0xf0, 0x12, 0x16, 0xd1, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x09a0,      16,     {0x26, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x28, 0x12, 0x17, 0xa9, 0xef, 0x30, 0xe0} },
+{ 0x09b0,      16,     {0x21, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12} },
+{ 0x09c0,      16,     {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02} },
+{ 0x09d0,      16,     {0x0a, 0x69, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfd} },
+{ 0x09e0,      16,     {0xf0, 0xe5, 0x1a, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x09f0,      16,     {0xe4, 0xf0, 0x22, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x0a00,      16,     {0x30, 0xe7, 0x29, 0xe5, 0x1a, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x1a, 0x20, 0x85, 0x1a, 0x08} },
+{ 0x0a10,      16,     {0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x0f, 0xf5, 0x10} },
+{ 0x0a20,      16,     {0x12, 0x13, 0x06, 0xe5, 0x1a, 0x25, 0xe0, 0xff, 0x12, 0x14, 0x42, 0x22, 0xe5, 0x1a, 0xd3, 0x94} },
+{ 0x0a30,      16,     {0x3f, 0x40, 0x03, 0x75, 0x1a, 0x3f, 0x85, 0x1a, 0x08, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3} },
+{ 0x0a40,      16,     {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x85, 0x27, 0x82, 0x85, 0x26} },
+{ 0x0a50,      16,     {0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12} },
+{ 0x0a60,      9,      {0x13, 0x95, 0xe5, 0x1a, 0x04, 0xff, 0x12, 0x14, 0x42} },
+{ 0x0a69,      1,      {0x22} },
+{ 0x0a6a,      16,     {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x0a7a,      16,     {0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0} },
+{ 0x0a8a,      16,     {0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0x90, 0x78, 0x43} },
+{ 0x0a9a,      16,     {0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f} },
+{ 0x0aaa,      16,     {0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b} },
+{ 0x0aba,      16,     {0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0aca,      16,     {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x0ada,      16,     {0x28, 0x01, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0x7e} },
+{ 0x0aea,      16,     {0x7e, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0} },
+{ 0x0afa,      16,     {0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3} },
+{ 0x0b0a,      16,     {0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96} },
+{ 0x0b1a,      16,     {0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0b2a,      16,     {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0b3a,      16,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x27} },
+{ 0x0b4a,      16,     {0x82, 0x85, 0x26, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85} },
+{ 0x0b5a,      16,     {0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c} },
+{ 0x0b6a,      16,     {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0b7a,      16,     {0x04, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0b8a,      16,     {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0b9a,      16,     {0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74} },
+{ 0x0baa,      16,     {0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83} },
+{ 0x0bba,      16,     {0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c} },
+{ 0x0bca,      16,     {0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0bda,      16,     {0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75} },
+{ 0x0bea,      16,     {0x28, 0x08, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0} },
+{ 0x0bfa,      16,     {0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0} },
+{ 0x0c0a,      16,     {0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0} },
+{ 0x0c1a,      7,      {0xa3, 0x74, 0x00, 0xf0, 0xd2, 0x02, 0x22} },
+{ 0x0c21,      16,     {0xe5, 0x22, 0x04, 0x54, 0x03, 0xf5, 0x22, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14, 0x60, 0x43} },
+{ 0x0c31,      16,     {0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f} },
+{ 0x0c41,      16,     {0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0c51,      16,     {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x80, 0x28, 0x7e, 0x7c} },
+{ 0x0c61,      16,     {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0c71,      16,     {0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0c81,      16,     {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0xe5, 0x15, 0x55, 0x28, 0x70, 0x03, 0x02, 0x0d, 0xbf, 0xe5} },
+{ 0x0c91,      16,     {0x28, 0xf4, 0xff, 0x52, 0x15, 0xe5, 0x0b, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x0d, 0x55, 0x28} },
+{ 0x0ca1,      16,     {0x60, 0x24, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18, 0xe5, 0x27} },
+{ 0x0cb1,      16,     {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5, 0x0d} },
+{ 0x0cc1,      16,     {0x90, 0x7f, 0x98, 0xe0, 0x5f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0cd1,      16,     {0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x27, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0ce1,      16,     {0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0d, 0xbf, 0x74, 0x0a} },
+{ 0x0cf1,      16,     {0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0d01,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d11,      16,     {0x12, 0x17, 0xd9, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0d21,      16,     {0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d31,      16,     {0xe5, 0x27, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54} },
+{ 0x0d41,      16,     {0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x29, 0xf5} },
+{ 0x0d51,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x20, 0xfe, 0x6f, 0x60, 0x15} },
+{ 0x0d61,      16,     {0xee, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe4} },
+{ 0x0d71,      16,     {0x04, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x24, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2a} },
+{ 0x0d81,      16,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x1a, 0xf0, 0xe5, 0x27} },
+{ 0x0d91,      16,     {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x28, 0x42} },
+{ 0x0da1,      16,     {0x25, 0xe5, 0x29, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0db1,      14,     {0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0dbf,      1,      {0x22} },
+{ 0x0dc0,      16,     {0xe5, 0x09, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60, 0x58, 0x14, 0x60, 0x6f, 0x24, 0x04} },
+{ 0x0dd0,      16,     {0x60, 0x03, 0x02, 0x0e, 0x77, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90} },
+{ 0x0de0,      16,     {0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x01, 0x22, 0x7e} },
+{ 0x0df0,      16,     {0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75} },
+{ 0x0e00,      16,     {0x28, 0x02, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x02, 0x22, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c} },
+{ 0x0e10,      16,     {0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x12, 0x3d, 0x75} },
+{ 0x0e20,      16,     {0x09, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0e30,      16,     {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x04, 0x22, 0x30, 0x04, 0x33} },
+{ 0x0e40,      16,     {0xc2, 0x04, 0x53, 0x25, 0xdf, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x11, 0x25, 0x1a} },
+{ 0x0e50,      16,     {0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4} },
+{ 0x0e60,      16,     {0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3} },
+{ 0x0e70,      16,     {0x74, 0x03, 0xf0, 0x75, 0x09, 0x05, 0x22, 0xe5, 0x17, 0x60, 0x34, 0xd5, 0x17, 0x03, 0x53, 0x25} },
+{ 0x0e80,      16,     {0xef, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x16, 0x25, 0x1a, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x0e90,      16,     {0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0ea0,      16,     {0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} },
+{ 0x0eb0,      2,      {0xf5, 0x09} },
+{ 0x0eb2,      1,      {0x22} },
+{ 0x0eb3,      16,     {0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x27, 0x25, 0x19, 0xf9, 0xee, 0x35, 0x26, 0xfa} },
+{ 0x0ec3,      16,     {0xe4, 0x12, 0x11, 0x90, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x3c, 0xe8, 0xe5, 0x27, 0x24, 0x35, 0xf5} },
+{ 0x0ed3,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5} },
+{ 0x0ee3,      16,     {0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0ef3,      16,     {0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x15, 0x3d, 0x7f, 0x10, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82} },
+{ 0x0f03,      16,     {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x14, 0xad, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0} },
+{ 0x0f13,      16,     {0x7f, 0x01, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x44} },
+{ 0x0f23,      16,     {0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5} },
+{ 0x0f33,      16,     {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd} },
+{ 0x0f43,      16,     {0x12, 0x15, 0x3d, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0f53,      16,     {0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0} },
+{ 0x0f63,      16,     {0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x15, 0x3d, 0x7f, 0x01, 0x12, 0x14, 0x78, 0x7f} },
+{ 0x0f73,      6,      {0x03, 0x7d, 0x07, 0x12, 0x15, 0x3d} },
+{ 0x0f79,      1,      {0x22} },
+{ 0x0f7a,      16,     {0x53, 0x25, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26} },
+{ 0x0f8a,      16,     {0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x08, 0x80} },
+{ 0x0f9a,      16,     {0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x0faa,      16,     {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x08, 0x80, 0x90, 0x7c, 0x71} },
+{ 0x0fba,      16,     {0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0fca,      16,     {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x08, 0x80, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3} },
+{ 0x0fda,      16,     {0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f} },
+{ 0x0fea,      16,     {0xf0, 0x75, 0x28, 0x08, 0x12, 0x08, 0x80, 0x05, 0x23, 0xe5, 0x23, 0x54, 0x0f, 0xf5, 0x19, 0x70} },
+{ 0x0ffa,      16,     {0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf5, 0x29, 0x90, 0x78} },
+{ 0x100a,      16,     {0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf4, 0xf5, 0x24, 0x12, 0x10, 0xc2, 0x22} },
+{ 0x101a,      16,     {0xe5, 0x19, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x21, 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08} },
+{ 0x102a,      11,     {0xe5, 0x25, 0x60, 0x04, 0x12, 0x0d, 0xc0, 0x22, 0x12, 0x0c, 0x21} },
+{ 0x1035,      1,      {0x22} },
+{ 0x1036,      12,     {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x29, 0x02, 0x10, 0x7d} },
+{ 0x1042,      16,     {0x02, 0x11, 0xc8, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x1052,      16,     {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x1062,      16,     {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x1072,      16,     {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x17, 0x67, 0xe4, 0x7e} },
+{ 0x1082,      16,     {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x1092,      16,     {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x10a2,      16,     {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x10b2,      16,     {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x10c2,      16,     {0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x49, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60} },
+{ 0x10d2,      16,     {0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e} },
+{ 0x10e2,      16,     {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x10f2,      16,     {0x28, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1102,      16,     {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e} },
+{ 0x1112,      16,     {0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75} },
+{ 0x1122,      16,     {0x28, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1132,      16,     {0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12} },
+{ 0x1142,      8,      {0x16, 0x56, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22} },
+{ 0x114a,      16,     {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x115a,      9,      {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1163,      16,     {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x1173,      16,     {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x1183,      13,     {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1190,      16,     {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x11a0,      2,      {0xf3, 0x22} },
+{ 0x11a2,      16,     {0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x11b2,      16,     {0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x11c2,      6,      {0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x11c8,      16,     {0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8} },
+{ 0x11d8,      16,     {0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab} },
+{ 0x11e8,      16,     {0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x11f8,      16,     {0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x09, 0x12, 0x17} },
+{ 0x1208,      16,     {0x13, 0xc2, 0x01, 0xe4, 0xf5, 0x0e, 0xf5, 0x14, 0xc2, 0x07, 0xc2, 0x02, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x1218,      16,     {0x65, 0x0b, 0x60, 0x06, 0x75, 0x15, 0x0f, 0xe0, 0xf5, 0x0b, 0x30, 0x02, 0x03, 0x12, 0x0f, 0x7a} },
+{ 0x1228,      16,     {0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x45, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12} },
+{ 0x1238,      5,      {0x17, 0x95, 0x80, 0xd8, 0x22} },
+{ 0x123d,      16,     {0xe5, 0x25, 0x55, 0x28, 0x60, 0x6a, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x124d,      16,     {0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x28, 0xf4, 0x52, 0x25, 0xe5, 0x27, 0x24, 0x26, 0xff, 0xe4, 0x35} },
+{ 0x125d,      16,     {0x26, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83} },
+{ 0x126d,      16,     {0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd} },
+{ 0x127d,      16,     {0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x128d,      16,     {0x26, 0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x129d,      16,     {0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x12ad,      1,      {0x22} },
+{ 0x12ae,      16,     {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x12be,      16,     {0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
+{ 0x12ce,      16,     {0x7f, 0x97, 0xf0, 0xe5, 0x0c, 0x54, 0xf0, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0, 0xe4, 0x90, 0x7f} },
+{ 0x12de,      16,     {0x98, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98} },
+{ 0x12ee,      16,     {0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x12fe,      8,      {0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22} },
+{ 0x1306,      16,     {0x8f, 0x1b, 0x05, 0x10, 0xe5, 0x10, 0xae, 0x0f, 0x70, 0x02, 0x05, 0x0f, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x1316,      16,     {0x83, 0xe5, 0x1b, 0xf0, 0x12, 0x17, 0xe5, 0x05, 0x10, 0xe5, 0x10, 0xac, 0x0f, 0x70, 0x02, 0x05} },
+{ 0x1326,      16,     {0x0f, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x1f, 0xe5, 0x27} },
+{ 0x1336,      16,     {0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12} },
+{ 0x1346,      14,     {0x17, 0xcd, 0x8f, 0x1b, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22} },
+{ 0x1354,      2,      {0x8f, 0x19} },
+{ 0x1356,      16,     {0xe4, 0xf5, 0x1a, 0x75, 0x1b, 0xff, 0x75, 0x1c, 0x19, 0x75, 0x1d, 0x86, 0xab, 0x1b, 0xaa, 0x1c} },
+{ 0x1366,      16,     {0xa9, 0x1d, 0x90, 0x00, 0x01, 0x12, 0x11, 0x63, 0xb4, 0x03, 0x1d, 0xaf, 0x1a, 0x05, 0x1a, 0xef} },
+{ 0x1376,      16,     {0xb5, 0x19, 0x01, 0x22, 0x12, 0x11, 0x4a, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x1386,      14,     {0x1b, 0xff, 0xf5, 0x1c, 0x89, 0x1d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x1394,      1,      {0x22} },
+{ 0x1395,      16,     {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x78, 0x4f, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0} },
+{ 0x13a5,      16,     {0xe5, 0x0f, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13b5,      16,     {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10} },
+{ 0x13c5,      16,     {0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa} },
+{ 0x13d5,      1,      {0x22} },
+{ 0x13d6,      16,     {0xe4, 0x90, 0x78, 0x41, 0xf0, 0xe5, 0x0f, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90} },
+{ 0x13e6,      16,     {0x78, 0x50, 0xf0, 0x90, 0x78, 0x51, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13f6,      16,     {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90} },
+{ 0x1406,      6,      {0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22} },
+{ 0x140c,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x141c,      16,     {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x142c,      16,     {0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd, 0xef} },
+{ 0x143c,      6,      {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1442,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x1452,      16,     {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x1462,      16,     {0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef} },
+{ 0x1472,      6,      {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1478,      16,     {0xae, 0x07, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x1488,      16,     {0x54, 0x7f, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee} },
+{ 0x1498,      16,     {0xf0, 0xe4, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80} },
+{ 0x14a8,      5,      {0xfd, 0x12, 0x15, 0x3d, 0x22} },
+{ 0x14ad,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14bd,      16,     {0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14cd,      16,     {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x14dd,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14ed,      16,     {0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14fd,      16,     {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x150d,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x151d,      16,     {0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x152d,      16,     {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x153d,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x154d,      16,     {0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x07, 0xf0, 0x90, 0xc0} },
+{ 0x155d,      15,     {0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x156c,      16,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0xe4, 0x90, 0x78, 0x41} },
+{ 0x157c,      16,     {0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37} },
+{ 0x158c,      15,     {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x159b,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15ab,      16,     {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc8} },
+{ 0x15bb,      15,     {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0, 0xff, 0x22} },
+{ 0x15ca,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15da,      16,     {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xb8} },
+{ 0x15ea,      15,     {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff, 0x22} },
+{ 0x15f9,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x1609,      16,     {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc9} },
+{ 0x1619,      15,     {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22} },
+{ 0x1628,      16,     {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1638,      16,     {0x05, 0x04, 0xc2, 0x05, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1648,      14,     {0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1656,      16,     {0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x17, 0x43, 0x25, 0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} },
+{ 0x1666,      16,     {0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b, 0x43, 0xe0, 0xf5, 0x18, 0x30, 0x00, 0x07, 0xa3} },
+{ 0x1676,      10,     {0xe0, 0x54, 0xf0, 0xf5, 0x0c, 0x22, 0xe4, 0xf5, 0x0c, 0x22} },
+{ 0x1680,      16,     {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x1690,      16,     {0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x16a0,      10,     {0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16aa,      16,     {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x16ba,      16,     {0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x16ca,      7,      {0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16d1,      16,     {0x12, 0x17, 0xb5, 0xae, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x17} },
+{ 0x16e1,      16,     {0xb5, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06} },
+{ 0x16f1,      1,      {0x22} },
+{ 0x16f2,      16,     {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x1702,      1,      {0x22} },
+{ 0x1703,      16,     {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x1713,      16,     {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x09, 0x04, 0xe0, 0x44} },
+{ 0x1723,      16,     {0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x17, 0x34, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1733,      1,      {0x22} },
+{ 0x1734,      16,     {0x8e, 0x19, 0x8f, 0x1a, 0xe5, 0x1a, 0x15, 0x1a, 0xae, 0x19, 0x70, 0x02, 0x15, 0x19, 0x4e, 0x60} },
+{ 0x1744,      10,     {0x08, 0x12, 0x16, 0xf2, 0x12, 0x16, 0xf2, 0x80, 0xeb, 0x22} },
+{ 0x174e,      16,     {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10} },
+{ 0x175e,      9,      {0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22} },
+{ 0x1767,      16,     {0x03, 0x16, 0x80, 0x00, 0x00, 0x03, 0x11, 0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08} },
+{ 0x1777,      7,      {0xc1, 0x00, 0xc1, 0x86, 0x01, 0x09, 0x00} },
+{ 0x177e,      1,      {0x00} },
+{ 0x177f,      16,     {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x17, 0x34, 0x90, 0x7f} },
+{ 0x178f,      6,      {0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x1795,      16,     {0x12, 0x12, 0xae, 0x12, 0x17, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x03, 0x12, 0x17, 0x7f} },
+{ 0x17a5,      4,      {0x12, 0x0a, 0x6a, 0x22} },
+{ 0x17a9,      12,     {0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17b5,      12,     {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17c1,      12,     {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17cd,      12,     {0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17d9,      12,     {0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17e5,      11,     {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17f0,      4,      {0x53, 0xd8, 0xef, 0x32} },
+{ 0x1800,      15,     {0x02, 0x16, 0xaa, 0x00, 0x02, 0x18, 0x04, 0x00, 0x02, 0x16, 0x80, 0x00, 0x02, 0x16, 0x28} },
+{ 0x1900,      16,     {0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,      16,     {0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,      16,     {0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,      16,     {0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,      16,     {0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,      16,     {0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,      16,     {0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,      16,     {0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07} },
+{ 0x1980,      16,     {0x05, 0x87, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,      16,     {0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,      16,     {0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,      16,     {0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,      16,     {0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,      16,     {0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,      16,     {0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,      16,     {0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,      10,     {0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff,      0,      {0x00} }
+};
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
new file mode 100644 (file)
index 0000000..490f622
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
+ *
+ *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ * This program is largely derived from the Belkin USB Serial Adapter Driver
+ * (see belkin_sa.[ch]). All of the information about the device was acquired
+ * by using SniffUSB on Windows98. For technical details see mct_u232.h.
+ *
+ * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
+ * do the reverse engineering and how to write a USB serial device driver.
+ *
+ * TO BE DONE, TO BE CHECKED:
+ *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
+ *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
+ *   For further TODOs check also belkin_sa.c.
+ *
+ * TEST STATUS:
+ *   Basic tests have been performed with minicom/zmodem transfers and
+ *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
+ *
+ * 29-Nov-2000 Greg Kroah-Hartman
+ *   - Added device id table to fit with 2.4.0-test11 structure.
+ *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
+ *     (lots of things will change if/when the usb-serial core changes to
+ *     handle these issues.
+ *
+ * 27-Nov-2000 Wolfgang Grandegger
+ *   A version for kernel 2.4.0-test10 released to the Linux community 
+ *   (via linux-usb-devel).
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+#include "mct_u232.h"
+
+
+/*
+ * Some not properly written applications do not handle the return code of
+ * write() correctly. This can result in character losses. A work-a-round
+ * can be compiled in with the following definition. This work-a-round
+ * should _NOT_ be part of an 'official' kernel release, of course!
+ */
+#undef FIX_WRITE_RETURN_CODE_PROBLEM
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+static int write_blocking = 0; /* disabled by default */
+#endif
+
+/*
+ * Function prototypes
+ */
+static int  mct_u232_startup            (struct usb_serial *serial);
+static void mct_u232_shutdown           (struct usb_serial *serial);
+static int  mct_u232_open               (struct usb_serial_port *port,
+                                         struct file *filp);
+static void mct_u232_close              (struct usb_serial_port *port,
+                                         struct file *filp);
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+static int  mct_u232_write              (struct usb_serial_port *port,
+                                         int from_user,
+                                         const unsigned char *buf,
+                                         int count);
+static void mct_u232_write_bulk_callback (struct urb *urb);
+#endif
+static void mct_u232_read_int_callback   (struct urb *urb);
+static void mct_u232_set_termios         (struct usb_serial_port *port,
+                                         struct termios * old);
+static int  mct_u232_ioctl              (struct usb_serial_port *port,
+                                         struct file * file,
+                                         unsigned int cmd,
+                                         unsigned long arg);
+static void mct_u232_break_ctl          (struct usb_serial_port *port,
+                                         int break_state );
+
+/*
+ * All of the device info needed for the MCT USB-RS232 converter.
+ */
+static __devinitdata struct usb_device_id id_table [] = {
+       { idVendor: MCT_U232_VID, idProduct: MCT_U232_PID },
+       { }                                     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+struct usb_serial_device_type mct_u232_device = {
+       name:                "Magic Control Technology USB-RS232",
+       id_table:            id_table,
+       needs_interrupt_in:  MUST_HAVE,  /* 2 interrupt-in endpoints */
+       needs_bulk_in:       MUST_HAVE_NOT,   /* no bulk-in endpoint */
+       needs_bulk_out:      MUST_HAVE,       /* 1 bulk-out endpoint */
+       num_interrupt_in:    2,
+       num_bulk_in:         0,
+       num_bulk_out:        1,
+       num_ports:           1,
+       open:                mct_u232_open,
+       close:               mct_u232_close,
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+       write:               mct_u232_write,
+       write_bulk_callback: mct_u232_write_bulk_callback,
+#endif
+       read_int_callback:   mct_u232_read_int_callback,
+       ioctl:               mct_u232_ioctl,
+       set_termios:         mct_u232_set_termios,
+       break_ctl:           mct_u232_break_ctl,
+       startup:             mct_u232_startup,
+       shutdown:            mct_u232_shutdown,
+};
+
+struct mct_u232_private {
+       unsigned long        control_state; /* Modem Line Setting (TIOCM) */
+       unsigned char        last_lcr;      /* Line Control Register */
+       unsigned char        last_lsr;      /* Line Status Register */
+       unsigned char        last_msr;      /* Modem Status Register */
+};
+
+/*
+ * Handle vendor specific USB requests
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
+{
+       unsigned int divisor;
+        int rc;
+       divisor = MCT_U232_BAUD_RATE(value);
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                             MCT_U232_SET_BAUD_RATE_REQUEST,
+                            MCT_U232_SET_REQUEST_TYPE,
+                             0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
+                            WDR_TIMEOUT);
+       if (rc < 0)
+               err("Set BAUD RATE %d failed (error = %d)", value, rc);
+       dbg("set_baud_rate: 0x%x", divisor);
+        return rc;
+} /* mct_u232_set_baud_rate */
+
+static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
+{
+        int rc;
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                             MCT_U232_SET_LINE_CTRL_REQUEST,
+                            MCT_U232_SET_REQUEST_TYPE,
+                             0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
+                            WDR_TIMEOUT);
+       if (rc < 0)
+               err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
+       dbg("set_line_ctrl: 0x%x", lcr);
+        return rc;
+} /* mct_u232_set_line_ctrl */
+
+static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
+                                  unsigned long control_state)
+{
+        int rc;
+       unsigned char mcr = MCT_U232_MCR_NONE;
+
+       if (control_state & TIOCM_DTR)
+               mcr |= MCT_U232_MCR_DTR;
+       if (control_state & TIOCM_RTS)
+               mcr |= MCT_U232_MCR_RTS;
+
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                             MCT_U232_SET_MODEM_CTRL_REQUEST,
+                            MCT_U232_SET_REQUEST_TYPE,
+                             0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
+                            WDR_TIMEOUT);
+       if (rc < 0)
+               err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
+       dbg("set_modem_ctrl: state=0x%lx ==> mcr=0x%x", control_state, mcr);
+
+        return rc;
+} /* mct_u232_set_modem_ctrl */
+
+static int mct_u232_get_modem_stat(struct usb_serial *serial, unsigned char *msr)
+{
+        int rc;
+        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+                             MCT_U232_GET_MODEM_STAT_REQUEST,
+                            MCT_U232_GET_REQUEST_TYPE,
+                             0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
+                            WDR_TIMEOUT);
+       if (rc < 0) {
+               err("Get MODEM STATus failed (error = %d)", rc);
+               *msr = 0;
+       }
+       dbg("get_modem_stat: 0x%x", *msr);
+        return rc;
+} /* mct_u232_get_modem_stat */
+
+static void mct_u232_msr_to_state(unsigned long *control_state, unsigned char msr)
+{
+       /* Translate Control Line states */
+       if (msr & MCT_U232_MSR_DSR)
+               *control_state |=  TIOCM_DSR;
+       else
+               *control_state &= ~TIOCM_DSR;
+       if (msr & MCT_U232_MSR_CTS)
+               *control_state |=  TIOCM_CTS;
+       else
+               *control_state &= ~TIOCM_CTS;
+       if (msr & MCT_U232_MSR_RI)
+               *control_state |=  TIOCM_RI;
+       else
+               *control_state &= ~TIOCM_RI;
+       if (msr & MCT_U232_MSR_CD)
+               *control_state |=  TIOCM_CD;
+       else
+               *control_state &= ~TIOCM_CD;
+       dbg("msr_to_state: msr=0x%x ==> state=0x%lx", msr, *control_state);
+} /* mct_u232_msr_to_state */
+
+/*
+ * Driver's tty interface functions
+ */
+
+static int mct_u232_startup (struct usb_serial *serial)
+{
+       struct mct_u232_private *priv;
+
+       /* allocate the private data structure */
+       serial->port->private = kmalloc(sizeof(struct mct_u232_private),
+                                       GFP_KERNEL);
+       if (!serial->port->private)
+               return (-1); /* error */
+       priv = (struct mct_u232_private *)serial->port->private;
+       /* set initial values for control structures */
+       priv->control_state = 0;
+       priv->last_lsr = 0;
+       priv->last_msr = 0;
+
+       init_waitqueue_head(&serial->port->write_wait);
+       
+       return (0);
+} /* mct_u232_startup */
+
+
+static void mct_u232_shutdown (struct usb_serial *serial)
+{
+       int i;
+       
+       dbg (__FUNCTION__);
+
+       /* stop reads and writes on all ports */
+       for (i=0; i < serial->num_ports; ++i) {
+               while (serial->port[i].open_count > 0) {
+                       mct_u232_close (&serial->port[i], NULL);
+               }
+               /* My special items, the standard routines free my urbs */
+               if (serial->port->private)
+                       kfree(serial->port->private);
+       }
+} /* mct_u232_shutdown */
+
+static int  mct_u232_open (struct usb_serial_port *port, struct file *filp)
+{
+       unsigned long flags;
+       struct usb_serial *serial = port->serial;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+
+       dbg(__FUNCTION__" port %d", port->number);
+
+       spin_lock_irqsave (&port->port_lock, flags);
+       
+       ++port->open_count;
+       MOD_INC_USE_COUNT;
+
+       if (!port->active) {
+               port->active = 1;
+
+               /* Do a defined restart: the normal serial device seems to 
+                * always turn on DTR and RTS here, so do the same. I'm not
+                * sure if this is really necessary. But it should not harm
+                * either.
+                */
+               if (port->tty->termios->c_cflag & CBAUD)
+                       priv->control_state = TIOCM_DTR | TIOCM_RTS;
+               else
+                       priv->control_state = 0;
+               mct_u232_set_modem_ctrl(serial, priv->control_state);
+               
+               priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
+                                 MCT_U232_PARITY_NONE |
+                                 MCT_U232_STOP_BITS_1);
+               mct_u232_set_line_ctrl(serial, priv->last_lcr);
+
+               /* Read modem status and update control state */
+               mct_u232_get_modem_stat(serial, &priv->last_msr);
+               mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+
+               {
+                       /* Puh, that's dirty */
+                       struct usb_serial_port *rport;  
+                       rport = &serial->port[1];
+                       rport->tty = port->tty;
+                       rport->private = port->private;
+                       port->read_urb = rport->interrupt_in_urb;
+               }
+
+               port->read_urb->dev = port->serial->dev;
+               if (usb_submit_urb(port->read_urb))
+                       err("usb_submit_urb(read bulk) failed");
+
+               port->interrupt_in_urb->dev = port->serial->dev;
+               if (usb_submit_urb(port->interrupt_in_urb))
+                       err(" usb_submit_urb(read int) failed");
+
+       }
+
+       spin_unlock_irqrestore (&port->port_lock, flags);
+       
+       return 0;
+} /* mct_u232_open */
+
+
+static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
+{
+       unsigned long flags;
+
+       dbg(__FUNCTION__" port %d", port->number);
+
+       spin_lock_irqsave (&port->port_lock, flags);
+
+       --port->open_count;
+       MOD_DEC_USE_COUNT;
+
+       if (port->open_count <= 0) {
+               /* shutdown our bulk reads and writes */
+               usb_unlink_urb (port->write_urb);
+               usb_unlink_urb (port->read_urb);
+               /* wgg - do I need this? I think so. */
+               usb_unlink_urb (port->interrupt_in_urb);
+               port->active = 0;
+       }
+       
+       spin_unlock_irqrestore (&port->port_lock, flags);
+
+} /* mct_u232_close */
+
+
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+/* The generic routines work fine otherwise */
+
+static int mct_u232_write (struct usb_serial_port *port, int from_user,
+                          const unsigned char *buf, int count)
+{
+       struct usb_serial *serial = port->serial;
+       unsigned long flags;
+       int result, bytes_sent, size;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       if (count == 0) {
+               dbg(__FUNCTION__ " - write request of 0 bytes");
+               return (0);
+       }
+
+       /* only do something if we have a bulk out endpoint */
+       if (!serial->num_bulk_out)
+               return(0);;
+       
+       /* another write is still pending? */
+       if (port->write_urb->status == -EINPROGRESS) {
+               dbg (__FUNCTION__ " - already writing");
+               return (0);
+       }
+               
+       bytes_sent = 0;
+       while (count > 0) {
+               
+               spin_lock_irqsave (&port->port_lock, flags);
+               
+               size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+               
+               usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
+               
+               if (from_user) {
+                       copy_from_user(port->write_urb->transfer_buffer, buf, size);
+               }
+               else {
+                       memcpy (port->write_urb->transfer_buffer, buf, size);
+               }
+               
+               /* set up our urb */
+               FILL_BULK_URB(port->write_urb, serial->dev,
+                             usb_sndbulkpipe(serial->dev,
+                                             port->bulk_out_endpointAddress),
+                             port->write_urb->transfer_buffer, size,
+                             ((serial->type->write_bulk_callback) ?
+                              serial->type->write_bulk_callback :
+                              mct_u232_write_bulk_callback),
+                             port);
+               
+               /* send the data out the bulk port */
+               result = usb_submit_urb(port->write_urb);
+               if (result) {
+                       err(__FUNCTION__
+                           " - failed submitting write urb, error %d", result);
+                       spin_unlock_irqrestore (&port->port_lock, flags);
+                       return bytes_sent;
+               }
+
+               spin_unlock_irqrestore (&port->port_lock, flags);
+
+               bytes_sent += size;
+               if (write_blocking)
+                       interruptible_sleep_on(&port->write_wait);
+               else
+                       break;
+
+               buf += size;
+               count -= size;
+       }
+       
+       return bytes_sent;
+} /* mct_u232_write */
+
+static void mct_u232_write_bulk_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial *serial = port->serial;
+               struct tty_struct *tty = port->tty;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
+       if (urb->status) {
+               dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+                   urb->status);
+               return;
+       }
+
+       if (write_blocking) {
+               wake_up_interruptible(&port->write_wait);
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+               
+       } else {
+               /* from generic_write_bulk_callback */
+               queue_task(&port->tqueue, &tq_immediate);
+               mark_bh(IMMEDIATE_BH);
+       }
+
+       return;
+} /* mct_u232_write_bulk_callback */
+#endif
+
+static void mct_u232_read_int_callback (struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       struct usb_serial *serial = port->serial;
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+
+        dbg(__FUNCTION__ " - port %d", port->number);
+
+       /* The urb might have been killed. */
+        if (urb->status) {
+                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+                   urb->status);
+                return;
+        }
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+       
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+       /*
+        * Work-a-round: handle the 'usual' bulk-in pipe here
+        */
+       if (urb->transfer_buffer_length > 2) {
+               int i;
+               tty = port->tty;
+               if (urb->actual_length) {
+                       for (i = 0; i < urb->actual_length ; ++i) {
+                               tty_insert_flip_char(tty, data[i], 0);
+                       }
+                       tty_flip_buffer_push(tty);
+               }
+               /* INT urbs are automatically re-submitted */
+               return;
+       }
+       
+       /*
+        * The interrupt-in pipe signals exceptional conditions (modem line
+        * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
+        */
+       priv->last_msr = data[MCT_U232_MSR_INDEX];
+       
+       /* Record Control Line states */
+       mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+
+#if 0
+       /* Not yet handled. See belin_sa.c for further information */
+       /* Now to report any errors */
+       priv->last_lsr = data[MCT_U232_LSR_INDEX];
+       /*
+        * fill in the flip buffer here, but I do not know the relation
+        * to the current/next receive buffer or characters.  I need
+        * to look in to this before committing any code.
+        */
+       if (priv->last_lsr & MCT_U232_LSR_ERR) {
+               tty = port->tty;
+               /* Overrun Error */
+               if (priv->last_lsr & MCT_U232_LSR_OE) {
+               }
+               /* Parity Error */
+               if (priv->last_lsr & MCT_U232_LSR_PE) {
+               }
+               /* Framing Error */
+               if (priv->last_lsr & MCT_U232_LSR_FE) {
+               }
+               /* Break Indicator */
+               if (priv->last_lsr & MCT_U232_LSR_BI) {
+               }
+       }
+#endif
+
+       /* INT urbs are automatically re-submitted */
+} /* mct_u232_read_int_callback */
+
+
+static void mct_u232_set_termios (struct usb_serial_port *port,
+                                 struct termios *old_termios)
+{
+       struct usb_serial *serial = port->serial;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       unsigned int iflag = port->tty->termios->c_iflag;
+       unsigned int old_iflag = old_termios->c_iflag;
+       unsigned int cflag = port->tty->termios->c_cflag;
+       unsigned int old_cflag = old_termios->c_cflag;
+       
+       /*
+        * Update baud rate
+        */
+       if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
+               /* reassert DTR and (maybe) RTS on transition from B0 */
+               if( (old_cflag & CBAUD) == B0 ) {
+                       dbg(__FUNCTION__ ": baud was B0");
+                       priv->control_state |= TIOCM_DTR;
+                       /* don't set RTS if using hardware flow control */
+                       if (!(old_cflag & CRTSCTS)) {
+                               priv->control_state |= TIOCM_RTS;
+                       }
+                       mct_u232_set_modem_ctrl(serial, priv->control_state);
+               }
+               
+               switch(cflag & CBAUD) {
+               case B0: /* handled below */
+                       break;
+               case B300: mct_u232_set_baud_rate(serial, 300);
+                       break;
+               case B600: mct_u232_set_baud_rate(serial, 600);
+                       break;
+               case B1200: mct_u232_set_baud_rate(serial, 1200);
+                       break;
+               case B2400: mct_u232_set_baud_rate(serial, 2400);
+                       break;
+               case B4800: mct_u232_set_baud_rate(serial, 4800);
+                       break;
+               case B9600: mct_u232_set_baud_rate(serial, 9600);
+                       break;
+               case B19200: mct_u232_set_baud_rate(serial, 19200);
+                       break;
+               case B38400: mct_u232_set_baud_rate(serial, 38400);
+                       break;
+               case B57600: mct_u232_set_baud_rate(serial, 57600);
+                       break;
+               case B115200: mct_u232_set_baud_rate(serial, 115200);
+                       break;
+               default: err("MCT USB-RS232 converter: unsupported baudrate request, using default of 9600");
+                       mct_u232_set_baud_rate(serial, 9600); break;
+               }
+               if ((cflag & CBAUD) == B0 ) {
+                       dbg(__FUNCTION__ ": baud is B0");
+                       /* Drop RTS and DTR */
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+                       mct_u232_set_modem_ctrl(serial, priv->control_state);
+               }
+       }
+
+       /*
+        * Update line control register (LCR)
+        */
+       if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
+           || (cflag & CSIZE) != (old_cflag & CSIZE)
+           || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+               
+
+               priv->last_lcr = 0;
+
+               /* set the parity */
+               if (cflag & PARENB)
+                       priv->last_lcr |= (cflag & PARODD) ?
+                               MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
+               else
+                       priv->last_lcr |= MCT_U232_PARITY_NONE;
+
+               /* set the number of data bits */
+               switch (cflag & CSIZE) {
+               case CS5:
+                       priv->last_lcr |= MCT_U232_DATA_BITS_5; break;
+               case CS6:
+                       priv->last_lcr |= MCT_U232_DATA_BITS_6; break;
+               case CS7:
+                       priv->last_lcr |= MCT_U232_DATA_BITS_7; break;
+               case CS8:
+                       priv->last_lcr |= MCT_U232_DATA_BITS_8; break;
+               default:
+                       err("CSIZE was not CS5-CS8, using default of 8");
+                       priv->last_lcr |= MCT_U232_DATA_BITS_8;
+                       break;
+               }
+
+               /* set the number of stop bits */
+               priv->last_lcr |= (cflag & CSTOPB) ?
+                       MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+
+               mct_u232_set_line_ctrl(serial, priv->last_lcr);
+       }
+       
+       /*
+        * Set flow control: well, I do not really now how to handle DTR/RTS.
+        * Just do what we have seen with SniffUSB on Win98.
+        */
+       if( (iflag & IXOFF) != (old_iflag & IXOFF)
+           || (iflag & IXON) != (old_iflag & IXON)
+           ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+               
+               /* Drop DTR/RTS if no flow control otherwise assert */
+               if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
+                       priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+               else
+                       priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+               mct_u232_set_modem_ctrl(serial, priv->control_state);
+       }
+} /* mct_u232_set_termios */
+
+
+static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
+{
+       struct usb_serial *serial = port->serial;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       unsigned char lcr = priv->last_lcr;
+
+       dbg (__FUNCTION__ "state=%d", break_state);
+
+       if (break_state)
+               lcr |= MCT_U232_SET_BREAK;
+
+       mct_u232_set_line_ctrl(serial, lcr);
+} /* mct_u232_break_ctl */
+
+
+static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
+                          unsigned int cmd, unsigned long arg)
+{
+       struct usb_serial *serial = port->serial;
+       struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+       int ret, mask;
+       
+       dbg (__FUNCTION__ "cmd=0x%x", cmd);
+
+       /* Based on code from acm.c and others */
+       switch (cmd) {
+       case TIOCMGET:
+               return put_user(priv->control_state, (unsigned long *) arg);
+               break;
+
+       case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+       case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+       case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+               if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+                       /* RTS needs set */
+                       if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
+                           (cmd == TIOCMBIS) )
+                               priv->control_state |=  TIOCM_RTS;
+                       else
+                               priv->control_state &= ~TIOCM_RTS;
+               }
+
+               if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+                       /* DTR needs set */
+                       if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
+                           (cmd == TIOCMBIS) )
+                               priv->control_state |=  TIOCM_DTR;
+                       else
+                               priv->control_state &= ~TIOCM_DTR;
+               }
+               mct_u232_set_modem_ctrl(serial, priv->control_state);
+               break;
+                                       
+       case TIOCMIWAIT:
+               /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+               /* TODO */
+               return( 0 );
+
+       case TIOCGICOUNT:
+               /* return count of modemline transitions */
+               /* TODO */
+               return 0;
+
+       default:
+               dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+               return(-ENOIOCTLCMD);
+               break;
+       }
+       return 0;
+} /* mct_u232_ioctl */
+
+
+static int __init mct_u232_init (void)
+{
+       usb_serial_register (&mct_u232_device);
+       
+       return 0;
+}
+
+
+static void __exit mct_u232_exit (void)
+{
+       usb_serial_deregister (&mct_u232_device);
+}
+
+
+module_init (mct_u232_init);
+module_exit(mct_u232_exit);
+
+MODULE_AUTHOR("Wolfgang Grandegger <wolfgang@ces.ch>");
+MODULE_DESCRIPTION("Magic Control Technology USB-RS232 converter driver");
+
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+MODULE_PARM(write_blocking, "i");
+MODULE_PARM_DESC(write_blocking, 
+                "The write function will block to write out all data");
+#endif
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
new file mode 100644 (file)
index 0000000..d96dd61
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Definitions for MCT (Magic Control Technology) USB-RS232 Converter Driver
+ *
+ *   Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ * This driver is for the device MCT USB-RS232 Converter (25 pin, Model No.
+ * U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+ * Model No. U232-P9). See http://www.mct.com.tw/p_u232.html for further
+ * information. The properties of this device are listed at the end of this
+ * file. This device is available from various distributors. I know Hana,
+ * http://www.hana.de and D-Link, http://www.dlink.com/products/usb/dsbs25.
+ *
+ * All of the information about the device was acquired by using SniffUSB
+ * on Windows98. The technical details of the reverse engineering are
+ * summarized at the end of this file.
+ */
+
+#ifndef __LINUX_USB_SERIAL_MCT_U232_H
+#define __LINUX_USB_SERIAL_MCT_U232_H
+
+#define MCT_U232_VID                   0x0711  /* Vendor Id */
+#define MCT_U232_PID                   0x0210  /* Product Id */
+
+/*
+ * Vendor Request Interface
+ */
+#define MCT_U232_SET_REQUEST_TYPE      0x40
+#define MCT_U232_GET_REQUEST_TYPE      0xc0
+
+#define MCT_U232_GET_MODEM_STAT_REQUEST 2  /* Get Modem Status Register (MSR) */
+#define MCT_U232_GET_MODEM_STAT_SIZE    1
+
+#define MCT_U232_GET_LINE_CTRL_REQUEST  6  /* Get Line Control Register (LCR) */
+#define MCT_U232_GET_LINE_CTRL_SIZE     1  /* ... not used by this driver */
+
+#define MCT_U232_SET_BAUD_RATE_REQUEST 5  /* Set Baud Rate Divisor */
+#define MCT_U232_SET_BAUD_RATE_SIZE     4
+
+#define MCT_U232_SET_LINE_CTRL_REQUEST 7  /* Set Line Control Register (LCR) */
+#define MCT_U232_SET_LINE_CTRL_SIZE     1
+
+#define MCT_U232_SET_MODEM_CTRL_REQUEST        10 /* Set Modem Control Register (MCR) */
+#define MCT_U232_SET_MODEM_CTRL_SIZE    1
+
+/*
+ * Baud rate (divisor)
+ */
+#define MCT_U232_BAUD_RATE(b)          (115200/b)
+
+/*
+ * Line Control Register (LCR)
+ */
+#define MCT_U232_SET_BREAK              0x40
+
+#define MCT_U232_PARITY_SPACE          0x38
+#define MCT_U232_PARITY_MARK           0x28
+#define MCT_U232_PARITY_EVEN           0x18
+#define MCT_U232_PARITY_ODD            0x08
+#define MCT_U232_PARITY_NONE           0x00
+
+#define MCT_U232_DATA_BITS_5            0x00
+#define MCT_U232_DATA_BITS_6            0x01
+#define MCT_U232_DATA_BITS_7            0x02
+#define MCT_U232_DATA_BITS_8            0x03
+
+#define MCT_U232_STOP_BITS_2            0x04
+#define MCT_U232_STOP_BITS_1            0x00
+
+/*
+ * Modem Control Register (MCR)
+ */
+#define MCT_U232_MCR_NONE               0x8     /* Deactivate DTR and RTS */
+#define MCT_U232_MCR_RTS                0xa     /* Activate RTS */
+#define MCT_U232_MCR_DTR                0x9     /* Activate DTR */
+
+/*
+ * Modem Status Register (MSR)
+ */
+#define MCT_U232_MSR_INDEX              0x0     /* data[index] */
+#define MCT_U232_MSR_CD                 0x80    /* Current CD */
+#define MCT_U232_MSR_RI                 0x40    /* Current RI */
+#define MCT_U232_MSR_DSR                0x20    /* Current DSR */
+#define MCT_U232_MSR_CTS                0x10    /* Current CTS */
+#define MCT_U232_MSR_DCD                0x08    /* Delta CD */
+#define MCT_U232_MSR_DRI                0x04    /* Delta RI */
+#define MCT_U232_MSR_DDSR               0x02    /* Delta DSR */
+#define MCT_U232_MSR_DCTS               0x01    /* Delta CTS */
+
+/*
+ * Line Status Register (LSR)
+ */
+#define MCT_U232_LSR_INDEX              1       /* data[index] */
+#define MCT_U232_LSR_ERR                0x80    /* OE | PE | FE | BI */
+#define MCT_U232_LSR_TEMT               0x40    /* transmit register empty */
+#define MCT_U232_LSR_THRE               0x20    /* transmit holding register empty */
+#define MCT_U232_LSR_BI                 0x10    /* break indicator */
+#define MCT_U232_LSR_FE                 0x08    /* framing error */
+#define MCT_U232_LSR_OE                 0x02    /* overrun error */
+#define MCT_U232_LSR_PE                 0x04    /* parity error */
+#define MCT_U232_LSR_OE                 0x02    /* overrun error */
+#define MCT_U232_LSR_DR                 0x01    /* receive data ready */
+
+
+/* -----------------------------------------------------------------------------
+ * Technical Specification reverse engineered with SniffUSB on Windows98
+ * =====================================================================
+ *
+ *  The technical details of the device have been acquired be using "SniffUSB"
+ *  and the vendor-supplied device driver (version 2.3A) under Windows98. To
+ *  identify the USB vendor-specific requests and to assign them to terminal 
+ *  settings (flow control, baud rate, etc.) the program "SerialSettings" from
+ *  William G. Greathouse has been proven to be very useful. I also used the
+ *  Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and 
+ *  observations are summarized below:
+ *
+ *  The USB requests seem to be directly mapped to the registers of a 8250,
+ *  16450 or 16550 UART. The FreeBSD handbook (appendix F.4 "Input/Output
+ *  devices") contains a comprehensive description of UARTs and its registers.
+ *  The bit descriptions are actually taken from there.
+ *
+ *
+ * Baud rate (divisor)
+ * -------------------
+ *
+ *   BmRequestType:  0x4 (0100 0000B)
+ *   bRequest:       0x5
+ *   wValue:         0x0
+ *   wIndex:         0x0
+ *   wLength:        0x4
+ *   Data:           divisor = 115200 / baud_rate
+ *
+ *
+ * Line Control Register (LCR)
+ * ---------------------------
+ *
+ *  BmRequestType:  0x4 (0100 0000B)    0xc (1100 0000B)
+ *  bRequest:       0x7                 0x6
+ *  wValue:         0x0
+ *  wIndex:         0x0
+ *  wLength:        0x1
+ *  Data:           LCR (see below)
+ *
+ *  Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data
+ *        transmit/receive register (THR/RBR) and the Interrupt Enable Register
+ *        (IER) is disabled. Any access to these ports is now redirected to the
+ *        Divisor Latch Registers. Setting this bit, loading the Divisor
+ *        Registers, and clearing DLAB should be done with interrupts disabled.
+ *  Bit 6: Set Break. When set to "1", the transmitter begins to transmit
+ *        continuous Spacing until this bit is set to "0". This overrides any
+ *        bits of characters that are being transmitted.
+ *  Bit 5: Stick Parity. When parity is enabled, setting this bit causes parity
+ *        to always be "1" or "0", based on the value of Bit 4.
+ *  Bit 4: Even Parity Select (EPS). When parity is enabled and Bit 5 is "0",
+ *        setting this bit causes even parity to be transmitted and expected.
+ *        Otherwise, odd parity is used.
+ *  Bit 3: Parity Enable (PEN). When set to "1", a parity bit is inserted
+ *        between the last bit of the data and the Stop Bit. The UART will also
+ *        expect parity to be present in the received data.
+ *  Bit 2: Number of Stop Bits (STB). If set to "1" and using 5-bit data words,
+ *        1.5 Stop Bits are transmitted and expected in each data word. For
+ *        6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected.
+ *        When this bit is set to "0", one Stop Bit is used on each data word.
+ *  Bit 1: Word Length Select Bit #1 (WLSB1)
+ *  Bit 0: Word Length Select Bit #0 (WLSB0)
+ *        Together these bits specify the number of bits in each data word.
+ *          1 0  Word Length
+ *          0 0  5 Data Bits
+ *          0 1  6 Data Bits
+ *          1 0  7 Data Bits
+ *          1 1  8 Data Bits
+ *
+ *  SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs
+ *  in the Win98 driver: the break does not work (bit 6 is not asserted) and the
+ *  sticky parity bit is not cleared when set once. The LCR can also be read
+ *  back with USB request 6 but this has never been observed with SniffUSB.
+ *
+ *
+ * Modem Control Register (MCR)
+ * ----------------------------
+ *
+ *  BmRequestType:  0x4  (0100 0000B)
+ *  bRequest:       0xa
+ *  wValue:         0x0
+ *  wIndex:         0x0
+ *  wLength:        0x1
+ *  Data:           MCR (Bit 4..7, see below)
+ *
+ *  Bit 7: Reserved, always 0.
+ *  Bit 6: Reserved, always 0.
+ *  Bit 5: Reserved, always 0.
+ *  Bit 4: Loop-Back Enable. When set to "1", the UART transmitter and receiver
+ *        are internally connected together to allow diagnostic operations. In
+ *        addition, the UART modem control outputs are connected to the UART
+ *        modem control inputs. CTS is connected to RTS, DTR is connected to
+ *        DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD.
+ *  Bit 3: OUT 2. An auxiliary output that the host processor may set high or
+ *        low. In the IBM PC serial adapter (and most clones), OUT 2 is used
+ *        to tri-state (disable) the interrupt signal from the
+ *        8250/16450/16550 UART.
+ *  Bit 2: OUT 1. An auxiliary output that the host processor may set high or
+ *        low. This output is not used on the IBM PC serial adapter.
+ *  Bit 1: Request to Send (RTS). When set to "1", the output of the UART -RTS
+ *        line is Low (Active).
+ *  Bit 0: Data Terminal Ready (DTR). When set to "1", the output of the UART
+ *        -DTR line is Low (Active).
+ *
+ *  SniffUSB observations: Bit 2 and 4 seem not to be used but bit 3 has been
+ *  seen _always_ set.
+ *
+ *
+ * Modem Status Register (MSR)
+ * ---------------------------
+ *
+ *  BmRequestType:  0xc  (1100 0000B)
+ *  bRequest:       0x2
+ *  wValue:         0x0
+ *  wIndex:         0x0
+ *  wLength:        0x1
+ *  Data:           MSR (see below)
+ *
+ *  Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the
+ *        UART.
+ *  Bit 6: Ring Indicator (RI). Reflects the state of the RI line on the UART.
+ *  Bit 5: Data Set Ready (DSR). Reflects the state of the DSR line on the UART.
+ *  Bit 4: Clear To Send (CTS). Reflects the state of the CTS line on the UART.
+ *  Bit 3: Delta Data Carrier Detect (DDCD). Set to "1" if the -DCD line has
+ *        changed state one more more times since the last time the MSR was
+ *        read by the host.
+ *  Bit 2: Trailing Edge Ring Indicator (TERI). Set to "1" if the -RI line has
+ *        had a low to high transition since the last time the MSR was read by
+ *        the host.
+ *  Bit 1: Delta Data Set Ready (DDSR). Set to "1" if the -DSR line has changed
+ *        state one more more times since the last time the MSR was read by the
+ *        host.
+ *  Bit 0: Delta Clear To Send (DCTS). Set to "1" if the -CTS line has changed
+ *        state one more times since the last time the MSR was read by the
+ *        host.
+ *
+ *  SniffUSB observations: the MSR is also returned as first byte on the
+ *  interrupt-in endpoint 0x83 to signal changes of modem status lines. The USB
+ *  request to read MSR cannot be applied during normal device operation.
+ *
+ *
+ * Line Status Register (LSR)
+ * --------------------------
+ *
+ *  Bit 7   Error in Receiver FIFO. On the 8250/16450 UART, this bit is zero.
+ *         This bit is set to "1" when any of the bytes in the FIFO have one or
+ *         more of the following error conditions: PE, FE, or BI.
+ *  Bit 6   Transmitter Empty (TEMT). When set to "1", there are no words
+ *         remaining in the transmit FIFO or the transmit shift register. The
+ *         transmitter is completely idle.
+ *  Bit 5   Transmitter Holding Register Empty (THRE). When set to "1", the FIFO
+ *         (or holding register) now has room for at least one additional word
+ *         to transmit. The transmitter may still be transmitting when this bit
+ *         is set to "1".
+ *  Bit 4   Break Interrupt (BI). The receiver has detected a Break signal.
+ *  Bit 3   Framing Error (FE). A Start Bit was detected but the Stop Bit did not
+ *         appear at the expected time. The received word is probably garbled.
+ *  Bit 2   Parity Error (PE). The parity bit was incorrect for the word received.
+ *  Bit 1   Overrun Error (OE). A new word was received and there was no room in
+ *         the receive buffer. The newly-arrived word in the shift register is
+ *         discarded. On 8250/16450 UARTs, the word in the holding register is
+ *         discarded and the newly- arrived word is put in the holding register.
+ *  Bit 0   Data Ready (DR). One or more words are in the receive FIFO that the
+ *         host may read. A word must be completely received and moved from the
+ *         shift register into the FIFO (or holding register for 8250/16450
+ *         designs) before this bit is set.
+ *
+ *  SniffUSB observations: the LSR is returned as second byte on the interrupt-in
+ *  endpoint 0x83 to signal error conditions. Such errors have been seen with
+ *  minicom/zmodem transfers (CRC errors).
+ *
+ *
+ * Flow control
+ * ------------
+ *
+ *  SniffUSB observations: no flow control specific requests have been realized
+ *  apart from DTR/RTS settings. Both signals are dropped for no flow control
+ *  but asserted for hardware or software flow control.
+ *
+ *
+ * Endpoint usage
+ * --------------
+ *
+ *  SniffUSB observations: the bulk-out endpoint 0x1 and interrupt-in endpoint
+ *  0x81 is used to transmit and receive characters. The second interrupt-in 
+ *  endpoint 0x83 signals exceptional conditions like modem line changes and 
+ *  errors. The first byte returned is the MSR and the second byte the LSR.
+ *
+ *
+ * Other observations
+ * ------------------
+ *
+ *  Queued bulk transfers like used in visor.c did not work. 
+ *  
+ *
+ * Properties of the USB device used (as found in /var/log/messages)
+ * -----------------------------------------------------------------
+ *
+ *  Manufacturer: MCT Corporation.
+ *  Product: USB-232 Interfact Controller
+ *  SerialNumber: U2S22050
+ *
+ *    Length              = 18
+ *    DescriptorType      = 01
+ *    USB version         = 1.00
+ *    Vendor:Product      = 0711:0210
+ *    MaxPacketSize0      = 8
+ *    NumConfigurations   = 1
+ *    Device version      = 1.02
+ *    Device Class:SubClass:Protocol = 00:00:00
+ *      Per-interface classes
+ *  Configuration:
+ *    bLength             =    9
+ *    bDescriptorType     =   02
+ *    wTotalLength        = 0027
+ *    bNumInterfaces      =   01
+ *    bConfigurationValue =   01
+ *    iConfiguration      =   00
+ *    bmAttributes        =   c0
+ *    MaxPower            =  100mA
+ *
+ *    Interface: 0
+ *    Alternate Setting:  0
+ *      bLength             =    9
+ *      bDescriptorType     =   04
+ *      bInterfaceNumber    =   00
+ *      bAlternateSetting   =   00
+ *      bNumEndpoints       =   03
+ *      bInterface Class:SubClass:Protocol =   00:00:00
+ *      iInterface          =   00
+ *      Endpoint:
+ *       bLength             =    7
+ *       bDescriptorType     =   05
+ *       bEndpointAddress    =   81 (in)
+ *       bmAttributes        =   03 (Interrupt)
+ *       wMaxPacketSize      = 0040
+ *       bInterval           =   02
+ *      Endpoint:
+ *       bLength             =    7
+ *       bDescriptorType     =   05
+ *       bEndpointAddress    =   01 (out)
+ *       bmAttributes        =   02 (Bulk)
+ *       wMaxPacketSize      = 0040
+ *       bInterval           =   00
+ *      Endpoint:
+ *       bLength             =    7
+ *       bDescriptorType     =   05
+ *       bEndpointAddress    =   83 (in)
+ *       bmAttributes        =   03 (Interrupt)
+ *       wMaxPacketSize      = 0002
+ *       bInterval           =   02
+ */
+
+#endif /* __LINUX_USB_SERIAL_MCT_U232_H */
+
index 983d3a6e55994a07cd1011621dcc89d9055a1000..40cf2f74649ba764f34cc84126074fcc3e554737 100644 (file)
@@ -1755,11 +1755,11 @@ static void rh_int_timer_do(unsigned long ptr)
                urbp = (struct urb_priv *)u->hcpriv;
                if (urbp) {
                        /* Check if the FSBR timed out */
-                       if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
+                       if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
                                uhci_fsbr_timeout(uhci, u);
 
                        /* Check if the URB timed out */
-                       if (u->timeout && time_after(u->timeout, jiffies)) {
+                       if (u->timeout && time_after_eq(jiffies, u->timeout)) {
                                u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
                                uhci_unlink_urb(u);
                        }
index 71e014d4f35c19103b1629ddd85280af7a30886b..b4cace1dcf7971bae666182d5c337c19904b761a 100644 (file)
@@ -2626,14 +2626,14 @@ _static int process_urb (uhci_t *s, struct list_head *p)
                        // Completion
                        if (urb->complete) {
                                urb->dev = NULL;
+                               spin_unlock(&s->urb_list_lock);
                                urb->complete ((struct urb *) urb);
                                // Re-submit the URB if ring-linked
                                if (is_ring && (urb->status != -ENOENT) && !contains_killed) {
                                        urb->dev=usb_dev;
-                                       spin_unlock(&s->urb_list_lock);
                                        uhci_submit_urb (urb);
-                                       spin_lock(&s->urb_list_lock);
                                }
+                               spin_lock(&s->urb_list_lock);
                        }
                        
                        usb_dec_dev_use (usb_dev);
index e97f458cf739faaa2e568851ff8a2a537eab04d6..fad7e48f66fde5a3e689837b974d24688a582afb 100644 (file)
@@ -2053,9 +2053,9 @@ int usb_new_device(struct usb_device *dev)
        if (err < 0) {
                err("unable to get device %d configuration (error=%d)",
                        dev->devnum, err);
-               usb_destroy_configuration(dev);
                clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
                dev->devnum = -1;
+               usb_free_dev(dev);
                return 1;
        }
 
index f2d10d6770b47cc2e7ac9b40f05f16f1b5f4e171..dbe463e0502faa59da8592525548469923f3a749 100644 (file)
@@ -758,12 +758,6 @@ void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private)
        bh->b_private = private;
 }
 
-static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
-{
-       mark_buffer_uptodate(bh, uptodate);
-       unlock_buffer(bh);
-}
-
 static void end_buffer_io_bad(struct buffer_head *bh, int uptodate)
 {
        mark_buffer_uptodate(bh, uptodate);
@@ -1001,7 +995,7 @@ repeat:
         * and it is clean.
         */
        if (bh) {
-               init_buffer(bh, end_buffer_io_sync, NULL);
+               init_buffer(bh, end_buffer_io_bad, NULL);
                bh->b_dev = dev;
                bh->b_blocknr = block;
                bh->b_state = 1 << BH_Mapped;
@@ -1182,67 +1176,6 @@ struct buffer_head * bread(kdev_t dev, int block, int size)
        return NULL;
 }
 
-/*
- * Ok, breada can be used as bread, but additionally to mark other
- * blocks for reading as well. End the argument list with a negative
- * number.
- */
-
-#define NBUF 16
-
-struct buffer_head * breada(kdev_t dev, int block, int bufsize,
-       unsigned int pos, unsigned int filesize)
-{
-       struct buffer_head * bhlist[NBUF];
-       unsigned int blocks;
-       struct buffer_head * bh;
-       int index;
-       int i, j;
-
-       if (pos >= filesize)
-               return NULL;
-
-       if (block < 0)
-               return NULL;
-
-       bh = getblk(dev, block, bufsize);
-       index = BUFSIZE_INDEX(bh->b_size);
-
-       if (buffer_uptodate(bh))
-               return(bh);   
-       else ll_rw_block(READ, 1, &bh);
-
-       blocks = (filesize - pos) >> (9+index);
-
-       if (blocks > NBUF) 
-               blocks = NBUF;
-
-       bhlist[0] = bh;
-       j = 1;
-       for(i=1; i<blocks; i++) {
-               bh = getblk(dev,block+i,bufsize);
-               if (buffer_uptodate(bh)) {
-                       brelse(bh);
-                       break;
-               }
-               else bhlist[j++] = bh;
-       }
-
-       /* Request the read for these buffers, and then release them. */
-       if (j>1)  
-               ll_rw_block(READA, (j-1), bhlist+1); 
-       for(i=1; i<j; i++)
-               brelse(bhlist[i]);
-
-       /* Wait for this buffer, and then continue on. */
-       bh = bhlist[0];
-       wait_on_buffer(bh);
-       if (buffer_uptodate(bh))
-               return bh;
-       brelse(bh);
-       return NULL;
-}
-
 /*
  * Note: the caller should wake up the buffer_wait list if needed.
  */
@@ -1417,40 +1350,6 @@ no_grow:
        goto try_again;
 }
 
-static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size)
-{
-       struct buffer_head *head, *bh, *tail;
-       int block;
-
-       if (!PageLocked(page))
-               BUG();
-       /*
-        * Allocate async buffer heads pointing to this page, just for I/O.
-        * They don't show up in the buffer hash table, but they *are*
-        * registered in page->buffers.
-        */
-       head = create_buffers(page, size, 1);
-       if (page->buffers)
-               BUG();
-       if (!head)
-               BUG();
-       tail = head;
-       for (bh = head; bh; bh = bh->b_this_page) {
-               block = *(b++);
-
-               tail = bh;
-               init_buffer(bh, end_buffer_io_async, NULL);
-               bh->b_dev = dev;
-               bh->b_blocknr = block;
-
-               set_bit(BH_Mapped, &bh->b_state);
-       }
-       tail->b_this_page = head;
-       page_cache_get(page);
-       page->buffers = head;
-       return 0;
-}
-
 static void unmap_buffer(struct buffer_head * bh)
 {
        if (buffer_mapped(bh)) {
@@ -1515,7 +1414,7 @@ int block_flushpage(struct page *page, unsigned long offset)
        return 1;
 }
 
-static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
+static void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)
 {
        struct buffer_head *bh, *head, *tail;
 
@@ -1525,7 +1424,7 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
 
        bh = head;
        do {
-               bh->b_dev = inode->i_dev;
+               bh->b_dev = dev;
                bh->b_blocknr = 0;
                bh->b_end_io = end_buffer_io_bad;
                tail = bh;
@@ -1586,20 +1485,20 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
        int err, i;
        unsigned long block;
        struct buffer_head *bh, *head;
-       struct buffer_head *arr[MAX_BUF_PER_PAGE];
-       int nr = 0;
 
        if (!PageLocked(page))
                BUG();
 
        if (!page->buffers)
-               create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
+               create_empty_buffers(page, inode->i_dev, inode->i_sb->s_blocksize);
        head = page->buffers;
 
        block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 
        bh = head;
        i = 0;
+
+       /* Stage 1: make sure we have all the buffers mapped! */
        do {
                /*
                 * If the buffer isn't up-to-date, we can't be sure
@@ -1616,29 +1515,33 @@ static int __block_write_full_page(struct inode *inode, struct page *page, get_b
                        if (buffer_new(bh))
                                unmap_underlying_metadata(bh);
                }
-               set_bit(BH_Uptodate, &bh->b_state);
-               set_bit(BH_Dirty, &bh->b_state);
+               bh = bh->b_this_page;
+               block++;
+       } while (bh != head);
+
+       /* Stage 2: lock the buffers, mark them dirty */
+       do {
+               lock_buffer(bh);
                bh->b_end_io = end_buffer_io_async;
                atomic_inc(&bh->b_count);
-               arr[nr++] = bh;
+               set_bit(BH_Uptodate, &bh->b_state);
+               set_bit(BH_Dirty, &bh->b_state);
                bh = bh->b_this_page;
-               block++;
        } while (bh != head);
 
-       if (nr) {
-               ll_rw_block(WRITE, nr, arr);
-       } else {
-               UnlockPage(page);
-       }
+       /* Stage 3: submit the IO */
+       do {
+               submit_bh(WRITE, bh);
+               bh = bh->b_this_page;           
+       } while (bh != head);
+
+       /* Done - end_buffer_io_async will unlock */
        SetPageUptodate(page);
        return 0;
+
 out:
-       if (nr) {
-               ll_rw_block(WRITE, nr, arr);
-       } else {
-               UnlockPage(page);
-       }
        ClearPageUptodate(page);
+       UnlockPage(page);
        return err;
 }
 
@@ -1654,7 +1557,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
 
        blocksize = inode->i_sb->s_blocksize;
        if (!page->buffers)
-               create_empty_buffers(page, inode, blocksize);
+               create_empty_buffers(page, inode->i_dev, blocksize);
        head = page->buffers;
 
        bbits = inode->i_sb->s_blocksize_bits;
@@ -1669,7 +1572,6 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
                        continue;
                if (block_start >= to)
                        break;
-               bh->b_end_io = end_buffer_io_sync;
                if (!buffer_mapped(bh)) {
                        err = get_block(inode, block, bh, 1);
                        if (err)
@@ -1766,14 +1668,13 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
        unsigned long iblock, lblock;
        struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
        unsigned int blocksize, blocks;
-       char *kaddr = NULL;
        int nr, i;
 
        if (!PageLocked(page))
                PAGE_BUG(page);
        blocksize = inode->i_sb->s_blocksize;
        if (!page->buffers)
-               create_empty_buffers(page, inode, blocksize);
+               create_empty_buffers(page, inode->i_dev, blocksize);
        head = page->buffers;
 
        blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
@@ -1793,35 +1694,40 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
                                        continue;
                        }
                        if (!buffer_mapped(bh)) {
-                               if (!kaddr)
-                                       kaddr = kmap(page);
-                               memset(kaddr + i*blocksize, 0, blocksize);
+                               memset(kmap(page) + i*blocksize, 0, blocksize);
                                flush_dcache_page(page);
+                               kunmap(page);
                                set_bit(BH_Uptodate, &bh->b_state);
                                continue;
                        }
                }
 
-               init_buffer(bh, end_buffer_io_async, NULL);
-               atomic_inc(&bh->b_count);
                arr[nr] = bh;
                nr++;
        } while (i++, iblock++, (bh = bh->b_this_page) != head);
 
-       if (nr) {
-               if (Page_Uptodate(page))
-                       BUG();
-               ll_rw_block(READ, nr, arr);
-       } else {
+       if (!nr) {
                /*
                 * all buffers are uptodate - we can set the page
                 * uptodate as well.
                 */
                SetPageUptodate(page);
                UnlockPage(page);
+               return 0;
        }
-       if (kaddr)
-               kunmap(page);
+
+       /* Stage two: lock the buffers */
+       for (i = 0; i < nr; i++) {
+               struct buffer_head * bh = arr[i];
+               lock_buffer(bh);
+               bh->b_end_io = end_buffer_io_async;
+               atomic_inc(&bh->b_count);
+       }
+
+       /* Stage 3: start the IO */
+       for (i = 0; i < nr; i++)
+               submit_bh(READ, arr[i]);
+
        return 0;
 }
 
@@ -1963,7 +1869,7 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t
                goto out;
 
        if (!page->buffers)
-               create_empty_buffers(page, inode, blocksize);
+               create_empty_buffers(page, inode->i_dev, blocksize);
 
        /* Find the buffer that contains "offset" */
        bh = page->buffers;
@@ -1989,7 +1895,6 @@ int block_truncate_page(struct address_space *mapping, loff_t from, get_block_t
        if (Page_Uptodate(page))
                set_bit(BH_Uptodate, &bh->b_state);
 
-       bh->b_end_io = end_buffer_io_sync;
        if (!buffer_uptodate(bh)) {
                err = -EIO;
                ll_rw_block(READ, 1, &bh);
@@ -2263,67 +2168,30 @@ int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
  */
 int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size)
 {
-       struct buffer_head *head, *bh, *arr[MAX_BUF_PER_PAGE];
-       int nr, fresh /* temporary debugging flag */, block;
+       struct buffer_head *head, *bh;
 
        if (!PageLocked(page))
                panic("brw_page: page not locked for I/O");
-//     ClearPageError(page);
-       /*
-        * We pretty much rely on the page lock for this, because
-        * create_page_buffers() might sleep.
-        */
-       fresh = 0;
-       if (!page->buffers) {
-               create_page_buffers(rw, page, dev, b, size);
-               fresh = 1;
-       }
+
        if (!page->buffers)
-               BUG();
+               create_empty_buffers(page, dev, size);
+       head = bh = page->buffers;
 
-       head = page->buffers;
-       bh = head;
-       nr = 0;
+       /* Stage 1: lock all the buffers */
        do {
-               block = *(b++);
+               lock_buffer(bh);
+               bh->b_blocknr = *(b++);
+               set_bit(BH_Mapped, &bh->b_state);
+               bh->b_end_io = end_buffer_io_async;
+               atomic_inc(&bh->b_count);
+               bh = bh->b_this_page;
+       } while (bh != head);
 
-               if (fresh && (atomic_read(&bh->b_count) != 0))
-                       BUG();
-               if (rw == READ) {
-                       if (!fresh)
-                               BUG();
-                       if (!buffer_uptodate(bh)) {
-                               arr[nr++] = bh;
-                               atomic_inc(&bh->b_count);
-                       }
-               } else { /* WRITE */
-                       if (!bh->b_blocknr) {
-                               if (!block)
-                                       BUG();
-                               bh->b_blocknr = block;
-                       } else {
-                               if (!block)
-                                       BUG();
-                       }
-                       set_bit(BH_Uptodate, &bh->b_state);
-                       set_bit(BH_Dirty, &bh->b_state);
-                       arr[nr++] = bh;
-                       atomic_inc(&bh->b_count);
-               }
+       /* Stage 2: start the IO */
+       do {
+               submit_bh(rw, bh);
                bh = bh->b_this_page;
        } while (bh != head);
-       if ((rw == READ) && nr) {
-               if (Page_Uptodate(page))
-                       BUG();
-               ll_rw_block(rw, nr, arr);
-       } else {
-               if (!nr && rw == READ) {
-                       SetPageUptodate(page);
-                       UnlockPage(page);
-               }
-               if (nr && (rw == WRITE))
-                       ll_rw_block(rw, nr, arr);
-       }
        return 0;
 }
 
index 5f5ec196fbe582a309beb609ef51407bd5958dd5..c7b63f358c29fe254c19b4f56cb076af79be2144 100644 (file)
@@ -127,7 +127,7 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head
 
        if (!ahead || secno + ahead >= s->s_hpfs_fs_size)
                *bhp = bh = bread(dev, secno, 512);
-       else *bhp = bh = breada(dev, secno, 512, 0, (ahead + 1) << 9);
+       else *bhp = bh = bread(dev, secno, 512);
        if (bh != NULL)
                return bh->b_data;
        else {
@@ -175,7 +175,7 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
 
        if (!ahead || secno + 4 + ahead > s->s_hpfs_fs_size)
                qbh->bh[0] = bh = bread(dev, secno, 512);
-       else qbh->bh[0] = bh = breada(dev, secno, 512, 0, (ahead + 4) << 9);
+       else qbh->bh[0] = bh = bread(dev, secno, 512);
        if (!bh)
                goto bail0;
        memcpy(data, bh->b_data, 512);
index 4821de8d346aa03285ca6b64a7ac548621bda4be..564a47b321ebfdc3b295d91cbab147e99033a116 100644 (file)
@@ -533,13 +533,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
            NFS_FILEID(inode) != fattr.fileid)
                goto out_bad;
 
-       /* Filehandle matches? */
-       if (memcmp(NFS_FH(inode), fhandle.data, sizeof(struct nfs_fh)))
-               goto out_bad;
-
        /* Ok, remember that we successfully checked it.. */
        nfs_refresh_inode(inode, &fattr);
 
+       if (nfs_inode_is_stale(inode, &fhandle, &fattr))
+               goto out_bad;
+
  out_valid_renew:
        nfs_renew_times(dentry);
 out_valid:
index a205c3ad4a281230971a333275d32e6a8ad94d80..029b673f50dc6c70276a37def603ed5d7142a8fb 100644 (file)
@@ -613,7 +613,7 @@ nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
        return 1;
 }
 
-static int
+int
 nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
        /* Empty inodes are not stale */
@@ -628,7 +628,7 @@ nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fat
 
        /* Has the filehandle changed? If so is the old one stale? */
        if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
-           __nfs_revalidate_inode(NFS_SERVER(inode),inode) < 0)
+           __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
                return 1;
 
        return 0;
@@ -866,7 +866,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                inode->i_dev, (long long)NFS_FILEID(inode));
 
        lock_kernel();
-       if (!inode || is_bad_inode(inode)) {
+       if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) {
                unlock_kernel();
                return -ESTALE;
        }
@@ -878,8 +878,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
                        return status;
                }
                if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
-                       unlock_kernel();
-                       return 0;
+                       status = NFS_STALE(inode) ? -ESTALE : 0;
+                       goto out_nowait;
                }
        }
        NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
@@ -888,6 +888,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        if (status) {
                dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
                         inode->i_dev, (long long)NFS_FILEID(inode), status);
+               if (status == -ESTALE) {
+                       NFS_FLAGS(inode) |= NFS_INO_STALE;
+                       remove_inode_hash(inode);
+               }
                goto out;
        }
 
@@ -902,6 +906,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 out:
        NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
        wake_up(&inode->i_wait);
+ out_nowait:
        unlock_kernel();
        return status;
 }
index b2d5c40998f4dc422b822c5e49f098d909d47617..7b62899c12b6a433df4df26c757d99f7576e1d77 100644 (file)
@@ -124,7 +124,7 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        qname.len  = entry->len;
                        entry->ino = find_inode_number(dentry, &qname);
                        if (!entry->ino)
-                               entry->ino = smb_invent_inos(1);
+                               entry->ino = iunique(dentry->d_sb, 2);
                }
 
                if (filldir(dirent, entry->name, entry->len, 
@@ -325,7 +325,7 @@ smb_lookup(struct inode *dir, struct dentry *dentry)
                goto add_entry;
        if (!error) {
                error = -EACCES;
-               finfo.f_ino = smb_invent_inos(1);
+               finfo.f_ino = iunique(dentry->d_sb, 2);
                inode = smb_iget(dir->i_sb, &finfo);
                if (inode) {
        add_entry:
@@ -362,7 +362,7 @@ smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
                goto out_close;
 
        smb_renew_times(dentry);
-       fattr.f_ino = smb_invent_inos(1);
+       fattr.f_ino = iunique(dentry->d_sb, 2);
        inode = smb_iget(dentry->d_sb, &fattr);
        if (!inode)
                goto out_no_inode;
index f6c7a4112252173064d32444d1d6ab571ef2b26e..79627f8804709bbcc6cf69db44007460c35a5221 100644 (file)
@@ -48,8 +48,7 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
                DENTRY_PATH(dentry), count, offset, rsize);
 
        result = smb_open(dentry, SMB_O_RDONLY);
-       if (result < 0)
-       {
+       if (result < 0) {
                PARANOIA("%s/%s open failed, error=%d\n",
                         DENTRY_PATH(dentry), result);
                goto io_error;
@@ -59,7 +58,7 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
                if (count < rsize)
                        rsize = count;
 
-               result = smb_proc_read(dentry, offset, rsize, buffer);
+               result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
                if (result < 0)
                        goto io_error;
 
@@ -103,25 +102,27 @@ smb_readpage(struct file *file, struct page *page)
  * Offset is the data offset within the page.
  */
 static int
-smb_writepage_sync(struct dentry *dentry, struct page *page,
+smb_writepage_sync(struct inode *inode, struct page *page,
                   unsigned long offset, unsigned int count)
 {
-       struct inode *inode = dentry->d_inode;
        u8 *buffer = page_address(page) + offset;
-       int wsize = smb_get_wsize(server_from_dentry(dentry));
+       int wsize = smb_get_wsize(server_from_inode(inode));
        int result, written = 0;
 
        offset += page->index << PAGE_CACHE_SHIFT;
-       VERBOSE("file %s/%s, count=%d@%ld, wsize=%d\n",
-               DENTRY_PATH(dentry), count, offset, wsize);
+       VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
+               inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
 
        do {
                if (count < wsize)
                        wsize = count;
 
-               result = smb_proc_write(dentry, offset, wsize, buffer);
-               if (result < 0)
+               result = smb_proc_write(inode, offset, wsize, buffer);
+               if (result < 0) {
+                       PARANOIA("failed write, wsize=%d, result=%d\n",
+                                wsize, result);
                        break;
+               }
                /* N.B. what if result < wsize?? */
 #ifdef SMBFS_PARANOIA
                if (result < wsize)
@@ -153,9 +154,7 @@ static int
 smb_writepage(struct page *page)
 {
        struct address_space *mapping = page->mapping;
-       struct dentry *dentry;
        struct inode *inode;
-       struct list_head *head;
        unsigned long end_index;
        unsigned offset = PAGE_CACHE_SIZE;
        int err;
@@ -166,12 +165,6 @@ smb_writepage(struct page *page)
        if (!inode)
                BUG();
 
-       /* Pick the first dentry for this inode. */
-       head = &inode->i_dentry;
-       if (list_empty(head))
-               BUG();  /* We need one, are we guaranteed to have one?  */
-       dentry = list_entry(head->next, struct dentry, d_alias);
-
        end_index = inode->i_size >> PAGE_CACHE_SHIFT;
 
        /* easy case */
@@ -184,7 +177,7 @@ smb_writepage(struct page *page)
                return -EIO;
 do_it:
        get_page(page);
-       err = smb_writepage_sync(dentry, page, 0, offset);
+       err = smb_writepage_sync(inode, page, 0, offset);
        SetPageUptodate(page);
        UnlockPage(page);
        put_page(page);
@@ -200,7 +193,7 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset,
        DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry), 
               count, (page->index << PAGE_CACHE_SHIFT)+offset);
 
-       return smb_writepage_sync(dentry, page, offset, count);
+       return smb_writepage_sync(dentry->d_inode, page, offset, count);
 }
 
 static ssize_t
@@ -281,7 +274,7 @@ static int smb_commit_write(struct file *file, struct page *page,
 
 struct address_space_operations smb_file_aops = {
        readpage: smb_readpage,
-       /* writepage: smb_writepage, */
+       writepage: smb_writepage,
        prepare_write: smb_prepare_write,
        commit_write: smb_commit_write
 };
@@ -325,8 +318,16 @@ out:
 static int
 smb_file_open(struct inode *inode, struct file * file)
 {
+       int result;
+       struct dentry *dentry = file->f_dentry;
+       int smb_mode = (file->f_mode & O_ACCMODE) - 1;
+
        lock_kernel();
+       result = smb_open(dentry, smb_mode);
+       if (result)
+               goto out;
        inode->u.smbfs_i.openers++;
+out:
        unlock_kernel();
        return 0;
 }
index bcc900626c46c1a4e2c5feb42803e17d12fe201d..e502fb60b0e6e2174ec1263c4524a7c31599c1b0 100644 (file)
@@ -53,22 +53,6 @@ static struct super_operations smb_sops =
        statfs:         smb_statfs,
 };
 
-/* FIXME: Look at all inodes whether so that we do not get duplicate
- * inode numbers. */
-
-unsigned long
-smb_invent_inos(unsigned long n)
-{
-       static unsigned long ino = 2;
-
-       if (ino + 2*n < ino)
-       {
-               /* wrap around */
-               ino = 2;
-       }
-       ino += n;
-       return ino;
-}
 
 /* We are always generating a new inode here */
 struct inode *
@@ -282,7 +266,7 @@ out:
 static void
 smb_delete_inode(struct inode *ino)
 {
-       DEBUG1("\n");
+       DEBUG1("ino=%ld\n", ino->i_ino);
        lock_kernel();
        if (smb_close(ino))
                PARANOIA("could not close inode %ld\n", ino->i_ino);
index 7863cd2da6201291042d57f28e0fca6b40c0336b..f0444f97d7d4c2fb44dc002464fcd5e1340957c6 100644 (file)
@@ -1072,9 +1072,9 @@ smb_close_fileid(struct dentry *dentry, __u16 fileid)
    file-id would not be valid after a reconnection. */
 
 int
-smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
+smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
 {
-       struct smb_sb_info *server = server_from_dentry(dentry);
+       struct smb_sb_info *server = server_from_inode(inode);
        __u16 returned_count, data_len;
        unsigned char *buf;
        int result;
@@ -1082,7 +1082,7 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
        smb_lock_server(server);
        smb_setup_header(server, SMBread, 5, 0);
        buf = server->packet;
-       WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+       WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);
        WSET(buf, smb_vwv1, count);
        DSET(buf, smb_vwv2, offset);
        WSET(buf, smb_vwv4, 0);
@@ -1114,25 +1114,26 @@ smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
        result = data_len;
 
 out:
-       VERBOSE("file %s/%s, count=%d, result=%d\n",
-               DENTRY_PATH(dentry), count, result);
+       VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
+               inode->ino, inode->u.smbfs_i.fileid, count, result);
        smb_unlock_server(server);
        return result;
 }
 
 int
-smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data)
+smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
 {
-       struct smb_sb_info *server = server_from_dentry(dentry);
+       struct smb_sb_info *server = server_from_inode(inode);
        int result;
        __u8 *p;
        
-       VERBOSE("file %s/%s, count=%d@%ld, packet_size=%d\n",
-               DENTRY_PATH(dentry), count, offset, server->packet_size);
+       VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
+               inode->ino, inode->u.smbfs_i.fileid, count, offset,
+               server->packet_size);
 
        smb_lock_server(server);
        p = smb_setup_header(server, SMBwrite, 5, count + 3);
-       WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+       WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
        WSET(server->packet, smb_vwv1, count);
        DSET(server->packet, smb_vwv2, offset);
        WSET(server->packet, smb_vwv4, 0);
index 69ea9cf48686046f0c73a841104ca6c6528cc8e5..9dba26eebfa40f432c35caacb352bd37141ed7c3 100644 (file)
@@ -38,13 +38,22 @@ struct apm_bios_info {
        unsigned short  dseg_len;
 };
 
-                               /* Results of APM Installation Check */
+/* Results of APM Installation Check */
 #define APM_16_BIT_SUPPORT     0x0001
 #define APM_32_BIT_SUPPORT     0x0002
 #define APM_IDLE_SLOWS_CLOCK   0x0004
 #define APM_BIOS_DISABLED              0x0008
 #define APM_BIOS_DISENGAGED     0x0010
 
+/*
+ * Data for APM that is persistant across module unload/load
+ */
+struct apm_info {
+       struct apm_bios_info    bios;
+       unsigned short          connection_version;
+       int                     get_power_status_broken;
+};
+
 /*
  * The APM function codes
  */
@@ -91,12 +100,9 @@ struct apm_bios_info {
 #define        APM_FUNC_TIMER_GET      2
 
 /*
- * in init/main.c
+ * in arch/i386/kernel/setup.c
  */
-extern struct apm_bios_info    apm_bios_info;
-
-extern int             apm_register_callback(int (*callback)(apm_event_t));
-extern void            apm_unregister_callback(int (*callback)(apm_event_t));
+extern struct apm_info apm_info;
 
 #endif /* __KERNEL__ */
 
@@ -176,7 +182,7 @@ extern void         apm_unregister_callback(int (*callback)(apm_event_t));
 /*
  * This is the "All Devices" ID communicated to the BIOS
  */
-#define APM_DEVICE_BALL                ((apm_bios_info.version > 0x0100) ? \
+#define APM_DEVICE_BALL                ((apm_info.connection_version > 0x0100) ? \
                                 APM_DEVICE_ALL : APM_DEVICE_OLD_ALL)
 #endif
 
index 9d0d0166b4eaa55d5c10d1d3698abe5bd6abfbe1..2ef374aa195f4090044f182655f9d3efa99c843b 100644 (file)
@@ -1193,6 +1193,7 @@ extern void file_moveto(struct file *new, struct file *old);
 extern struct buffer_head * get_hash_table(kdev_t, int, int);
 extern struct buffer_head * getblk(kdev_t, int, int);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
+extern void submit_bh(int, struct buffer_head *);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
 static inline void brelse(struct buffer_head *buf)
@@ -1209,7 +1210,6 @@ static inline void bforget(struct buffer_head *buf)
 extern void set_blocksize(kdev_t, int);
 extern unsigned int get_hardblocksize(kdev_t);
 extern struct buffer_head * bread(kdev_t, int, int);
-extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int);
 extern void wakeup_bdflush(int wait);
 
 extern int brw_page(int, struct page *, kdev_t, int [], int);
index ee3e8906c5d6e26efd2ba2fab2423256f9935e9b..50ee124718961a928ba1ac3f0d929c7d487aa7d4 100644 (file)
@@ -63,6 +63,8 @@ extern int vsprintf(char *buf, const char *, va_list);
 extern int get_option(char **str, int *pint);
 extern char *get_options(char *str, int nints, int *ints);
 extern unsigned long memparse(char *ptr, char **retptr);
+extern void dev_probe_lock(void);
+extern void dev_probe_unlock(void);
 
 extern int session_of_pgrp(int pgrp);
 
index a8a0a5dd6899990d9752cf6ea4389a05f3834d0d..a7330e249407ebc77eef4274f58ecd6bf5ab454b 100644 (file)
@@ -92,6 +92,7 @@ do { \
 
 #define NFS_FLAGS(inode)               ((inode)->u.nfs_i.flags)
 #define NFS_REVALIDATING(inode)                (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
+#define NFS_STALE(inode)               (NFS_FLAGS(inode) & NFS_INO_STALE)
 
 #define NFS_FILEID(inode)              ((inode)->u.nfs_i.fileid)
 #define NFS_FSID(inode)                        ((inode)->u.nfs_i.fsid)
@@ -138,6 +139,8 @@ unsigned long page_index(struct page *page)
 extern struct super_block *nfs_read_super(struct super_block *, void *, int);
 extern int init_nfs_fs(void);
 extern void nfs_zap_caches(struct inode *);
+extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
+                               struct nfs_fattr *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
                                struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
index e795aaacf4ec6c47ab359963b43c123c425dbd2d..d948de2588565851687651d8753c91addcb5d67b 100644 (file)
@@ -150,8 +150,9 @@ extern signed long FASTCALL(schedule_timeout(signed long timeout));
 asmlinkage void schedule(void);
 
 extern int schedule_task(struct tq_struct *task);
-extern void run_schedule_tasks(void);
+extern void flush_scheduled_tasks(void);
 extern int start_context_thread(void);
+extern int current_is_keventd(void);
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
index e475057fc1340f6ab579b330cc7e1a2e477e503c..501ea4b964d6864900e1694af99e4acfdae5e5f4 100644 (file)
@@ -126,8 +126,8 @@ int smb_errno(struct smb_sb_info *);
 int smb_close(struct inode *);
 int smb_close_fileid(struct dentry *, __u16);
 int smb_open(struct dentry *, int);
-int smb_proc_read(struct dentry *, off_t, int, char *);
-int smb_proc_write(struct dentry *, off_t, int, const char *);
+int smb_proc_read(struct inode *, off_t, int, char *);
+int smb_proc_write(struct inode *, off_t, int, const char *);
 int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
 int smb_proc_mv(struct dentry *, struct dentry *);
 int smb_proc_mkdir(struct dentry *);
index 4bad7e9280096e33695813e3a203167f32d2099a..0d14b83ae52a92d5c352e9dd64f06fe34ea479f2 100644 (file)
@@ -14,8 +14,9 @@
 #include <linux/types.h>
 #include <linux/smb.h>
 
-/* Get the server for the specified dentry */
-#define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
+/* structure access macros */
+#define server_from_inode(inode) (&(inode)->i_sb->u.smbfs_sb)
+#define server_from_dentry(dentry) (&(dentry)->d_sb->u.smbfs_sb)
 #define SB_of(server) ((struct super_block *) ((char *)(server) - \
        (unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
 
index 285936f5cd9448afa87bc952e566451599e04cc9..a0363ffa677514a80bbb00d3e29dfdfa63d37ab1 100644 (file)
@@ -14,6 +14,7 @@
 #define _LINUX_TQUEUE_H
 
 #include <linux/spinlock.h>
+#include <linux/list.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
 
  */
 
 struct tq_struct {
-       struct tq_struct *next;         /* linked list of active bh's */
+       struct list_head list;          /* linked list of active bh's */
        unsigned long sync;             /* must be initialized to zero */
        void (*routine)(void *);        /* function to call */
        void *data;                     /* argument to function */
 };
 
-typedef struct tq_struct * task_queue;
+typedef struct list_head task_queue;
 
-#define DECLARE_TASK_QUEUE(q)  task_queue q = NULL
+#define DECLARE_TASK_QUEUE(q)  LIST_HEAD(q)
+#define TQ_ACTIVE(q)           (!list_empty(&q))
 
 extern task_queue tq_timer, tq_immediate, tq_disk;
 
@@ -51,9 +53,10 @@ extern task_queue tq_timer, tq_immediate, tq_disk;
  * To implement your own list of active bottom halfs, use the following
  * two definitions:
  *
- * struct tq_struct *my_bh = NULL;
+ * DECLARE_TASK_QUEUE(my_bh);
  * struct tq_struct run_my_bh = {
- *     0, 0, (void (*)(void *)) run_task_queue, &my_bh
+ *     routine: (void (*)(void *)) run_task_queue,
+ *     data: &my_bh
  * };
  *
  * To activate a bottom half on your list, use:
@@ -82,8 +85,7 @@ static inline int queue_task(struct tq_struct *bh_pointer,
        if (!test_and_set_bit(0,&bh_pointer->sync)) {
                unsigned long flags;
                spin_lock_irqsave(&tqueue_lock, flags);
-               bh_pointer->next = *bh_list;
-               *bh_list = bh_pointer;
+               list_add_tail(&bh_pointer->list, bh_list);
                spin_unlock_irqrestore(&tqueue_lock, flags);
                ret = 1;
        }
@@ -95,28 +97,29 @@ static inline int queue_task(struct tq_struct *bh_pointer,
  */
 static inline void run_task_queue(task_queue *list)
 {
-       if (*list) {
+       while (!list_empty(list)) {
                unsigned long flags;
-               struct tq_struct *p;
+               struct list_head *next;
 
                spin_lock_irqsave(&tqueue_lock, flags);
-               p = *list;
-               *list = NULL;
-               spin_unlock_irqrestore(&tqueue_lock, flags);
-               
-               while (p) {
+               next = list->next;
+               if (next != list) {
                        void *arg;
                        void (*f) (void *);
-                       struct tq_struct *save_p;
-                       arg    = p -> data;
-                       f      = p -> routine;
-                       save_p = p;
-                       p      = p -> next;
-                       smp_mb();
-                       save_p -> sync = 0;
+                       struct tq_struct *p;
+
+                       list_del(next);
+                       p = list_entry(next, struct tq_struct, list);
+                       arg = p->data;
+                       f = p->routine;
+                       p->sync = 0;
+                       spin_unlock_irqrestore(&tqueue_lock, flags);
+
                        if (f)
-                               (*f)(arg);
+                               f(arg);
+                       continue;
                }
+               spin_unlock_irqrestore(&tqueue_lock, flags);
        }
 }
 
index 42f0011cdc6e8fd9f1f665f4282da05455c3ec63..39e9f2eed0c3ed06c6cf97f8185f06cf6eb2b436 100644 (file)
@@ -545,7 +545,7 @@ struct usb_bus {
        struct list_head inodes;
 };
 
-#define USB_MAXCHILDREN (8)    /* This is arbitrary */
+#define USB_MAXCHILDREN                (16)    /* This is arbitrary */
 
 struct usb_device {
        int devnum;                     /* Device number on USB bus */
index c1e83578b4c525b5de46e95c1998f40110184200..7e8ac67a68f660db298118f85c1f1150f798ad4f 100644 (file)
@@ -716,14 +716,6 @@ static void __init do_basic_setup(void)
        /* Mount the root filesystem.. */
        mount_root();
 
-#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
-       /* do this after other 'do this last' stuff, because we want
-        * to minimize spurious executions of /sbin/hotplug
-        * during boot-up
-        */
-       net_notifier_init();
-#endif
-
        mount_devfs_fs ();
 
 #ifdef CONFIG_BLK_DEV_INITRD
index a8caa863a4eac9a8a24cd1cdf3da03959e4bc9c6..864a70131c88dfadc27ed1468362d061fc973e83 100644 (file)
@@ -3,7 +3,12 @@
  *
  * Mechanism for running arbitrary tasks in process context
  *
- * dwmw2@redhat.com
+ * dwmw2@redhat.com:           Genesis
+ *
+ * andrewm@uow.edu.au:         2.4.0-test12
+ *     - Child reaping
+ *     - Support for tasks which re-add themselves
+ *     - flush_scheduled_tasks.
  */
 
 #define __KERNEL_SYSCALLS__
 
 static DECLARE_TASK_QUEUE(tq_context);
 static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
+static DECLARE_WAIT_QUEUE_HEAD(context_task_done);
 static int keventd_running;
+static struct task_struct *keventd_task;
+
+static int need_keventd(const char *who)
+{
+       if (keventd_running == 0)
+               printk(KERN_ERR "%s(): keventd has not started\n", who);
+       return keventd_running;
+}
+       
+int current_is_keventd(void)
+{
+       int ret = 0;
+       if (need_keventd(__FUNCTION__))
+               ret = (current == keventd_task);
+       return ret;
+}
 
+/**
+ * schedule_task - schedule a function for subsequent execution in process context.
+ * @task: pointer to a &tq_struct which defines the function to be scheduled.
+ *
+ * May be called from interrupt context.  The scheduled function is run at some
+ * time in the near future by the keventd kernel thread.  If it can sleep, it
+ * should be designed to do so for the minimum possible time, as it will be
+ * stalling all other scheduled tasks.
+ *
+ * schedule_task() returns non-zero if the task was successfully scheduled.
+ * If @task is already residing on a task queue then schedule_task() fails
+ * to schedule your task and returns zero.
+ */
 int schedule_task(struct tq_struct *task)
 {
        int ret;
-       if (keventd_running == 0)
-               printk(KERN_ERR "schedule_task(): keventd has not started\n");
+       need_keventd(__FUNCTION__);
        ret = queue_task(task, &tq_context);
        wake_up(&context_task_wq);
        return ret;
@@ -38,6 +72,7 @@ static int context_thread(void *dummy)
        daemonize();
        strcpy(curtask->comm, "keventd");
        keventd_running = 1;
+       keventd_task = curtask;
 
        spin_lock_irq(&curtask->sigmask_lock);
        siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
@@ -50,18 +85,19 @@ static int context_thread(void *dummy)
        siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
        do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
 
-       /*
-        * If one of the functions on a task queue re-adds itself
-        * to the task queue we call schedule() in state TASK_RUNNING
-        */
-       for (;;) {
+       /*
+        * If one of the functions on a task queue re-adds itself
+        * to the task queue we call schedule() in state TASK_RUNNING
+        */
+       for (;;) {
                set_task_state(curtask, TASK_INTERRUPTIBLE);
-               add_wait_queue(&context_task_wq, &wait);
-               if (tq_context)
+               add_wait_queue(&context_task_wq, &wait);
+               if (TQ_ACTIVE(tq_context))
                        set_task_state(curtask, TASK_RUNNING);
                schedule();
-               remove_wait_queue(&context_task_wq, &wait);
-               run_task_queue(&tq_context);
+               remove_wait_queue(&context_task_wq, &wait);
+               run_task_queue(&tq_context);
+               wake_up(&context_task_done);
                if (signal_pending(curtask)) {
                        while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
                                ;
@@ -71,12 +107,43 @@ static int context_thread(void *dummy)
        }
 }
 
-/*
- * Run the tq_context queue right now.  Must be called from process context
+/**
+ * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion.
+ *
+ * Forces execution of the schedule_task() queue and blocks until its completion.
+ *
+ * If a kernel subsystem uses schedule_task() and wishes to flush any pending
+ * tasks, it should use this function.  This is typically used in driver shutdown
+ * handlers.
+ *
+ * The caller should hold no spinlocks and should hold no semaphores which could
+ * cause the scheduled tasks to block.
  */
-void run_schedule_tasks(void)
+static struct tq_struct dummy_task;
+
+void flush_scheduled_tasks(void)
 {
-       run_task_queue(&tq_context);
+       int count;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /*
+        * Do it twice. It's possible, albeit highly unlikely, that
+        * the caller queued a task immediately before calling us,
+        * and that the eventd thread was already past the run_task_queue()
+        * but not yet into wake_up(), so it woke us up before completing
+        * the caller's queued task or our new dummy task.
+        */
+       add_wait_queue(&context_task_done, &wait);
+       for (count = 0; count < 2; count++) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+
+               /* Queue a dummy task to make sure we get kicked */
+               schedule_task(&dummy_task);
+
+               /* Wait for it to complete */
+               schedule();
+       }
+       remove_wait_queue(&context_task_done, &wait);
 }
        
 int start_context_thread(void)
@@ -86,5 +153,5 @@ int start_context_thread(void)
 }
 
 EXPORT_SYMBOL(schedule_task);
-EXPORT_SYMBOL(run_schedule_tasks);
+EXPORT_SYMBOL(flush_scheduled_tasks);
 
index c60bafe8cdd6fed16a7a661c849b8b203cad084d..6b7138e33332560ead60dd782615db2b5c5f8ab0 100644 (file)
@@ -302,9 +302,9 @@ static inline void __exit_mm(struct task_struct * tsk)
 {
        struct mm_struct * mm = tsk->mm;
 
+       mm_release();
        if (mm) {
                atomic_inc(&mm->mm_count);
-               mm_release();
                if (mm != tsk->active_mm) BUG();
                /* more a memory barrier than a real lock */
                task_lock(tsk);
index 0239b8b0c190717e62f0837992c9be3d2d506467..b68392685aa5a50e594cbbcf0747d9d156d8eea9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/unistd.h>
+#include <linux/kmod.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
@@ -256,126 +257,107 @@ EXPORT_SYMBOL(hotplug_path);
 
 #endif /* CONFIG_HOTPLUG */
 
-
-static int exec_helper (void *arg)
-{
-       long ret;
-       void **params = (void **) arg;
-       char *path = (char *) params [0];
-       char **argv = (char **) params [1];
-       char **envp = (char **) params [2];
-
-       ret = exec_usermodehelper (path, argv, envp);
-       if (ret < 0)
-               ret = -ret;
-       do_exit(ret);
-}
-
 struct subprocess_info {
        struct semaphore *sem;
        char *path;
        char **argv;
        char **envp;
-       int retval;
+       pid_t retval;
 };
 
 /*
- * This is a standalone child of keventd.  It forks off another thread which
- * is the desired usermode helper and then waits for the child to exit.
- * We return the usermode process's exit code, or some -ve error code.
+ * This is the task which runs the usermode application
  */
 static int ____call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
-       struct task_struct *curtask = current;
-       void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
-       pid_t pid, pid2;
-       mm_segment_t fs;
-       int retval = 0;
-
-       if (!curtask->fs->root) {
-               printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
-               retval = -EPERM;
-               goto up_and_out;
-       }
-       if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
-               printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
-               retval = pid;
-               goto up_and_out;
-       }
+       int retval;
 
-       if (retval >= 0) {
-               /* Block everything but SIGKILL/SIGSTOP */
-               spin_lock_irq(&curtask->sigmask_lock);
-               siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
-               recalc_sigpending(curtask);
-               spin_unlock_irq(&curtask->sigmask_lock);
-
-               /* Allow the system call to access kernel memory */
-               fs = get_fs();
-               set_fs(KERNEL_DS);
-               pid2 = waitpid(pid, &retval, __WCLONE);
-               if (pid2 == -1 && errno < 0)
-                       pid2 = errno;
-               set_fs(fs);
-
-               if (pid2 != pid) {
-                       printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
-                       retval = (pid2 < 0) ? pid2 : -1;
-               }
-       }
+       retval = -EPERM;
+       if (current->fs->root)
+               retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
 
-up_and_out:
-       sub_info->retval = retval;
-       curtask->exit_signal = SIGCHLD;         /* Wake up parent */
-       up_and_exit(sub_info->sem, retval);
+       /* Exec failed? */
+       sub_info->retval = (pid_t)retval;
+       do_exit(0);
 }
 
 /*
- * This is a schedule_task function, so we must not sleep for very long at all.
- * But the exec'ed process could do anything at all.  So we launch another
- * kernel thread.
+ * This is run by keventd.
  */
 static void __call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
        pid_t pid;
 
-       if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
-               printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
+       /*
+        * CLONE_VFORK: wait until the usermode helper has execve'd successfully
+        * We need the data structures to stay around until that is done.
+        */
+       pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
+       if (pid < 0)
                sub_info->retval = pid;
-               up(sub_info->sem);
-       }
+       up(sub_info->sem);
 }
 
-/*
- * This function can be called via do_exit->__exit_files, which means that
- * we're partway through exitting and things break if we fork children.
- * So we use keventd to parent the usermode helper.
- * We return the usermode application's exit code or some -ve error.
+/**
+ * call_usermodehelper - start a usermode application
+ * @path: pathname for the application
+ * @argv: null-terminated argument list
+ * @envp: null-terminated environment list
+ *
+ * Runs a user-space application.  The application is started asynchronously.  It
+ * runs as a child of keventd.  It runs with full root capabilities.  keventd silently
+ * reaps the child when it exits.
+ *
+ * Must be called from process context.  Returns zero on success, else a negative
+ * error code.
  */
-int call_usermodehelper (char *path, char **argv, char **envp)
+int call_usermodehelper(char *path, char **argv, char **envp)
 {
        DECLARE_MUTEX_LOCKED(sem);
        struct subprocess_info sub_info = {
-               sem:    &sem,
-               path:   path,
-               argv:   argv,
-               envp:   envp,
-               retval: 0,
+               sem:            &sem,
+               path:           path,
+               argv:           argv,
+               envp:           envp,
+               retval:         0,
        };
        struct tq_struct tqs = {
-               next:           0,
-               sync:           0,
                routine:        __call_usermodehelper,
                data:           &sub_info,
        };
 
-       schedule_task(&tqs);
-       down(&sem);             /* Wait for an error or completion */
+       if (path[0] == '\0')
+               goto out;
+
+       if (current_is_keventd()) {
+               /* We can't wait on keventd! */
+               __call_usermodehelper(&sub_info);
+       } else {
+               schedule_task(&tqs);
+               down(&sem);             /* Wait until keventd has started the subprocess */
+       }
+out:
        return sub_info.retval;
 }
 
+/*
+ * This is for the serialisation of device probe() functions
+ * against device open() functions
+ */
+static DECLARE_MUTEX(dev_probe_sem);
+
+void dev_probe_lock(void)
+{
+       down(&dev_probe_sem);
+}
+
+void dev_probe_unlock(void)
+{
+       up(&dev_probe_sem);
+}
+
 EXPORT_SYMBOL(exec_usermodehelper);
 EXPORT_SYMBOL(call_usermodehelper);
 
index abbe3d9a55375a78ee50def44e13d09bcf88c901..4ed94117e63409a516a3502835031b42811c9de1 100644 (file)
@@ -185,7 +185,6 @@ EXPORT_SYMBOL(getblk);
 EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bread);
-EXPORT_SYMBOL(breada);
 EXPORT_SYMBOL(__brelse);
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);
index c30ebb8d5f4d86d98a36c4833410a90568f5d0e8..579b065f3f466d06aba30040f60c97820a62388c 100644 (file)
@@ -680,7 +680,7 @@ void do_timer(struct pt_regs *regs)
        update_process_times(user_mode(regs));
 #endif
        mark_bh(TIMER_BH);
-       if (tq_timer)
+       if (TQ_ACTIVE(tq_timer))
                mark_bh(TQUEUE_BH);
 }
 
index aca470c072aa9e1e683e6358361ce1a6d3f2898a..c49ae2ff694caa4632afcc1f73ae5a4a111e6bac 100644 (file)
@@ -154,6 +154,12 @@ static void sample_queue(unsigned long dummy);
 static struct timer_list samp_timer = { function: sample_queue };
 #endif
 
+#ifdef CONFIG_HOTPLUG
+static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+#else
+#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#endif
+
 /*
  *     Our notifier list
  */
@@ -2196,9 +2202,11 @@ int dev_ioctl(unsigned int cmd, void *arg)
                        if (!capable(CAP_NET_ADMIN))
                                return -EPERM;
                        dev_load(ifr.ifr_name);
+                       dev_probe_lock();
                        rtnl_lock();
                        ret = dev_ifsioc(&ifr, cmd);
                        rtnl_unlock();
+                       dev_probe_unlock();
                        return ret;
        
                case SIOCGIFMEM:
@@ -2217,9 +2225,11 @@ int dev_ioctl(unsigned int cmd, void *arg)
                        if (cmd >= SIOCDEVPRIVATE &&
                            cmd <= SIOCDEVPRIVATE + 15) {
                                dev_load(ifr.ifr_name);
+                               dev_probe_lock();
                                rtnl_lock();
                                ret = dev_ifsioc(&ifr, cmd);
                                rtnl_unlock();
+                               dev_probe_unlock();
                                if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                                        return -EFAULT;
                                return ret;
@@ -2388,10 +2398,12 @@ int register_netdevice(struct net_device *dev)
        if (ret)
                return ret;
 #endif /* CONFIG_NET_DIVERT */
-       
+
        /* Notify protocols, that a new device appeared. */
        notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
+       net_run_sbin_hotplug(dev, "register");
+
        return 0;
 }
 
@@ -2475,6 +2487,8 @@ int unregister_netdevice(struct net_device *dev)
                /* Shutdown queueing discipline. */
                dev_shutdown(dev);
 
+               net_run_sbin_hotplug(dev, "unregister");
+
                /* Notify protocols, that we are about to destroy
                   this device. They should clean all the things.
                 */
@@ -2714,29 +2728,15 @@ int __init net_dev_init(void)
 /* Notify userspace when a netdevice event occurs,
  * by running '/sbin/hotplug net' with certain
  * environment variables set.
- *
- * Currently reported events are listed in netdev_event_names[].
  */
 
-/* /sbin/hotplug ONLY executes for events named here */
-static char *netdev_event_names[] = {
-       [NETDEV_REGISTER]       = "register",
-       [NETDEV_UNREGISTER]     = "unregister",
-};
-
-static int run_sbin_hotplug(struct notifier_block *this,
-                           unsigned long event, void *ptr)
+static int net_run_sbin_hotplug(struct net_device *dev, char *action)
 {
-       struct net_device *dev = (struct net_device *) ptr;
-       char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+       char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
        int i;
 
-       if ((event >= ARRAY_SIZE(netdev_event_names)) ||
-           !netdev_event_names[event])
-               return NOTIFY_DONE;
-
        sprintf(ifname, "INTERFACE=%s", dev->name);
-       sprintf(action, "ACTION=%s", netdev_event_names[event]);
+       sprintf(action_str, "ACTION=%s", action);
 
         i = 0;
         argv[i++] = hotplug_path;
@@ -2748,27 +2748,9 @@ static int run_sbin_hotplug(struct notifier_block *this,
        envp [i++] = "HOME=/";
        envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
        envp [i++] = ifname;
-       envp [i++] = action;
+       envp [i++] = action_str;
        envp [i] = 0;
        
-       call_usermodehelper (argv [0], argv, envp);
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block sbin_hotplug = {
-       notifier_call: run_sbin_hotplug,
-};
-
-/*
- * called from init/main.c, -after- all the initcalls are complete.
- * Registers a hook that calls /sbin/hotplug on every netdev
- * addition and removal.
- */
-void __init net_notifier_init (void)
-{
-       if (register_netdevice_notifier(&sbin_hotplug))
-               printk (KERN_WARNING "unable to register netdev notifier\n"
-                       KERN_WARNING "/sbin/hotplug will not be run.\n");
+       return call_usermodehelper(argv [0], argv, envp);
 }
 #endif
index 7af589b756a9a3556ec7d8bc019249bb25f3128a..276f7bd4f0f177ed0b95a736ec56a7536fb76a29 100644 (file)
@@ -519,6 +519,7 @@ int devinet_ioctl(unsigned int cmd, void *arg)
                return -EINVAL;
        }
 
+       dev_probe_lock();
        rtnl_lock();
 
        if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
@@ -649,10 +650,12 @@ int devinet_ioctl(unsigned int cmd, void *arg)
        }
 done:
        rtnl_unlock();
+       dev_probe_unlock();
        return ret;
 
 rarok:
        rtnl_unlock();
+       dev_probe_unlock();
        if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
                return -EFAULT;
        return 0;