This patch add the new iuu_phoenix driver.

Signed-off-by: Alain Degreffe <[EMAIL PROTECTED]>


diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 3efe670..1afcd0d 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -554,6 +554,15 @@ config USB_SERIAL_OMNINET
          To compile this driver as a module, choose M here: the
          module will be called omninet.
 
+config USB_SERIAL_IUU
+       tristate "Infinity Usb  Unlimited SM Reader (EXPERIMENTAL)"
+       depends on USB_SERIAL && EXPERIMENTAL
+       help
+         Say Y here if you want to use a IUU in phoenix mode.
+
+         To compile this driver as a module, choose M here: the
+         module will be called iuu_phoenix.
+
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
        depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 61166ad..96b8ddc 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -47,4 +47,5 @@ obj-$(CONFIG_USB_SERIAL_TI)                   += 
ti_usb_3410_5052.o
 obj-$(CONFIG_USB_SERIAL_VISOR)                 += visor.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)             += whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)                        += keyspan_pda.o
+obj-$(CONFIG USB_SERIAL_IUU)                   += iuu_phoenix.o
 
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
new file mode 100644
index 0000000..00f3e96
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -0,0 +1,1095 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe ([EMAIL PROTECTED])
+ *
+ *
+ * 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"
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.1"
+#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,
+};
+
+static int iuu_startup(struct usb_serial *serial);
+
+static void iuu_shutdown(struct usb_serial *serial);
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp);
+static void iuu_close(struct usb_serial_port *port, struct file *filp);
+
+static int iuu_uart_write(struct usb_serial_port *port,
+                         const u8 *buf, int count);
+
+static int read_immediate(struct usb_serial_port *port, u8 *buf,
+                         u8 count);
+static int iuu_uart_flush(struct usb_serial_port *port);
+static int iuu_uart_read(struct usb_serial_port *port, u8 *data,
+                        u8 *len);
+static int iuu_uart_baud(struct usb_serial_port *port, u_int32_t baud,
+                        u_int32_t *actual, u_int8_t parity);
+static int iuu_reset(struct usb_serial_port *port, u_int8_t wt);
+static int bulk_immediate(struct usb_serial_port *port, u8 *buf,
+                         u8 count);
+
+static int iuu_ioctl(struct usb_serial_port *port, struct file *file,
+                    unsigned int cmd, unsigned long arg);
+static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
+                       unsigned int set, unsigned int clear);
+static int iuu_tiocmget(struct usb_serial_port *port, struct file *file);
+
+static int iuu_uart_read_and_store(struct usb_serial_port *port);
+static int iuu_uart_on(struct usb_serial_port *port);
+static int iuu_uart_off(struct usb_serial_port *port);
+
+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,
+       .ioctl = iuu_ioctl,
+       .tiocmget = iuu_tiocmget,
+       .tiocmset = iuu_tiocmset,
+       .attach = iuu_startup,
+       .shutdown = iuu_shutdown,
+};
+
+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 write_busy;
+       int TIOSTATUS;
+};
+
+/* Structure used for write/read operation */
+
+struct iuu_buffers {
+       u8 buf[256];
+       u8 finalbuf[256];
+       u8 dbgbuf[512];
+       u8 len;
+};
+
+/* turbo parameter */
+
+int multiplicator = 100;
+int clockmode = 1;
+int smart = 1;
+
+static int iuu_startup(struct usb_serial *serial)
+{
+       struct iuu_private *priv;
+       priv = kmalloc(sizeof(struct iuu_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       memset(priv, 0x00, sizeof(struct iuu_private));
+       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)
+{
+
+       dbg("%s", __FUNCTION__);
+       kfree(usb_get_serial_port_data(serial->port[0]));
+       usb_set_serial_port_data(serial->port[0], NULL);
+}
+
+/* Status Function
+ * Return value is
+ * 0x00 = no card
+ * 0x01 = smartcard
+ * 0x02 = sim card
+ */
+
+int iuu_status(struct usb_serial_port *port, char *st)
+{
+       int status;
+       st[0] = IUU_GET_STATE_REGISTER;
+
+       status = bulk_immediate(port, st, 1);
+       if (status != IUU_OPERATION_OK) {
+               return status;
+       }
+
+       status = read_immediate(port, st, 1);
+       return status;
+}
+
+/* Fake settings
+ * The IUU need to be reset to deliver the ATR value
+ * ioctl is used ( tiocmget/set in new kernels) to pass the RST order
+ * In real life, a period of 500 ms is required to reset a card
+ * Here we just care that RST followed by a NONE is received to call iuu_reset
+ */
+
+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 == 0) && priv->TIOSTATUS == TIOCM_RTS) {
+               dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+               priv->TIOSTATUS = 0;
+               if (iuu_reset(port, 0x0C))
+                       return -EIO;
+               current->state = TASK_INTERRUPTIBLE;
+               schedule_timeout(1 + 500 * HZ / 1000);
+               iuu_uart_read_and_store(port);
+       }
+
+       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)
+{
+       u8 *st;
+       st = kmalloc(sizeof(u8), GFP_KERNEL);
+       iuu_status(port, st);
+
+       dbg("%s (%d) msg ", __FUNCTION__, port->number);
+       if (st[0] & IUU_FULLCARD_IN) {
+               dbg("%s  card present ! value returned %i ", __FUNCTION__,
+                   TIOCM_CD);
+               kfree(st);
+               return 0;
+       } else {
+               kfree(st);
+               return TIOCM_CD;
+       }
+}
+
+static int
+iuu_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd,
+         unsigned long arg)
+{
+
+       int mask;
+
+       dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
+
+       get_user(mask, (unsigned long *)arg);
+
+       dbg("%s (%d) msg = %04x", __FUNCTION__, port->number, mask);
+       switch (cmd) {
+       case TCGETS:
+               return (0);
+
+       case TCFLSH:
+               return (-1);
+
+       case TIOCMBIS:
+       case TIOCMBIC:
+       case TCSETS:
+       case TIOCSSERIAL:
+               if (mask & CS8)
+                       dbg("%s  TIOCMSET CS8", __FUNCTION__);
+               if (mask & CS7)
+                       dbg("%s  TIOCMSET CS7", __FUNCTION__);
+               if (mask & CSTOPB)
+                       dbg("%s  TIOCMSET CSTOPB", __FUNCTION__);
+               if (mask & PARENB)
+                       dbg("%s  TIOCMSET PARENB", __FUNCTION__);
+               if (mask & PARODD)
+                       dbg("%s  TIOCMSET PARODD", __FUNCTION__);
+
+               dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+                   port->number);
+               return (0);
+
+       case TIOCMIWAIT:
+               dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+               return 0;
+
+       default:
+               dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
+
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int iuu_reset(struct usb_serial_port *port, u_int8_t wt)
+{
+       int status;
+       u8 *buf;
+
+       status = iuu_uart_flush(port);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - reset (flush) error ", __FUNCTION__);
+               return status;
+       }
+
+       buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = IUU_RST_SET;
+       buf[1] = IUU_DELAY_MS;
+       buf[2] = wt;            /* miliseconds */
+       buf[3] = IUU_RST_CLEAR;
+
+       status = bulk_immediate(port, buf, 4);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - reset error ", __FUNCTION__);
+       else
+               dbg("%s - reset OK ", __FUNCTION__);
+       kfree(buf);
+       return status;
+}
+
+static int
+bulk_immediate(struct usb_serial_port *port, u8 *buf,
+              u8 count)
+{
+       int status;
+       struct usb_serial *serial = port->serial;
+       int actual = 0;
+
+       /* 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;
+
+       /* 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;
+}
+
+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(sizeof(u_int8_t) * 8, GFP_KERNEL);
+
+       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 int
+iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
+              int count)
+{
+       int status;
+       int curpos = 0;
+       int i;
+       int security = 0;
+
+       struct iuu_private *priv = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       struct iuu_buffers *tmp;
+
+       if (count == 0)
+               return (0);
+
+       /* prevent buffer overflow */
+       if (count > 256)
+               return -ENOMEM;
+
+       if (priv->write_busy)
+               return -1;
+
+       tmp = kmalloc(sizeof(struct iuu_buffers), GFP_KERNEL);
+       if (!tmp)
+               return -EIO;
+
+       priv->write_busy = 1;
+       dbg("%s - try to write %i chars : %02X ", __FUNCTION__, count, buf[0]);
+       tmp->buf[0] = IUU_UART_ESC;
+       tmp->buf[1] = IUU_UART_TX;
+       tmp->buf[2] = count;
+       memcpy(&tmp->buf[3], buf, count);
+       dbg("%s - try to write %i chars ", __FUNCTION__, tmp->buf[2]);
+       status = bulk_immediate(port, tmp->buf, count + 3);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - uart_write error", __FUNCTION__);
+               kfree(tmp);
+               priv->write_busy = 0;
+               return status;
+       }
+
+       tty = port->tty;
+       tty->low_latency = 1;
+
+       while (security < 200) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(1 + 1 * HZ / 1000);
+               if (iuu_uart_read(port, tmp->buf, &tmp->len) < 0) {
+                       kfree(tmp);
+                       dbg("%s - read error", __FUNCTION__);
+                       return -EIO;
+               }
+               dbg("%s - port = %i , round = %i" , __FUNCTION__,
+                       port->number, security );
+               if (tmp->len > 0) {
+                       /* test buffer overflow */
+                       if (curpos + tmp->len > 256) {
+                               kfree(tmp);
+                               return -1;
+                       }
+                       memcpy(&tmp->finalbuf[curpos], tmp->buf, tmp->len);
+                       curpos += tmp->len;
+                       for (i = 0; i < tmp->len; ++i) {
+                               if (tty_buffer_request_room(tty, 1) == 0)
+                                       break;
+                               tty_insert_flip_char(tty, tmp->buf[i],
+                                                    TTY_NORMAL);
+                               sprintf(tmp->dbgbuf +
+                                       ((curpos - tmp->len + i) * 2), "%02X",
+                                       tmp->buf[i]);
+                       }
+                       tmp->dbgbuf[curpos * 2] = '\0';
+                       dbg("%s - read reader %i round %i = %s", __FUNCTION__,
+                               port->number, security, tmp->dbgbuf);
+                       tty_schedule_flip(tty);
+               }
+               if ( smart == 1 ) {
+
+                       if ( (tmp->finalbuf[curpos - 2] == 0x90)
+                               && (curpos > count+1 )
+                               && (tmp->finalbuf[curpos - 1] == 0x00))
+                                       security = 200;
+                       if (count == 5
+                               && curpos == count + 1
+                               && buf[2] != 0
+                               && buf[3] != 0 )
+                                       security = 200;
+                       if ((tmp->finalbuf[curpos - 2] == 0x90)
+                               && (curpos == count + 2 )
+                               && (count > 5 ))
+                                       security = 200;
+               }
+               security++;
+       }
+       if ( security == 200 )
+               iuu_uart_flush(port);
+       kfree(tmp);
+       priv->write_busy = 0;
+       return count;
+
+}
+
+static int iuu_uart_read_and_store(struct usb_serial_port *port)
+{
+       struct iuu_buffers *tmp;
+       struct tty_struct *tty;
+       int i;
+
+       tmp = kmalloc(sizeof(struct iuu_buffers), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       if (iuu_uart_read(port, tmp->buf, &tmp->len) < 0) {
+               kfree(tmp);
+               return -EIO;
+       }
+
+       tty = port->tty;
+       tty->low_latency = 1;
+       for (i = 0; i < tmp->len; ++i) {
+               if (tty_buffer_request_room(tty, 1) == 0)
+                       break;
+               tty_insert_flip_char(tty, tmp->buf[i], TTY_NORMAL);
+               sprintf(&tmp->dbgbuf[i * 2], "%02X", tmp->buf[i]);
+       }
+       tmp->dbgbuf[i * 2] = '\0';
+       dbg("%s - read = %s", __FUNCTION__, tmp->dbgbuf);
+       tty_flip_buffer_push(tty);
+       kfree(tmp);
+       return i;
+}
+
+static int iuu_clk(struct usb_serial_port *port, int dwFrq)
+{
+       int status;
+       struct iuu_buffers *tmp;
+       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;
+
+       tmp = kmalloc(sizeof(struct iuu_buffers), GFP_KERNEL);
+
+       if (!tmp)
+               return -ENOMEM;
+
+       if (frq == 0) {
+               tmp->buf[Count++] = IUU_UART_WRITE_I2C;
+               tmp->buf[Count++] = FrqGenAdr << 1;
+               tmp->buf[Count++] = 0x09;
+               tmp->buf[Count++] = 0x00;
+
+               status = bulk_immediate(port, (u_int8_t *) tmp->buf, Count);
+               if (status != 0) {
+                       dbg("%s - write error ", __FUNCTION__);
+                       kfree(tmp);
+                       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;
+
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x09;
+       tmp->buf[Count++] = 0x20;       /* Adr = 0x09 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x0C;
+       tmp->buf[Count++] = DIV;        /* Adr = 0x0C */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x12;
+       tmp->buf[Count++] = XDRV;       /* Adr = 0x12 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x13;
+       tmp->buf[Count++] = 0x6B;       /* Adr = 0x13 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x40;
+       tmp->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2))
+                               | (PBmsb & 0x03); /* Adr = 0x40 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x41;
+       tmp->buf[Count++] = PBlsb;      /* Adr = 0x41 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x42;
+       tmp->buf[Count++] = Q | (((PO & 0x01) << 7));   /* Adr = 0x42 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x44;
+       tmp->buf[Count++] = (char)0xFF; /* Adr = 0x44 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x45;
+       tmp->buf[Count++] = (char)0xFE; /* Adr = 0x45 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x46;
+       tmp->buf[Count++] = 0x7F;       /* Adr = 0x46 */
+       tmp->buf[Count++] = IUU_UART_WRITE_I2C; /*  0x4C */
+       tmp->buf[Count++] = FrqGenAdr << 1;
+       tmp->buf[Count++] = 0x47;
+       tmp->buf[Count++] = (char)0x84; /* Adr = 0x47 */
+
+       status = bulk_immediate(port, (u8 *)tmp->buf,
+                                                       Count);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - write error ", __FUNCTION__);
+
+       kfree(tmp);
+       return status;
+}
+
+static int iuu_uart_flush(struct usb_serial_port *port)
+{
+       int i;
+       int status;
+       u8 rxcmd = IUU_UART_RX;
+       struct iuu_buffers *tmp;
+
+       tmp = kmalloc(sizeof(struct iuu_buffers), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       /* u_int8_t datain[256]; */
+
+       if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) {
+               kfree(tmp);
+               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, &tmp->len, 1);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_read error", __FUNCTION__);
+                       kfree(tmp);
+                       return status;
+               }
+
+               if (tmp->len > 0) {
+                       dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+                           tmp->len);
+                       status = read_immediate(port, tmp->buf, tmp->len);
+                       if (status != IUU_OPERATION_OK) {
+                               dbg("%s - uart_flush_read error", __FUNCTION__);
+                               kfree(tmp);
+                               return status;
+                       }
+               }
+       }
+       dbg("%s - uart_flush_read OK!", __FUNCTION__);
+       iuu_led(port, 0, 0xF000, 0, 0xFF);
+       kfree(tmp);
+       return status;
+}
+
+static int
+iuu_uart_read(struct usb_serial_port *port, u8 *data,
+             u8 *len)
+{
+       int status;
+       u8 rxcmd = IUU_UART_RX;
+       status = bulk_immediate(port, &rxcmd, 1);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - uart_flush_write error", __FUNCTION__);
+               len = 0;
+               return status;
+       }
+
+       status = read_immediate(port, len, 1);
+       if (status != IUU_OPERATION_OK) {
+               dbg("%s - uart_flush_read error", __FUNCTION__);
+               len[0] = 0;
+               return status;
+       }
+
+       if (len[0] > 0) {
+               dbg("%s - uart_read datalen is : %i ", __FUNCTION__, len[0]);
+               status = read_immediate(port, data, len[0]);
+               if (status != IUU_OPERATION_OK) {
+                       dbg("%s - uart_flush_read error", __FUNCTION__);
+                       len[0] = 0;
+                       return status;
+               }
+       }
+       dbg("%s - uart_read OK!", __FUNCTION__);
+       return len[0];
+}
+
+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__);
+               kfree(buf);
+               return status;
+       }
+       /*  iuu_reset() the card after iuu_uart_on() */
+       status = iuu_uart_flush(port);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_flush error", __FUNCTION__);
+
+       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 = IUU_UART_DISABLE;
+
+       status = bulk_immediate(port, &buf, 1);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+
+       return status;
+}
+
+/*
+static int
+iuu_uart_set(struct usb_serial_port *port, u8 br,
+            u8 parity, u8 sbits)
+{
+       int status;
+       u8 *buf;
+
+       buf = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = IUU_UART_ESC;
+       buf[1] = IUU_UART_CHANGE;
+       buf[2] = (u_int8_t) ((br >> 8) & 0x00FF);
+       buf[3] = (u_int8_t) (0x00FF & br);
+       buf[4] = (u_int8_t) (parity | sbits);
+
+       status = bulk_immediate(port, buf, 5);
+       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, u_int32_t baud, u_int32_t *actual,
+             u_int8_t parity)
+{
+
+       /* SDK_STATUS sdk_status = SDK_SUCCESS; */
+       /* u8 dataout[10]; */
+       /* DWORD dwWritten = 0; */
+       /* unsigned void DataCount = 0; */
+
+       int status;
+       u8 *dataout;
+       u_int8_t 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)
+               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:
+               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:
+               return IUU_INVALID_PARAMETER;
+               break;
+       }
+
+       status = bulk_immediate(port, dataout, DataCount);
+       if (status != IUU_OPERATION_OK)
+               dbg("%s - uart_off error", __FUNCTION__);
+
+       return status;
+}
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct usb_serial *serial = port->serial;
+       u8 *buf;
+       int result;
+       u_int32_t 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;
+
+/* 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 = ONLCR;
+       port->tty->termios->c_iflag = 0;
+       priv->termios_initialized = 1;
+       /* } */
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+#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);
+       iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
+       iuu_clk(port, IUU_CLK_6000000);
+       /* iuu_clk(serial->port, IUU_CLK_3579000); */
+       iuu_uart_on(port);
+       switch (clockmode) {
+       case 2:         /*  3.680 Mhz */
+               iuu_clk(port, IUU_CLK_3680000 * multiplicator / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * multiplicator / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       case 3:         /*  6.00 Mhz */
+               iuu_clk(port, IUU_CLK_6000000 * multiplicator / 100);
+               result =
+                   iuu_uart_baud(port, 16457 * multiplicator / 100, &actual,
+                                 IUU_PARITY_EVEN);
+               break;
+       default:                /*  3.579 Mhz */
+               iuu_clk(port, IUU_CLK_3579000 * multiplicator / 100);
+               result =
+                   iuu_uart_baud(port, 9600 * multiplicator / 100, &actual,
+                                 IUU_PARITY_EVEN);
+       }
+
+       iuu_uart_flush(port);
+
+       return 0;
+}
+
+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;
+       unsigned long flags;
+       unsigned int c_cflag;
+       int result;
+
+       serial = port->serial;
+       if (!serial)
+               return;
+       iuu_led(port, 0, 0, 0xF000, 0xFF);
+       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);
+                       }
+               }
+
+               /* shutdown our urbs */
+               dbg("%s - shutting down urbs", __FUNCTION__);
+               result = usb_unlink_urb(port->write_urb);
+               if (result)
+                       dbg("%s - usb_unlink_urb (write_urb)"
+                           " failed with reason: %d", __FUNCTION__, result);
+
+               result = usb_unlink_urb(port->read_urb);
+               if (result)
+                       dbg("%s - usb_unlink_urb (read_urb) "
+                           "failed with reason: %d", __FUNCTION__, result);
+
+               result = usb_unlink_urb(port->interrupt_in_urb);
+               if (result)
+                       dbg("%s - usb_unlink_urb (voiderrupt_in_urb)"
+                           " failed with reason: %d", __FUNCTION__, result);
+       }
+}
+
+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_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(smart, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(smart, "stop processing if card answer is 90 00  !");
+
+module_param(multiplicator, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(multiplicator, "overclock multiplicator percent 100 to 500");
+
+module_param(clockmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
new file mode 100644
index 0000000..3c9a766
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.h
@@ -0,0 +1,122 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe ([EMAIL PROTECTED])
+ *
+ *
+ * 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

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to