2007-10-26 15:51:49 +04:00
/*
* Infinity Unlimited USB Phoenix driver
*
2010-05-21 14:53:25 +04:00
* Copyright ( C ) 2010 James Courtier - Dutton ( James @ superbug . co . uk )
2007-10-26 15:51:49 +04:00
* Copyright ( C ) 2007 Alain Degreffe ( eczema @ ecze . com )
*
* Original code taken from iuutool ( Copyright ( C ) 2006 Juan Carlos Borrà ¡ s )
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* And tested with help of WB Electronics
*
*/
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/serial.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/spinlock.h>
# include <linux/uaccess.h>
# include <linux/usb.h>
# include <linux/usb/serial.h>
# include "iuu_phoenix.h"
# include <linux/random.h>
# ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1 ;
# else
static int debug ;
# endif
/*
* Version Information
*/
2010-05-21 14:53:25 +04:00
# define DRIVER_VERSION "v0.12"
2007-10-26 15:51:49 +04:00
# define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
2010-01-10 17:34:24 +03:00
static const struct usb_device_id id_table [ ] = {
2007-10-26 15:51:49 +04:00
{ USB_DEVICE ( IUU_USB_VENDOR_ID , IUU_USB_PRODUCT_ID ) } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( usb , id_table ) ;
static struct usb_driver iuu_driver = {
. name = " iuu_phoenix " ,
. probe = usb_serial_probe ,
. disconnect = usb_serial_disconnect ,
. id_table = id_table ,
. no_dynamic_id = 1 ,
} ;
/* turbo parameter */
static int boost = 100 ;
static int clockmode = 1 ;
static int cdmode = 1 ;
static int iuu_cardin ;
static int iuu_cardout ;
static int xmas ;
2009-08-18 23:05:57 +04:00
static int vcc_default = 5 ;
2007-10-26 15:51:49 +04:00
static void read_rxcmd_callback ( struct urb * urb ) ;
struct iuu_private {
spinlock_t lock ; /* store irq state */
wait_queue_head_t delta_msr_wait ;
u8 line_status ;
int tiostatus ; /* store IUART SIGNAL for tiocmget call */
u8 reset ; /* if 1 reset is needed */
int poll ; /* number of poll */
u8 * writebuf ; /* buffer for writing to device */
int writelen ; /* num of byte to write to device */
u8 * buf ; /* used for initialize speed */
u8 * dbgbuf ; /* debug buffer */
u8 len ;
2009-08-18 23:05:55 +04:00
int vcc ; /* vcc (either 3 or 5 V) */
2010-05-21 14:53:25 +04:00
u32 baud ;
u32 boost ;
u32 clk ;
2007-10-26 15:51:49 +04:00
} ;
static void iuu_free_buf ( struct iuu_private * priv )
{
kfree ( priv - > buf ) ;
kfree ( priv - > dbgbuf ) ;
kfree ( priv - > writebuf ) ;
}
static int iuu_alloc_buf ( struct iuu_private * priv )
{
priv - > buf = kzalloc ( 256 , GFP_KERNEL ) ;
priv - > dbgbuf = kzalloc ( 256 , GFP_KERNEL ) ;
priv - > writebuf = kzalloc ( 256 , GFP_KERNEL ) ;
if ( ! priv - > buf | | ! priv - > dbgbuf | | ! priv - > writebuf ) {
iuu_free_buf ( priv ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s problem allocation buffer " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return - ENOMEM ;
}
2008-03-04 03:08:34 +03:00
dbg ( " %s - Privates buffers allocation success " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return 0 ;
}
static int iuu_startup ( struct usb_serial * serial )
{
struct iuu_private * priv ;
priv = kzalloc ( sizeof ( struct iuu_private ) , GFP_KERNEL ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s- priv allocation success " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( ! priv )
return - ENOMEM ;
if ( iuu_alloc_buf ( priv ) ) {
kfree ( priv ) ;
return - ENOMEM ;
}
2009-08-18 23:05:57 +04:00
priv - > vcc = vcc_default ;
2007-10-26 15:51:49 +04:00
spin_lock_init ( & priv - > lock ) ;
init_waitqueue_head ( & priv - > delta_msr_wait ) ;
usb_set_serial_port_data ( serial - > port [ 0 ] , priv ) ;
return 0 ;
}
2009-06-02 19:53:55 +04:00
/* Release function */
static void iuu_release ( struct usb_serial * serial )
2007-10-26 15:51:49 +04:00
{
struct usb_serial_port * port = serial - > port [ 0 ] ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
if ( ! port )
return ;
2008-03-04 03:08:34 +03:00
dbg ( " %s " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( priv ) {
iuu_free_buf ( priv ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - I will free all " , __func__ ) ;
2007-10-26 15:51:49 +04:00
usb_set_serial_port_data ( port , NULL ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - priv is not anymore in port structure " , __func__ ) ;
2007-10-26 15:51:49 +04:00
kfree ( priv ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s priv is now kfree " , __func__ ) ;
2007-10-26 15:51:49 +04:00
}
}
2008-07-22 14:09:07 +04:00
static int iuu_tiocmset ( struct tty_struct * tty , struct file * file ,
2007-10-26 15:51:49 +04:00
unsigned int set , unsigned int clear )
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2007-10-26 15:51:49 +04:00
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-02-21 00:39:25 +03:00
unsigned long flags ;
2007-10-26 15:51:49 +04:00
2008-02-21 00:39:25 +03:00
/* FIXME: locking on tiomstatus */
2008-03-04 03:08:34 +03:00
dbg ( " %s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x " , __func__ ,
2007-10-26 15:51:49 +04:00
port - > number , set , clear ) ;
2008-02-21 00:39:25 +03:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2007-10-26 15:51:49 +04:00
2010-05-21 14:53:25 +04:00
if ( ( set & TIOCM_RTS ) & & ! ( priv - > tiostatus = = TIOCM_RTS ) ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s TIOCMSET RESET called !!! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
priv - > reset = 1 ;
}
2010-05-21 14:53:25 +04:00
if ( set & TIOCM_RTS )
priv - > tiostatus = TIOCM_RTS ;
2008-02-21 00:39:25 +03:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2007-10-26 15:51:49 +04:00
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
*/
2008-07-22 14:09:07 +04:00
static int iuu_tiocmget ( struct tty_struct * tty , struct file * file )
2007-10-26 15:51:49 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2007-10-26 15:51:49 +04:00
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-02-21 00:39:25 +03:00
unsigned long flags ;
int rc ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
rc = priv - > tiostatus ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
return rc ;
2007-10-26 15:51:49 +04:00
}
static void iuu_rxcmd ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
int result ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
if ( status ) {
dbg ( " %s - status = %d " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
/* error stop all */
return ;
}
memset ( port - > write_urb - > transfer_buffer , IUU_UART_RX , 1 ) ;
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 1 ,
read_rxcmd_callback , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
}
static int iuu_reset ( struct usb_serial_port * port , u8 wt )
{
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
int result ;
char * buf_ptr = port - > write_urb - > transfer_buffer ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
/* Prepare the reset sequence */
* buf_ptr + + = IUU_RST_SET ;
* buf_ptr + + = IUU_DELAY_MS ;
* buf_ptr + + = wt ;
* buf_ptr = IUU_RST_CLEAR ;
/* send the sequence */
usb_fill_bulk_urb ( port - > write_urb ,
port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 4 , iuu_rxcmd , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
priv - > reset = 0 ;
return result ;
}
/* Status Function
* Return value is
* 0x00 = no card
* 0x01 = smartcard
* 0x02 = sim card
*/
static void iuu_update_status_callback ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
u8 * st ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
if ( status ) {
dbg ( " %s - status = %d " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
/* error stop all */
return ;
}
st = urb - > transfer_buffer ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( urb - > actual_length = = 1 ) {
switch ( st [ 0 ] ) {
case 0x1 :
priv - > tiostatus = iuu_cardout ;
break ;
case 0x0 :
priv - > tiostatus = iuu_cardin ;
break ;
default :
priv - > tiostatus = iuu_cardin ;
}
}
iuu_rxcmd ( urb ) ;
}
static void iuu_status_callback ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
int result ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
dbg ( " %s - status = %d " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
usb_fill_bulk_urb ( port - > read_urb , port - > serial - > dev ,
usb_rcvbulkpipe ( port - > serial - > dev ,
port - > bulk_in_endpointAddress ) ,
port - > read_urb - > transfer_buffer , 256 ,
iuu_update_status_callback , port ) ;
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
}
static int iuu_status ( struct usb_serial_port * port )
{
int result ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
memset ( port - > write_urb - > transfer_buffer , IUU_GET_STATE_REGISTER , 1 ) ;
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 1 ,
iuu_status_callback , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
return result ;
}
static int bulk_immediate ( struct usb_serial_port * port , u8 * buf , u8 count )
{
int status ;
struct usb_serial * serial = port - > serial ;
int actual = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
/* 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 ) ;
2008-07-22 14:12:59 +04:00
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - error = %2x " , __func__ , status ) ;
2008-07-22 14:12:59 +04:00
else
2008-03-04 03:08:34 +03:00
dbg ( " %s - write OK ! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
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 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
/* 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 ) ;
2008-07-22 14:12:59 +04:00
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - error = %2x " , __func__ , status ) ;
2008-07-22 14:12:59 +04:00
else
2008-03-04 03:08:34 +03:00
dbg ( " %s - read OK ! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
static int iuu_led ( struct usb_serial_port * port , unsigned int R ,
unsigned int G , unsigned int B , u8 f )
{
int status ;
u8 * buf ;
buf = kmalloc ( 8 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
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 )
2008-03-04 03:08:34 +03:00
dbg ( " %s - led error status = %2x " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
else
2008-03-04 03:08:34 +03:00
dbg ( " %s - led OK ! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return IUU_OPERATION_OK ;
}
static void iuu_rgbf_fill_buffer ( u8 * buf , u8 r1 , u8 r2 , u8 g1 , u8 g2 , u8 b1 ,
u8 b2 , u8 freq )
{
* buf + + = IUU_SET_LED ;
* buf + + = r1 ;
* buf + + = r2 ;
* buf + + = g1 ;
* buf + + = g2 ;
* buf + + = b1 ;
* buf + + = b2 ;
* buf = freq ;
}
static void iuu_led_activity_on ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
int result ;
char * buf_ptr = port - > write_urb - > transfer_buffer ;
* buf_ptr + + = IUU_SET_LED ;
if ( xmas = = 1 ) {
get_random_bytes ( buf_ptr , 6 ) ;
* ( buf_ptr + 7 ) = 1 ;
} else {
iuu_rgbf_fill_buffer ( buf_ptr , 255 , 255 , 0 , 0 , 0 , 0 , 255 ) ;
}
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 8 ,
iuu_rxcmd , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
}
static void iuu_led_activity_off ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
int result ;
char * buf_ptr = port - > write_urb - > transfer_buffer ;
if ( xmas = = 1 ) {
iuu_rxcmd ( urb ) ;
return ;
} else {
* buf_ptr + + = IUU_SET_LED ;
iuu_rgbf_fill_buffer ( buf_ptr , 0 , 0 , 255 , 255 , 0 , 0 , 255 ) ;
}
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 8 ,
iuu_rxcmd , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
}
static int iuu_clk ( struct usb_serial_port * port , int dwFrq )
{
int status ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
int Count = 0 ;
u8 FrqGenAdr = 0x69 ;
u8 DIV = 0 ; /* 8bit */
u8 XDRV = 0 ; /* 8bit */
u8 PUMP = 0 ; /* 3bit */
u8 PBmsb = 0 ; /* 2bit */
u8 PBlsb = 0 ; /* 8bit */
u8 PO = 0 ; /* 1bit */
u8 Q = 0 ; /* 7bit */
/* 24bit = 3bytes */
unsigned int P = 0 ;
unsigned int P2 = 0 ;
int frq = ( int ) dwFrq ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( frq = = 0 ) {
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ;
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x09 ;
priv - > buf [ Count + + ] = 0x00 ;
status = bulk_immediate ( port , ( u8 * ) priv - > buf , Count ) ;
if ( status ! = 0 ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - write error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
} else if ( frq = = 3579000 ) {
DIV = 100 ;
P = 1193 ;
Q = 40 ;
XDRV = 0 ;
} else if ( frq = = 3680000 ) {
DIV = 105 ;
P = 161 ;
Q = 5 ;
XDRV = 0 ;
} else if ( frq = = 6000000 ) {
DIV = 66 ;
P = 66 ;
Q = 2 ;
XDRV = 0x28 ;
} else {
unsigned int result = 0 ;
unsigned int tmp = 0 ;
unsigned int check ;
unsigned int check2 ;
char found = 0x00 ;
unsigned int lQ = 2 ;
unsigned int lP = 2055 ;
unsigned int lDiv = 4 ;
for ( lQ = 2 ; lQ < = 47 & & ! found ; lQ + + )
for ( lP = 2055 ; lP > = 8 & & ! found ; lP - - )
for ( lDiv = 4 ; lDiv < = 127 & & ! found ; lDiv + + ) {
tmp = ( 12000000 / lDiv ) * ( lP / lQ ) ;
if ( abs ( ( int ) ( tmp - frq ) ) <
abs ( ( int ) ( frq - result ) ) ) {
check2 = ( 12000000 / lQ ) ;
if ( check2 < 250000 )
continue ;
check = ( 12000000 / lQ ) * lP ;
if ( check > 400000000 )
continue ;
if ( check < 100000000 )
continue ;
if ( lDiv < 4 | | lDiv > 127 )
continue ;
result = tmp ;
P = lP ;
DIV = lDiv ;
Q = lQ ;
if ( result = = frq )
found = 0x01 ;
}
}
}
P2 = ( ( P - PO ) / 2 ) - 4 ;
DIV = DIV ;
PUMP = 0x04 ;
PBmsb = ( P2 > > 8 & 0x03 ) ;
PBlsb = P2 & 0xFF ;
PO = ( P > > 10 ) & 0x01 ;
Q = Q - 2 ;
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x09 ;
priv - > buf [ Count + + ] = 0x20 ; /* Adr = 0x09 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x0C ;
priv - > buf [ Count + + ] = DIV ; /* Adr = 0x0C */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x12 ;
priv - > buf [ Count + + ] = XDRV ; /* Adr = 0x12 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x13 ;
priv - > buf [ Count + + ] = 0x6B ; /* Adr = 0x13 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x40 ;
priv - > buf [ Count + + ] = ( 0xC0 | ( ( PUMP & 0x07 ) < < 2 ) ) |
( PBmsb & 0x03 ) ; /* Adr = 0x40 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x41 ;
priv - > buf [ Count + + ] = PBlsb ; /* Adr = 0x41 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x42 ;
priv - > buf [ Count + + ] = Q | ( ( ( PO & 0x01 ) < < 7 ) ) ; /* Adr = 0x42 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x44 ;
priv - > buf [ Count + + ] = ( char ) 0xFF ; /* Adr = 0x44 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x45 ;
priv - > buf [ Count + + ] = ( char ) 0xFE ; /* Adr = 0x45 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x46 ;
priv - > buf [ Count + + ] = 0x7F ; /* Adr = 0x46 */
priv - > buf [ Count + + ] = IUU_UART_WRITE_I2C ; /* 0x4C */
priv - > buf [ Count + + ] = FrqGenAdr < < 1 ;
priv - > buf [ Count + + ] = 0x47 ;
priv - > buf [ Count + + ] = ( char ) 0x84 ; /* Adr = 0x47 */
status = bulk_immediate ( port , ( u8 * ) priv - > buf , Count ) ;
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - write error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
static int iuu_uart_flush ( struct usb_serial_port * port )
{
int i ;
int status ;
u8 rxcmd = IUU_UART_RX ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( iuu_led ( port , 0xF000 , 0 , 0 , 0xFF ) < 0 )
return - EIO ;
for ( i = 0 ; i < 2 ; i + + ) {
status = bulk_immediate ( port , & rxcmd , 1 ) ;
if ( status ! = IUU_OPERATION_OK ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush_write error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
status = read_immediate ( port , & priv - > len , 1 ) ;
if ( status ! = IUU_OPERATION_OK ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush_read error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
if ( priv - > len > 0 ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush datalen is : %i " , __func__ ,
2007-10-26 15:51:49 +04:00
priv - > len ) ;
status = read_immediate ( port , priv - > buf , priv - > len ) ;
if ( status ! = IUU_OPERATION_OK ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush_read error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
return status ;
}
}
}
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush_read OK! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
iuu_led ( port , 0 , 0xF000 , 0 , 0xFF ) ;
return status ;
}
static void read_buf_callback ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
unsigned char * data = urb - > transfer_buffer ;
struct tty_struct * tty ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
dbg ( " %s - status = %d " , __func__ , status ) ;
if ( status ) {
if ( status = = - EPROTO ) {
2007-10-26 15:51:49 +04:00
/* reschedule needed */
}
return ;
}
2008-03-04 03:08:34 +03:00
dbg ( " %s - %i chars to write " , __func__ , urb - > actual_length ) ;
2008-10-13 13:39:46 +04:00
tty = tty_port_tty_get ( & port - > port ) ;
2007-10-26 15:51:49 +04:00
if ( data = = NULL )
2008-03-04 03:08:34 +03:00
dbg ( " %s - data is NULL !!! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( tty & & urb - > actual_length & & data ) {
tty_insert_flip_string ( tty , data , urb - > actual_length ) ;
tty_flip_buffer_push ( tty ) ;
}
2008-10-13 13:39:46 +04:00
tty_kref_put ( tty ) ;
2007-10-26 15:51:49 +04:00
iuu_led_activity_on ( urb ) ;
}
static int iuu_bulk_write ( struct usb_serial_port * port )
{
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-05-07 07:42:31 +04:00
unsigned long flags ;
2007-10-26 15:51:49 +04:00
int result ;
int i ;
2009-06-11 15:52:26 +04:00
int buf_len ;
2007-10-26 15:51:49 +04:00
char * buf_ptr = port - > write_urb - > transfer_buffer ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
2009-06-11 15:52:26 +04:00
spin_lock_irqsave ( & priv - > lock , flags ) ;
2007-10-26 15:51:49 +04:00
* buf_ptr + + = IUU_UART_ESC ;
* buf_ptr + + = IUU_UART_TX ;
* buf_ptr + + = priv - > writelen ;
2009-06-11 15:52:26 +04:00
memcpy ( buf_ptr , priv - > writebuf , priv - > writelen ) ;
buf_len = priv - > writelen ;
priv - > writelen = 0 ;
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2007-10-26 15:51:49 +04:00
if ( debug = = 1 ) {
2009-06-11 15:52:26 +04:00
for ( i = 0 ; i < buf_len ; i + + )
2007-10-26 15:51:49 +04:00
sprintf ( priv - > dbgbuf + i * 2 ,
" %02X " , priv - > writebuf [ i ] ) ;
2009-06-11 15:52:26 +04:00
priv - > dbgbuf [ buf_len + i * 2 ] = 0 ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - writing %i chars : %s " , __func__ ,
2009-06-11 15:52:26 +04:00
buf_len , priv - > dbgbuf ) ;
2007-10-26 15:51:49 +04:00
}
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
2009-06-11 15:52:26 +04:00
port - > write_urb - > transfer_buffer , buf_len + 3 ,
2007-10-26 15:51:49 +04:00
iuu_rxcmd , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_ATOMIC ) ;
usb_serial_port_softint ( port ) ;
return result ;
}
static int iuu_read_buf ( struct usb_serial_port * port , int len )
{
int result ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
usb_fill_bulk_urb ( port - > read_urb , port - > serial - > dev ,
usb_rcvbulkpipe ( port - > serial - > dev ,
port - > bulk_in_endpointAddress ) ,
port - > read_urb - > transfer_buffer , len ,
read_buf_callback , port ) ;
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
return result ;
}
static void iuu_uart_read_callback ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-05-07 07:42:31 +04:00
unsigned long flags ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2007-10-26 15:51:49 +04:00
int error = 0 ;
int len = 0 ;
unsigned char * data = urb - > transfer_buffer ;
priv - > poll + + ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
if ( status ) {
dbg ( " %s - status = %d " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
/* error stop all */
return ;
}
if ( data = = NULL )
2008-03-04 03:08:34 +03:00
dbg ( " %s - data is NULL !!! " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( urb - > actual_length = = 1 & & data ! = NULL )
len = ( int ) data [ 0 ] ;
if ( urb - > actual_length > 1 ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - urb->actual_length = %i " , __func__ ,
2007-10-26 15:51:49 +04:00
urb - > actual_length ) ;
error = 1 ;
return ;
}
/* if len > 0 call readbuf */
if ( len > 0 & & error = = 0 ) {
dbg ( " %s - call read buf - len to read is %i " ,
2008-03-04 03:08:34 +03:00
__func__ , len ) ;
2007-10-26 15:51:49 +04:00
status = iuu_read_buf ( port , len ) ;
return ;
}
/* need to update status ? */
if ( priv - > poll > 99 ) {
status = iuu_status ( port ) ;
priv - > poll = 0 ;
return ;
}
/* reset waiting ? */
if ( priv - > reset = = 1 ) {
status = iuu_reset ( port , 0xC ) ;
return ;
}
/* Writebuf is waiting */
spin_lock_irqsave ( & priv - > lock , flags ) ;
if ( priv - > writelen > 0 ) {
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
status = iuu_bulk_write ( port ) ;
return ;
}
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
/* if nothing to write call again rxcmd */
2008-03-04 03:08:34 +03:00
dbg ( " %s - rxcmd recall " , __func__ ) ;
2007-10-26 15:51:49 +04:00
iuu_led_activity_off ( urb ) ;
}
2008-07-22 14:09:07 +04:00
static int iuu_uart_write ( struct tty_struct * tty , struct usb_serial_port * port ,
const u8 * buf , int count )
2007-10-26 15:51:49 +04:00
{
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2008-05-07 07:42:31 +04:00
unsigned long flags ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - enter " , __func__ ) ;
2007-10-26 15:51:49 +04:00
if ( count > 256 )
return - ENOMEM ;
spin_lock_irqsave ( & priv - > lock , flags ) ;
2009-06-11 15:52:26 +04:00
2007-10-26 15:51:49 +04:00
/* fill the buffer */
2009-06-11 15:52:26 +04:00
memcpy ( priv - > writebuf + priv - > writelen , buf , count ) ;
priv - > writelen + = count ;
2007-10-26 15:51:49 +04:00
spin_unlock_irqrestore ( & priv - > lock , flags ) ;
2008-07-22 14:12:59 +04:00
return count ;
2007-10-26 15:51:49 +04:00
}
static void read_rxcmd_callback ( struct urb * urb )
{
2008-02-24 13:41:47 +03:00
struct usb_serial_port * port = urb - > context ;
2007-10-26 15:51:49 +04:00
int result ;
2008-12-11 03:00:30 +03:00
int status = urb - > status ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
dbg ( " %s - status = %d " , __func__ , status ) ;
2007-10-26 15:51:49 +04:00
2008-12-11 03:00:30 +03:00
if ( status ) {
2007-10-26 15:51:49 +04:00
/* error stop all */
return ;
}
usb_fill_bulk_urb ( port - > read_urb , port - > serial - > dev ,
usb_rcvbulkpipe ( port - > serial - > dev ,
port - > bulk_in_endpointAddress ) ,
port - > read_urb - > transfer_buffer , 256 ,
iuu_uart_read_callback , port ) ;
result = usb_submit_urb ( port - > read_urb , GFP_ATOMIC ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - submit result = %d " , __func__ , result ) ;
2007-10-26 15:51:49 +04:00
}
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 ) ;
2009-06-11 15:53:24 +04:00
buf [ 3 ] = ( u8 ) ( 0x0F0 & IUU_ONE_STOP_BIT ) | ( 0x07 & IUU_PARITY_EVEN ) ;
2007-10-26 15:51:49 +04:00
status = bulk_immediate ( port , buf , 4 ) ;
if ( status ! = IUU_OPERATION_OK ) {
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_on error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
goto uart_enable_failed ;
}
/* iuu_reset() the card after iuu_uart_on() */
status = iuu_uart_flush ( port ) ;
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_flush error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
uart_enable_failed :
kfree ( buf ) ;
return status ;
}
/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */
static int iuu_uart_off ( struct usb_serial_port * port )
{
int status ;
u8 * buf ;
buf = kmalloc ( 1 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
buf [ 0 ] = IUU_UART_DISABLE ;
status = bulk_immediate ( port , buf , 1 ) ;
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_off error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
kfree ( buf ) ;
return status ;
}
2010-05-21 14:53:25 +04:00
static int iuu_uart_baud ( struct usb_serial_port * port , u32 baud_base ,
2007-10-26 15:51:49 +04:00
u32 * actual , u8 parity )
{
int status ;
2010-05-21 14:53:25 +04:00
u32 baud ;
2007-10-26 15:51:49 +04:00
u8 * dataout ;
u8 DataCount = 0 ;
u8 T1Frekvens = 0 ;
u8 T1reload = 0 ;
unsigned int T1FrekvensHZ = 0 ;
2010-05-21 14:53:25 +04:00
dbg ( " %s - enter baud_base=%d " , __func__ , baud_base ) ;
2007-10-26 15:51:49 +04:00
dataout = kmalloc ( sizeof ( u8 ) * 5 , GFP_KERNEL ) ;
if ( ! dataout )
return - ENOMEM ;
2010-05-21 14:53:25 +04:00
/*baud = (((priv->clk / 35) * baud_base) / 100000); */
baud = baud_base ;
2007-10-26 15:51:49 +04:00
if ( baud < 1200 | | baud > 230400 ) {
kfree ( dataout ) ;
return IUU_INVALID_PARAMETER ;
}
if ( baud > 977 ) {
T1Frekvens = 3 ;
T1FrekvensHZ = 500000 ;
}
if ( baud > 3906 ) {
T1Frekvens = 2 ;
T1FrekvensHZ = 2000000 ;
}
if ( baud > 11718 ) {
T1Frekvens = 1 ;
T1FrekvensHZ = 6000000 ;
}
if ( baud > 46875 ) {
T1Frekvens = 0 ;
T1FrekvensHZ = 24000000 ;
}
T1reload = 256 - ( u8 ) ( T1FrekvensHZ / ( baud * 2 ) ) ;
/* magic number here: ENTER_FIRMWARE_UPDATE; */
dataout [ DataCount + + ] = IUU_UART_ESC ;
/* magic number here: CHANGE_BAUD; */
dataout [ DataCount + + ] = IUU_UART_CHANGE ;
dataout [ DataCount + + ] = T1Frekvens ;
dataout [ DataCount + + ] = T1reload ;
* actual = ( T1FrekvensHZ / ( 256 - T1reload ) ) / 2 ;
switch ( parity & 0x0F ) {
case IUU_PARITY_NONE :
dataout [ DataCount + + ] = 0x00 ;
break ;
case IUU_PARITY_EVEN :
dataout [ DataCount + + ] = 0x01 ;
break ;
case IUU_PARITY_ODD :
dataout [ DataCount + + ] = 0x02 ;
break ;
case IUU_PARITY_MARK :
dataout [ DataCount + + ] = 0x03 ;
break ;
case IUU_PARITY_SPACE :
dataout [ DataCount + + ] = 0x04 ;
break ;
default :
kfree ( dataout ) ;
return IUU_INVALID_PARAMETER ;
break ;
}
switch ( parity & 0xF0 ) {
case IUU_ONE_STOP_BIT :
dataout [ DataCount - 1 ] | = IUU_ONE_STOP_BIT ;
break ;
case IUU_TWO_STOP_BITS :
dataout [ DataCount - 1 ] | = IUU_TWO_STOP_BITS ;
break ;
default :
kfree ( dataout ) ;
return IUU_INVALID_PARAMETER ;
break ;
}
status = bulk_immediate ( port , dataout , DataCount ) ;
if ( status ! = IUU_OPERATION_OK )
2008-03-04 03:08:34 +03:00
dbg ( " %s - uart_off error " , __func__ ) ;
2007-10-26 15:51:49 +04:00
kfree ( dataout ) ;
return status ;
}
2009-06-11 15:54:20 +04:00
static void iuu_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old_termios )
{
const u32 supported_mask = CMSPAR | PARENB | PARODD ;
2010-05-21 14:53:25 +04:00
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2009-06-11 15:54:20 +04:00
unsigned int cflag = tty - > termios - > c_cflag ;
int status ;
u32 actual ;
u32 parity ;
int csize = CS7 ;
2010-05-21 14:53:25 +04:00
int baud ;
2009-06-11 15:54:20 +04:00
u32 newval = cflag & supported_mask ;
2010-05-21 14:53:25 +04:00
/* Just use the ospeed. ispeed should be the same. */
baud = tty - > termios - > c_ospeed ;
dbg ( " %s - enter c_ospeed or baud=%d " , __func__ , baud ) ;
2009-06-11 15:54:20 +04:00
/* compute the parity parameter */
parity = 0 ;
if ( cflag & CMSPAR ) { /* Using mark space */
if ( cflag & PARODD )
parity | = IUU_PARITY_SPACE ;
else
parity | = IUU_PARITY_MARK ;
} else if ( ! ( cflag & PARENB ) ) {
parity | = IUU_PARITY_NONE ;
csize = CS8 ;
} else if ( cflag & PARODD )
parity | = IUU_PARITY_ODD ;
else
parity | = IUU_PARITY_EVEN ;
parity | = ( cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT ) ;
/* set it */
status = iuu_uart_baud ( port ,
2010-05-21 14:53:25 +04:00
baud * priv - > boost / 100 ,
2009-06-11 15:54:20 +04:00
& actual , parity ) ;
/* set the termios value to the real one, so the user now what has
* changed . We support few fields so its easies to copy the old hw
* settings back over and then adjust them
*/
2010-05-21 14:53:25 +04:00
if ( old_termios )
tty_termios_copy_hw ( tty - > termios , old_termios ) ;
2009-06-11 15:54:20 +04:00
if ( status ! = 0 ) /* Set failed - return old bits */
return ;
/* Re-encode speed, parity and csize */
tty_encode_baud_rate ( tty , baud , baud ) ;
tty - > termios - > c_cflag & = ~ ( supported_mask | CSIZE ) ;
tty - > termios - > c_cflag | = newval | csize ;
}
2009-06-11 15:26:29 +04:00
static void iuu_close ( struct usb_serial_port * port )
2007-10-26 15:51:49 +04:00
{
/* iuu_led (port,255,0,0,0); */
struct usb_serial * serial ;
serial = port - > serial ;
if ( ! serial )
return ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - port %d " , __func__ , port - > number ) ;
2007-10-26 15:51:49 +04:00
iuu_uart_off ( port ) ;
if ( serial - > dev ) {
/* free writebuf */
/* shutdown our urbs */
2008-03-04 03:08:34 +03:00
dbg ( " %s - shutting down urbs " , __func__ ) ;
2007-10-26 15:51:49 +04:00
usb_kill_urb ( port - > write_urb ) ;
usb_kill_urb ( port - > read_urb ) ;
usb_kill_urb ( port - > interrupt_in_urb ) ;
iuu_led ( port , 0 , 0 , 0xF000 , 0xFF ) ;
}
}
2009-09-20 00:13:33 +04:00
static void iuu_init_termios ( struct tty_struct * tty )
{
2010-05-21 14:53:25 +04:00
dbg ( " %s - enter " , __func__ ) ;
2009-09-20 00:13:33 +04:00
* ( tty - > termios ) = tty_std_termios ;
tty - > termios - > c_cflag = CLOCAL | CREAD | CS8 | B9600
| TIOCM_CTS | CSTOPB | PARENB ;
tty - > termios - > c_ispeed = 9600 ;
tty - > termios - > c_ospeed = 9600 ;
tty - > termios - > c_lflag = 0 ;
tty - > termios - > c_oflag = 0 ;
tty - > termios - > c_iflag = 0 ;
}
2009-09-20 00:13:26 +04:00
static int iuu_open ( struct tty_struct * tty , struct usb_serial_port * port )
2007-10-26 15:51:49 +04:00
{
struct usb_serial * serial = port - > serial ;
u8 * buf ;
int result ;
2010-05-21 14:53:25 +04:00
int baud ;
2007-10-26 15:51:49 +04:00
u32 actual ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
2010-05-21 14:53:25 +04:00
baud = tty - > termios - > c_ospeed ;
tty - > termios - > c_ispeed = baud ;
/* Re-encode speed */
tty_encode_baud_rate ( tty , baud , baud ) ;
dbg ( " %s - port %d, baud %d " , __func__ , port - > number , baud ) ;
2007-10-26 15:51:49 +04:00
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 ;
2009-09-20 00:13:33 +04:00
priv - > poll = 0 ;
2007-10-26 15:51:49 +04:00
/* initialize writebuf */
# define FISH(a, b, c, d) do { \
result = usb_control_msg ( port - > serial - > dev , \
usb_rcvctrlpipe ( port - > serial - > dev , 0 ) , \
b , a , c , d , buf , 1 , 1000 ) ; \
dbg ( " 0x%x:0x%x:0x%x:0x%x %d - %x " , a , b , c , d , result , \
buf [ 0 ] ) ; } while ( 0 ) ;
# define SOUP(a, b, c, d) do { \
result = usb_control_msg ( port - > serial - > dev , \
usb_sndctrlpipe ( port - > serial - > dev , 0 ) , \
b , a , c , d , NULL , 0 , 1000 ) ; \
dbg ( " 0x%x:0x%x:0x%x:0x%x %d " , a , b , c , d , result ) ; } while ( 0 )
/* This is not UART related but IUU USB driver related or something */
/* like that. Basically no IUU will accept any commands from the USB */
/* host unless it has received the following message */
/* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
SOUP ( 0x03 , 0x02 , 0x02 , 0x0 ) ;
kfree ( buf ) ;
iuu_led ( port , 0xF000 , 0xF000 , 0 , 0xFF ) ;
iuu_uart_on ( port ) ;
if ( boost < 100 )
boost = 100 ;
2010-05-21 14:53:25 +04:00
priv - > boost = boost ;
priv - > baud = baud ;
2007-10-26 15:51:49 +04:00
switch ( clockmode ) {
case 2 : /* 3.680 Mhz */
2010-05-21 14:53:25 +04:00
priv - > clk = IUU_CLK_3680000 ;
2007-10-26 15:51:49 +04:00
iuu_clk ( port , IUU_CLK_3680000 * boost / 100 ) ;
result =
2010-05-21 14:53:25 +04:00
iuu_uart_baud ( port , baud * boost / 100 , & actual ,
2007-10-26 15:51:49 +04:00
IUU_PARITY_EVEN ) ;
break ;
case 3 : /* 6.00 Mhz */
iuu_clk ( port , IUU_CLK_6000000 * boost / 100 ) ;
2010-05-21 14:53:25 +04:00
priv - > clk = IUU_CLK_6000000 ;
/* Ratio of 6000000 to 3500000 for baud 9600 */
2007-10-26 15:51:49 +04:00
result =
iuu_uart_baud ( port , 16457 * boost / 100 , & actual ,
IUU_PARITY_EVEN ) ;
break ;
default : /* 3.579 Mhz */
iuu_clk ( port , IUU_CLK_3579000 * boost / 100 ) ;
2010-05-21 14:53:25 +04:00
priv - > clk = IUU_CLK_3579000 ;
2007-10-26 15:51:49 +04:00
result =
2010-05-21 14:53:25 +04:00
iuu_uart_baud ( port , baud * boost / 100 , & actual ,
2007-10-26 15:51:49 +04:00
IUU_PARITY_EVEN ) ;
}
/* set the cardin cardout signals */
switch ( cdmode ) {
case 0 :
iuu_cardin = 0 ;
iuu_cardout = 0 ;
break ;
case 1 :
iuu_cardin = TIOCM_CD ;
iuu_cardout = 0 ;
break ;
case 2 :
iuu_cardin = 0 ;
iuu_cardout = TIOCM_CD ;
break ;
case 3 :
iuu_cardin = TIOCM_DSR ;
iuu_cardout = 0 ;
break ;
case 4 :
iuu_cardin = 0 ;
iuu_cardout = TIOCM_DSR ;
break ;
case 5 :
iuu_cardin = TIOCM_CTS ;
iuu_cardout = 0 ;
break ;
case 6 :
iuu_cardin = 0 ;
iuu_cardout = TIOCM_CTS ;
break ;
case 7 :
iuu_cardin = TIOCM_RNG ;
iuu_cardout = 0 ;
break ;
case 8 :
iuu_cardin = 0 ;
iuu_cardout = TIOCM_RNG ;
}
iuu_uart_flush ( port ) ;
2008-03-04 03:08:34 +03:00
dbg ( " %s - initialization done " , __func__ ) ;
2007-10-26 15:51:49 +04:00
memset ( port - > write_urb - > transfer_buffer , IUU_UART_RX , 1 ) ;
usb_fill_bulk_urb ( port - > write_urb , port - > serial - > dev ,
usb_sndbulkpipe ( port - > serial - > dev ,
port - > bulk_out_endpointAddress ) ,
port - > write_urb - > transfer_buffer , 1 ,
read_rxcmd_callback , port ) ;
result = usb_submit_urb ( port - > write_urb , GFP_KERNEL ) ;
if ( result ) {
dev_err ( & port - > dev , " %s - failed submitting read urb, "
2008-03-04 03:08:34 +03:00
" error %d \n " , __func__ , result ) ;
2009-06-11 15:26:29 +04:00
iuu_close ( port ) ;
2007-10-26 15:51:49 +04:00
return - EPROTO ;
} else {
2008-03-04 03:08:34 +03:00
dbg ( " %s - rxcmd OK " , __func__ ) ;
2007-10-26 15:51:49 +04:00
}
return result ;
}
2009-08-18 23:05:55 +04:00
/* how to change VCC */
static int iuu_vcc_set ( struct usb_serial_port * port , unsigned int vcc )
{
int status ;
u8 * buf ;
buf = kmalloc ( 5 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
dbg ( " %s - enter " , __func__ ) ;
buf [ 0 ] = IUU_SET_VCC ;
buf [ 1 ] = vcc & 0xFF ;
buf [ 2 ] = ( vcc > > 8 ) & 0xFF ;
buf [ 3 ] = ( vcc > > 16 ) & 0xFF ;
buf [ 4 ] = ( vcc > > 24 ) & 0xFF ;
status = bulk_immediate ( port , buf , 5 ) ;
kfree ( buf ) ;
if ( status ! = IUU_OPERATION_OK )
dbg ( " %s - vcc error status = %2x " , __func__ , status ) ;
else
dbg ( " %s - vcc OK ! " , __func__ ) ;
return status ;
}
/*
* Sysfs Attributes
*/
static ssize_t show_vcc_mode ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct usb_serial_port * port = to_usb_serial_port ( dev ) ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
return sprintf ( buf , " %d \n " , priv - > vcc ) ;
}
static ssize_t store_vcc_mode ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
struct usb_serial_port * port = to_usb_serial_port ( dev ) ;
struct iuu_private * priv = usb_get_serial_port_data ( port ) ;
unsigned long v ;
if ( strict_strtoul ( buf , 10 , & v ) ) {
dev_err ( dev , " %s - vcc_mode: %s is not a unsigned long \n " ,
__func__ , buf ) ;
goto fail_store_vcc_mode ;
}
dbg ( " %s: setting vcc_mode = %ld " , __func__ , v ) ;
if ( ( v ! = 3 ) & & ( v ! = 5 ) ) {
dev_err ( dev , " %s - vcc_mode %ld is invalid \n " , __func__ , v ) ;
} else {
iuu_vcc_set ( port , v ) ;
priv - > vcc = v ;
}
fail_store_vcc_mode :
return count ;
}
static DEVICE_ATTR ( vcc_mode , S_IRUSR | S_IWUSR , show_vcc_mode ,
store_vcc_mode ) ;
static int iuu_create_sysfs_attrs ( struct usb_serial_port * port )
{
dbg ( " %s " , __func__ ) ;
return device_create_file ( & port - > dev , & dev_attr_vcc_mode ) ;
}
static int iuu_remove_sysfs_attrs ( struct usb_serial_port * port )
{
dbg ( " %s " , __func__ ) ;
device_remove_file ( & port - > dev , & dev_attr_vcc_mode ) ;
return 0 ;
}
/*
* End Sysfs Attributes
*/
2007-10-26 15:51:49 +04:00
static struct usb_serial_driver iuu_device = {
. driver = {
. owner = THIS_MODULE ,
. name = " iuu_phoenix " ,
} ,
. id_table = id_table ,
2011-01-11 22:16:50 +03:00
. usb_driver = & iuu_driver ,
2007-10-26 15:51:49 +04:00
. num_ports = 1 ,
2010-03-18 01:00:37 +03:00
. bulk_in_size = 512 ,
. bulk_out_size = 512 ,
2009-08-18 23:05:55 +04:00
. port_probe = iuu_create_sysfs_attrs ,
. port_remove = iuu_remove_sysfs_attrs ,
2007-10-26 15:51:49 +04:00
. open = iuu_open ,
. close = iuu_close ,
. write = iuu_uart_write ,
. read_bulk_callback = iuu_uart_read_callback ,
. tiocmget = iuu_tiocmget ,
. tiocmset = iuu_tiocmset ,
2009-06-11 15:54:20 +04:00
. set_termios = iuu_set_termios ,
2009-09-20 00:13:33 +04:00
. init_termios = iuu_init_termios ,
2007-10-26 15:51:49 +04:00
. attach = iuu_startup ,
2009-06-02 19:53:55 +04:00
. release = iuu_release ,
2007-10-26 15:51:49 +04:00
} ;
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 ;
2008-08-19 00:21:04 +04:00
printk ( KERN_INFO KBUILD_MODNAME " : " DRIVER_VERSION " : "
DRIVER_DESC " \n " ) ;
2007-10-26 15:51:49 +04:00
return 0 ;
failed_usb_register :
usb_serial_deregister ( & iuu_device ) ;
failed_usb_serial_register :
return retval ;
}
static void __exit iuu_exit ( void )
{
usb_deregister ( & iuu_driver ) ;
usb_serial_deregister ( & iuu_device ) ;
}
module_init ( iuu_init ) ;
module_exit ( iuu_exit ) ;
MODULE_AUTHOR ( " Alain Degreffe eczema@ecze.com " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRIVER_VERSION ) ;
module_param ( debug , bool , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( debug , " Debug enabled or not " ) ;
module_param ( xmas , bool , S_IRUGO | S_IWUSR ) ;
2009-08-18 23:05:54 +04:00
MODULE_PARM_DESC ( xmas , " Xmas colors enabled or not " ) ;
2007-10-26 15:51:49 +04:00
module_param ( boost , int , S_IRUGO | S_IWUSR ) ;
2009-08-18 23:05:54 +04:00
MODULE_PARM_DESC ( boost , " Card overclock boost (in percent 100-500) " ) ;
2007-10-26 15:51:49 +04:00
module_param ( clockmode , int , S_IRUGO | S_IWUSR ) ;
2009-08-18 23:05:54 +04:00
MODULE_PARM_DESC ( clockmode , " Card clock mode (1=3.579 MHz, 2=3.680 MHz, "
" 3=6 Mhz) " ) ;
2007-10-26 15:51:49 +04:00
module_param ( cdmode , int , S_IRUGO | S_IWUSR ) ;
2009-08-18 23:05:54 +04:00
MODULE_PARM_DESC ( cdmode , " Card detect mode (0=none, 1=CD, 2=!CD, 3=DSR, "
" 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING) " ) ;
2009-08-18 23:05:57 +04:00
module_param ( vcc_default , int , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( vcc_default , " Set default VCC (either 3 for 3.3V or 5 "
" for 5V). Default to 5. " ) ;