This patch updates the keyspan_pda driver, which includes new firmware
and support for the Entregra and Xircom devices.



diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c  Thu Jan  3 21:41:54 2002
+++ b/drivers/usb/serial/keyspan_pda.c  Thu Jan  3 21:41:54 2002
@@ -1,7 +1,7 @@
 /*
- * USB Keyspan PDA Converter driver
+ * USB Keyspan PDA / Xircom / Entregra Converter driver
  *
- * Copyright (c) 1999, 2000 Greg Kroah-Hartman <[EMAIL PROTECTED]>
+ * Copyright (c) 1999 - 2001 Greg Kroah-Hartman        <[EMAIL PROTECTED]>
  * Copyright (c) 1999, 2000 Brian Warner       <[EMAIL PROTECTED]>
  * Copyright (c) 2000 Al Borchers              <[EMAIL PROTECTED]>
  *
@@ -12,6 +12,17 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (09/07/2001) gkh
+ *     cleaned up the Xircom support.  Added ids for Entregra device which is
+ *     the same as the Xircom device.  Enabled the code to be compiled for
+ *     either Xircom or Keyspan devices.
+ *
+ * (08/11/2001) Cristian M. Craciunescu
+ *     support for Xircom PGSDB9
+ *
+ * (05/31/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (04/08/2001) gb
  *     Identify version on module load.
  * 
@@ -82,13 +93,32 @@
        __u8 data[16];
 };
 
+/* make a simple define to handle if we are compiling keyspan_pda or xircom support */
+#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || 
+defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE)
+       #define KEYSPAN
+#else
+       #undef KEYSPAN
+#endif
+#if defined(CONFIG_USB_SERIAL_XIRCOM) || defined(CONFIG_USB_SERIAL_XIRCOM_MODULE)
+       #define XIRCOM
+#else
+       #undef XIRCOM
+#endif
+
+#ifdef KEYSPAN
 #include "keyspan_pda_fw.h"
+#endif
+
+#ifdef XIRCOM
+#include "xircom_pgs_fw.h"
+#endif
+
 #include "usb-serial.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Brian Warner <[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB Keyspan PDA Converter driver"
 
@@ -99,14 +129,25 @@
        struct tq_struct        unthrottle_task;
 };
 
+
 #define KEYSPAN_VENDOR_ID              0x06cd
 #define KEYSPAN_PDA_FAKE_ID            0x0103
 #define KEYSPAN_PDA_ID                 0x0104 /* no clue */
 
+/* For Xircom PGSDB9 and older Entregra version of the same device */
+#define XIRCOM_VENDOR_ID               0x085a
+#define XIRCOM_FAKE_ID                 0x8027
+#define ENTREGRA_VENDOR_ID             0x1645
+#define ENTREGRA_FAKE_ID               0x8093
+
 /* All of the device info needed for the Keyspan PDA serial converter */
 static __u16   keyspan_vendor_id               = KEYSPAN_VENDOR_ID;
 static __u16   keyspan_pda_fake_product_id     = KEYSPAN_PDA_FAKE_ID;
 static __u16   keyspan_pda_product_id          = KEYSPAN_PDA_ID;
+static __u16   xircom_vendor_id                = XIRCOM_VENDOR_ID;
+static __u16   xircom_fake_product_id          = XIRCOM_FAKE_ID;
+static __u16   entregra_vendor_id              = ENTREGRA_VENDOR_ID;
+static __u16   entregra_fake_product_id        = ENTREGRA_FAKE_ID;
 
 
 
@@ -438,7 +479,6 @@
        int request_unthrottle = 0;
        int rc = 0;
        struct keyspan_pda_private *priv;
-       unsigned long flags;
 
        priv = (struct keyspan_pda_private *)(port->private);
        /* guess how much room is left in the device's ring buffer, and if we
@@ -468,7 +508,6 @@
           finished).  Also, the tx process is not throttled. So we are
           ready to write. */
 
-       spin_lock_irqsave (&port->port_lock, flags);
        count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
        /* Check if we might overrun the Tx buffer.   If so, ask the
@@ -488,13 +527,12 @@
                                     2*HZ);
                if (rc < 0) {
                        dbg(" roomquery failed");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return rc; /* failed */
+                       goto exit;
                }
                if (rc == 0) {
                        dbg(" roomquery returned 0 bytes");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return -EIO; /* device didn't return any data */
+                       rc = -EIO; /* device didn't return any data */
+                       goto exit;
                }
                dbg(" roomquery says %d", room);
                priv->tx_room = room;
@@ -511,8 +549,8 @@
                if (from_user) {
                        if( copy_from_user(port->write_urb->transfer_buffer,
                        buf, count) ) {
-                               spin_unlock_irqrestore (&port->port_lock, flags);
-                               return( -EFAULT );
+                               rc = -EFAULT;
+                               goto exit;
                        }
                }
                else {
@@ -524,10 +562,10 @@
                priv->tx_room -= count;
 
                port->write_urb->dev = port->serial->dev;
-               if (usb_submit_urb(port->write_urb)) {
+               rc = usb_submit_urb(port->write_urb);
+               if (rc) {
                        dbg(" usb_submit_urb(write bulk) failed");
-                       spin_unlock_irqrestore (&port->port_lock, flags);
-                       return (0);
+                       goto exit;
                }
        }
        else {
@@ -543,8 +581,9 @@
                        MOD_DEC_USE_COUNT;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
-       return (count);
+       rc = count;
+exit:
+       return rc;
 }
 
 
@@ -602,11 +641,10 @@
 {
        struct usb_serial *serial = port->serial;
        unsigned char room;
-       int rc;
+       int rc = 0;
        struct keyspan_pda_private *priv;
-       unsigned long flags;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        MOD_INC_USE_COUNT;
        ++port->open_count;
@@ -615,7 +653,6 @@
                port->active = 1;
  
                /* find out how much room is in the Tx ring */
-               spin_unlock_irqrestore (&port->port_lock, flags);
                rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                     6, /* write_room */
                                     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
@@ -625,7 +662,6 @@
                                     &room,
                                     1,
                                     2*HZ);
-               spin_lock_irqsave (&port->port_lock, flags);
                if (rc < 0) {
                        dbg(__FUNCTION__" - roomquery failed");
                        goto error;
@@ -641,7 +677,6 @@
 
                /* the normal serial device seems to always turn on DTR and RTS here,
                   so do the same */
-               spin_unlock_irqrestore (&port->port_lock, flags);
                if (port->tty->termios->c_cflag & CBAUD)
                        keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
                else
@@ -649,19 +684,22 @@
 
                /*Start reading from the device*/
                port->interrupt_in_urb->dev = serial->dev;
-               if (usb_submit_urb(port->interrupt_in_urb))
+               rc = usb_submit_urb(port->interrupt_in_urb);
+               if (rc) {
                        dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
-       } else {
-               spin_unlock_irqrestore (&port->port_lock, flags);
+                       goto error;
+               }
+
        }
 
 
-       return (0);
+       up (&port->sem);
+       return rc;
 error:
        --port->open_count;
        port->active = 0;
        MOD_DEC_USE_COUNT;
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
        return rc;
 }
 
@@ -669,28 +707,27 @@
 static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
 {
        struct usb_serial *serial = port->serial;
-       unsigned long flags;
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
-               /* the normal serial device seems to always shut off DTR and RTS now */
-               spin_unlock_irqrestore (&port->port_lock, flags);
-               if (port->tty->termios->c_cflag & HUPCL)
-                       keyspan_pda_set_modem_info(serial, 0);
-               spin_lock_irqsave (&port->port_lock, flags);
-
-               /* shutdown our bulk reads and writes */
-               usb_unlink_urb (port->write_urb);
-               usb_unlink_urb (port->interrupt_in_urb);
+               if (serial->dev) {
+                       /* the normal serial device seems to always shut off DTR and 
+RTS now */
+                       if (port->tty->termios->c_cflag & HUPCL)
+                               keyspan_pda_set_modem_info(serial, 0);
+
+                       /* shutdown our bulk reads and writes */
+                       usb_unlink_urb (port->write_urb);
+                       usb_unlink_urb (port->interrupt_in_urb);
+               }
                port->active = 0;
                port->open_count = 0;
        }
 
-       spin_unlock_irqrestore (&port->port_lock, flags);
+       up (&port->sem);
+       MOD_DEC_USE_COUNT;
 }
 
 
@@ -698,12 +735,25 @@
 static int keyspan_pda_fake_startup (struct usb_serial *serial)
 {
        int response;
-       const struct ezusb_hex_record *record;
+       const struct ezusb_hex_record *record = NULL;
 
        /* download the firmware here ... */
        response = ezusb_set_reset(serial, 1);
 
-       record = &keyspan_pda_firmware[0];
+#ifdef KEYSPAN
+       if (serial->dev->descriptor.idVendor == KEYSPAN_VENDOR_ID)
+               record = &keyspan_pda_firmware[0];
+#endif
+#ifdef XIRCOM
+       if ((serial->dev->descriptor.idVendor == XIRCOM_VENDOR_ID) ||
+           (serial->dev->descriptor.idVendor == ENTREGRA_VENDOR_ID))
+               record = &xircom_pgs_firmware[0];
+#endif
+       if (record == NULL) {
+               err(__FUNCTION__": unknown vendor, aborting.");
+               return -ENODEV;
+       }
+
        while(record->address != 0xffff) {
                response = ezusb_writememory(serial, record->address,
                                             (unsigned char *)record->data,
@@ -738,11 +788,9 @@
        if (!priv)
                return (1); /* error */
        init_waitqueue_head(&serial->port[0].write_wait);
-       priv->wakeup_task.next = NULL;
        priv->wakeup_task.sync = 0;
        priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write;
        priv->wakeup_task.data = (void *)(&serial->port[0]);
-       priv->unthrottle_task.next = NULL;
        priv->unthrottle_task.sync = 0;
        priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle;
        priv->unthrottle_task.data = (void *)(serial);
@@ -759,7 +807,8 @@
        kfree(serial->port[0].private);
 }
 
-struct usb_serial_device_type keyspan_pda_fake_device = {
+#ifdef KEYSPAN
+static struct usb_serial_device_type keyspan_pda_fake_device = {
        name:                   "Keyspan PDA - (prerenumeration)",
        idVendor:               &keyspan_vendor_id,
        idProduct:              &keyspan_pda_fake_product_id,
@@ -772,8 +821,39 @@
        num_ports:              1,
        startup:                keyspan_pda_fake_startup,
 };
+#endif
+
+#ifdef XIRCOM
+static struct usb_serial_device_type xircom_pgs_fake_device = {
+        name:                   "Xircom PGS - (prerenumeration)",
+       idVendor:               &xircom_vendor_id,
+       idProduct:              &xircom_fake_product_id,
+        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:              1,
+        startup:                keyspan_pda_fake_startup,
+};
+
+static struct usb_serial_device_type entregra_pgs_fake_device = {
+        name:                   "Entregra PGS - (prerenumeration)",
+               idVendor:               &entregra_vendor_id,
+       idProduct:              &entregra_fake_product_id,
+        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:              1,
+        startup:                keyspan_pda_fake_startup,
+};
+#endif
 
-struct usb_serial_device_type keyspan_pda_device = {
+static struct usb_serial_device_type keyspan_pda_device = {
        name:                   "Keyspan PDA",
        idVendor:               &keyspan_vendor_id,
        idProduct:              &keyspan_pda_product_id,
@@ -805,15 +885,28 @@
 {
        usb_serial_register (&keyspan_pda_fake_device);
        usb_serial_register (&keyspan_pda_device);
-       info(DRIVER_VERSION ":" DRIVER_DESC);
+#ifdef KEYSPAN
+       usb_serial_register (&keyspan_pda_fake_device);
+#endif
+#ifdef XIRCOM
+       usb_serial_register (&xircom_pgs_fake_device);
+       usb_serial_register (&entregra_pgs_fake_device);
+#endif
+       info(DRIVER_DESC " " DRIVER_VERSION);
        return 0;
 }
 
 
 static void __exit keyspan_pda_exit (void)
 {
-       usb_serial_deregister (&keyspan_pda_fake_device);
        usb_serial_deregister (&keyspan_pda_device);
+#ifdef KEYSPAN
+       usb_serial_deregister (&keyspan_pda_fake_device);
+#endif
+#ifdef XIRCOM
+       usb_serial_deregister (&entregra_pgs_fake_device);
+       usb_serial_deregister (&xircom_pgs_fake_device);
+#endif
 }
 
 
diff -Nru a/drivers/usb/serial/xircom_pgs.S b/drivers/usb/serial/xircom_pgs.S
--- /dev/null   Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/serial/xircom_pgs.S   Thu Jan  3 21:41:54 2002
@@ -0,0 +1,1192 @@
+/*  $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ * 
+ *  Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ *  the EzUSB microcontroller.
+ * 
+ *  (C) Copyright 2000 Brian Warner <[EMAIL PROTECTED]>
+ * 
+ *     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.
+ * 
+ *  "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ *  company.
+ * 
+ *  This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ *  in a little widget that has a DB-9 on one end and a USB plug on the other.
+ *  It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ *  as a baud-rate generator. The wiring is:
+ *   PC0/RxD0 <- rxd (DB9 pin 2)         PC4 <- dsr pin 6
+ *   PC1/TxD0 -> txd pin 3               PC5 <- ri  pin 9
+ *   PC2      -> rts pin 7               PC6 <- dcd pin 1
+ *   PC3      <- cts pin 8               PC7 -> dtr pin 4
+ *   PB1 -> line driver standby
+ *
+ *  The EzUSB register constants below come from their excellent documentation
+ *  and sample code (which used to be available at www.anchorchips.com, but
+ *  that has now been absorbed into Cypress' site and the CD-ROM contents
+ *  don't appear to be available online anymore). If we get multiple
+ *  EzUSB-based drivers into the kernel, it might be useful to pull them out
+ *  into a separate .h file.
+ * 
+ * THEORY OF OPERATION:
+ *
+ *   There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ *   EP2out is pure tx data. When it appears, the data is copied into the tx
+ *   ring and serial transmission is started if it wasn't already running. The
+ *   "tx buffer empty" interrupt may kick off another character if the ring
+ *   still has data. If the host is tx-blocked because the ring filled up,
+ *   it will request a "tx unthrottle" interrupt. If sending a serial character
+ *   empties the ring below the desired threshold, we set a bit that will send
+ *   up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ *   EP2in (interrupt) is used to send both rx chars and rx status messages
+ *   (only "tx unthrottle" at this time) back up to the host. The first byte
+ *   of the rx message indicates data (0) or status msg (1). Status messages
+ *   are sent before any data.
+ *
+ *   Incoming serial characters are put into the rx ring by the serial
+ *   interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ *   When the EP2in buffer returns, the interrupt prompts us to send more
+ *   rx chars (or status messages) if they are pending.
+ *
+ *   Device control happens through "vendor specific" control messages on EP0.
+ *   All messages are destined for the "Interface" (with the index always 0,
+ *   so that if their two-port device might someday use similar firmware, we
+ *   can use index=1 to refer to the second port). The messages defined are:
+ *
+ *    bRequest = 0 : set baud/bits/parity
+ *               1 : unused
+ *               2 : reserved for setting HW flow control (CTSRTS)
+ *               3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ *               4 : set break (on/off)
+ *               5 : reserved for requesting interrupts on pin state change
+ *               6 : query buffer room or chars in tx buffer
+ *               7 : request tx unthrottle interrupt
+ *
+ *  The host-side driver is set to recognize the device ID values stashed in
+ *  serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ *  start it running. This firmware will use EzUSB's "renumeration" trick by
+ *  simulating a bus disconnect, then reconnect with a different device ID
+ *  (encoded in the desc_device descriptor below). The host driver then
+ *  recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ *  EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ *  8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ *   basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ *   use totally different registers!
+ *  USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ *  gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ *  as31 -l keyspan_pda.asm
+ *  mv keyspan_pda.obj keyspan_pda.hex
+ *  perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ *  Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ *  AnchorChips, for making such an incredibly useful little microcontroller.
+ *  KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ *           apart and trace with an ohmmeter.
+ *
+ * TODO:
+ *  lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ *  control. Interrupting host upon change in DCD, etc, counting transitions.
+ *  Need to find a safe device id to use (the one used by the Keyspan firmware
+ *  under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ *  More baud rates. Oh, and the string-descriptor-length silicon bug
+ *  workaround should be implemented, but I'm lazy, and the consequence is
+ *  that the device name strings that show up in your kernel log will have
+ *  lots of trailing binary garbage in them (appears as ????). Device strings
+ *  should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ *  -Brian Warner <[EMAIL PROTECTED]>
+ *
+ */
+       
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+       
+       ;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+       .flag EUSB, EIE.0
+       .flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5         
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTBCFG #0x7f94
+#define PORTCCFG #0x7f95
+#define OEA    #0x7f9c
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+               
+       ;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+       .org 0
+       ljmp start
+       ;; interrupt vectors
+       .org 23H
+       ljmp serial_int
+       .byte 0
+       
+       .org 43H
+       ljmp USB_Jump_Table
+       .byte 0                 ; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+       .org 30H
+rx_ring_in:    .byte 0
+rx_ring_out:   .byte 0
+tx_ring_in:    .byte 0
+tx_ring_out:   .byte 0
+tx_unthrottle_threshold:       .byte 0
+               
+       .org 0x100H             ; wants to be on a page boundary
+USB_Jump_Table:
+       ljmp    ISR_Sudav       ; Setup Data Available
+       .byte 0
+       ljmp    0               ; Start of Frame
+       .byte 0
+       ljmp    0               ; Setup Data Loading
+       .byte 0
+       ljmp    0               ; Global Suspend
+       .byte   0
+       ljmp    0               ; USB Reset     
+       .byte   0
+       ljmp    0               ; Reserved
+       .byte   0
+       ljmp    0               ; End Point 0 In
+       .byte   0
+       ljmp    0               ; End Point 0 Out
+       .byte   0
+       ljmp    0               ; End Point 1 In
+       .byte   0
+       ljmp    0               ; End Point 1 Out
+       .byte   0
+       ljmp    ISR_Ep2in
+       .byte   0
+       ljmp    ISR_Ep2out
+       .byte   0
+
+
+       .org 0x200
+               
+start: mov SP,STACK-1 ; set stack
+       ;; clear local variables
+       clr a
+       mov tx_ring_in, a
+       mov tx_ring_out, a
+       mov rx_ring_in, a
+       mov rx_ring_out, a
+       mov tx_unthrottle_threshold, a
+       clr TX_RUNNING
+       clr DO_TX_UNTHROTTLE
+       
+       ;; clear fifo with "fe"
+       mov r1, 0
+       mov a, #0xfe
+       mov dptr, #tx_ring
+clear_tx_ring_loop:
+       movx @dptr, a
+       inc dptr
+       djnz r1, clear_tx_ring_loop
+
+       mov a, #0xfd
+       mov dptr, #rx_ring
+clear_rx_ring_loop:
+       movx @dptr, a
+       inc dptr
+       djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+;;; on Xircom the STANDBY is wired to PB6 and PC4 
+       mov dptr, PORTBCFG
+        mov a, #0xBf
+        movx @dptr, a
+       mov dptr, PORTCCFG
+        mov a, #0xef
+        movx @dptr, a
+       
+       ;; set OEC.4
+        mov a, #0x10
+        mov dptr,OEC
+        movx @dptr,a
+
+        ;; clear PC4
+        mov a, #0x00
+        mov dptr,OUTC
+        movx @dptr,a
+
+       ;; set OEB.6
+       mov a, #0x40
+       mov dptr,OEB
+       movx @dptr,a
+
+       ;; clear PB6
+       mov a, #0x00
+       mov dptr,OUTB
+       movx @dptr,a
+
+       ;; set OEC.[17]
+       mov a, #0x82
+       mov dptr,OEC
+       movx @dptr,a
+
+
+       ;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+       mov dptr, PORTCCFG
+       mov a, #0x03
+       movx @dptr, a
+       
+       ;; set up interrupts, autovectoring
+       ;; set BKPT
+       mov dptr, USBBAV
+       movx a,@dptr
+       setb acc.0              ; AVEN bit to 0
+       movx @dptr, a
+
+       mov a,#0x01             ; enable SUDAV: setup data available (for ep0)
+       mov dptr, USBIRQ
+       movx @dptr, a           ; clear SUDAVI
+       mov dptr, USBIEN
+       movx @dptr, a
+       
+       mov dptr, IN07IEN
+       mov a,#0x04             ; enable IN2 int
+       movx @dptr, a
+       
+       mov dptr, OUT07IEN
+       mov a,#0x04             ; enable OUT2 int
+       movx @dptr, a
+       mov dptr, OUT2BC
+       movx @dptr, a           ; arm OUT2
+
+;;     mov a, #0x84            ; turn on RTS, DTR
+;;     mov dptr,OUTC
+;;     movx @dptr, a
+
+       mov a, #0x7             ; turn on  DTR
+        mov dptr,USBBAV
+        movx @dptr, a
+
+       mov a, #0x20             ; turn on the RED led 
+        mov dptr,OEA
+        movx @dptr, a
+
+       mov a, #0x80            ; turn on  RTS
+        mov dptr,OUTC
+        movx @dptr, a
+
+       ;; setup the serial port. 9600 8N1.
+       mov a,#0x53             ; mode 1, enable rx, clear int
+       mov SCON, a
+       ;;  using timer2, in 16-bit baud-rate-generator mode
+       ;;   (xtal 12MHz, internal fosc 24MHz)
+       ;;  RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+       ;;  57600: 0xFFF2.F, say 0xFFF3
+       ;;   9600: 0xFFB1.E, say 0xFFB2
+       ;;    300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+               
+       mov T2CON, #030h        ; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+       mov r3, #5
+       acall set_baud
+       setb TR2
+       mov SCON, #050h
+       
+#if 0
+       mov r1, #0x40
+       mov a, #0x41
+send:  
+       mov SBUF, a
+       inc a
+       anl a, #0x3F
+       orl a, #0x40
+;      xrl a, #0x02
+wait1: 
+       jnb TI, wait1
+       clr TI
+       djnz r1, send
+;done: sjmp done
+
+#endif
+       
+       setb EUSB
+       setb EA
+       setb ES0
+       ;acall dump_stat
+
+       ;; hey, what say we RENUMERATE! (TRM p.62)
+       mov a, #0
+       mov dps, a
+       mov dptr, USBCS
+       mov a, #0x02            ; DISCON=0, DISCOE=0, RENUM=1
+       movx @dptr, a
+       ;; now presence pin is floating, simulating disconnect. wait 0.5s
+       mov r1, #46
+renum_wait1:
+       mov r2, #0
+renum_wait2:
+       mov r3, #0
+renum_wait3:
+       djnz r3, renum_wait3
+       djnz r2, renum_wait2
+       djnz r1, renum_wait1    ; wait about n*(256^2) 6MHz clocks
+       mov a, #0x06            ; DISCON=0, DISCOE=1, RENUM=1
+       movx @dptr, a
+       ;; we are back online. the host device will now re-query us
+       
+       
+main:  sjmp main
+
+       
+
+ISR_Sudav:
+       push dps
+       push dpl
+       push dph
+       push dpl1
+       push dph1
+       push acc
+       mov a,EXIF
+       clr acc.4
+       mov EXIF,a              ; clear INT2 first
+       mov dptr, USBIRQ        ; clear USB int
+       mov a,#01h
+       movx @dptr,a
+
+       ;; get request type
+       mov dptr, SETUPDAT
+       movx a, @dptr
+       mov r1, a               ; r1 = bmRequestType
+       inc dptr
+       movx a, @dptr
+       mov r2, a               ; r2 = bRequest
+       inc dptr
+       movx a, @dptr
+       mov r3, a               ; r3 = wValueL
+       inc dptr
+       movx a, @dptr
+       mov r4, a               ; r4 = wValueH
+
+       ;; main switch on bmRequest.type: standard or vendor
+       mov a, r1
+       anl a, #0x60
+       cjne a, #0x00, setup_bmreq_type_not_standard
+       ;; standard request: now main switch is on bRequest
+       ljmp setup_bmreq_is_standard
+       
+setup_bmreq_type_not_standard: 
+       ;; a still has bmreq&0x60
+       cjne a, #0x40, setup_bmreq_type_not_vendor
+       ;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+       ;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+       cjne r2, #0x00, setup_ctrl_not_00
+       ;; 00 is set baud, wValue[0] has baud rate index
+       lcall set_baud          ; index in r3, carry set if error
+       jc setup_bmreq_type_not_standard__do_stall
+       ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+       ljmp setup_stall
+setup_ctrl_not_00:
+       cjne r2, #0x01, setup_ctrl_not_01
+       ;; 01 is reserved for set bits (parity). TODO
+       ljmp setup_stall
+setup_ctrl_not_01:
+       cjne r2, #0x02, setup_ctrl_not_02
+       ;; 02 is set HW flow control. TODO
+       ljmp setup_stall
+setup_ctrl_not_02:
+       cjne r2, #0x03, setup_ctrl_not_03
+       ;; 03 is control pins (RTS, DTR).
+       ljmp control_pins       ; will jump to setup_done_ack,
+                               ;  or setup_return_one_byte
+setup_ctrl_not_03:
+       cjne r2, #0x04, setup_ctrl_not_04
+       ;; 04 is send break (really "turn break on/off"). TODO
+       cjne r3, #0x00, setup_ctrl_do_break_on
+       ;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+       mov dptr, PORTCCFG
+       movx a, @dptr
+       orl a, #0x02
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_ctrl_do_break_on:
+       ;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+       mov dptr, OUTC
+       movx a, @dptr
+       anl a, #0xfd            ; ~0x02
+       movx @dptr, a
+       mov dptr, PORTCCFG
+       movx a, @dptr
+       anl a, #0xfd            ; ~0x02
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_ctrl_not_04:
+       cjne r2, #0x05, setup_ctrl_not_05
+       ;; 05 is set desired interrupt bitmap. TODO
+       ljmp setup_stall
+setup_ctrl_not_05:
+       cjne r2, #0x06, setup_ctrl_not_06
+       ;; 06 is query room
+       cjne r3, #0x00, setup_ctrl_06_not_00
+       ;; 06, wValue[0]=0 is query write_room
+       mov a, tx_ring_out
+       setb c
+       subb a, tx_ring_in      ; out-1-in = 255 - (in-out)
+       ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+       cjne r3, #0x01, setup_ctrl_06_not_01
+       ;; 06, wValue[0]=1 is query chars_in_buffer
+       mov a, tx_ring_in
+       clr c
+       subb a, tx_ring_out     ; in-out
+       ljmp setup_return_one_byte
+setup_ctrl_06_not_01:  
+       ljmp setup_stall
+setup_ctrl_not_06:
+       cjne r2, #0x07, setup_ctrl_not_07
+       ;; 07 is request tx unthrottle interrupt
+       mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+       ljmp setup_done_ack
+setup_ctrl_not_07:
+       ljmp setup_stall
+       
+setup_bmreq_type_not_vendor:
+       ljmp setup_stall
+
+
+setup_bmreq_is_standard:       
+       cjne r2, #0x00, setup_breq_not_00
+       ;; 00:  Get_Status (sub-switch on bmRequestType: device, ep, int)
+       cjne r1, #0x80, setup_Get_Status_not_device
+       ;; Get_Status(device)
+       ;;  are we self-powered? no. can we do remote wakeup? no
+       ;;   so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+       mov dptr, IN0BUF
+       clr a
+       movx @dptr, a
+       inc dptr
+       movx @dptr, a
+       mov dptr, IN0BC
+       mov a, #2
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_Get_Status_not_device:
+       cjne r1, #0x82, setup_Get_Status_not_endpoint
+       ;; Get_Status(endpoint)
+       ;;  must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+       ;; for now: cheat. TODO
+       sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+       cjne r1, #0x81, setup_Get_Status_not_interface
+       ;; Get_Status(interface): return two zeros
+       sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:        
+       ljmp setup_stall
+       
+setup_breq_not_00:
+       cjne r2, #0x01, setup_breq_not_01
+       ;; 01:  Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+       cjne r3, #0x00, setup_Clear_Feature_not_stall
+       ;; Clear_Feature(stall). should clear a stall bit. TODO
+       ljmp setup_stall
+setup_Clear_Feature_not_stall:
+       cjne r3, #0x01, setup_Clear_Feature_not_rwake
+       ;; Clear_Feature(remote wakeup). ignored.
+       ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+       ljmp setup_stall
+       
+setup_breq_not_01:
+       cjne r2, #0x03, setup_breq_not_03
+       ;; 03:  Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+       cjne r3, #0x00, setup_Set_Feature_not_stall
+       ;; Set_Feature(stall). Should set a stall bit. TODO
+       ljmp setup_stall
+setup_Set_Feature_not_stall:
+       cjne r3, #0x01, setup_Set_Feature_not_rwake
+       ;; Set_Feature(remote wakeup). ignored.
+       ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+       ljmp setup_stall
+       
+setup_breq_not_03:     
+       cjne r2, #0x06, setup_breq_not_06
+       ;; 06:  Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+       cjne r4, #0x01, setup_Get_Descriptor_not_device
+       ;; Get_Descriptor(device)
+       mov dptr, SUDPTRH
+       mov a, #HIGH(desc_device)
+       movx @dptr, a
+       mov dptr, SUDPTRL
+       mov a, #LOW(desc_device)
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+       cjne r4, #0x02, setup_Get_Descriptor_not_config
+       ;; Get_Descriptor(config[n])
+       cjne r3, #0x00, setup_stall; only handle n==0
+       ;; Get_Descriptor(config[0])
+       mov dptr, SUDPTRH
+       mov a, #HIGH(desc_config1)
+       movx @dptr, a
+       mov dptr, SUDPTRL
+       mov a, #LOW(desc_config1)
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+       cjne r4, #0x03, setup_Get_Descriptor_not_string
+       ;; Get_Descriptor(string[wValueL])
+       ;;  if (wValueL >= maxstrings) stall
+       mov a, #((desc_strings_end-desc_strings)/2)
+       clr c
+       subb a,r3               ; a=4, r3 = 0..3 . if a<=0 then stall
+       jc  setup_stall
+       jz  setup_stall
+       mov a, r3
+       add a, r3               ; a = 2*wValueL
+       mov dptr, #desc_strings
+       add a, dpl
+       mov dpl, a
+       mov a, #0
+       addc a, dph
+       mov dph, a              ; dph = desc_strings[a]. big endian! (handy)
+       ;; it looks like my adapter uses a revision of the EZUSB that
+       ;; contains "rev D errata number 8", as hinted in the EzUSB example
+       ;; code. I cannot find an actual errata description on the Cypress
+       ;; web site, but from the example code it looks like this bug causes
+       ;; the length of string descriptors to be read incorrectly, possibly
+       ;; sending back more characters than the descriptor has. The workaround
+       ;; is to manually send out all of the data. The consequence of not
+       ;; using the workaround is that the strings gathered by the kernel
+       ;; driver are too long and are filled with trailing garbage (including
+       ;; leftover strings). Writing this out by hand is a nuisance, so for
+       ;; now I will just live with the bug.
+       movx a, @dptr
+       mov r1, a
+       inc dptr
+       movx a, @dptr
+       mov r2, a
+       mov dptr, SUDPTRH
+       mov a, r1
+       movx @dptr, a
+       mov dptr, SUDPTRL
+       mov a, r2
+       movx @dptr, a
+       ;; done
+       ljmp setup_done_ack
+       
+setup_Get_Descriptor_not_string:
+       ljmp setup_stall
+       
+setup_breq_not_06:
+       cjne r2, #0x08, setup_breq_not_08
+       ;; Get_Configuration. always 1. return one byte.
+       ;; this is reusable
+       mov a, #1
+setup_return_one_byte: 
+       mov dptr, IN0BUF
+       movx @dptr, a
+       mov a, #1
+       mov dptr, IN0BC
+       movx @dptr, a
+       ljmp setup_done_ack
+setup_breq_not_08:
+       cjne r2, #0x09, setup_breq_not_09
+       ;; 09: Set_Configuration. ignored.
+       ljmp setup_done_ack
+setup_breq_not_09:
+       cjne r2, #0x0a, setup_breq_not_0a
+       ;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+       ;;  since we only have one interface, ignore wIndexL, return a 0
+       mov a, #0
+       ljmp setup_return_one_byte
+setup_breq_not_0a:
+       cjne r2, #0x0b, setup_breq_not_0b
+       ;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+       ljmp setup_done_ack
+setup_breq_not_0b:
+       ljmp setup_stall
+
+               
+setup_done_ack:        
+       ;; now clear HSNAK
+       mov dptr, EP0CS
+       mov a, #0x02
+       movx @dptr, a
+       sjmp setup_done
+setup_stall:   
+       ;; unhandled. STALL
+       ;EP0CS |= bmEPSTALL
+       mov dptr, EP0CS
+       movx a, @dptr
+       orl a, EP0STALLbit
+       movx @dptr, a
+       sjmp setup_done
+       
+setup_done:    
+       pop acc
+       pop dph1
+       pop dpl1
+       pop dph
+       pop dpl
+       pop dps
+       reti
+
+;;; ==============================================================
+       
+set_baud:                      ; baud index in r3
+       ;; verify a < 10
+       mov a, r3
+       jb ACC.7, set_baud__badbaud
+       clr c
+       subb a, #10
+       jnc set_baud__badbaud
+       mov a, r3
+       rl a                    ; a = index*2
+       add a, #LOW(baud_table)
+       mov dpl, a
+       mov a, #HIGH(baud_table)
+       addc a, #0
+       mov dph, a
+       ;; TODO: shut down xmit/receive
+       ;; TODO: wait for current xmit char to leave
+       ;; TODO: shut down timer to avoid partial-char glitch
+       movx a,@dptr            ; BAUD_HIGH
+       mov RCAP2H, a
+       mov TH2, a
+       inc dptr
+       movx a,@dptr            ; BAUD_LOW
+       mov RCAP2L, a
+       mov TL2, a
+       ;; TODO: restart xmit/receive
+       ;; TODO: reenable interrupts, resume tx if pending
+       clr c                   ; c=0: success
+       ret
+set_baud__badbaud:
+       setb c                  ; c=1: failure
+       ret
+       
+;;; ==================================================
+control_pins:
+       cjne r1, #0x41, control_pins_in
+control_pins_out:
+               ;TODO BKPT is DTR
+       mov a, r3 ; wValue[0] holds new bits:   b7 is new RTS
+       xrl a, #0xff            ; 1 means active, 0V, +12V ?
+       anl a, #0x80
+       mov r3, a
+       mov dptr, OUTC
+       movx a, @dptr           ; only change bit 7 
+       anl a, #0x7F            ; ~0x84
+       orl a, r3
+       movx @dptr, a           ; other pins are inputs, bits ignored
+       ljmp setup_done_ack
+control_pins_in:
+       mov dptr, PINSC
+       movx a, @dptr
+       xrl a, #0xff
+       ljmp setup_return_one_byte
+
+;;; ========================================
+       
+ISR_Ep2in:
+       push dps
+       push dpl
+       push dph
+       push dpl1
+       push dph1
+       push acc
+       mov a,EXIF
+       clr acc.4
+       mov EXIF,a              ; clear INT2 first
+       mov dptr, IN07IRQ       ; clear USB int
+       mov a,#04h
+       movx @dptr,a
+
+       mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+       ;; do stuff
+       lcall start_in
+
+       mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+       
+       pop acc
+       pop dph1
+       pop dpl1
+       pop dph
+       pop dpl
+       pop dps
+       reti
+
+ISR_Ep2out:
+       push dps
+       push dpl
+       push dph
+       push dpl1
+       push dph1
+       push acc
+
+        mov a, #0x10             ; Turn the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+
+       mov a,EXIF
+       clr acc.4
+       mov EXIF,a              ; clear INT2 first
+       mov dptr, OUT07IRQ      ; clear USB int
+       mov a,#04h
+       movx @dptr,a
+
+       ;; do stuff
+
+       ;; copy data into buffer. for now, assume we will have enough space
+       mov dptr, OUT2BC        ; get byte count
+       movx a,@dptr
+       mov r1, a
+       clr a
+       mov dps, a
+       mov dptr, OUT2BUF       ; load DPTR0 with source
+       mov dph1, #HIGH(tx_ring)        ; load DPTR1 with target
+       mov dpl1, tx_ring_in
+OUT_loop:
+       movx a,@dptr            ; read
+       inc dps                 ; switch to DPTR1: target
+       inc dpl1                ; target = tx_ring_in+1
+       movx @dptr,a            ; store
+       mov a,dpl1
+       cjne a, tx_ring_out, OUT_no_overflow
+       sjmp OUT_overflow
+OUT_no_overflow:       
+       inc tx_ring_in          ; tx_ring_in++
+       inc dps                 ; switch to DPTR0: source
+       inc dptr
+       djnz r1, OUT_loop
+       sjmp OUT_done
+OUT_overflow:
+       ;; signal overflow
+       ;; fall through
+OUT_done:      
+       ;; ack
+       mov dptr,OUT2BC
+       movx @dptr,a
+
+       ;; start tx
+       acall maybe_start_tx
+       ;acall dump_stat
+
+        mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+       
+       pop acc
+       pop dph1
+       pop dpl1
+       pop dph
+       pop dpl
+       pop dps
+       reti
+
+dump_stat:
+       ;; fill in EP4in with a debugging message:
+       ;;   tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+       ;;   tx_active
+       ;;   tx_ring[0..15]
+       ;;   0xfc
+       ;;   rx_ring[0..15]
+       clr a
+       mov dps, a
+       
+       mov dptr, IN4CS
+       movx a, @dptr
+       jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+       mov dptr, IN4BUF
+       
+       mov a, tx_ring_in
+       movx @dptr, a
+       inc dptr
+       mov a, tx_ring_out
+       movx @dptr, a
+       inc dptr
+
+       mov a, rx_ring_in
+       movx @dptr, a
+       inc dptr
+       mov a, rx_ring_out
+       movx @dptr, a
+       inc dptr
+       
+       clr a
+       jnb TX_RUNNING, dump_stat__no_tx_running
+       inc a
+dump_stat__no_tx_running:
+       movx @dptr, a
+       inc dptr
+       ;; tx_ring[0..15]
+       inc dps
+       mov dptr, #tx_ring      ; DPTR1: source
+       mov r1, #16
+dump_stat__tx_ring_loop:
+       movx a, @dptr
+       inc dptr
+       inc dps
+       movx @dptr, a
+       inc dptr
+       inc dps
+       djnz r1, dump_stat__tx_ring_loop
+       inc dps
+       
+       mov a, #0xfc
+       movx @dptr, a
+       inc dptr
+       
+       ;; rx_ring[0..15]
+       inc dps
+       mov dptr, #rx_ring      ; DPTR1: source
+       mov r1, #16
+dump_stat__rx_ring_loop:
+       movx a, @dptr
+       inc dptr
+       inc dps
+       movx @dptr, a
+       inc dptr
+       inc dps
+       djnz r1, dump_stat__rx_ring_loop
+       
+       ;; now send it
+       clr a
+       mov dps, a
+       mov dptr, IN4BC
+       mov a, #38
+       movx @dptr, a
+dump_stat__done:       
+       ret
+               
+;;; ============================================================
+       
+maybe_start_tx:
+       ;; make sure the tx process is running.
+       jb TX_RUNNING, start_tx_done
+start_tx:
+       ;; is there work to be done?
+       mov a, tx_ring_in
+       cjne a,tx_ring_out, start_tx__work
+       ret                     ; no work
+start_tx__work:        
+       ;; tx was not running. send the first character, setup the TI int
+       inc tx_ring_out         ; [++tx_ring_out]
+       mov dph, #HIGH(tx_ring)
+       mov dpl, tx_ring_out
+       movx a, @dptr
+       mov sbuf, a
+       setb TX_RUNNING
+start_tx_done:
+       ;; can we unthrottle the host tx process?
+       ;;  step 1: do we care?
+       mov a, #0
+       cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+       ;; nope
+start_tx_really_done:
+       ret
+start_tx__maybe_unthrottle_tx:
+       ;;  step 2: is there now room?
+       mov a, tx_ring_out
+       setb c
+       subb a, tx_ring_in
+       ;; a is now write_room. If thresh >= a, we can unthrottle
+       clr c
+       subb a, tx_unthrottle_threshold
+       jc start_tx_really_done ; nope
+       ;; yes, we can unthrottle. remove the threshold and mark a request
+       mov tx_unthrottle_threshold, #0
+       setb DO_TX_UNTHROTTLE
+       ;; prod rx, which will actually send the message when in2 becomes free
+       ljmp start_in
+       
+
+serial_int:
+       push dps
+       push dpl
+       push dph
+       push dpl1
+       push dph1
+       push acc
+       jnb TI, serial_int__not_tx
+       ;; tx finished. send another character if we have one
+       clr TI                  ; clear int
+       clr TX_RUNNING
+       lcall start_tx
+serial_int__not_tx:
+       jnb RI, serial_int__not_rx
+       lcall get_rx_char
+       clr RI                  ; clear int
+serial_int__not_rx:    
+       ;; return
+       pop acc
+       pop dph1
+       pop dpl1
+       pop dph
+       pop dpl
+       pop dps
+       reti
+
+get_rx_char:
+       mov dph, #HIGH(rx_ring)
+       mov dpl, rx_ring_in
+       inc dpl                 ; target = rx_ring_in+1
+       mov a, sbuf
+       movx @dptr, a
+       ;; check for overflow before incrementing rx_ring_in
+       mov a, dpl
+       cjne a, rx_ring_out, get_rx_char__no_overflow
+       ;; signal overflow
+       ret
+get_rx_char__no_overflow:      
+       inc rx_ring_in
+       ;; kick off USB INpipe
+       acall start_in
+       ret
+
+start_in:
+       ;; check if the inpipe is already running.
+       mov  a,#0x10
+       mov dptr, OEA
+       movx @dptr,a
+
+       mov dptr, IN2CS
+       movx a, @dptr
+       jb acc.1, start_in__done; int will handle it
+       jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+       ;; see if there is any work to do. a serial interrupt might occur
+       ;; during this sequence?
+       mov a, rx_ring_in
+       cjne a, rx_ring_out, start_in__have_work
+       ret                     ; nope
+start_in__have_work:   
+       ;; now copy as much data as possible into the pipe. 63 bytes max.
+       clr a
+       mov dps, a
+       mov dph, #HIGH(rx_ring) ; load DPTR0 with source
+       inc dps
+       mov dptr, IN2BUF        ; load DPTR1 with target
+       movx @dptr, a           ; in[0] signals that rest of IN is rx data
+       inc dptr
+       inc dps
+       ;; loop until we run out of data, or we have copied 64 bytes
+       mov r1, #1              ; INbuf size counter
+start_in__loop:
+       mov a, rx_ring_in
+       cjne a, rx_ring_out, start_in__still_copying
+       sjmp start_in__kick
+start_in__still_copying:
+       inc rx_ring_out
+       mov dpl, rx_ring_out
+       movx a, @dptr
+       inc dps
+       movx @dptr, a           ; write into IN buffer
+       inc dptr
+       inc dps
+       inc r1
+       cjne r1, #64, start_in__loop; loop
+start_in__kick:
+       ;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+       ;; kick off IN
+       mov a, #0x10             ; Turn the green LED
+        mov dptr,OEA
+        movx @dptr, a
+       mov dptr, IN2BC
+       mov a, r1
+       jz start_in__done
+       movx @dptr, a
+       ;; done
+start_in__done:
+       ;acall dump_stat
+       ret
+start_in__do_tx_unthrottle:
+       ;; special sequence: send a tx unthrottle message
+       clr DO_TX_UNTHROTTLE
+       clr a
+       mov dps, a
+       mov dptr, IN2BUF
+       mov a, #1
+       movx @dptr, a
+       inc dptr
+       mov a, #2
+       movx @dptr, a
+       mov dptr, IN2BC
+       movx @dptr, a
+       ret
+       
+putchar:
+       clr TI
+       mov SBUF, a
+putchar_wait:
+       jnb TI, putchar_wait
+       clr TI
+       ret
+
+       
+baud_table:                    ; baud_high, then baud_low
+       ;; baud[0]: 110
+       .byte BAUD_HIGH(110)
+       .byte BAUD_LOW(110)
+       ;; baud[1]: 300
+       .byte BAUD_HIGH(300)
+       .byte BAUD_LOW(300)
+       ;; baud[2]: 1200
+       .byte BAUD_HIGH(1200)
+       .byte BAUD_LOW(1200)
+       ;; baud[3]: 2400
+       .byte BAUD_HIGH(2400)
+       .byte BAUD_LOW(2400)
+       ;; baud[4]: 4800
+       .byte BAUD_HIGH(4800)
+       .byte BAUD_LOW(4800)
+       ;; baud[5]: 9600
+       .byte BAUD_HIGH(9600)
+       .byte BAUD_LOW(9600)
+       ;; baud[6]: 19200
+       .byte BAUD_HIGH(19200)
+       .byte BAUD_LOW(19200)
+       ;; baud[7]: 38400
+       .byte BAUD_HIGH(38400)
+       .byte BAUD_LOW(38400)
+       ;; baud[8]: 57600
+       .byte BAUD_HIGH(57600)
+       .byte BAUD_LOW(57600)
+       ;; baud[9]: 115200
+       .byte BAUD_HIGH(115200)
+       .byte BAUD_LOW(115200)
+
+desc_device:
+       .byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+       .byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+       
+desc_config1:
+       .byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+       .byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+       .byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+       .byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+       .word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids:        .byte string_langids_end-string_langids
+       .byte 3
+       .word 0
+string_langids_end:
+
+       ;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+       ;; *that* is a pain in the ass to encode. And they are little-endian
+       ;; too. Use this perl snippet to get the bytecodes:
+       /* while (<>) {
+           @c = split(//);
+           foreach $c (@c) {
+            printf("0x%02x, 0x00, ", ord($c));
+           }
+          }
+       */
+
+string_mfg:    .byte string_mfg_end-string_mfg
+       .byte 3
+;      .byte "ACME usb widgets"
+       .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 
+0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 
+0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+       
+string_product:        .byte string_product_end-string_product
+       .byte 3
+;      .byte "ACME USB serial widget"
+       .byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 
+0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 
+0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 
+0x65, 0x00, 0x74, 0x00
+string_product_end:
+       
+string_serial: .byte string_serial_end-string_serial
+       .byte 3
+;      .byte "47"
+       .byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+               
+;;; ring buffer memory
+       ;; tx_ring_in+1 is where the next input byte will go
+       ;; [tx_ring_out] has been sent
+       ;; if tx_ring_in == tx_ring_out, theres no work to do
+       ;; there are (tx_ring_in - tx_ring_out) chars to be written
+       ;; dont let _in lap _out
+       ;;   cannot inc if tx_ring_in+1 == tx_ring_out
+       ;;  write [tx_ring_in+1] then tx_ring_in++
+       ;;   if (tx_ring_in+1 == tx_ring_out), overflow
+       ;;   else tx_ring_in++
+       ;;  read/send [tx_ring_out+1], then tx_ring_out++
+
+       ;; rx_ring_in works the same way
+       
+       .org 0x1000
+tx_ring:
+       .skip 0x100             ; 256 bytes
+rx_ring:
+       .skip 0x100             ; 256 bytes
+       
+       
+       .END
+       
diff -Nru a/drivers/usb/serial/xircom_pgs_fw.h b/drivers/usb/serial/xircom_pgs_fw.h
--- /dev/null   Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/serial/xircom_pgs_fw.h        Thu Jan  3 21:41:54 2002
@@ -0,0 +1,103 @@
+/*
+ * USB Xircom PGS Firmware
+ *
+ * Copyright (c) 1999, 2000 Brian Warner        <[EMAIL PROTECTED]>
+ * Copyright (c) 2001 Cristian M. Craciunescu  <[EMAIL PROTECTED]>
+ *
+ *      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.
+ *
+ * Generated from xircom_pgs.S by ezusb_convert_x.pl
+ */
+
+static const struct ezusb_hex_record xircom_pgs_firmware[] = {
+{ 0x0000,      3,      {0x02, 0x02, 0x00} },
+{ 0x0023,      4,      {0x02, 0x05, 0x9b, 0x00} },
+{ 0x0030,      5,      {0x00, 0x00, 0x00, 0x00, 0x00} },
+{ 0x0043,      4,      {0x02, 0x01, 0x00, 0x00} },
+{ 0x0100,      16,     {0x02, 0x02, 0xba, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 
+0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0110,      16,     {0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 
+0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0120,      16,     {0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x04, 
+0x85, 0x00, 0x02, 0x04, 0xb9, 0x00} },
+{ 0x0200,      16,     {0x75, 0x81, 0x5e, 0xe4, 0xf5, 0x32, 0xf5, 0x33, 0xf5, 0x30, 
+0xf5, 0x31, 0xf5, 0x34, 0xc2, 0x00} },
+{ 0x0210,      16,     {0xc2, 0x01, 0xa9, 0x00, 0x74, 0xfe, 0x90, 0x10, 0x00, 0xf0, 
+0xa3, 0xd9, 0xfc, 0x74, 0xfd, 0x90} },
+{ 0x0220,      16,     {0x11, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x90, 0x7f, 0x94, 0x74, 
+0xbf, 0xf0, 0x90, 0x7f, 0x95, 0x74} },
+{ 0x0230,      16,     {0xef, 0xf0, 0x74, 0x10, 0x90, 0x7f, 0x9e, 0xf0, 0x74, 0x00, 
+0x90, 0x7f, 0x98, 0xf0, 0x74, 0x40} },
+{ 0x0240,      16,     {0x90, 0x7f, 0x9d, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0x97, 0xf0, 
+0x74, 0x82, 0x90, 0x7f, 0x9e, 0xf0} },
+{ 0x0250,      16,     {0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f, 0xaf, 0xe0, 
+0xd2, 0xe0, 0xf0, 0x74, 0x01, 0x90} },
+{ 0x0260,      16,     {0x7f, 0xab, 0xf0, 0x90, 0x7f, 0xae, 0xf0, 0x90, 0x7f, 0xac, 
+0x74, 0x04, 0xf0, 0x90, 0x7f, 0xad} },
+{ 0x0270,      16,     {0x74, 0x04, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x74, 0x07, 0x90, 
+0x7f, 0xaf, 0xf0, 0x74, 0x20, 0x90} },
+{ 0x0280,      16,     {0x7f, 0x9c, 0xf0, 0x74, 0x80, 0x90, 0x7f, 0x98, 0xf0, 0x74, 
+0x53, 0xf5, 0x98, 0x75, 0xc8, 0x30} },
+{ 0x0290,      16,     {0x7b, 0x05, 0x91, 0x44, 0xd2, 0xca, 0x75, 0x98, 0x50, 0xd2, 
+0xe8, 0xd2, 0xaf, 0xd2, 0xac, 0x74} },
+{ 0x02a0,      16,     {0x00, 0xf5, 0x86, 0x90, 0x7f, 0xd6, 0x74, 0x02, 0xf0, 0x79, 
+0x2e, 0x7a, 0x00, 0x7b, 0x00, 0xdb} },
+{ 0x02b0,      16,     {0xfe, 0xda, 0xfa, 0xd9, 0xf6, 0x74, 0x06, 0xf0, 0x80, 0xfe, 
+0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83} },
+{ 0x02c0,      16,     {0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 
+0xf5, 0x91, 0x90, 0x7f, 0xab, 0x74} },
+{ 0x02d0,      16,     {0x01, 0xf0, 0x90, 0x7f, 0xe8, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 
+0xa3, 0xe0, 0xfb, 0xa3, 0xe0, 0xfc} },
+{ 0x02e0,      16,     {0xe9, 0x54, 0x60, 0xb4, 0x00, 0x03, 0x02, 0x03, 0x5d, 0xb4, 
+0x40, 0x6e, 0xba, 0x00, 0x0b, 0x12} },
+{ 0x02f0,      16,     {0x04, 0x44, 0x40, 0x03, 0x02, 0x04, 0x26, 0x02, 0x04, 0x2e, 
+0xba, 0x01, 0x03, 0x02, 0x04, 0x2e} },
+{ 0x0300,      16,     {0xba, 0x02, 0x03, 0x02, 0x04, 0x2e, 0xba, 0x03, 0x03, 0x02, 
+0x04, 0x68, 0xba, 0x04, 0x1e, 0xbb} },
+{ 0x0310,      16,     {0x00, 0x0a, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0x02, 
+0x04, 0x26, 0x90, 0x7f, 0x98, 0xe0} },
+{ 0x0320,      16,     {0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 
+0x02, 0x04, 0x26, 0xba, 0x05, 0x03} },
+{ 0x0330,      16,     {0x02, 0x04, 0x2e, 0xba, 0x06, 0x19, 0xbb, 0x00, 0x08, 0xe5, 
+0x33, 0xd3, 0x95, 0x32, 0x02, 0x04} },
+{ 0x0340,      16,     {0x02, 0xbb, 0x01, 0x08, 0xe5, 0x32, 0xc3, 0x95, 0x33, 0x02, 
+0x04, 0x02, 0x02, 0x04, 0x2e, 0xba} },
+{ 0x0350,      16,     {0x07, 0x05, 0x8b, 0x34, 0x02, 0x04, 0x26, 0x02, 0x04, 0x2e, 
+0x02, 0x04, 0x2e, 0xba, 0x00, 0x20} },
+{ 0x0360,      16,     {0xb9, 0x80, 0x10, 0x90, 0x7f, 0x00, 0xe4, 0xf0, 0xa3, 0xf0, 
+0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0} },
+{ 0x0370,      16,     {0x02, 0x04, 0x26, 0xb9, 0x82, 0x02, 0x80, 0xeb, 0xb9, 0x81, 
+0x02, 0x80, 0xe6, 0x02, 0x04, 0x2e} },
+{ 0x0380,      16,     {0xba, 0x01, 0x0f, 0xbb, 0x00, 0x03, 0x02, 0x04, 0x2e, 0xbb, 
+0x01, 0x03, 0x02, 0x04, 0x26, 0x02} },
+{ 0x0390,      16,     {0x04, 0x2e, 0xba, 0x03, 0x0f, 0xbb, 0x00, 0x03, 0x02, 0x04, 
+0x2e, 0xbb, 0x01, 0x03, 0x02, 0x04} },
+{ 0x03a0,      16,     {0x26, 0x02, 0x04, 0x2e, 0xba, 0x06, 0x56, 0xbc, 0x01, 0x0f, 
+0x90, 0x7f, 0xd4, 0x74, 0x06, 0xf0} },
+{ 0x03b0,      16,     {0x90, 0x7f, 0xd5, 0x74, 0x5a, 0xf0, 0x02, 0x04, 0x26, 0xbc, 
+0x02, 0x12, 0xbb, 0x00, 0x6f, 0x90} },
+{ 0x03c0,      16,     {0x7f, 0xd4, 0x74, 0x06, 0xf0, 0x90, 0x7f, 0xd5, 0x74, 0x6c, 
+0xf0, 0x02, 0x04, 0x26, 0xbc, 0x03} },
+{ 0x03d0,      16,     {0x29, 0x74, 0x04, 0xc3, 0x9b, 0x40, 0x57, 0x60, 0x55, 0xeb, 
+0x2b, 0x90, 0x06, 0x8c, 0x25, 0x82} },
+{ 0x03e0,      16,     {0xf5, 0x82, 0x74, 0x00, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0xf9, 
+0xa3, 0xe0, 0xfa, 0x90, 0x7f, 0xd4} },
+{ 0x03f0,      16,     {0xe9, 0xf0, 0x90, 0x7f, 0xd5, 0xea, 0xf0, 0x02, 0x04, 0x26, 
+0x02, 0x04, 0x2e, 0xba, 0x08, 0x0f} },
+{ 0x0400,      16,     {0x74, 0x01, 0x90, 0x7f, 0x00, 0xf0, 0x74, 0x01, 0x90, 0x7f, 
+0xb5, 0xf0, 0x02, 0x04, 0x26, 0xba} },
+{ 0x0410,      16,     {0x09, 0x03, 0x02, 0x04, 0x26, 0xba, 0x0a, 0x05, 0x74, 0x00, 
+0x02, 0x04, 0x02, 0xba, 0x0b, 0x03} },
+{ 0x0420,      16,     {0x02, 0x04, 0x26, 0x02, 0x04, 0x2e, 0x90, 0x7f, 0xb4, 0x74, 
+0x02, 0xf0, 0x80, 0x09, 0x90, 0x7f} },
+{ 0x0430,      16,     {0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x00, 0xd0, 0xe0, 0xd0, 
+0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0} },
+{ 0x0440,      16,     {0x82, 0xd0, 0x86, 0x32, 0xeb, 0x20, 0xe7, 0x1e, 0xc3, 0x94, 
+0x0a, 0x50, 0x19, 0xeb, 0x23, 0x24} },
+{ 0x0450,      16,     {0x46, 0xf5, 0x82, 0x74, 0x06, 0x34, 0x00, 0xf5, 0x83, 0xe0, 
+0xf5, 0xcb, 0xf5, 0xcd, 0xa3, 0xe0} },
+{ 0x0460,      16,     {0xf5, 0xca, 0xf5, 0xcc, 0xc3, 0x22, 0xd3, 0x22, 0xb9, 0x41, 
+0x11, 0xeb, 0x64, 0xff, 0x54, 0x80} },
+{ 0x0470,      16,     {0xfb, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0x7f, 0x4b, 0xf0, 0x02, 
+0x04, 0x26, 0x90, 0x7f, 0x9b, 0xe0} },
+{ 0x0480,      16,     {0x64, 0xff, 0x02, 0x04, 0x02, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 
+0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0} },
+{ 0x0490,      16,     {0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xa9, 
+0x74, 0x04, 0xf0, 0x74, 0x20, 0x90} },
+{ 0x04a0,      16,     {0x7f, 0x9c, 0xf0, 0x12, 0x05, 0xdc, 0x74, 0x20, 0x90, 0x7f, 
+0x9c, 0xf0, 0xd0, 0xe0, 0xd0, 0x85} },
+{ 0x04b0,      16,     {0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xc0, 
+0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0} },
+{ 0x04c0,      16,     {0x84, 0xc0, 0x85, 0xc0, 0xe0, 0x74, 0x10, 0x90, 0x7f, 0x9c, 
+0xf0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5} },
+{ 0x04d0,      16,     {0x91, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xc9, 
+0xe0, 0xf9, 0xe4, 0xf5, 0x86, 0x90} },
+{ 0x04e0,      16,     {0x7d, 0xc0, 0x75, 0x85, 0x10, 0x85, 0x32, 0x84, 0xe0, 0x05, 
+0x86, 0x05, 0x84, 0xf0, 0xe5, 0x84} },
+{ 0x04f0,      16,     {0xb5, 0x33, 0x02, 0x80, 0x09, 0x05, 0x32, 0x05, 0x86, 0xa3, 
+0xd9, 0xec, 0x80, 0x00, 0x90, 0x7f} },
+{ 0x0500,      16,     {0xc9, 0xf0, 0xb1, 0x6d, 0x74, 0x20, 0x90, 0x7f, 0x9c, 0xf0, 
+0xd0, 0xe0, 0xd0, 0x85, 0xd0, 0x84} },
+{ 0x0510,      16,     {0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xe4, 0xf5, 0x86, 
+0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1} },
+{ 0x0520,      16,     {0x4b, 0x90, 0x7d, 0x00, 0xe5, 0x32, 0xf0, 0xa3, 0xe5, 0x33, 
+0xf0, 0xa3, 0xe5, 0x30, 0xf0, 0xa3} },
+{ 0x0530,      16,     {0xe5, 0x31, 0xf0, 0xa3, 0xe4, 0x30, 0x00, 0x01, 0x04, 0xf0, 
+0xa3, 0x05, 0x86, 0x90, 0x10, 0x00} },
+{ 0x0540,      16,     {0x79, 0x10, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 
+0xd9, 0xf6, 0x05, 0x86, 0x74, 0xfc} },
+{ 0x0550,      16,     {0xf0, 0xa3, 0x05, 0x86, 0x90, 0x11, 0x00, 0x79, 0x10, 0xe0, 
+0xa3, 0x05, 0x86, 0xf0, 0xa3, 0x05} },
+{ 0x0560,      16,     {0x86, 0xd9, 0xf6, 0xe4, 0xf5, 0x86, 0x90, 0x7f, 0xbd, 0x74, 
+0x26, 0xf0, 0x22, 0x20, 0x00, 0x13} },
+{ 0x0570,      16,     {0xe5, 0x32, 0xb5, 0x33, 0x01, 0x22, 0x05, 0x33, 0x75, 0x83, 
+0x10, 0x85, 0x33, 0x82, 0xe0, 0xf5} },
+{ 0x0580,      16,     {0x99, 0xd2, 0x00, 0x74, 0x00, 0xb5, 0x34, 0x01, 0x22, 0xe5, 
+0x33, 0xd3, 0x95, 0x32, 0xc3, 0x95} },
+{ 0x0590,      16,     {0x34, 0x40, 0xf5, 0x75, 0x34, 0x00, 0xd2, 0x01, 0x02, 0x05, 
+0xdc, 0xc0, 0x86, 0xc0, 0x82, 0xc0} },
+{ 0x05a0,      16,     {0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0x30, 0x99, 0x07, 
+0xc2, 0x99, 0xc2, 0x00, 0x12, 0x05} },
+{ 0x05b0,      16,     {0x70, 0x30, 0x98, 0x05, 0x12, 0x05, 0xc6, 0xc2, 0x98, 0xd0, 
+0xe0, 0xd0, 0x85, 0xd0, 0x84, 0xd0} },
+{ 0x05c0,      16,     {0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0x75, 0x83, 0x11, 0x85, 
+0x30, 0x82, 0x05, 0x82, 0xe5, 0x99} },
+{ 0x05d0,      16,     {0xf0, 0xe5, 0x82, 0xb5, 0x31, 0x01, 0x22, 0x05, 0x30, 0xb1, 
+0xdc, 0x22, 0x74, 0x10, 0x90, 0x7f} },
+{ 0x05e0,      16,     {0x9c, 0xf0, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x3e, 0x20, 
+0x01, 0x3c, 0xe5, 0x30, 0xb5, 0x31} },
+{ 0x05f0,      16,     {0x01, 0x22, 0xe4, 0xf5, 0x86, 0x75, 0x83, 0x11, 0x05, 0x86, 
+0x90, 0x7e, 0x00, 0xf0, 0xa3, 0x05} },
+{ 0x0600,      16,     {0x86, 0x79, 0x01, 0xe5, 0x30, 0xb5, 0x31, 0x02, 0x80, 0x10, 
+0x05, 0x31, 0x85, 0x31, 0x82, 0xe0} },
+{ 0x0610,      16,     {0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0x09, 0xb9, 0x40, 0xe9, 
+0x74, 0x10, 0x90, 0x7f, 0x9c, 0xf0} },
+{ 0x0620,      16,     {0x90, 0x7f, 0xb9, 0xe9, 0x60, 0x01, 0xf0, 0x22, 0xc2, 0x01, 
+0xe4, 0xf5, 0x86, 0x90, 0x7e, 0x00} },
+{ 0x0630,      16,     {0x74, 0x01, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xb9, 
+0xf0, 0x22, 0xc2, 0x99, 0xf5, 0x99} },
+{ 0x0640,      16,     {0x30, 0x99, 0xfd, 0xc2, 0x99, 0x22, 0xe5, 0x5e, 0xf6, 0x3c, 
+0xfd, 0x8f, 0xfe, 0xc8, 0xff, 0x64} },
+{ 0x0650,      16,     {0xff, 0xb2, 0xff, 0xd9, 0xff, 0xed, 0xff, 0xf3, 0xff, 0xfa, 
+0x12, 0x01, 0x00, 0x01, 0xff, 0xff} },
+{ 0x0660,      16,     {0xff, 0x40, 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 0x01, 0x02, 
+0x03, 0x01, 0x09, 0x02, 0x20, 0x00} },
+{ 0x0670,      16,     {0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, 0x00, 0x02, 
+0xff, 0xff, 0xff, 0x00, 0x07, 0x05} },
+{ 0x0680,      16,     {0x82, 0x03, 0x40, 0x00, 0x01, 0x07, 0x05, 0x02, 0x02, 0x40, 
+0x00, 0x00, 0x06, 0x94, 0x06, 0x98} },
+{ 0x0690,      16,     {0x06, 0xba, 0x06, 0xe8, 0x04, 0x03, 0x00, 0x00, 0x22, 0x03, 
+0x41, 0x00, 0x43, 0x00, 0x4d, 0x00} },
+{ 0x06a0,      16,     {0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 
+0x20, 0x00, 0x77, 0x00, 0x69, 0x00} },
+{ 0x06b0,      16,     {0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00, 
+0x2e, 0x03, 0x41, 0x00, 0x43, 0x00} },
+{ 0x06c0,      16,     {0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 
+0x42, 0x00, 0x20, 0x00, 0x73, 0x00} },
+{ 0x06d0,      16,     {0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 
+0x20, 0x00, 0x77, 0x00, 0x69, 0x00} },
+{ 0x06e0,      14,     {0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x06, 0x03, 
+0x34, 0x00, 0x37, 0x00} },
+{ 0xffff,      0,      {0x00} }
+};

_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to