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