USB: add iuu_phoenix driver
authorAlain Degreffe <info@ecze.com>
Fri, 26 Oct 2007 11:51:49 +0000 (13:51 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Feb 2008 22:34:47 +0000 (14:34 -0800)
Signed-off-by: Alain Degreffe <eczema@ecze.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Documentation/usb/iuu_phoenix.txt [new file with mode: 0644]
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/iuu_phoenix.c [new file with mode: 0644]
drivers/usb/serial/iuu_phoenix.h [new file with mode: 0644]

diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt
new file mode 100644 (file)
index 0000000..e5f0480
--- /dev/null
@@ -0,0 +1,84 @@
+Infinity Usb Unlimited Readme
+-----------------------------
+
+Hi all,
+
+
+This module provide a serial interface to use your
+IUU unit in phoenix mode. Loading this module will
+bring a ttyUSB[0-x] interface. This driver must be
+used by your favorite application to pilot the IUU
+
+This driver is still in beta stage, so bugs can
+occur and your system may freeze. As far I now,
+I never had any problem with it, but I'm not a real
+guru, so don't blame me if your system is unstable
+
+You can plug more than one IUU. Every unit will
+have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...)
+
+
+
+How to tune the reader speed ?
+
+ A few parameters can be used at load time
+ To use parameters, just unload the module if it is
+ already loaded and use modprobe iuu_phoenix param=value.
+ In case of prebuilt module, use the command
+ insmod iuu_phoenix param=value.
+
+ Example:
+
+ modprobe iuu_phoenix clockmode=3
+
+ The parameters are:
+
+ parm:           clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int)
+ parm:           boost:overclock boost percent 100 to 500 (int)
+ parm:           cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int)
+ parm:           xmas:xmas color enabled or not (bool)
+ parm:           debug:Debug enabled or not (bool)
+
+-  clockmode will provide 3 different base settings commonly adopted by
+   different software:
+       1. 3Mhz579
+       2. 3Mhz680
+       3. 6Mhz
+
+-  boost provide a way to overclock the reader ( my favorite :-)  )
+   For example to have best performance than a simple clockmode=3, try this:
+
+      modprobe boost=195
+
+   This will put the reader in a base of 3Mhz579 but boosted a 195 % !
+   the real clock will be now : 6979050 Hz ( 6Mhz979 ) and will increase
+   the speed to a score 10 to 20% better than the simple clockmode=3 !!!
+
+
+-  cdmode permit to setup the signal used to inform the userland ( ioctl answer )
+   if the card is present or not. Eight signals are possible.
+
+-  xmas is completely useless except for your eyes. This is one of my friend who was
+   so sad to have a nice device like the iuu without seeing all color range available.
+   So I have added this option to permit him to see a lot of color ( each activity change the color
+   and the frequency randomly )
+
+-  debug will produce a lot of debugging messages...
+
+
+ Last notes:
+
+ Don't worry about the serial settings, the serial emulation
+ is an abstraction, so use any speed or parity setting will
+ work. ( This will not change anything ).Later I will perhaps
+ use this settings to deduce de boost but is that feature
+ really necessary ?
+ The autodetect feature used is the serial CD. If that doesn't
+ work for your software, disable detection mechanism in it.
+
+
+ Have fun !
+
+ Alain Degreffe
+
+ eczema(at)ecze.com
index 4a86696e6c7dd20240aca1776139669c9ac4005c..e2d1d928a1e4e91d1388a41b55b5820264fc0d90 100644 (file)
@@ -282,6 +282,17 @@ config USB_SERIAL_IPW
          To compile this driver as a module, choose M here: the
          module will be called ipw.
 
+config USB_SERIAL_IUU
+       tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
+       depends on USB_SERIAL && EXPERIMENTAL
+       help
+         Say Y here if you want to use a IUU in phoenix mode and get
+         an extra ttyUSBx device. More information available on
+         http://eczema.ecze.com/iuu_phoenix.html
+
+         To compile this driver as a module, choose M here: the
+         module will be called iuu_phoenix.o
+
 config USB_SERIAL_KEYSPAN_PDA
        tristate "USB Keyspan PDA Single Port Serial Driver"
        depends on USB_SERIAL
index d6fb384e52b24ab1dca674e1ceaa9bfd515595e0..0db109a54d10b621242f1ca489f23362ed2a3528 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN)                       += garmin_gps.o
 obj-$(CONFIG_USB_SERIAL_HP4X)                  += hp4x.o
 obj-$(CONFIG_USB_SERIAL_IPAQ)                  += ipaq.o
 obj-$(CONFIG_USB_SERIAL_IPW)                   += ipw.o
+obj-$(CONFIG_USB_SERIAL_IUU)                   += iuu_phoenix.o
 obj-$(CONFIG_USB_SERIAL_IR)                    += ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KEYSPAN)               += keyspan.o
 obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)           += keyspan_pda.o
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
new file mode 100644 (file)
index 0000000..fde188e
--- /dev/null
@@ -0,0 +1,1217 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
+ *
+ *     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.
+ *
+ *  And tested with help of WB Electronics
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include "iuu_phoenix.h"
+#include <linux/random.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
+
+static struct usb_device_id id_table[] = {
+       {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
+       {}                      /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver iuu_driver = {
+       .name = "iuu_phoenix",
+       .probe = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .id_table = id_table,
+       .no_dynamic_id = 1,
+};
+
+/* turbo parameter */
+static int boost = 100;
+static int clockmode = 1;
+static int cdmode = 1;
+static int iuu_cardin;
+static int iuu_cardout;
+static int xmas;
+
+static void read_rxcmd_callback(struct urb *urb);
+
+struct iuu_private {
+       spinlock_t lock;        /* store irq state */
+       wait_queue_head_t delta_msr_wait;
+       u8 line_control;
+       u8 line_status;
+       u8 termios_initialized;
+       int tiostatus;          /* store IUART SIGNAL for tiocmget call */
+       u8 reset;               /* if 1 reset is needed */
+       int poll;               /* number of poll */
+       u8 *writebuf;           /* buffer for writing to device */
+       int writelen;           /* num of byte to write to device */
+       u8 *buf;                /* used for initialize speed */
+       u8 *dbgbuf;             /* debug buffer */
+       u8 len;
+};
+
+
+static void iuu_free_buf(struct iuu_private *priv)
+{
+       kfree(priv->buf);
+       kfree(priv->dbgbuf);
+       kfree(priv->writebuf);
+}
+
+static int iuu_alloc_buf(struct iuu_private *priv)
+{
+       priv->buf = kzalloc(256, GFP_KERNEL);
+       priv->dbgbuf = kzalloc(256, GFP_KERNEL);
+       priv->writebuf = kzalloc(256, GFP_KERNEL);
+       if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
+               iuu_free_buf(priv);
+               dbg("%s problem allocation buffer", __FUNCTION__);
+               return -ENOMEM;
+       }
+       dbg("%s - Privates buffers allocation success", __FUNCTION__);
+       return 0;
+}
+
+static int iuu_startup(struct usb_serial *serial)
+{
+       struct iuu_private *priv;
+       priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
+       dbg("%s- priv allocation success", __FUNCTION__);
+       if (!priv)
+               return -ENOMEM;
+       if (iuu_alloc_buf(priv)) {
+               kfree(priv);
+               return -ENOMEM;
+       }
+       spin_lock_init(&priv->lock);
+       init_waitqueue_head(&priv->delta_msr_wait);
+       usb_set_serial_port_data(serial->port[0], priv);
+       return 0;
+}
+
+/* Shutdown function */
+static void iuu_shutdown(struct usb_serial *serial)
+{
+       struct usb_serial_port *port = serial->port[0];
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       if (!port)
+               return;
+
+       dbg("%s", __FUNCTION__);
+
+       if (priv) {
+               iuu_free_buf(priv);
+               dbg("%s - I will free all", __FUNCTION__);
+               usb_set_serial_port_data(port, NULL);
+
+               dbg("%s - priv is not anymore in port structure", __FUNCTION__);
+               kfree(priv);
+
+               dbg("%s priv is now kfree", __FUNCTION__);
+       }
+}
+
+static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
+                       unsigned int set, unsigned int clear)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       tty = port->tty;
+
+       dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
+           port->number, set, clear);
+       if (set & TIOCM_RTS)
+               priv->tiostatus = TIOCM_RTS;
+
+       if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
+               dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+               priv->reset = 1;
+               return 0;
+       }
+
+       return 0;
+}
+
+/* This is used to provide a carrier detect mechanism
+ * When a card is present, the response is 0x00
+ * When no card , the reader respond with TIOCM_CD
+ * This is known as CD autodetect mechanism
+ */
+static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       return priv->tiostatus;
+}
+
+static void iuu_rxcmd(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+
+       memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         read_rxcmd_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static int iuu_reset(struct usb_serial_port *port, u8 wt)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+
+       /* Prepare the reset sequence */
+
+       *buf_ptr++ = IUU_RST_SET;
+       *buf_ptr++ = IUU_DELAY_MS;
+       *buf_ptr++ = wt;
+       *buf_ptr = IUU_RST_CLEAR;
+
+       /* send the sequence */
+
+       usb_fill_bulk_urb(port->write_urb,
+                         port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       priv->reset = 0;
+       return result;
+}
+
+/* Status Function
+ * Return value is
+ * 0x00 = no card
+ * 0x01 = smartcard
+ * 0x02 = sim card
+ */
+static void iuu_update_status_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       u8 *st;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+       st = urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+       if (urb->actual_length == 1) {
+               switch (st[0]) {
+               case 0x1:
+                       priv->tiostatus = iuu_cardout;
+                       break;
+               case 0x0:
+                       priv->tiostatus = iuu_cardin;
+                       break;
+               default:
+                       priv->tiostatus = iuu_cardin;
+               }
+       }
+       iuu_rxcmd(urb);
+}
+
+static void iuu_status_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, 256,
+                         iuu_update_status_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+}
+
+static int iuu_status(struct usb_serial_port *port)
+{
+       int result;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         iuu_status_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       return result;
+
+}
+
+static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+       int status;
+       struct usb_serial *serial = port->serial;
+       int actual = 0;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       /* send the data out the bulk port */
+
+       status =
+           usb_bulk_msg(serial->dev,
+                        usb_sndbulkpipe(serial->dev,
+                                        port->bulk_out_endpointAddress), buf,
+                        count, &actual, HZ * 1);
+
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - error = %2x", __FUNCTION__, status);
+       } else {
+               dbg("%s - write OK !", __FUNCTION__);
+       }
+       return status;
+}
+
+static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+       int status;
+       struct usb_serial *serial = port->serial;
+       int actual = 0;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       /* send the data out the bulk port */
+
+       status =
+           usb_bulk_msg(serial->dev,
+                        usb_rcvbulkpipe(serial->dev,
+                                        port->bulk_in_endpointAddress), buf,
+                        count, &actual, HZ * 1);
+
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - error = %2x", __FUNCTION__, status);
+       } else {
+               dbg("%s - read OK !", __FUNCTION__);
+       }
+
+       return status;
+}
+
+static int iuu_led(struct usb_serial_port *port, unsigned int R,
+                  unsigned int G, unsigned int B, u8 f)
+{
+       int status;
+       u8 *buf;
+       buf = kmalloc(8, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       buf[0] = IUU_SET_LED;
+       buf[1] = R & 0xFF;
+       buf[2] = (R >> 8) & 0xFF;
+       buf[3] = G & 0xFF;
+       buf[4] = (G >> 8) & 0xFF;
+       buf[5] = B & 0xFF;
+       buf[6] = (B >> 8) & 0xFF;
+       buf[7] = f;
+       status = bulk_immediate(port, buf, 8);
+       kfree(buf);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - led error status = %2x", __FUNCTION__, status);
+       else
+               dbg("%s - led OK !", __FUNCTION__);
+       return IUU_OPERATION_OK;
+}
+
+static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
+                                u8 b2, u8 freq)
+{
+       *buf++ = IUU_SET_LED;
+       *buf++ = r1;
+       *buf++ = r2;
+       *buf++ = g1;
+       *buf++ = g2;
+       *buf++ = b1;
+       *buf++ = b2;
+       *buf = freq;
+}
+
+static void iuu_led_activity_on(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       *buf_ptr++ = IUU_SET_LED;
+       if (xmas == 1) {
+               get_random_bytes(buf_ptr, 6);
+               *(buf_ptr+7) = 1;
+       } else {
+               iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
+       }
+
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 8 ,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static void iuu_led_activity_off(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       if (xmas == 1) {
+               iuu_rxcmd(urb);
+               return;
+       } else {
+               *buf_ptr++ = IUU_SET_LED;
+               iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
+       }
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 8 ,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+
+
+static int iuu_clk(struct usb_serial_port *port, int dwFrq)
+{
+       int status;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       int Count = 0;
+       u8 FrqGenAdr = 0x69;
+       u8 DIV = 0;             /* 8bit */
+       u8 XDRV = 0;            /* 8bit */
+       u8 PUMP = 0;            /* 3bit */
+       u8 PBmsb = 0;           /* 2bit */
+       u8 PBlsb = 0;           /* 8bit */
+       u8 PO = 0;              /* 1bit */
+       u8 Q = 0;               /* 7bit */
+       /* 24bit = 3bytes */
+       unsigned int P = 0;
+       unsigned int P2 = 0;
+       int frq = (int)dwFrq;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (frq == 0) {
+               priv->buf[Count++] = IUU_UART_WRITE_I2C;
+               priv->buf[Count++] = FrqGenAdr << 1;
+               priv->buf[Count++] = 0x09;
+               priv->buf[Count++] = 0x00;
+
+               status = bulk_immediate(port, (u8 *) priv->buf, Count);
+               if (status != 0) {
+                       dbg("%s - write error ", __FUNCTION__);
+                       return status;
+               }
+       } else if (frq == 3579000) {
+               DIV = 100;
+               P = 1193;
+               Q = 40;
+               XDRV = 0;
+       } else if (frq == 3680000) {
+               DIV = 105;
+               P = 161;
+               Q = 5;
+               XDRV = 0;
+       } else if (frq == 6000000) {
+               DIV = 66;
+               P = 66;
+               Q = 2;
+               XDRV = 0x28;
+       } else {
+               unsigned int result = 0;
+               unsigned int tmp = 0;
+               unsigned int check;
+               unsigned int check2;
+               char found = 0x00;
+               unsigned int lQ = 2;
+               unsigned int lP = 2055;
+               unsigned int lDiv = 4;
+
+               for (lQ = 2; lQ <= 47 && !found; lQ++)
+                       for (lP = 2055; lP >= 8 && !found; lP--)
+                               for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
+                                       tmp = (12000000 / lDiv) * (lP / lQ);
+                                       if (abs((int)(tmp - frq)) <
+                                           abs((int)(frq - result))) {
+                                               check2 = (12000000 / lQ);
+                                               if (check2 < 250000)
+                                                       continue;
+                                               check = (12000000 / lQ) * lP;
+                                               if (check > 400000000)
+                                                       continue;
+                                               if (check < 100000000)
+                                                       continue;
+                                               if (lDiv < 4 || lDiv > 127)
+                                                       continue;
+                                               result = tmp;
+                                               P = lP;
+                                               DIV = lDiv;
+                                               Q = lQ;
+                                               if (result == frq)
+                                                       found = 0x01;
+                                       }
+                               }
+       }
+       P2 = ((P - PO) / 2) - 4;
+       DIV = DIV;
+       PUMP = 0x04;
+       PBmsb = (P2 >> 8 & 0x03);
+       PBlsb = P2 & 0xFF;
+       PO = (P >> 10) & 0x01;
+       Q = Q - 2;
+
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x09;
+       priv->buf[Count++] = 0x20;      /* Adr = 0x09 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x0C;
+       priv->buf[Count++] = DIV;       /* Adr = 0x0C */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /* 0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x12;
+       priv->buf[Count++] = XDRV;      /* Adr = 0x12 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x13;
+       priv->buf[Count++] = 0x6B;      /* Adr = 0x13 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x40;
+       priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
+                            (PBmsb & 0x03);    /* Adr = 0x40 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x41;
+       priv->buf[Count++] = PBlsb;     /* Adr = 0x41 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x42;
+       priv->buf[Count++] = Q | (((PO & 0x01) << 7));  /* Adr = 0x42 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x44;
+       priv->buf[Count++] = (char)0xFF;        /* Adr = 0x44 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x45;
+       priv->buf[Count++] = (char)0xFE;        /* Adr = 0x45 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x46;
+       priv->buf[Count++] = 0x7F;      /* Adr = 0x46 */
+       priv->buf[Count++] = IUU_UART_WRITE_I2C;        /*  0x4C */
+       priv->buf[Count++] = FrqGenAdr << 1;
+       priv->buf[Count++] = 0x47;
+       priv->buf[Count++] = (char)0x84;        /* Adr = 0x47 */
+
+       status = bulk_immediate(port, (u8 *) priv->buf, Count);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - write error ", __FUNCTION__);
+       return status;
+}
+
+static int iuu_uart_flush(struct usb_serial_port *port)
+{
+       int i;
+       int status;
+       u8 rxcmd = IUU_UART_RX;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
+               return -EIO;
+
+       for (i = 0; i < 2; i++) {
+               status = bulk_immediate(port, &rxcmd, 1);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_write error", __FUNCTION__);
+                       return status;
+               }
+
+               status = read_immediate(port, &priv->len, 1);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_read error", __FUNCTION__);
+                       return status;
+               }
+
+               if (priv->len > 0) {
+                       dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+                           priv->len);
+                       status = read_immediate(port, priv->buf, priv->len);
+                       if (status != IUU_OPERATION_OK) {
+                               dbg("%s - uart_flush_read error", __FUNCTION__);
+                               return status;
+                       }
+               }
+       }
+       dbg("%s - uart_flush_read OK!", __FUNCTION__);
+       iuu_led(port, 0, 0xF000, 0, 0xFF);
+       return status;
+}
+
+static void read_buf_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       struct tty_struct *tty;
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               if (urb->status == -EPROTO) {
+                       /* reschedule needed */
+               }
+               return;
+       }
+
+       dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
+       tty = port->tty;
+       if (data == NULL)
+               dbg("%s - data is NULL !!!", __FUNCTION__);
+       if (tty && urb->actual_length && data) {
+               tty_insert_flip_string(tty, data, urb->actual_length);
+               tty_flip_buffer_push(tty);
+       }
+       iuu_led_activity_on(urb);
+}
+
+static int iuu_bulk_write(struct usb_serial_port *port)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       int result;
+       int i;
+       char *buf_ptr = port->write_urb->transfer_buffer;
+       dbg("%s - enter", __FUNCTION__);
+
+       *buf_ptr++ = IUU_UART_ESC;
+       *buf_ptr++ = IUU_UART_TX;
+       *buf_ptr++ = priv->writelen;
+
+       memcpy(buf_ptr, priv->writebuf,
+              priv->writelen);
+       if (debug == 1) {
+               for (i = 0; i < priv->writelen; i++)
+                       sprintf(priv->dbgbuf + i*2 ,
+                               "%02X", priv->writebuf[i]);
+               priv->dbgbuf[priv->writelen+i*2] = 0;
+               dbg("%s - writing %i chars : %s", __FUNCTION__,
+                   priv->writelen, priv->dbgbuf);
+       }
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, priv->writelen + 3,
+                         iuu_rxcmd, port);
+       result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->writelen = 0;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       usb_serial_port_softint(port);
+       return result;
+}
+
+static int iuu_read_buf(struct usb_serial_port *port, int len)
+{
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, len,
+                         read_buf_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       return result;
+}
+
+static void iuu_uart_read_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       int status;
+       int error = 0;
+       int len = 0;
+       unsigned char *data = urb->transfer_buffer;
+       priv->poll++;
+
+       dbg("%s - enter", __FUNCTION__);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+       if (data == NULL)
+               dbg("%s - data is NULL !!!", __FUNCTION__);
+
+       if (urb->actual_length == 1  && data != NULL)
+               len = (int) data[0];
+
+       if (urb->actual_length > 1) {
+               dbg("%s - urb->actual_length = %i", __FUNCTION__,
+                   urb->actual_length);
+               error = 1;
+               return;
+       }
+       /* if len > 0 call readbuf */
+
+       if (len > 0 && error == 0) {
+               dbg("%s - call read buf - len to read is %i ",
+                       __FUNCTION__, len);
+               status = iuu_read_buf(port, len);
+               return;
+       }
+       /* need to update status  ? */
+       if (priv->poll > 99) {
+               status = iuu_status(port);
+               priv->poll = 0;
+               return;
+       }
+
+       /* reset waiting ? */
+
+       if (priv->reset == 1) {
+               status = iuu_reset(port, 0xC);
+               return;
+       }
+       /* Writebuf is waiting */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->writelen > 0) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               status = iuu_bulk_write(port);
+               return;
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       /* if nothing to write call again rxcmd */
+       dbg("%s - rxcmd recall", __FUNCTION__);
+       iuu_led_activity_off(urb);
+       return;
+}
+
+static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
+                         int count)
+{
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned int flags;
+       dbg("%s - enter", __FUNCTION__);
+
+       if (count > 256)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->writelen > 0) {
+               /* buffer already filled but not commited */
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return (0);
+       }
+       /* fill the buffer */
+       memcpy(priv->writebuf, buf, count);
+       priv->writelen = count;
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return (count);
+}
+
+static void read_rxcmd_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       int result;
+       dbg("%s - enter", __FUNCTION__);
+
+       dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+       if (urb->status) {
+               dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+               /* error stop all */
+               return;
+       }
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer, 256,
+                         iuu_uart_read_callback, port);
+       result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+       dbg("%s - submit result = %d", __FUNCTION__, result);
+       return;
+}
+
+static int iuu_uart_on(struct usb_serial_port *port)
+{
+       int status;
+       u8 *buf;
+
+       buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = IUU_UART_ENABLE;
+       buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
+       buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
+       buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
+
+       status = bulk_immediate(port, buf, 4);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - uart_on error", __FUNCTION__);
+               goto uart_enable_failed;
+       }
+       /*  iuu_reset() the card after iuu_uart_on() */
+       status = iuu_uart_flush(port);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_flush error", __FUNCTION__);
+uart_enable_failed:
+       kfree(buf);
+       return status;
+}
+
+/*  Diables the IUU UART (a.k.a. the Phoenix voiderface) */
+static int iuu_uart_off(struct usb_serial_port *port)
+{
+       int status;
+       u8 *buf;
+       buf = kmalloc(1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       buf[0] = IUU_UART_DISABLE;
+
+       status = bulk_immediate(port, buf, 1);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+
+       kfree(buf);
+       return status;
+}
+
+static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
+                        u32 *actual, u8 parity)
+{
+       int status;
+       u8 *dataout;
+       u8 DataCount = 0;
+       u8 T1Frekvens = 0;
+       u8 T1reload = 0;
+       unsigned int T1FrekvensHZ = 0;
+
+       dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
+
+       if (!dataout)
+               return -ENOMEM;
+
+       if (baud < 1200 || baud > 230400) {
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+       }
+       if (baud > 977) {
+               T1Frekvens = 3;
+               T1FrekvensHZ = 500000;
+       }
+
+       if (baud > 3906) {
+               T1Frekvens = 2;
+               T1FrekvensHZ = 2000000;
+       }
+
+       if (baud > 11718) {
+               T1Frekvens = 1;
+               T1FrekvensHZ = 6000000;
+       }
+
+       if (baud > 46875) {
+               T1Frekvens = 0;
+               T1FrekvensHZ = 24000000;
+       }
+
+       T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
+
+       /*  magic number here:  ENTER_FIRMWARE_UPDATE; */
+       dataout[DataCount++] = IUU_UART_ESC;
+       /*  magic number here:  CHANGE_BAUD; */
+       dataout[DataCount++] = IUU_UART_CHANGE;
+       dataout[DataCount++] = T1Frekvens;
+       dataout[DataCount++] = T1reload;
+
+       *actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
+
+       switch (parity & 0x0F) {
+       case IUU_PARITY_NONE:
+               dataout[DataCount++] = 0x00;
+               break;
+       case IUU_PARITY_EVEN:
+               dataout[DataCount++] = 0x01;
+               break;
+       case IUU_PARITY_ODD:
+               dataout[DataCount++] = 0x02;
+               break;
+       case IUU_PARITY_MARK:
+               dataout[DataCount++] = 0x03;
+               break;
+       case IUU_PARITY_SPACE:
+               dataout[DataCount++] = 0x04;
+               break;
+       default:
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+               break;
+       }
+
+       switch (parity & 0xF0) {
+       case IUU_ONE_STOP_BIT:
+               dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
+               break;
+
+       case IUU_TWO_STOP_BITS:
+               dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
+               break;
+       default:
+               kfree(dataout);
+               return IUU_INVALID_PARAMETER;
+               break;
+       }
+
+       status = bulk_immediate(port, dataout, DataCount);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+       kfree(dataout);
+       return status;
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+       return 0;
+}
+
+static void iuu_close(struct usb_serial_port *port, struct file *filp)
+{
+       /* iuu_led (port,255,0,0,0); */
+       struct usb_serial *serial;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       unsigned long flags;
+       unsigned int c_cflag;
+
+       serial = port->serial;
+       if (!serial)
+               return;
+
+       dbg("%s - port %d", __FUNCTION__, port->number);
+
+       iuu_uart_off(port);
+       if (serial->dev) {
+               if (port->tty) {
+                       c_cflag = port->tty->termios->c_cflag;
+                       if (c_cflag & HUPCL) {
+                               /* drop DTR and RTS */
+                               priv = usb_get_serial_port_data(port);
+                               spin_lock_irqsave(&priv->lock, flags);
+                               priv->line_control = 0;
+                               spin_unlock_irqrestore(&priv->lock, flags);
+                               set_control_lines(port->serial->dev, 0);
+                       }
+               }
+               /* free writebuf */
+               /* shutdown our urbs */
+               dbg("%s - shutting down urbs", __FUNCTION__);
+               usb_kill_urb(port->write_urb);
+               usb_kill_urb(port->read_urb);
+               usb_kill_urb(port->interrupt_in_urb);
+               msleep(1000);
+               /* wait one second to free all buffers */
+               iuu_led(port, 0, 0, 0xF000, 0xFF);
+               msleep(1000);
+               usb_reset_device(port->serial->dev);
+       }
+}
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       u8 *buf;
+       int result;
+       u32 actual;
+       unsigned long flags;
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+
+       dbg("%s -  port %d", __FUNCTION__, port->number);
+       usb_clear_halt(serial->dev, port->write_urb->pipe);
+       usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+       buf = kmalloc(10, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       /* fixup the endpoint buffer size */
+       kfree(port->bulk_out_buffer);
+       port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
+       port->bulk_out_size = 512;
+       kfree(port->bulk_in_buffer);
+       port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
+       port->bulk_in_size = 512;
+
+       if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
+               kfree(port->bulk_out_buffer);
+               kfree(port->bulk_in_buffer);
+               kfree(buf);
+               return -ENOMEM;
+       }
+
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->bulk_out_buffer, 512,
+                         NULL, NULL);
+
+
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                         port->bulk_in_endpointAddress),
+                         port->bulk_in_buffer, 512,
+                         NULL, NULL);
+
+       /* set the termios structure */
+       spin_lock_irqsave(&priv->lock, flags);
+       if (!priv->termios_initialized) {
+               *(port->tty->termios) = tty_std_termios;
+               port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+                                               | TIOCM_CTS | CSTOPB | PARENB;
+               port->tty->termios->c_lflag = 0;
+               port->tty->termios->c_oflag = 0;
+               port->tty->termios->c_iflag = 0;
+               priv->termios_initialized = 1;
+               port->tty->low_latency = 1;
+               priv->poll = 0;
+        }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* initialize writebuf */
+#define FISH(a, b, c, d) do { \
+       result = usb_control_msg(port->serial->dev,     \
+                               usb_rcvctrlpipe(port->serial->dev, 0),  \
+                               b, a, c, d, buf, 1, 1000); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d - %x", a, b, c, d, result, \
+                               buf[0]); } while (0);
+
+#define SOUP(a, b, c, d)  do { \
+       result = usb_control_msg(port->serial->dev,     \
+                               usb_sndctrlpipe(port->serial->dev, 0),  \
+                               b, a, c, d, NULL, 0, 1000); \
+       dbg("0x%x:0x%x:0x%x:0x%x  %d", a, b, c, d, result); } while (0)
+
+       /*  This is not UART related but IUU USB driver related or something */
+       /*  like that. Basically no IUU will accept any commands from the USB */
+       /*  host unless it has received the following message */
+       /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
+
+       SOUP(0x03, 0x02, 0x02, 0x0);
+       kfree(buf);
+       iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
+       iuu_uart_on(port);
+       if (boost < 100)
+               boost = 100;
+       switch (clockmode) {
+       case 2:         /*  3.680 Mhz */
+               iuu_clk(port, IUU_CLK_3680000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       case 3:         /*  6.00 Mhz */
+               iuu_clk(port, IUU_CLK_6000000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 16457 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       default:                /*  3.579 Mhz */
+               iuu_clk(port, IUU_CLK_3579000 * boost / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * boost / 100, &actual,
+                                 IUU_PARITY_EVEN);
+       }
+
+       /* set the cardin cardout signals */
+       switch (cdmode) {
+       case 0:
+               iuu_cardin = 0;
+               iuu_cardout = 0;
+               break;
+       case 1:
+               iuu_cardin = TIOCM_CD;
+               iuu_cardout =  0;
+               break;
+       case 2:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_CD;
+               break;
+       case 3:
+               iuu_cardin = TIOCM_DSR;
+               iuu_cardout = 0;
+               break;
+       case 4:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_DSR;
+               break;
+       case 5:
+               iuu_cardin = TIOCM_CTS;
+               iuu_cardout = 0;
+               break;
+       case 6:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_CTS;
+               break;
+       case 7:
+               iuu_cardin = TIOCM_RNG;
+               iuu_cardout = 0;
+               break;
+       case 8:
+               iuu_cardin = 0;
+               iuu_cardout = TIOCM_RNG;
+       }
+
+       iuu_uart_flush(port);
+
+       dbg("%s - initialization done", __FUNCTION__);
+
+       memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+                         usb_sndbulkpipe(port->serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         port->write_urb->transfer_buffer, 1,
+                         read_rxcmd_callback, port);
+       result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+
+       if (result) {
+               dev_err(&port->dev, "%s - failed submitting read urb,"
+                       " error %d\n", __FUNCTION__, result);
+               iuu_close(port, NULL);
+               return -EPROTO;
+       } else {
+               dbg("%s - rxcmd OK", __FUNCTION__);
+       }
+       return result;
+}
+
+static struct usb_serial_driver iuu_device = {
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "iuu_phoenix",
+                  },
+       .id_table = id_table,
+       .num_interrupt_in = NUM_DONT_CARE,
+       .num_bulk_in = 1,
+       .num_bulk_out = 1,
+       .num_ports = 1,
+       .open = iuu_open,
+       .close = iuu_close,
+       .write = iuu_uart_write,
+       .read_bulk_callback = iuu_uart_read_callback,
+       .tiocmget = iuu_tiocmget,
+       .tiocmset = iuu_tiocmset,
+       .attach = iuu_startup,
+       .shutdown = iuu_shutdown,
+};
+
+static int __init iuu_init(void)
+{
+       int retval;
+       retval = usb_serial_register(&iuu_device);
+       if (retval)
+               goto failed_usb_serial_register;
+       retval = usb_register(&iuu_driver);
+       if (retval)
+               goto failed_usb_register;
+       info(DRIVER_DESC " " DRIVER_VERSION);
+       return 0;
+failed_usb_register:
+       usb_serial_deregister(&iuu_device);
+failed_usb_serial_register:
+       return retval;
+}
+
+static void __exit iuu_exit(void)
+{
+       usb_deregister(&iuu_driver);
+       usb_serial_deregister(&iuu_device);
+}
+
+module_init(iuu_init);
+module_exit(iuu_exit);
+
+MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(xmas, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(xmas, "xmas color enabled or not");
+
+module_param(boost, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500");
+
+module_param(clockmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
+
+module_param(cdmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, "
+                "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING");
diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
new file mode 100644 (file)
index 0000000..b82630a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ *
+ * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás )
+ *
+ *     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.
+ *
+ *  And tested with help of WB Electronics
+ *
+ */
+
+#define   IUU_USB_VENDOR_ID  0x104f
+#define   IUU_USB_PRODUCT_ID  0x0004
+#define   IUU_USB_OP_TIMEOUT  0x0200
+
+/* Programmer commands */
+
+#define IUU_NO_OPERATION   0x00
+#define IUU_GET_FIRMWARE_VERSION   0x01
+#define IUU_GET_PRODUCT_NAME   0x02
+#define IUU_GET_STATE_REGISTER   0x03
+#define IUU_SET_LED   0x04
+#define IUU_WAIT_MUS   0x05
+#define IUU_WAIT_MS   0x06
+#define IUU_GET_LOADER_VERSION   0x50
+#define IUU_RST_SET   0x52
+#define IUU_RST_CLEAR   0x53
+#define IUU_SET_VCC   0x59
+#define IUU_UART_ENABLE   0x49
+#define IUU_UART_DISABLE   0x4A
+#define IUU_UART_WRITE_I2C   0x4C
+#define IUU_UART_ESC   0x5E
+#define IUU_UART_TRAP   0x54
+#define IUU_UART_TRAP_BREAK   0x5B
+#define IUU_UART_RX   0x56
+#define IUU_AVR_ON   0x21
+#define IUU_AVR_OFF   0x22
+#define IUU_AVR_1CLK   0x23
+#define IUU_AVR_RESET   0x24
+#define IUU_AVR_RESET_PC   0x25
+#define IUU_AVR_INC_PC   0x26
+#define IUU_AVR_INCN_PC   0x27
+#define IUU_AVR_PREAD   0x29
+#define IUU_AVR_PREADN   0x2A
+#define IUU_AVR_PWRITE   0x28
+#define IUU_AVR_DREAD   0x2C
+#define IUU_AVR_DREADN   0x2D
+#define IUU_AVR_DWRITE   0x2B
+#define IUU_AVR_PWRITEN   0x2E
+#define IUU_EEPROM_ON   0x37
+#define IUU_EEPROM_OFF   0x38
+#define IUU_EEPROM_WRITE   0x39
+#define IUU_EEPROM_WRITEX   0x3A
+#define IUU_EEPROM_WRITE8   0x3B
+#define IUU_EEPROM_WRITE16   0x3C
+#define IUU_EEPROM_WRITEX32   0x3D
+#define IUU_EEPROM_WRITEX64   0x3E
+#define IUU_EEPROM_READ   0x3F
+#define IUU_EEPROM_READX   0x40
+#define IUU_EEPROM_BREAD   0x41
+#define IUU_EEPROM_BREADX   0x42
+#define IUU_PIC_CMD   0x0A
+#define IUU_PIC_CMD_LOAD   0x0B
+#define IUU_PIC_CMD_READ   0x0C
+#define IUU_PIC_ON   0x0D
+#define IUU_PIC_OFF   0x0E
+#define IUU_PIC_RESET   0x16
+#define IUU_PIC_INC_PC   0x0F
+#define IUU_PIC_INCN_PC   0x10
+#define IUU_PIC_PWRITE   0x11
+#define IUU_PIC_PREAD   0x12
+#define IUU_PIC_PREADN   0x13
+#define IUU_PIC_DWRITE   0x14
+#define IUU_PIC_DREAD   0x15
+#define IUU_UART_NOP   0x00
+#define IUU_UART_CHANGE   0x02
+#define IUU_UART_TX   0x04
+#define IUU_DELAY_MS   0x06
+
+#define IUU_OPERATION_OK   0x00
+#define IUU_DEVICE_NOT_FOUND   0x01
+#define IUU_INVALID_HANDLE   0x02
+#define IUU_INVALID_PARAMETER   0x03
+#define IUU_INVALID_voidERFACE   0x04
+#define IUU_INVALID_REQUEST_LENGTH   0x05
+#define IUU_UART_NOT_ENABLED   0x06
+#define IUU_WRITE_ERROR   0x07
+#define IUU_READ_ERROR   0x08
+#define IUU_TX_ERROR   0x09
+#define IUU_RX_ERROR   0x0A
+
+#define IUU_PARITY_NONE   0x00
+#define IUU_PARITY_EVEN   0x01
+#define IUU_PARITY_ODD   0x02
+#define IUU_PARITY_MARK   0x03
+#define IUU_PARITY_SPACE   0x04
+#define IUU_SC_INSERTED   0x01
+#define IUU_VERIFY_ERROR   0x02
+#define IUU_SIM_INSERTED   0x04
+#define IUU_TWO_STOP_BITS   0x00
+#define IUU_ONE_STOP_BIT   0x20
+#define IUU_BAUD_2400   0x0398
+#define IUU_BAUD_9600   0x0298
+#define IUU_BAUD_19200   0x0164
+#define IUU_BAUD_28800   0x0198
+#define IUU_BAUD_38400   0x01B2
+#define IUU_BAUD_57600   0x0030
+#define IUU_BAUD_115200   0x0098
+#define IUU_CLK_3579000   3579000
+#define IUU_CLK_3680000   3680000
+#define IUU_CLK_6000000   6000000
+#define IUU_FULLCARD_IN   0x01
+#define IUU_DEV_ERROR   0x02
+#define IUU_MINICARD_IN   0x04
+#define IUU_VCC_5V   0x00
+#define IUU_VCC_3V   0x01