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