2005-04-17 02:20:36 +04:00
/*
* Edgeport USB Serial Converter driver
*
* Copyright ( C ) 2000 Inside Out Networks , All rights reserved .
* Copyright ( C ) 2001 - 2002 Greg Kroah - Hartman < greg @ kroah . com >
*
* 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 .
*
* Supports the following devices :
* Edgeport / 4
* Edgeport / 4 t
* Edgeport / 2
* Edgeport / 4 i
* Edgeport / 2 i
* Edgeport / 421
* Edgeport / 21
* Rapidport / 4
* Edgeport / 8
* Edgeport / 2 D8
* Edgeport / 4 D8
* Edgeport / 8 i
*
* For questions or problems with this driver , contact Inside Out
* Networks technical support , or Peter Berger < pberger @ brimson . com > ,
* or Al Borchers < alborchers @ steinerpoint . com > .
*
*/
# include <linux/kernel.h>
# include <linux/jiffies.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/tty_driver.h>
# include <linux/tty_flip.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/serial.h>
# include <linux/ioctl.h>
# include <linux/wait.h>
2008-07-03 15:30:23 +04:00
# include <linux/firmware.h>
# include <linux/ihex.h>
2008-07-22 14:16:34 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2006-07-12 08:22:58 +04:00
# include <linux/usb/serial.h>
2005-04-17 02:20:36 +04:00
# include "io_edgeport.h"
# include "io_ionsp.h" /* info for the iosp messages */
# include "io_16654.h" /* 16654 UART defines */
# define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
# define DRIVER_DESC "Edgeport USB Serial Driver"
# define MAX_NAME_LEN 64
# define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
/* receive port state */
enum RXSTATE {
2008-07-22 14:16:34 +04:00
EXPECT_HDR1 = 0 , /* Expect header byte 1 */
EXPECT_HDR2 = 1 , /* Expect header byte 2 */
EXPECT_DATA = 2 , /* Expect 'RxBytesRemaining' data */
EXPECT_HDR3 = 3 , /* Expect header byte 3 (for status hdrs only) */
2005-04-17 02:20:36 +04:00
} ;
2008-07-22 14:16:34 +04:00
/* Transmit Fifo
* This Transmit queue is an extension of the edgeport Rx buffer .
* The maximum amount of data buffered in both the edgeport
2005-04-17 02:20:36 +04:00
* Rx buffer ( maxTxCredits ) and this buffer will never exceed maxTxCredits .
*/
struct TxFifo {
unsigned int head ; /* index to head pointer (write) */
unsigned int tail ; /* index to tail pointer (read) */
unsigned int count ; /* Bytes in queue */
unsigned int size ; /* Max size of queue (equal to Max number of TxCredits) */
unsigned char * fifo ; /* allocated Buffer */
} ;
/* This structure holds all of the local port information */
struct edgeport_port {
__u16 txCredits ; /* our current credits for this port */
__u16 maxTxCredits ; /* the max size of the port */
struct TxFifo txfifo ; /* transmit fifo -- size will be maxTxCredits */
struct urb * write_urb ; /* write URB for this port */
2007-03-17 03:35:53 +03:00
bool write_in_progress ; /* 'true' while a write URB is outstanding */
2005-04-17 02:20:36 +04:00
spinlock_t ep_lock ;
__u8 shadowLCR ; /* last LCR value received */
__u8 shadowMCR ; /* last MCR value received */
__u8 shadowMSR ; /* last MSR value received */
__u8 shadowLSR ; /* last LSR value received */
__u8 shadowXonChar ; /* last value set as XON char in Edgeport */
__u8 shadowXoffChar ; /* last value set as XOFF char in Edgeport */
__u8 validDataMask ;
__u32 baudRate ;
2007-03-17 03:35:53 +03:00
bool open ;
bool openPending ;
bool commandPending ;
bool closePending ;
bool chaseResponsePending ;
2005-04-17 02:20:36 +04:00
wait_queue_head_t wait_chase ; /* for handling sleeping while waiting for chase to finish */
wait_queue_head_t wait_open ; /* for handling sleeping while waiting for open to finish */
wait_queue_head_t wait_command ; /* for handling sleeping while waiting for command to finish */
struct usb_serial_port * port ; /* loop back to the owner of this object */
} ;
/* This structure holds all of the individual device information */
struct edgeport_serial {
2006-05-23 08:49:44 +04:00
char name [ MAX_NAME_LEN + 2 ] ; /* string name of this device */
2005-04-17 02:20:36 +04:00
struct edge_manuf_descriptor manuf_descriptor ; /* the manufacturer descriptor */
struct edge_boot_descriptor boot_descriptor ; /* the boot firmware descriptor */
struct edgeport_product_info product_info ; /* Product Info */
2007-01-18 11:20:19 +03:00
struct edge_compatibility_descriptor epic_descriptor ; /* Edgeport compatible descriptor */
int is_epic ; /* flag if EPiC device or not */
2005-04-17 02:20:36 +04:00
__u8 interrupt_in_endpoint ; /* the interrupt endpoint handle */
2008-07-22 14:16:34 +04:00
unsigned char * interrupt_in_buffer ; /* the buffer we use for the interrupt endpoint */
struct urb * interrupt_read_urb ; /* our interrupt urb */
2005-04-17 02:20:36 +04:00
__u8 bulk_in_endpoint ; /* the bulk in endpoint handle */
2008-07-22 14:16:34 +04:00
unsigned char * bulk_in_buffer ; /* the buffer we use for the bulk in endpoint */
struct urb * read_urb ; /* our bulk read urb */
2007-03-17 03:35:53 +03:00
bool read_in_progress ;
2005-04-17 02:20:36 +04:00
spinlock_t es_lock ;
__u8 bulk_out_endpoint ; /* the bulk out endpoint handle */
__s16 rxBytesAvail ; /* the number of bytes that we need to read from this device */
enum RXSTATE rxState ; /* the current state of the bulk receive processor */
__u8 rxHeader1 ; /* receive header byte 1 */
__u8 rxHeader2 ; /* receive header byte 2 */
__u8 rxHeader3 ; /* receive header byte 3 */
__u8 rxPort ; /* the port that we are currently receiving data for */
__u8 rxStatusCode ; /* the receive status code */
__u8 rxStatusParam ; /* the receive status paramater */
__s16 rxBytesRemaining ; /* the number of port bytes left to read */
struct usb_serial * serial ; /* loop back to the owner of this object */
} ;
/* baud rate information */
struct divisor_table_entry {
__u32 BaudRate ;
__u16 Divisor ;
} ;
2008-07-22 14:16:34 +04:00
/*
* Define table of divisors for Rev A EdgePort / 4 hardware
* These assume a 3.6864 MHz crystal , the standard / 16 , and
* MCR .7 = 0.
*/
2005-11-29 11:43:42 +03:00
static const struct divisor_table_entry divisor_table [ ] = {
2008-07-22 14:16:34 +04:00
{ 50 , 4608 } ,
{ 75 , 3072 } ,
{ 110 , 2095 } , /* 2094.545455 => 230450 => .0217 % over */
{ 134 , 1713 } , /* 1713.011152 => 230398.5 => .00065% under */
2005-04-17 02:20:36 +04:00
{ 150 , 1536 } ,
{ 300 , 768 } ,
{ 600 , 384 } ,
{ 1200 , 192 } ,
{ 1800 , 128 } ,
{ 2400 , 96 } ,
{ 4800 , 48 } ,
{ 7200 , 32 } ,
{ 9600 , 24 } ,
{ 14400 , 16 } ,
{ 19200 , 12 } ,
{ 38400 , 6 } ,
{ 57600 , 4 } ,
{ 115200 , 2 } ,
{ 230400 , 1 } ,
} ;
2012-02-29 01:11:51 +04:00
/* Number of outstanding Command Write Urbs */
static atomic_t CmdUrbs = ATOMIC_INIT ( 0 ) ;
2005-04-17 02:20:36 +04:00
/* local function prototypes */
/* function prototypes for all URB callbacks */
2008-07-22 14:16:34 +04:00
static void edge_interrupt_callback ( struct urb * urb ) ;
static void edge_bulk_in_callback ( struct urb * urb ) ;
static void edge_bulk_out_data_callback ( struct urb * urb ) ;
static void edge_bulk_out_cmd_callback ( struct urb * urb ) ;
2005-04-17 02:20:36 +04:00
/* function prototypes for the usbserial callbacks */
2009-09-20 00:13:26 +04:00
static int edge_open ( struct tty_struct * tty , struct usb_serial_port * port ) ;
2009-06-11 15:26:29 +04:00
static void edge_close ( struct usb_serial_port * port ) ;
2008-07-22 14:16:34 +04:00
static int edge_write ( struct tty_struct * tty , struct usb_serial_port * port ,
const unsigned char * buf , int count ) ;
static int edge_write_room ( struct tty_struct * tty ) ;
static int edge_chars_in_buffer ( struct tty_struct * tty ) ;
static void edge_throttle ( struct tty_struct * tty ) ;
static void edge_unthrottle ( struct tty_struct * tty ) ;
static void edge_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port ,
struct ktermios * old_termios ) ;
2011-02-14 19:27:06 +03:00
static int edge_ioctl ( struct tty_struct * tty ,
2008-07-22 14:16:34 +04:00
unsigned int cmd , unsigned long arg ) ;
static void edge_break ( struct tty_struct * tty , int break_state ) ;
2011-02-14 19:26:14 +03:00
static int edge_tiocmget ( struct tty_struct * tty ) ;
2011-02-14 19:26:50 +03:00
static int edge_tiocmset ( struct tty_struct * tty ,
2008-07-22 14:16:34 +04:00
unsigned int set , unsigned int clear ) ;
static int edge_startup ( struct usb_serial * serial ) ;
2009-06-02 19:53:55 +04:00
static void edge_disconnect ( struct usb_serial * serial ) ;
static void edge_release ( struct usb_serial * serial ) ;
2012-10-17 15:34:57 +04:00
static int edge_port_probe ( struct usb_serial_port * port ) ;
static int edge_port_remove ( struct usb_serial_port * port ) ;
2005-04-17 02:20:36 +04:00
# include "io_tables.h" /* all of the devices that this driver supports */
/* function prototypes for all of our local functions */
2008-07-22 14:16:34 +04:00
static void process_rcvd_data ( struct edgeport_serial * edge_serial ,
unsigned char * buffer , __u16 bufferLength ) ;
static void process_rcvd_status ( struct edgeport_serial * edge_serial ,
__u8 byte2 , __u8 byte3 ) ;
2013-01-03 18:53:06 +04:00
static void edge_tty_recv ( struct usb_serial_port * port , unsigned char * data ,
int length ) ;
2008-07-22 14:16:34 +04:00
static void handle_new_msr ( struct edgeport_port * edge_port , __u8 newMsr ) ;
static void handle_new_lsr ( struct edgeport_port * edge_port , __u8 lsrData ,
__u8 lsr , __u8 data ) ;
static int send_iosp_ext_cmd ( struct edgeport_port * edge_port , __u8 command ,
__u8 param ) ;
2012-09-18 12:33:23 +04:00
static int calc_baud_rate_divisor ( struct device * dev , int baud_rate , int * divisor ) ;
2008-07-22 14:16:34 +04:00
static int send_cmd_write_baud_rate ( struct edgeport_port * edge_port ,
int baudRate ) ;
static void change_port_settings ( struct tty_struct * tty ,
struct edgeport_port * edge_port ,
struct ktermios * old_termios ) ;
static int send_cmd_write_uart_register ( struct edgeport_port * edge_port ,
__u8 regNum , __u8 regValue ) ;
static int write_cmd_usb ( struct edgeport_port * edge_port ,
unsigned char * buffer , int writeLength ) ;
static void send_more_port_data ( struct edgeport_serial * edge_serial ,
struct edgeport_port * edge_port ) ;
static int sram_write ( struct usb_serial * serial , __u16 extAddr , __u16 addr ,
__u16 length , const __u8 * data ) ;
static int rom_read ( struct usb_serial * serial , __u16 extAddr , __u16 addr ,
__u16 length , __u8 * data ) ;
static int rom_write ( struct usb_serial * serial , __u16 extAddr , __u16 addr ,
__u16 length , const __u8 * data ) ;
static void get_manufacturing_desc ( struct edgeport_serial * edge_serial ) ;
static void get_boot_desc ( struct edgeport_serial * edge_serial ) ;
static void load_application_firmware ( struct edgeport_serial * edge_serial ) ;
static void unicode_to_ascii ( char * string , int buflen ,
__le16 * unicode , int unicode_size ) ;
/* ************************************************************************ */
/* ************************************************************************ */
/* ************************************************************************ */
/* ************************************************************************ */
2005-04-17 02:20:36 +04:00
/************************************************************************
* *
* update_edgeport_E2PROM ( ) Compare current versions of *
* Boot ROM and Manufacture *
* Descriptors with versions *
* embedded in this driver *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void update_edgeport_E2PROM ( struct edgeport_serial * edge_serial )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2005-04-17 02:20:36 +04:00
__u32 BootCurVer ;
__u32 BootNewVer ;
2008-07-03 15:30:23 +04:00
__u8 BootMajorVersion ;
__u8 BootMinorVersion ;
__u16 BootBuildNumber ;
__u32 Bootaddr ;
const struct ihex_binrec * rec ;
const struct firmware * fw ;
const char * fw_name ;
2005-04-17 02:20:36 +04:00
int response ;
switch ( edge_serial - > product_info . iDownloadFile ) {
2008-07-22 14:16:34 +04:00
case EDGE_DOWNLOAD_FILE_I930 :
fw_name = " edgeport/boot.fw " ;
break ;
case EDGE_DOWNLOAD_FILE_80251 :
fw_name = " edgeport/boot2.fw " ;
break ;
default :
return ;
2005-04-17 02:20:36 +04:00
}
2008-07-03 15:30:23 +04:00
response = request_ihex_firmware ( & fw , fw_name ,
& edge_serial - > serial - > dev - > dev ) ;
if ( response ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev , " Failed to load image \" %s \" err %d \n " ,
2008-07-03 15:30:23 +04:00
fw_name , response ) ;
return ;
}
rec = ( const struct ihex_binrec * ) fw - > data ;
BootMajorVersion = rec - > data [ 0 ] ;
BootMinorVersion = rec - > data [ 1 ] ;
BootBuildNumber = ( rec - > data [ 2 ] < < 8 ) | rec - > data [ 3 ] ;
2008-07-22 14:16:34 +04:00
/* Check Boot Image Version */
2005-04-17 02:20:36 +04:00
BootCurVer = ( edge_serial - > boot_descriptor . MajorVersion < < 24 ) +
( edge_serial - > boot_descriptor . MinorVersion < < 16 ) +
le16_to_cpu ( edge_serial - > boot_descriptor . BuildNumber ) ;
BootNewVer = ( BootMajorVersion < < 24 ) +
( BootMinorVersion < < 16 ) +
2008-07-03 15:30:23 +04:00
BootBuildNumber ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " Current Boot Image version %d.%d.%d \n " ,
2005-04-17 02:20:36 +04:00
edge_serial - > boot_descriptor . MajorVersion ,
edge_serial - > boot_descriptor . MinorVersion ,
le16_to_cpu ( edge_serial - > boot_descriptor . BuildNumber ) ) ;
if ( BootNewVer > BootCurVer ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " **Update Boot Image from %d.%d.%d to %d.%d.%d \n " ,
2005-04-17 02:20:36 +04:00
edge_serial - > boot_descriptor . MajorVersion ,
edge_serial - > boot_descriptor . MinorVersion ,
le16_to_cpu ( edge_serial - > boot_descriptor . BuildNumber ) ,
2008-07-03 15:30:23 +04:00
BootMajorVersion , BootMinorVersion , BootBuildNumber ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " Downloading new Boot Image \n " ) ;
2005-04-17 02:20:36 +04:00
2008-07-03 15:30:23 +04:00
for ( rec = ihex_next_binrec ( rec ) ; rec ;
rec = ihex_next_binrec ( rec ) ) {
Bootaddr = be32_to_cpu ( rec - > addr ) ;
response = rom_write ( edge_serial - > serial ,
Bootaddr > > 16 ,
Bootaddr & 0xFFFF ,
be16_to_cpu ( rec - > len ) ,
& rec - > data [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
if ( response < 0 ) {
2008-07-03 15:30:23 +04:00
dev_err ( & edge_serial - > serial - > dev - > dev ,
" rom_write failed (%x, %x, %d) \n " ,
Bootaddr > > 16 , Bootaddr & 0xFFFF ,
be16_to_cpu ( rec - > len ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " Boot Image -- already up to date \n " ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-03 15:30:23 +04:00
release_firmware ( fw ) ;
2005-04-17 02:20:36 +04:00
}
#if 0
/************************************************************************
*
* Get string descriptor from device
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int get_string_desc ( struct usb_device * dev , int Id ,
struct usb_string_descriptor * * pRetDesc )
2005-04-17 02:20:36 +04:00
{
struct usb_string_descriptor StringDesc ;
struct usb_string_descriptor * pStringDesc ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & dev - > dev , " %s - USB String ID = %d \n " , __func__ , Id ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
if ( ! usb_get_descriptor ( dev , USB_DT_STRING , Id , & StringDesc ,
sizeof ( StringDesc ) ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-07-22 14:16:34 +04:00
pStringDesc = kmalloc ( StringDesc . bLength , GFP_KERNEL ) ;
if ( ! pStringDesc )
2005-04-17 02:20:36 +04:00
return - 1 ;
2008-07-22 14:16:34 +04:00
if ( ! usb_get_descriptor ( dev , USB_DT_STRING , Id , pStringDesc ,
StringDesc . bLength ) ) {
2005-04-17 02:20:36 +04:00
kfree ( pStringDesc ) ;
return - 1 ;
}
* pRetDesc = pStringDesc ;
return 0 ;
}
# endif
2012-09-18 12:33:23 +04:00
static void dump_product_info ( struct edgeport_serial * edge_serial ,
struct edgeport_product_info * product_info )
2007-01-18 11:20:19 +03:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2008-07-22 14:16:34 +04:00
/* Dump Product Info structure */
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " **Product Information: \n " ) ;
dev_dbg ( dev , " ProductId %x \n " , product_info - > ProductId ) ;
dev_dbg ( dev , " NumPorts %d \n " , product_info - > NumPorts ) ;
dev_dbg ( dev , " ProdInfoVer %d \n " , product_info - > ProdInfoVer ) ;
dev_dbg ( dev , " IsServer %d \n " , product_info - > IsServer ) ;
dev_dbg ( dev , " IsRS232 %d \n " , product_info - > IsRS232 ) ;
dev_dbg ( dev , " IsRS422 %d \n " , product_info - > IsRS422 ) ;
dev_dbg ( dev , " IsRS485 %d \n " , product_info - > IsRS485 ) ;
dev_dbg ( dev , " RomSize %d \n " , product_info - > RomSize ) ;
dev_dbg ( dev , " RamSize %d \n " , product_info - > RamSize ) ;
dev_dbg ( dev , " CpuRev %x \n " , product_info - > CpuRev ) ;
dev_dbg ( dev , " BoardRev %x \n " , product_info - > BoardRev ) ;
dev_dbg ( dev , " BootMajorVersion %d.%d.%d \n " ,
product_info - > BootMajorVersion ,
product_info - > BootMinorVersion ,
le16_to_cpu ( product_info - > BootBuildNumber ) ) ;
dev_dbg ( dev , " FirmwareMajorVersion %d.%d.%d \n " ,
product_info - > FirmwareMajorVersion ,
product_info - > FirmwareMinorVersion ,
le16_to_cpu ( product_info - > FirmwareBuildNumber ) ) ;
dev_dbg ( dev , " ManufactureDescDate %d/%d/%d \n " ,
product_info - > ManufactureDescDate [ 0 ] ,
product_info - > ManufactureDescDate [ 1 ] ,
product_info - > ManufactureDescDate [ 2 ] + 1900 ) ;
dev_dbg ( dev , " iDownloadFile 0x%x \n " ,
product_info - > iDownloadFile ) ;
dev_dbg ( dev , " EpicVer %d \n " , product_info - > EpicVer ) ;
2007-01-18 11:20:19 +03:00
}
2005-04-17 02:20:36 +04:00
static void get_product_info ( struct edgeport_serial * edge_serial )
{
struct edgeport_product_info * product_info = & edge_serial - > product_info ;
2008-07-22 14:16:34 +04:00
memset ( product_info , 0 , sizeof ( struct edgeport_product_info ) ) ;
product_info - > ProductId = ( __u16 ) ( le16_to_cpu ( edge_serial - > serial - > dev - > descriptor . idProduct ) & ~ ION_DEVICE_ID_80251_NETCHIP ) ;
product_info - > NumPorts = edge_serial - > manuf_descriptor . NumPorts ;
product_info - > ProdInfoVer = 0 ;
product_info - > RomSize = edge_serial - > manuf_descriptor . RomSize ;
product_info - > RamSize = edge_serial - > manuf_descriptor . RamSize ;
product_info - > CpuRev = edge_serial - > manuf_descriptor . CpuRev ;
product_info - > BoardRev = edge_serial - > manuf_descriptor . BoardRev ;
product_info - > BootMajorVersion =
edge_serial - > boot_descriptor . MajorVersion ;
product_info - > BootMinorVersion =
edge_serial - > boot_descriptor . MinorVersion ;
product_info - > BootBuildNumber =
edge_serial - > boot_descriptor . BuildNumber ;
memcpy ( product_info - > ManufactureDescDate ,
edge_serial - > manuf_descriptor . DescDate ,
sizeof ( edge_serial - > manuf_descriptor . DescDate ) ) ;
/* check if this is 2nd generation hardware */
if ( le16_to_cpu ( edge_serial - > serial - > dev - > descriptor . idProduct )
& ION_DEVICE_ID_80251_NETCHIP )
product_info - > iDownloadFile = EDGE_DOWNLOAD_FILE_80251 ;
else
product_info - > iDownloadFile = EDGE_DOWNLOAD_FILE_I930 ;
2012-09-18 12:33:23 +04:00
2008-07-22 14:16:34 +04:00
/* Determine Product type and set appropriate flags */
2005-04-17 02:20:36 +04:00
switch ( DEVICE_ID_FROM_USB_PRODUCT_ID ( product_info - > ProductId ) ) {
2008-07-22 14:16:34 +04:00
case ION_DEVICE_ID_EDGEPORT_COMPATIBLE :
case ION_DEVICE_ID_EDGEPORT_4T :
case ION_DEVICE_ID_EDGEPORT_4 :
case ION_DEVICE_ID_EDGEPORT_2 :
case ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU :
case ION_DEVICE_ID_EDGEPORT_8 :
case ION_DEVICE_ID_EDGEPORT_421 :
case ION_DEVICE_ID_EDGEPORT_21 :
case ION_DEVICE_ID_EDGEPORT_2_DIN :
case ION_DEVICE_ID_EDGEPORT_4_DIN :
case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU :
product_info - > IsRS232 = 1 ;
break ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
case ION_DEVICE_ID_EDGEPORT_2I : /* Edgeport/2 RS422/RS485 */
product_info - > IsRS422 = 1 ;
product_info - > IsRS485 = 1 ;
break ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
case ION_DEVICE_ID_EDGEPORT_8I : /* Edgeport/4 RS422 */
case ION_DEVICE_ID_EDGEPORT_4I : /* Edgeport/4 RS422 */
product_info - > IsRS422 = 1 ;
break ;
2005-04-17 02:20:36 +04:00
}
2012-09-18 12:33:23 +04:00
dump_product_info ( edge_serial , product_info ) ;
2007-01-18 11:20:19 +03:00
}
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
static int get_epic_descriptor ( struct edgeport_serial * ep )
{
int result ;
struct usb_serial * serial = ep - > serial ;
struct edgeport_product_info * product_info = & ep - > product_info ;
struct edge_compatibility_descriptor * epic = & ep - > epic_descriptor ;
struct edge_compatibility_bits * bits ;
2012-09-18 12:33:23 +04:00
struct device * dev = & serial - > dev - > dev ;
2007-01-18 11:20:19 +03:00
ep - > is_epic = 0 ;
result = usb_control_msg ( serial - > dev , usb_rcvctrlpipe ( serial - > dev , 0 ) ,
USB_REQUEST_ION_GET_EPIC_DESC ,
0xC0 , 0x00 , 0x00 ,
& ep - > epic_descriptor ,
sizeof ( struct edge_compatibility_descriptor ) ,
300 ) ;
if ( result > 0 ) {
ep - > is_epic = 1 ;
memset ( product_info , 0 , sizeof ( struct edgeport_product_info ) ) ;
2008-07-22 14:16:34 +04:00
product_info - > NumPorts = epic - > NumPorts ;
product_info - > ProdInfoVer = 0 ;
product_info - > FirmwareMajorVersion = epic - > MajorVersion ;
product_info - > FirmwareMinorVersion = epic - > MinorVersion ;
product_info - > FirmwareBuildNumber = epic - > BuildNumber ;
product_info - > iDownloadFile = epic - > iDownloadFile ;
product_info - > EpicVer = epic - > EpicVer ;
product_info - > Epic = epic - > Supports ;
product_info - > ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE ;
2012-09-18 12:33:23 +04:00
dump_product_info ( ep , product_info ) ;
2007-01-18 11:20:19 +03:00
bits = & ep - > epic_descriptor . Supports ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " **EPIC descriptor: \n " ) ;
dev_dbg ( dev , " VendEnableSuspend: %s \n " , bits - > VendEnableSuspend ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPOpen : %s \n " , bits - > IOSPOpen ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPClose : %s \n " , bits - > IOSPClose ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPChase : %s \n " , bits - > IOSPChase ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPSetRxFlow : %s \n " , bits - > IOSPSetRxFlow ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPSetTxFlow : %s \n " , bits - > IOSPSetTxFlow ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPSetXChar : %s \n " , bits - > IOSPSetXChar ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPRxCheck : %s \n " , bits - > IOSPRxCheck ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPSetClrBreak : %s \n " , bits - > IOSPSetClrBreak ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPWriteMCR : %s \n " , bits - > IOSPWriteMCR ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPWriteLCR : %s \n " , bits - > IOSPWriteLCR ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " IOSPSetBaudRate : %s \n " , bits - > IOSPSetBaudRate ? " TRUE " : " FALSE " ) ;
dev_dbg ( dev , " TrueEdgeport : %s \n " , bits - > TrueEdgeport ? " TRUE " : " FALSE " ) ;
2007-01-18 11:20:19 +03:00
}
return result ;
2005-04-17 02:20:36 +04:00
}
/************************************************************************/
/************************************************************************/
/* U S B C A L L B A C K F U N C T I O N S */
/* U S B C A L L B A C K F U N C T I O N S */
/************************************************************************/
/************************************************************************/
/*****************************************************************************
* edge_interrupt_callback
2008-07-22 14:16:34 +04:00
* this is the callback function for when we have received data on the
2005-04-17 02:20:36 +04:00
* interrupt endpoint .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void edge_interrupt_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct edgeport_serial * edge_serial = urb - > context ;
struct device * dev ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port ;
struct usb_serial_port * port ;
unsigned char * data = urb - > transfer_buffer ;
int length = urb - > actual_length ;
int bytes_avail ;
int position ;
int txCredits ;
int portNumber ;
int result ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
switch ( status ) {
2005-04-17 02:20:36 +04:00
case 0 :
/* success */
break ;
case - ECONNRESET :
case - ENOENT :
case - ESHUTDOWN :
/* this urb is terminated, clean up */
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - urb shutting down with status: %d \n " , __func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
default :
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - nonzero urb status received: %d \n " , __func__ , status ) ;
2005-04-17 02:20:36 +04:00
goto exit ;
}
2012-09-18 12:33:23 +04:00
dev = & edge_serial - > serial - > dev - > dev ;
2008-07-22 14:16:34 +04:00
/* process this interrupt-read even if there are no ports open */
2005-04-17 02:20:36 +04:00
if ( length ) {
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , length , data ) ;
2005-04-17 02:20:36 +04:00
if ( length > 1 ) {
bytes_avail = data [ 0 ] | ( data [ 1 ] < < 8 ) ;
if ( bytes_avail ) {
spin_lock ( & edge_serial - > es_lock ) ;
edge_serial - > rxBytesAvail + = bytes_avail ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev ,
" %s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d \n " ,
__func__ , bytes_avail ,
edge_serial - > rxBytesAvail ,
edge_serial - > read_in_progress ) ;
2005-04-17 02:20:36 +04:00
if ( edge_serial - > rxBytesAvail > 0 & &
! edge_serial - > read_in_progress ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - posting a read \n " , __func__ ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = true ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* we have pending bytes on the
bulk in pipe , send a request */
2005-04-17 02:20:36 +04:00
result = usb_submit_urb ( edge_serial - > read_urb , GFP_ATOMIC ) ;
if ( result ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev ,
" %s - usb_submit_urb(read bulk) failed with result = %d \n " ,
__func__ , result ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
}
}
spin_unlock ( & edge_serial - > es_lock ) ;
}
}
/* grab the txcredits for the ports if available */
position = 2 ;
portNumber = 0 ;
2008-07-22 14:16:34 +04:00
while ( ( position < length ) & &
( portNumber < edge_serial - > serial - > num_ports ) ) {
2005-04-17 02:20:36 +04:00
txCredits = data [ position ] | ( data [ position + 1 ] < < 8 ) ;
if ( txCredits ) {
port = edge_serial - > serial - > port [ portNumber ] ;
edge_port = usb_get_serial_port_data ( port ) ;
if ( edge_port - > open ) {
spin_lock ( & edge_port - > ep_lock ) ;
edge_port - > txCredits + = txCredits ;
spin_unlock ( & edge_port - > ep_lock ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - txcredits for port%d = %d \n " ,
__func__ , portNumber ,
edge_port - > txCredits ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* tell the tty driver that something
has changed */
2013-03-07 16:12:29 +04:00
tty_port_tty_wakeup ( & edge_port - > port - > port ) ;
2008-07-22 14:16:34 +04:00
/* Since we have more credit, check
if more data can be sent */
send_more_port_data ( edge_serial ,
edge_port ) ;
2005-04-17 02:20:36 +04:00
}
}
position + = 2 ;
+ + portNumber ;
}
}
exit :
2008-07-22 14:16:34 +04:00
result = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( result )
dev_err ( & urb - > dev - > dev ,
" %s - Error %d submitting control urb \n " ,
__func__ , result ) ;
2005-04-17 02:20:36 +04:00
}
/*****************************************************************************
* edge_bulk_in_callback
2008-07-22 14:16:34 +04:00
* this is the callback function for when we have received data on the
2005-04-17 02:20:36 +04:00
* bulk in endpoint .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void edge_bulk_in_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct edgeport_serial * edge_serial = urb - > context ;
2012-09-18 12:33:23 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
unsigned char * data = urb - > transfer_buffer ;
2007-06-16 02:44:13 +04:00
int retval ;
2005-04-17 02:20:36 +04:00
__u16 raw_data_length ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - nonzero read bulk status received: %d \n " ,
__func__ , status ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( urb - > actual_length = = 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - read bulk callback with no data \n " , __func__ ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
return ;
}
2012-09-18 12:33:23 +04:00
dev = & edge_serial - > serial - > dev - > dev ;
2005-04-17 02:20:36 +04:00
raw_data_length = urb - > actual_length ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , raw_data_length , data ) ;
2005-04-17 02:20:36 +04:00
spin_lock ( & edge_serial - > es_lock ) ;
/* decrement our rxBytes available by the number that we just got */
edge_serial - > rxBytesAvail - = raw_data_length ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Received = %d, rxBytesAvail %d \n " , __func__ ,
raw_data_length , edge_serial - > rxBytesAvail ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
process_rcvd_data ( edge_serial , data , urb - > actual_length ) ;
2005-04-17 02:20:36 +04:00
/* check to see if there's any more data for us to read */
if ( edge_serial - > rxBytesAvail > 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - posting a read \n " , __func__ ) ;
2007-06-16 02:44:13 +04:00
retval = usb_submit_urb ( edge_serial - > read_urb , GFP_ATOMIC ) ;
if ( retval ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev ,
" %s - usb_submit_urb(read bulk) failed, retval = %d \n " ,
__func__ , retval ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
}
} else {
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & edge_serial - > es_lock ) ;
}
/*****************************************************************************
* edge_bulk_out_data_callback
2008-07-22 14:16:34 +04:00
* this is the callback function for when we have finished sending
* serial data on the bulk out endpoint .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void edge_bulk_out_data_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct edgeport_port * edge_port = urb - > context ;
2007-06-16 02:44:13 +04:00
int status = urb - > status ;
2005-04-17 02:20:36 +04:00
2007-06-16 02:44:13 +04:00
if ( status ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev ,
" %s - nonzero write bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
}
2013-03-07 16:12:29 +04:00
if ( edge_port - > open )
tty_port_tty_wakeup ( & edge_port - > port - > port ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* Release the Write URB */
2007-03-17 03:35:53 +03:00
edge_port - > write_in_progress = false ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* Check if more data needs to be sent */
send_more_port_data ( ( struct edgeport_serial * )
( usb_get_serial_data ( edge_port - > port - > serial ) ) , edge_port ) ;
2005-04-17 02:20:36 +04:00
}
/*****************************************************************************
* BulkOutCmdCallback
2008-07-22 14:16:34 +04:00
* this is the callback function for when we have finished sending a
* command on the bulk out endpoint .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void edge_bulk_out_cmd_callback ( struct urb * urb )
2005-04-17 02:20:36 +04:00
{
2008-02-24 13:41:47 +03:00
struct edgeport_port * edge_port = urb - > context ;
2005-04-17 02:20:36 +04:00
int status = urb - > status ;
2007-03-15 17:27:17 +03:00
atomic_dec ( & CmdUrbs ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev , " %s - FREE URB %p (outstanding %d) \n " ,
__func__ , urb , atomic_read ( & CmdUrbs ) ) ;
2005-04-17 02:20:36 +04:00
/* clean up the transfer buffer */
2005-04-19 04:39:34 +04:00
kfree ( urb - > transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
/* Free the command urb */
2008-07-22 14:16:34 +04:00
usb_free_urb ( urb ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & urb - > dev - > dev ,
" %s - nonzero write bulk status received: %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* tell the tty driver that something has changed */
2013-03-07 16:12:29 +04:00
if ( edge_port - > open )
tty_port_tty_wakeup ( & edge_port - > port - > port ) ;
2005-04-17 02:20:36 +04:00
/* we have completed the command */
2007-03-17 03:35:53 +03:00
edge_port - > commandPending = false ;
2005-04-17 02:20:36 +04:00
wake_up ( & edge_port - > wait_command ) ;
}
/*****************************************************************************
* Driver tty interface functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*****************************************************************************
* SerialOpen
* this function is called by the tty driver when a port is opened
* If successful , we return 0
* Otherwise we return a negative error number .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-09-20 00:13:26 +04:00
static int edge_open ( struct tty_struct * tty , struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
2012-09-18 12:33:23 +04:00
struct device * dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
struct usb_serial * serial ;
struct edgeport_serial * edge_serial ;
int response ;
if ( edge_port = = NULL )
return - ENODEV ;
2008-07-22 14:16:34 +04:00
/* see if we've set up our endpoint info yet (can't set it up
in edge_startup as the structures were not set up at that time . ) */
2005-04-17 02:20:36 +04:00
serial = port - > serial ;
edge_serial = usb_get_serial_data ( serial ) ;
2008-07-22 14:09:07 +04:00
if ( edge_serial = = NULL )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
if ( edge_serial - > interrupt_in_buffer = = NULL ) {
struct usb_serial_port * port0 = serial - > port [ 0 ] ;
2008-07-22 14:16:34 +04:00
2005-04-17 02:20:36 +04:00
/* not set up yet, so do it now */
2008-07-22 14:16:34 +04:00
edge_serial - > interrupt_in_buffer =
port0 - > interrupt_in_buffer ;
edge_serial - > interrupt_in_endpoint =
port0 - > interrupt_in_endpointAddress ;
2005-04-17 02:20:36 +04:00
edge_serial - > interrupt_read_urb = port0 - > interrupt_in_urb ;
edge_serial - > bulk_in_buffer = port0 - > bulk_in_buffer ;
2008-07-22 14:16:34 +04:00
edge_serial - > bulk_in_endpoint =
port0 - > bulk_in_endpointAddress ;
2005-04-17 02:20:36 +04:00
edge_serial - > read_urb = port0 - > read_urb ;
2008-07-22 14:16:34 +04:00
edge_serial - > bulk_out_endpoint =
port0 - > bulk_out_endpointAddress ;
2005-04-17 02:20:36 +04:00
/* set up our interrupt urb */
usb_fill_int_urb ( edge_serial - > interrupt_read_urb ,
2008-07-22 14:16:34 +04:00
serial - > dev ,
usb_rcvintpipe ( serial - > dev ,
port0 - > interrupt_in_endpointAddress ) ,
port0 - > interrupt_in_buffer ,
edge_serial - > interrupt_read_urb - > transfer_buffer_length ,
edge_interrupt_callback , edge_serial ,
edge_serial - > interrupt_read_urb - > interval ) ;
2005-04-17 02:20:36 +04:00
/* set up our bulk in urb */
usb_fill_bulk_urb ( edge_serial - > read_urb , serial - > dev ,
2008-07-22 14:16:34 +04:00
usb_rcvbulkpipe ( serial - > dev ,
port0 - > bulk_in_endpointAddress ) ,
port0 - > bulk_in_buffer ,
edge_serial - > read_urb - > transfer_buffer_length ,
edge_bulk_in_callback , edge_serial ) ;
2007-03-17 03:35:53 +03:00
edge_serial - > read_in_progress = false ;
2005-04-17 02:20:36 +04:00
/* start interrupt read for this edgeport
2008-07-22 14:16:34 +04:00
* this interrupt will continue as long
* as the edgeport is connected */
response = usb_submit_urb ( edge_serial - > interrupt_read_urb ,
GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( response ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev , " %s - Error %d submitting control urb \n " ,
__func__ , response ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-22 14:16:34 +04:00
2005-04-17 02:20:36 +04:00
/* initialize our wait queues */
init_waitqueue_head ( & edge_port - > wait_open ) ;
init_waitqueue_head ( & edge_port - > wait_chase ) ;
init_waitqueue_head ( & edge_port - > wait_command ) ;
/* initialize our port settings */
2008-07-22 14:16:34 +04:00
edge_port - > txCredits = 0 ; /* Can't send any data yet */
/* Must always set this bit to enable ints! */
edge_port - > shadowMCR = MCR_MASTER_IE ;
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = false ;
2005-04-17 02:20:36 +04:00
/* send a open port command */
2007-03-17 03:35:53 +03:00
edge_port - > openPending = true ;
edge_port - > open = false ;
2008-07-22 14:16:34 +04:00
response = send_iosp_ext_cmd ( edge_port , IOSP_CMD_OPEN_PORT , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( response < 0 ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev , " %s - error sending open port command \n " , __func__ ) ;
2007-03-17 03:35:53 +03:00
edge_port - > openPending = false ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/* now wait for the port to be completely opened */
2008-07-22 14:16:34 +04:00
wait_event_timeout ( edge_port - > wait_open , ! edge_port - > openPending ,
OPEN_TIMEOUT ) ;
2005-04-17 02:20:36 +04:00
2007-03-17 03:35:53 +03:00
if ( ! edge_port - > open ) {
2005-04-17 02:20:36 +04:00
/* open timed out */
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - open timedout \n " , __func__ ) ;
2007-03-17 03:35:53 +03:00
edge_port - > openPending = false ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/* create the txfifo */
edge_port - > txfifo . head = 0 ;
edge_port - > txfifo . tail = 0 ;
edge_port - > txfifo . count = 0 ;
edge_port - > txfifo . size = edge_port - > maxTxCredits ;
2008-07-22 14:16:34 +04:00
edge_port - > txfifo . fifo = kmalloc ( edge_port - > maxTxCredits , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! edge_port - > txfifo . fifo ) {
2009-06-11 15:26:29 +04:00
edge_close ( port ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
/* Allocate a URB for the write */
2008-07-22 14:16:34 +04:00
edge_port - > write_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2007-03-17 03:35:53 +03:00
edge_port - > write_in_progress = false ;
2005-04-17 02:20:36 +04:00
if ( ! edge_port - > write_urb ) {
2009-06-11 15:26:29 +04:00
edge_close ( port ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
2013-06-06 21:32:00 +04:00
dev_dbg ( dev , " %s - Initialize TX fifo to %d bytes \n " ,
__func__ , edge_port - > maxTxCredits ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/************************************************************************
*
* block_until_chase_response
*
* This function will block the close until one of the following :
* 1. Response to our Chase comes from Edgeport
2007-12-17 22:40:18 +03:00
* 2. A timeout of 10 seconds without activity has expired
2005-04-17 02:20:36 +04:00
* ( 1 K of Edgeport data @ 2400 baud = = > 4 sec to empty )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void block_until_chase_response ( struct edgeport_port * edge_port )
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
DEFINE_WAIT ( wait ) ;
__u16 lastCredits ;
int timeout = 1 * HZ ;
int loop = 10 ;
while ( 1 ) {
2008-07-22 14:16:34 +04:00
/* Save Last credits */
2005-04-17 02:20:36 +04:00
lastCredits = edge_port - > txCredits ;
2008-07-22 14:16:34 +04:00
/* Did we get our Chase response */
2007-03-17 03:35:53 +03:00
if ( ! edge_port - > chaseResponsePending ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Got Chase Response \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* did we get all of our credit back? */
if ( edge_port - > txCredits = = edge_port - > maxTxCredits ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Got all credits \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
}
2008-07-22 14:16:34 +04:00
/* Block the thread for a while */
prepare_to_wait ( & edge_port - > wait_chase , & wait ,
TASK_UNINTERRUPTIBLE ) ;
2005-04-17 02:20:36 +04:00
schedule_timeout ( timeout ) ;
finish_wait ( & edge_port - > wait_chase , & wait ) ;
if ( lastCredits = = edge_port - > txCredits ) {
2008-07-22 14:16:34 +04:00
/* No activity.. count down. */
2005-04-17 02:20:36 +04:00
loop - - ;
if ( loop = = 0 ) {
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = false ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Chase TIMEOUT \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
} else {
2008-07-22 14:16:34 +04:00
/* Reset timeout value back to 10 seconds */
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Last %d, Current %d \n " , __func__ ,
2008-07-22 14:16:34 +04:00
lastCredits , edge_port - > txCredits ) ;
2005-04-17 02:20:36 +04:00
loop = 10 ;
}
}
}
/************************************************************************
*
* block_until_tx_empty
*
* This function will block the close until one of the following :
* 1. TX count are 0
* 2. The edgeport has stopped
2007-12-17 22:40:18 +03:00
* 3. A timeout of 3 seconds without activity has expired
2005-04-17 02:20:36 +04:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void block_until_tx_empty ( struct edgeport_port * edge_port )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
DEFINE_WAIT ( wait ) ;
struct TxFifo * fifo = & edge_port - > txfifo ;
__u32 lastCount ;
int timeout = HZ / 10 ;
int loop = 30 ;
while ( 1 ) {
2008-07-22 14:16:34 +04:00
/* Save Last count */
2005-04-17 02:20:36 +04:00
lastCount = fifo - > count ;
2008-07-22 14:16:34 +04:00
/* Is the Edgeport Buffer empty? */
2005-04-17 02:20:36 +04:00
if ( lastCount = = 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - TX Buffer Empty \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2008-07-22 14:16:34 +04:00
/* Block the thread for a while */
prepare_to_wait ( & edge_port - > wait_chase , & wait ,
TASK_UNINTERRUPTIBLE ) ;
2005-04-17 02:20:36 +04:00
schedule_timeout ( timeout ) ;
finish_wait ( & edge_port - > wait_chase , & wait ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s wait \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
if ( lastCount = = fifo - > count ) {
2008-07-22 14:16:34 +04:00
/* No activity.. count down. */
2005-04-17 02:20:36 +04:00
loop - - ;
if ( loop = = 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - TIMEOUT \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
} else {
2008-07-22 14:16:34 +04:00
/* Reset timeout value back to seconds */
2005-04-17 02:20:36 +04:00
loop = 30 ;
}
}
}
/*****************************************************************************
* edge_close
* this function is called by the tty driver when a port is closed
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-11 15:26:29 +04:00
static void edge_close ( struct usb_serial_port * port )
2005-04-17 02:20:36 +04:00
{
struct edgeport_serial * edge_serial ;
struct edgeport_port * edge_port ;
int status ;
edge_serial = usb_get_serial_data ( port - > serial ) ;
edge_port = usb_get_serial_port_data ( port ) ;
2008-07-22 14:16:34 +04:00
if ( edge_serial = = NULL | | edge_port = = NULL )
2005-04-17 02:20:36 +04:00
return ;
2008-07-22 14:16:34 +04:00
/* block until tx is empty */
2005-04-17 02:20:36 +04:00
block_until_tx_empty ( edge_port ) ;
2007-03-17 03:35:53 +03:00
edge_port - > closePending = true ;
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPChase ) ) ) {
/* flush and chase */
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = true ;
2007-01-18 11:20:19 +03:00
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - Sending IOSP_CMD_CHASE_PORT \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
status = send_iosp_ext_cmd ( edge_port , IOSP_CMD_CHASE_PORT , 0 ) ;
if ( status = = 0 )
/* block until chase finished */
2007-01-18 11:20:19 +03:00
block_until_chase_response ( edge_port ) ;
2008-07-22 14:16:34 +04:00
else
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = false ;
2005-04-17 02:20:36 +04:00
}
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPClose ) ) ) {
/* close the port */
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - Sending IOSP_CMD_CLOSE_PORT \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
send_iosp_ext_cmd ( edge_port , IOSP_CMD_CLOSE_PORT , 0 ) ;
2007-01-18 11:20:19 +03:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* port->close = true; */
2007-03-17 03:35:53 +03:00
edge_port - > closePending = false ;
edge_port - > open = false ;
edge_port - > openPending = false ;
2005-04-17 02:20:36 +04:00
2006-11-08 17:36:29 +03:00
usb_kill_urb ( edge_port - > write_urb ) ;
2005-04-17 02:20:36 +04:00
if ( edge_port - > write_urb ) {
2008-07-22 14:16:34 +04:00
/* if this urb had a transfer buffer already
( old transfer ) free it */
2005-04-19 04:39:34 +04:00
kfree ( edge_port - > write_urb - > transfer_buffer ) ;
usb_free_urb ( edge_port - > write_urb ) ;
2005-04-17 02:20:36 +04:00
edge_port - > write_urb = NULL ;
}
2005-04-19 04:39:34 +04:00
kfree ( edge_port - > txfifo . fifo ) ;
edge_port - > txfifo . fifo = NULL ;
2008-07-22 14:16:34 +04:00
}
2005-04-17 02:20:36 +04:00
/*****************************************************************************
* SerialWrite
2008-07-22 14:16:34 +04:00
* this function is called by the tty driver when data should be written
* to the port .
* If successful , we return the number of bytes written , otherwise we
* return a negative error number .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static int edge_write ( struct tty_struct * tty , struct usb_serial_port * port ,
const unsigned char * data , int count )
2005-04-17 02:20:36 +04:00
{
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
struct TxFifo * fifo ;
int copySize ;
int bytesleft ;
int firsthalf ;
int secondhalf ;
unsigned long flags ;
if ( edge_port = = NULL )
return - ENODEV ;
2008-07-22 14:16:34 +04:00
/* get a pointer to the Tx fifo */
2005-04-17 02:20:36 +04:00
fifo = & edge_port - > txfifo ;
spin_lock_irqsave ( & edge_port - > ep_lock , flags ) ;
2008-07-22 14:16:34 +04:00
/* calculate number of bytes to put in fifo */
copySize = min ( ( unsigned int ) count ,
( edge_port - > txCredits - fifo - > count ) ) ;
2005-04-17 02:20:36 +04:00
2013-06-06 21:32:00 +04:00
dev_dbg ( & port - > dev , " %s of %d byte(s) Fifo room %d -- will copy %d bytes \n " ,
__func__ , count , edge_port - > txCredits - fifo - > count , copySize ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* catch writes of 0 bytes which the tty driver likes to give us,
and when txCredits is empty */
2005-04-17 02:20:36 +04:00
if ( copySize = = 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - copySize = Zero \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto finish_write ;
}
2008-07-22 14:16:34 +04:00
/* queue the data
* since we can never overflow the buffer we do not have to check for a
* full condition
*
* the copy is done is two parts - - first fill to the end of the buffer
* then copy the reset from the start of the buffer
*/
2005-04-17 02:20:36 +04:00
bytesleft = fifo - > size - fifo - > head ;
2008-07-22 14:16:34 +04:00
firsthalf = min ( bytesleft , copySize ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - copy %d bytes of %d into fifo \n " , __func__ ,
firsthalf , bytesleft ) ;
2005-04-17 02:20:36 +04:00
/* now copy our data */
memcpy ( & fifo - > fifo [ fifo - > head ] , data , firsthalf ) ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , firsthalf , & fifo - > fifo [ fifo - > head ] ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* update the index and size */
2005-04-17 02:20:36 +04:00
fifo - > head + = firsthalf ;
fifo - > count + = firsthalf ;
2008-07-22 14:16:34 +04:00
/* wrap the index */
if ( fifo - > head = = fifo - > size )
2005-04-17 02:20:36 +04:00
fifo - > head = 0 ;
secondhalf = copySize - firsthalf ;
if ( secondhalf ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - copy rest of data %d \n " , __func__ , secondhalf ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & fifo - > fifo [ fifo - > head ] , & data [ firsthalf ] , secondhalf ) ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & port - > dev , __func__ , secondhalf , & fifo - > fifo [ fifo - > head ] ) ;
2008-07-22 14:16:34 +04:00
/* update the index and size */
2005-04-17 02:20:36 +04:00
fifo - > count + = secondhalf ;
fifo - > head + = secondhalf ;
2008-07-22 14:16:34 +04:00
/* No need to check for wrap since we can not get to end of
* the fifo in this part
*/
2005-04-17 02:20:36 +04:00
}
finish_write :
spin_unlock_irqrestore ( & edge_port - > ep_lock , flags ) ;
2008-07-22 14:16:34 +04:00
send_more_port_data ( ( struct edgeport_serial * )
usb_get_serial_data ( port - > serial ) , edge_port ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s wrote %d byte(s) TxCredits %d, Fifo %d \n " ,
__func__ , copySize , edge_port - > txCredits , fifo - > count ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
return copySize ;
2005-04-17 02:20:36 +04:00
}
/************************************************************************
*
* send_more_port_data ( )
*
* This routine attempts to write additional UART transmit data
* to a port over the USB bulk pipe . It is called ( 1 ) when new
* data has been written to a port ' s TxBuffer from higher layers
* ( 2 ) when the peripheral sends us additional TxCredits indicating
* that it can accept more Tx data for a given port ; and ( 3 ) when
* a bulk write completes successfully and we want to see if we
* can transmit more .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void send_more_port_data ( struct edgeport_serial * edge_serial ,
struct edgeport_port * edge_port )
2005-04-17 02:20:36 +04:00
{
struct TxFifo * fifo = & edge_port - > txfifo ;
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
struct urb * urb ;
unsigned char * buffer ;
int status ;
int count ;
int bytesleft ;
int firsthalf ;
int secondhalf ;
unsigned long flags ;
spin_lock_irqsave ( & edge_port - > ep_lock , flags ) ;
if ( edge_port - > write_in_progress | |
! edge_port - > open | |
( fifo - > count = = 0 ) ) {
2013-06-06 21:32:00 +04:00
dev_dbg ( dev , " %s EXIT - fifo %d, PendingWrite = %d \n " ,
__func__ , fifo - > count , edge_port - > write_in_progress ) ;
2005-04-17 02:20:36 +04:00
goto exit_send ;
}
2008-07-22 14:16:34 +04:00
/* since the amount of data in the fifo will always fit into the
* edgeport buffer we do not need to check the write length
*
* Do we have enough credits for this port to make it worthwhile
* to bother queueing a write . If it ' s too small , say a few bytes ,
* it ' s better to wait for more credits so we can do a larger write .
*/
if ( edge_port - > txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD ( edge_port - > maxTxCredits , EDGE_FW_BULK_MAX_PACKET_SIZE ) ) {
2013-06-06 21:32:00 +04:00
dev_dbg ( dev , " %s Not enough credit - fifo %d TxCredit %d \n " ,
__func__ , fifo - > count , edge_port - > txCredits ) ;
2005-04-17 02:20:36 +04:00
goto exit_send ;
}
2008-07-22 14:16:34 +04:00
/* lock this write */
2007-03-17 03:35:53 +03:00
edge_port - > write_in_progress = true ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* get a pointer to the write_urb */
2005-04-17 02:20:36 +04:00
urb = edge_port - > write_urb ;
2005-04-19 04:39:34 +04:00
/* make sure transfer buffer is freed */
kfree ( urb - > transfer_buffer ) ;
urb - > transfer_buffer = NULL ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* build the data header for the buffer and port that we are about
to send out */
2005-04-17 02:20:36 +04:00
count = fifo - > count ;
2008-07-22 14:16:34 +04:00
buffer = kmalloc ( count + 2 , GFP_ATOMIC ) ;
2013-12-29 22:22:56 +04:00
if ( ! buffer ) {
2007-03-17 03:35:53 +03:00
edge_port - > write_in_progress = false ;
2005-04-17 02:20:36 +04:00
goto exit_send ;
}
2013-06-06 21:32:00 +04:00
buffer [ 0 ] = IOSP_BUILD_DATA_HDR1 ( edge_port - > port - > port_number , count ) ;
buffer [ 1 ] = IOSP_BUILD_DATA_HDR2 ( edge_port - > port - > port_number , count ) ;
2005-04-17 02:20:36 +04:00
/* now copy our data */
bytesleft = fifo - > size - fifo - > tail ;
2008-07-22 14:16:34 +04:00
firsthalf = min ( bytesleft , count ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & buffer [ 2 ] , & fifo - > fifo [ fifo - > tail ] , firsthalf ) ;
fifo - > tail + = firsthalf ;
fifo - > count - = firsthalf ;
2008-07-22 14:16:34 +04:00
if ( fifo - > tail = = fifo - > size )
2005-04-17 02:20:36 +04:00
fifo - > tail = 0 ;
secondhalf = count - firsthalf ;
if ( secondhalf ) {
2008-07-22 14:16:34 +04:00
memcpy ( & buffer [ 2 + firsthalf ] , & fifo - > fifo [ fifo - > tail ] ,
secondhalf ) ;
2005-04-17 02:20:36 +04:00
fifo - > tail + = secondhalf ;
fifo - > count - = secondhalf ;
}
if ( count )
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( & edge_port - > port - > dev , __func__ , count , & buffer [ 2 ] ) ;
2005-04-17 02:20:36 +04:00
/* fill up the urb with all of our data and submit it */
2008-07-22 14:16:34 +04:00
usb_fill_bulk_urb ( urb , edge_serial - > serial - > dev ,
usb_sndbulkpipe ( edge_serial - > serial - > dev ,
edge_serial - > bulk_out_endpoint ) ,
buffer , count + 2 ,
edge_bulk_out_data_callback , edge_port ) ;
2005-04-17 02:20:36 +04:00
/* decrement the number of credits we have by the number we just sent */
edge_port - > txCredits - = count ;
2013-03-21 15:37:07 +04:00
edge_port - > port - > icount . tx + = count ;
2005-04-17 02:20:36 +04:00
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ) {
/* something went wrong */
2012-02-10 16:20:51 +04:00
dev_err_console ( edge_port - > port ,
2008-07-22 14:16:34 +04:00
" %s - usb_submit_urb(write bulk) failed, status = %d, data lost \n " ,
__func__ , status ) ;
2007-03-17 03:35:53 +03:00
edge_port - > write_in_progress = false ;
2005-04-17 02:20:36 +04:00
/* revert the credits as something bad happened. */
edge_port - > txCredits + = count ;
2013-03-21 15:37:07 +04:00
edge_port - > port - > icount . tx - = count ;
2005-04-17 02:20:36 +04:00
}
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s wrote %d byte(s) TxCredit %d, Fifo %d \n " ,
__func__ , count , edge_port - > txCredits , fifo - > count ) ;
2005-04-17 02:20:36 +04:00
exit_send :
spin_unlock_irqrestore ( & edge_port - > ep_lock , flags ) ;
}
/*****************************************************************************
* edge_write_room
2008-07-22 14:16:34 +04:00
* this function is called by the tty driver when it wants to know how
* many bytes of data we can accept for a specific port . If successful ,
* we return the amount of room that we have for this port ( the txCredits )
* otherwise we return a negative error number .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static int edge_write_room ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
int room ;
unsigned long flags ;
if ( edge_port = = NULL )
2008-07-22 14:16:42 +04:00
return 0 ;
2007-03-17 03:35:53 +03:00
if ( edge_port - > closePending )
2008-07-22 14:16:42 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( ! edge_port - > open ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - port not opened \n " , __func__ ) ;
2008-07-22 14:16:42 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:16:34 +04:00
/* total of both buffers is still txCredit */
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & edge_port - > ep_lock , flags ) ;
room = edge_port - > txCredits - edge_port - > txfifo . count ;
spin_unlock_irqrestore ( & edge_port - > ep_lock , flags ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - returns %d \n " , __func__ , room ) ;
2005-04-17 02:20:36 +04:00
return room ;
}
/*****************************************************************************
* edge_chars_in_buffer
2008-07-22 14:16:34 +04:00
* this function is called by the tty driver when it wants to know how
* many bytes of data we currently have outstanding in the port ( data that
* has been written , but hasn ' t made it out the port yet )
* If successful , we return the number of bytes left to be written in the
* system ,
2005-04-17 02:20:36 +04:00
* Otherwise we return a negative error number .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static int edge_chars_in_buffer ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
int num_chars ;
unsigned long flags ;
if ( edge_port = = NULL )
2008-07-22 14:16:42 +04:00
return 0 ;
2007-03-17 03:35:53 +03:00
if ( edge_port - > closePending )
2008-07-22 14:16:42 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
if ( ! edge_port - > open ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - port not opened \n " , __func__ ) ;
2008-07-22 14:16:42 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
spin_lock_irqsave ( & edge_port - > ep_lock , flags ) ;
2008-07-22 14:16:34 +04:00
num_chars = edge_port - > maxTxCredits - edge_port - > txCredits +
edge_port - > txfifo . count ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & edge_port - > ep_lock , flags ) ;
if ( num_chars ) {
2013-06-06 21:32:00 +04:00
dev_dbg ( & port - > dev , " %s - returns %d \n " , __func__ , num_chars ) ;
2005-04-17 02:20:36 +04:00
}
return num_chars ;
}
/*****************************************************************************
* SerialThrottle
* this function is called by the tty driver when it wants to stop the data
* being read from the port .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static void edge_throttle ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
int status ;
if ( edge_port = = NULL )
return ;
if ( ! edge_port - > open ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - port not opened \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* if we are implementing XON/XOFF, send the stop character */
if ( I_IXOFF ( tty ) ) {
unsigned char stop_char = STOP_CHAR ( tty ) ;
2008-07-22 14:16:34 +04:00
status = edge_write ( tty , port , & stop_char , 1 ) ;
if ( status < = 0 )
2005-04-17 02:20:36 +04:00
return ;
}
/* if we are implementing RTS/CTS, toggle that line */
2012-07-14 18:31:47 +04:00
if ( tty - > termios . c_cflag & CRTSCTS ) {
2005-04-17 02:20:36 +04:00
edge_port - > shadowMCR & = ~ MCR_RTS ;
2008-07-22 14:16:34 +04:00
status = send_cmd_write_uart_register ( edge_port , MCR ,
edge_port - > shadowMCR ) ;
if ( status ! = 0 )
2005-04-17 02:20:36 +04:00
return ;
}
}
/*****************************************************************************
* edge_unthrottle
2008-07-22 14:16:34 +04:00
* this function is called by the tty driver when it wants to resume the
* data being read from the port ( called after SerialThrottle is called )
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static void edge_unthrottle ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
int status ;
if ( edge_port = = NULL )
return ;
if ( ! edge_port - > open ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - port not opened \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* if we are implementing XON/XOFF, send the start character */
if ( I_IXOFF ( tty ) ) {
unsigned char start_char = START_CHAR ( tty ) ;
2008-07-22 14:09:07 +04:00
status = edge_write ( tty , port , & start_char , 1 ) ;
if ( status < = 0 )
2005-04-17 02:20:36 +04:00
return ;
}
/* if we are implementing RTS/CTS, toggle that line */
2012-07-14 18:31:47 +04:00
if ( tty - > termios . c_cflag & CRTSCTS ) {
2005-04-17 02:20:36 +04:00
edge_port - > shadowMCR | = MCR_RTS ;
2008-07-22 14:16:34 +04:00
send_cmd_write_uart_register ( edge_port , MCR ,
edge_port - > shadowMCR ) ;
2005-04-17 02:20:36 +04:00
}
}
/*****************************************************************************
* SerialSetTermios
2008-07-22 14:16:34 +04:00
* this function is called by the tty driver when it wants to change
* the termios structure
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static void edge_set_termios ( struct tty_struct * tty ,
struct usb_serial_port * port , struct ktermios * old_termios )
2005-04-17 02:20:36 +04:00
{
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
unsigned int cflag ;
2012-07-14 18:31:47 +04:00
cflag = tty - > termios . c_cflag ;
2012-10-02 00:23:01 +04:00
dev_dbg ( & port - > dev , " %s - clfag %08x iflag %08x \n " , __func__ , tty - > termios . c_cflag , tty - > termios . c_iflag ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - old clfag %08x old iflag %08x \n " , __func__ , old_termios - > c_cflag , old_termios - > c_iflag ) ;
2005-04-17 02:20:36 +04:00
if ( edge_port = = NULL )
return ;
if ( ! edge_port - > open ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - port not opened \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* change the port settings to the new ones specified */
2008-07-22 14:09:07 +04:00
change_port_settings ( tty , edge_port , old_termios ) ;
2005-04-17 02:20:36 +04:00
}
/*****************************************************************************
* get_lsr_info - get line status register info
*
* Purpose : Let user call ioctl ( ) to get info when the UART physically
* is emptied . On bus types like RS485 , the transmitter must
* release the bus after transmitting . This must be done when
* the transmit shift register is empty , not be done when the
* transmit holding register is empty . This functionality
2008-07-22 14:16:34 +04:00
* allows an RS485 driver to be written in user space .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int get_lsr_info ( struct edgeport_port * edge_port ,
unsigned int __user * value )
2005-04-17 02:20:36 +04:00
{
unsigned int result = 0 ;
unsigned long flags ;
spin_lock_irqsave ( & edge_port - > ep_lock , flags ) ;
if ( edge_port - > maxTxCredits = = edge_port - > txCredits & &
edge_port - > txfifo . count = = 0 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & edge_port - > port - > dev , " %s -- Empty \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
result = TIOCSER_TEMT ;
}
spin_unlock_irqrestore ( & edge_port - > ep_lock , flags ) ;
if ( copy_to_user ( value , & result , sizeof ( int ) ) )
return - EFAULT ;
return 0 ;
}
2011-02-14 19:26:50 +03:00
static int edge_tiocmset ( struct tty_struct * tty ,
2008-07-22 14:16:34 +04:00
unsigned int set , unsigned int clear )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
unsigned int mcr ;
mcr = edge_port - > shadowMCR ;
if ( set & TIOCM_RTS )
mcr | = MCR_RTS ;
if ( set & TIOCM_DTR )
mcr | = MCR_DTR ;
if ( set & TIOCM_LOOP )
mcr | = MCR_LOOPBACK ;
if ( clear & TIOCM_RTS )
mcr & = ~ MCR_RTS ;
if ( clear & TIOCM_DTR )
mcr & = ~ MCR_DTR ;
if ( clear & TIOCM_LOOP )
mcr & = ~ MCR_LOOPBACK ;
edge_port - > shadowMCR = mcr ;
send_cmd_write_uart_register ( edge_port , MCR , edge_port - > shadowMCR ) ;
return 0 ;
}
2011-02-14 19:26:14 +03:00
static int edge_tiocmget ( struct tty_struct * tty )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
unsigned int result = 0 ;
unsigned int msr ;
unsigned int mcr ;
msr = edge_port - > shadowMSR ;
mcr = edge_port - > shadowMCR ;
result = ( ( mcr & MCR_DTR ) ? TIOCM_DTR : 0 ) /* 0x002 */
| ( ( mcr & MCR_RTS ) ? TIOCM_RTS : 0 ) /* 0x004 */
| ( ( msr & EDGEPORT_MSR_CTS ) ? TIOCM_CTS : 0 ) /* 0x020 */
| ( ( msr & EDGEPORT_MSR_CD ) ? TIOCM_CAR : 0 ) /* 0x040 */
| ( ( msr & EDGEPORT_MSR_RI ) ? TIOCM_RI : 0 ) /* 0x080 */
| ( ( msr & EDGEPORT_MSR_DSR ) ? TIOCM_DSR : 0 ) ; /* 0x100 */
return result ;
}
2008-07-22 14:16:34 +04:00
static int get_serial_info ( struct edgeport_port * edge_port ,
struct serial_struct __user * retinfo )
2005-04-17 02:20:36 +04:00
{
struct serial_struct tmp ;
if ( ! retinfo )
return - EFAULT ;
memset ( & tmp , 0 , sizeof ( tmp ) ) ;
tmp . type = PORT_16550A ;
2013-06-07 22:04:28 +04:00
tmp . line = edge_port - > port - > minor ;
2013-06-06 21:32:00 +04:00
tmp . port = edge_port - > port - > port_number ;
2005-04-17 02:20:36 +04:00
tmp . irq = 0 ;
tmp . flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ ;
tmp . xmit_fifo_size = edge_port - > maxTxCredits ;
tmp . baud_base = 9600 ;
tmp . close_delay = 5 * HZ ;
tmp . closing_wait = 30 * HZ ;
if ( copy_to_user ( retinfo , & tmp , sizeof ( * retinfo ) ) )
return - EFAULT ;
return 0 ;
}
/*****************************************************************************
* SerialIoctl
* this function handles any ioctl calls to the driver
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-02-14 19:27:06 +03:00
static int edge_ioctl ( struct tty_struct * tty ,
2008-07-22 14:09:07 +04:00
unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
DEFINE_WAIT ( wait ) ;
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
switch ( cmd ) {
2008-07-22 14:16:34 +04:00
case TIOCSERGETLSR :
2013-06-06 21:32:00 +04:00
dev_dbg ( & port - > dev , " %s TIOCSERGETLSR \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
return get_lsr_info ( edge_port , ( unsigned int __user * ) arg ) ;
case TIOCGSERIAL :
2013-06-06 21:32:00 +04:00
dev_dbg ( & port - > dev , " %s TIOCGSERIAL \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
return get_serial_info ( edge_port , ( struct serial_struct __user * ) arg ) ;
2005-04-17 02:20:36 +04:00
}
return - ENOIOCTLCMD ;
}
/*****************************************************************************
* SerialBreak
* this function sends a break to the port
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void edge_break ( struct tty_struct * tty , int break_state )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:09:07 +04:00
struct usb_serial_port * port = tty - > driver_data ;
2005-04-17 02:20:36 +04:00
struct edgeport_port * edge_port = usb_get_serial_port_data ( port ) ;
2007-01-18 11:20:19 +03:00
struct edgeport_serial * edge_serial = usb_get_serial_data ( port - > serial ) ;
2005-04-17 02:20:36 +04:00
int status ;
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPChase ) ) ) {
/* flush and chase */
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = true ;
2007-01-18 11:20:19 +03:00
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - Sending IOSP_CMD_CHASE_PORT \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
status = send_iosp_ext_cmd ( edge_port , IOSP_CMD_CHASE_PORT , 0 ) ;
2007-01-18 11:20:19 +03:00
if ( status = = 0 ) {
2008-07-22 14:16:34 +04:00
/* block until chase finished */
2007-01-18 11:20:19 +03:00
block_until_chase_response ( edge_port ) ;
} else {
2007-03-17 03:35:53 +03:00
edge_port - > chaseResponsePending = false ;
2007-01-18 11:20:19 +03:00
}
2005-04-17 02:20:36 +04:00
}
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPSetClrBreak ) ) ) {
if ( break_state = = - 1 ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - Sending IOSP_CMD_SET_BREAK \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
status = send_iosp_ext_cmd ( edge_port ,
IOSP_CMD_SET_BREAK , 0 ) ;
2007-01-18 11:20:19 +03:00
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - Sending IOSP_CMD_CLEAR_BREAK \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
status = send_iosp_ext_cmd ( edge_port ,
IOSP_CMD_CLEAR_BREAK , 0 ) ;
2007-01-18 11:20:19 +03:00
}
2008-07-22 14:16:34 +04:00
if ( status )
2012-09-18 12:33:23 +04:00
dev_dbg ( & port - > dev , " %s - error sending break set/clear command. \n " ,
2008-07-22 14:16:34 +04:00
__func__ ) ;
2005-04-17 02:20:36 +04:00
}
}
/*****************************************************************************
* process_rcvd_data
* this function handles the data received on the bulk in pipe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void process_rcvd_data ( struct edgeport_serial * edge_serial ,
unsigned char * buffer , __u16 bufferLength )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2005-04-17 02:20:36 +04:00
struct usb_serial_port * port ;
struct edgeport_port * edge_port ;
__u16 lastBufferLength ;
__u16 rxLen ;
lastBufferLength = bufferLength + 1 ;
while ( bufferLength > 0 ) {
/* failsafe incase we get a message that we don't understand */
if ( lastBufferLength = = bufferLength ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - stuck in loop, exiting it. \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
break ;
}
lastBufferLength = bufferLength ;
switch ( edge_serial - > rxState ) {
2008-07-22 14:16:34 +04:00
case EXPECT_HDR1 :
edge_serial - > rxHeader1 = * buffer ;
+ + buffer ;
- - bufferLength ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
if ( bufferLength = = 0 ) {
edge_serial - > rxState = EXPECT_HDR2 ;
break ;
}
/* otherwise, drop on through */
case EXPECT_HDR2 :
edge_serial - > rxHeader2 = * buffer ;
+ + buffer ;
- - bufferLength ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Hdr1=%02X Hdr2=%02X \n " , __func__ ,
edge_serial - > rxHeader1 , edge_serial - > rxHeader2 ) ;
2008-07-22 14:16:34 +04:00
/* Process depending on whether this header is
* data or status */
if ( IS_CMD_STAT_HDR ( edge_serial - > rxHeader1 ) ) {
/* Decode this status header and go to
* EXPECT_HDR1 ( if we can process the status
* with only 2 bytes ) , or go to EXPECT_HDR3 to
* get the third byte . */
edge_serial - > rxPort =
IOSP_GET_HDR_PORT ( edge_serial - > rxHeader1 ) ;
edge_serial - > rxStatusCode =
IOSP_GET_STATUS_CODE (
edge_serial - > rxHeader1 ) ;
if ( ! IOSP_STATUS_IS_2BYTE (
edge_serial - > rxStatusCode ) ) {
/* This status needs additional bytes.
* Save what we have and then wait for
* more data .
*/
edge_serial - > rxStatusParam
= edge_serial - > rxHeader2 ;
edge_serial - > rxState = EXPECT_HDR3 ;
2005-04-17 02:20:36 +04:00
break ;
}
2008-07-22 14:16:34 +04:00
/* We have all the header bytes, process the
status now */
process_rcvd_status ( edge_serial ,
edge_serial - > rxHeader2 , 0 ) ;
edge_serial - > rxState = EXPECT_HDR1 ;
break ;
} else {
edge_serial - > rxPort =
IOSP_GET_HDR_PORT ( edge_serial - > rxHeader1 ) ;
edge_serial - > rxBytesRemaining =
IOSP_GET_HDR_DATA_LEN (
edge_serial - > rxHeader1 ,
edge_serial - > rxHeader2 ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Data for Port %u Len %u \n " ,
__func__ ,
edge_serial - > rxPort ,
edge_serial - > rxBytesRemaining ) ;
2008-07-22 14:16:34 +04:00
/* ASSERT(DevExt->RxPort < DevExt->NumPorts);
* ASSERT ( DevExt - > RxBytesRemaining <
* IOSP_MAX_DATA_LENGTH ) ;
*/
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
if ( bufferLength = = 0 ) {
edge_serial - > rxState = EXPECT_DATA ;
2005-04-17 02:20:36 +04:00
break ;
}
2008-07-22 14:16:34 +04:00
/* Else, drop through */
}
case EXPECT_DATA : /* Expect data */
if ( bufferLength < edge_serial - > rxBytesRemaining ) {
rxLen = bufferLength ;
/* Expect data to start next buffer */
edge_serial - > rxState = EXPECT_DATA ;
} else {
/* BufLen >= RxBytesRemaining */
rxLen = edge_serial - > rxBytesRemaining ;
/* Start another header next time */
edge_serial - > rxState = EXPECT_HDR1 ;
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
bufferLength - = rxLen ;
edge_serial - > rxBytesRemaining - = rxLen ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* spit this data back into the tty driver if this
port is open */
if ( rxLen ) {
port = edge_serial - > serial - > port [
edge_serial - > rxPort ] ;
edge_port = usb_get_serial_port_data ( port ) ;
if ( edge_port - > open ) {
2013-01-03 18:53:06 +04:00
dev_dbg ( dev , " %s - Sending %d bytes to TTY for port %d \n " ,
__func__ , rxLen ,
edge_serial - > rxPort ) ;
edge_tty_recv ( edge_port - > port , buffer ,
rxLen ) ;
2013-03-21 15:37:07 +04:00
edge_port - > port - > icount . rx + = rxLen ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:16:34 +04:00
buffer + = rxLen ;
}
break ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
case EXPECT_HDR3 : /* Expect 3rd byte of status header */
edge_serial - > rxHeader3 = * buffer ;
+ + buffer ;
- - bufferLength ;
/* We have all the header bytes, process the
status now */
process_rcvd_status ( edge_serial ,
edge_serial - > rxStatusParam ,
edge_serial - > rxHeader3 ) ;
edge_serial - > rxState = EXPECT_HDR1 ;
break ;
2005-04-17 02:20:36 +04:00
}
}
}
/*****************************************************************************
* process_rcvd_status
2008-07-22 14:16:34 +04:00
* this function handles the any status messages received on the
* bulk in pipe .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void process_rcvd_status ( struct edgeport_serial * edge_serial ,
__u8 byte2 , __u8 byte3 )
2005-04-17 02:20:36 +04:00
{
struct usb_serial_port * port ;
struct edgeport_port * edge_port ;
2008-10-13 13:39:46 +04:00
struct tty_struct * tty ;
2012-09-18 12:33:23 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
__u8 code = edge_serial - > rxStatusCode ;
/* switch the port pointer to the one being currently talked about */
port = edge_serial - > serial - > port [ edge_serial - > rxPort ] ;
edge_port = usb_get_serial_port_data ( port ) ;
if ( edge_port = = NULL ) {
2008-07-22 14:16:34 +04:00
dev_err ( & edge_serial - > serial - > dev - > dev ,
" %s - edge_port == NULL for port %d \n " ,
__func__ , edge_serial - > rxPort ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2012-09-18 12:33:23 +04:00
dev = & port - > dev ;
2005-04-17 02:20:36 +04:00
if ( code = = IOSP_EXT_STATUS ) {
switch ( byte2 ) {
2008-07-22 14:16:34 +04:00
case IOSP_EXT_STATUS_CHASE_RSP :
/* we want to do EXT status regardless of port
* open / closed */
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Port %u EXT CHASE_RSP Data = %02x \n " ,
__func__ , edge_serial - > rxPort , byte3 ) ;
2008-07-22 14:16:34 +04:00
/* Currently, the only EXT_STATUS is Chase, so process
* here instead of one more call to one more subroutine
* If / when more EXT_STATUS , there ' ll be more work to do
* Also , we currently clear flag and close the port
* regardless of content of above ' s Byte3 .
* We could choose to do something else when Byte3 says
* Timeout on Chase from Edgeport , like wait longer in
* block_until_chase_response , but for now we don ' t .
*/
edge_port - > chaseResponsePending = false ;
wake_up ( & edge_port - > wait_chase ) ;
return ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
case IOSP_EXT_STATUS_RX_CHECK_RSP :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s ========== Port %u CHECK_RSP Sequence = %02x ============= \n " ,
__func__ , edge_serial - > rxPort , byte3 ) ;
2008-07-22 14:16:34 +04:00
/* Port->RxCheckRsp = true; */
return ;
2005-04-17 02:20:36 +04:00
}
}
if ( code = = IOSP_STATUS_OPEN_RSP ) {
edge_port - > txCredits = GET_TX_BUFFER_SIZE ( byte3 ) ;
edge_port - > maxTxCredits = edge_port - > txCredits ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d \n " ,
__func__ , edge_serial - > rxPort , byte2 , edge_port - > txCredits ) ;
2008-07-22 14:16:34 +04:00
handle_new_msr ( edge_port , byte2 ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* send the current line settings to the port so we are
in sync with any further termios calls */
2008-10-13 13:39:46 +04:00
tty = tty_port_tty_get ( & edge_port - > port - > port ) ;
if ( tty ) {
change_port_settings ( tty ,
2012-07-14 18:31:47 +04:00
edge_port , & tty - > termios ) ;
2008-10-13 13:39:46 +04:00
tty_kref_put ( tty ) ;
}
2005-04-17 02:20:36 +04:00
/* we have completed the open */
2007-03-17 03:35:53 +03:00
edge_port - > openPending = false ;
edge_port - > open = true ;
2005-04-17 02:20:36 +04:00
wake_up ( & edge_port - > wait_open ) ;
return ;
}
2008-07-22 14:16:34 +04:00
/* If port is closed, silently discard all rcvd status. We can
* have cases where buffered status is received AFTER the close
* port command is sent to the Edgeport .
*/
if ( ! edge_port - > open | | edge_port - > closePending )
2005-04-17 02:20:36 +04:00
return ;
switch ( code ) {
2008-07-22 14:16:34 +04:00
/* Not currently sent by Edgeport */
case IOSP_STATUS_LSR :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Port %u LSR Status = %02x \n " ,
__func__ , edge_serial - > rxPort , byte2 ) ;
2008-07-22 14:16:34 +04:00
handle_new_lsr ( edge_port , false , byte2 , 0 ) ;
break ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
case IOSP_STATUS_LSR_DATA :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Port %u LSR Status = %02x, Data = %02x \n " ,
__func__ , edge_serial - > rxPort , byte2 , byte3 ) ;
2008-07-22 14:16:34 +04:00
/* byte2 is LSR Register */
/* byte3 is broken data byte */
handle_new_lsr ( edge_port , true , byte2 , byte3 ) ;
break ;
/*
* case IOSP_EXT_4_STATUS :
2012-09-18 12:33:23 +04:00
* dev_dbg ( dev , " %s - Port %u LSR Status = %02x Data = %02x \n " ,
2008-07-22 14:16:34 +04:00
* __func__ , edge_serial - > rxPort , byte2 , byte3 ) ;
* break ;
*/
case IOSP_STATUS_MSR :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Port %u MSR Status = %02x \n " ,
__func__ , edge_serial - > rxPort , byte2 ) ;
2008-07-22 14:16:34 +04:00
/*
* Process this new modem status and generate appropriate
* events , etc , based on the new status . This routine
* also saves the MSR in Port - > ShadowMsr .
*/
handle_new_msr ( edge_port , byte2 ) ;
break ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
default :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Unrecognized IOSP status code %u \n " , __func__ , code ) ;
2008-07-22 14:16:34 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
}
/*****************************************************************************
* edge_tty_recv
* this function passes data on to the tty flip buffer
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-01-03 18:53:06 +04:00
static void edge_tty_recv ( struct usb_serial_port * port , unsigned char * data ,
int length )
2005-04-17 02:20:36 +04:00
{
int cnt ;
2013-01-03 18:53:04 +04:00
cnt = tty_insert_flip_string ( & port - > port , data , length ) ;
2010-02-18 19:44:01 +03:00
if ( cnt < length ) {
2013-01-03 18:53:04 +04:00
dev_err ( & port - > dev , " %s - dropping data, %d bytes lost \n " ,
2010-02-18 19:44:01 +03:00
__func__ , length - cnt ) ;
}
data + = cnt ;
length - = cnt ;
2005-04-17 02:20:36 +04:00
2013-01-03 18:53:06 +04:00
tty_flip_buffer_push ( & port - > port ) ;
2005-04-17 02:20:36 +04:00
}
/*****************************************************************************
* handle_new_msr
* this function handles any change to the msr register for a port .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void handle_new_msr ( struct edgeport_port * edge_port , __u8 newMsr )
{
struct async_icount * icount ;
2008-07-22 14:16:34 +04:00
if ( newMsr & ( EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD ) ) {
2013-03-21 15:37:07 +04:00
icount = & edge_port - > port - > icount ;
2005-04-17 02:20:36 +04:00
/* update input line counters */
2008-07-22 14:16:34 +04:00
if ( newMsr & EDGEPORT_MSR_DELTA_CTS )
2005-04-17 02:20:36 +04:00
icount - > cts + + ;
2008-07-22 14:16:34 +04:00
if ( newMsr & EDGEPORT_MSR_DELTA_DSR )
2005-04-17 02:20:36 +04:00
icount - > dsr + + ;
2008-07-22 14:16:34 +04:00
if ( newMsr & EDGEPORT_MSR_DELTA_CD )
2005-04-17 02:20:36 +04:00
icount - > dcd + + ;
2008-07-22 14:16:34 +04:00
if ( newMsr & EDGEPORT_MSR_DELTA_RI )
2005-04-17 02:20:36 +04:00
icount - > rng + + ;
2013-03-21 15:37:08 +04:00
wake_up_interruptible ( & edge_port - > port - > port . delta_msr_wait ) ;
2005-04-17 02:20:36 +04:00
}
/* Save the new modem status */
edge_port - > shadowMSR = newMsr & 0xf0 ;
}
/*****************************************************************************
* handle_new_lsr
* this function handles any change to the lsr register for a port .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void handle_new_lsr ( struct edgeport_port * edge_port , __u8 lsrData ,
__u8 lsr , __u8 data )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:16:34 +04:00
__u8 newLsr = ( __u8 ) ( lsr & ( __u8 )
( LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK ) ) ;
struct async_icount * icount ;
2005-04-17 02:20:36 +04:00
edge_port - > shadowLSR = lsr ;
if ( newLsr & LSR_BREAK ) {
2008-07-22 14:16:34 +04:00
/*
* Parity and Framing errors only count if they
* occur exclusive of a break being
* received .
*/
2005-04-17 02:20:36 +04:00
newLsr & = ( __u8 ) ( LSR_OVER_ERR | LSR_BREAK ) ;
}
/* Place LSR data byte into Rx buffer */
2013-01-03 18:53:06 +04:00
if ( lsrData )
edge_tty_recv ( edge_port - > port , & data , 1 ) ;
2005-04-17 02:20:36 +04:00
/* update input line counters */
2013-03-21 15:37:07 +04:00
icount = & edge_port - > port - > icount ;
2008-07-22 14:16:34 +04:00
if ( newLsr & LSR_BREAK )
2005-04-17 02:20:36 +04:00
icount - > brk + + ;
2008-07-22 14:16:34 +04:00
if ( newLsr & LSR_OVER_ERR )
2005-04-17 02:20:36 +04:00
icount - > overrun + + ;
2008-07-22 14:16:34 +04:00
if ( newLsr & LSR_PAR_ERR )
2005-04-17 02:20:36 +04:00
icount - > parity + + ;
2008-07-22 14:16:34 +04:00
if ( newLsr & LSR_FRM_ERR )
2005-04-17 02:20:36 +04:00
icount - > frame + + ;
}
/****************************************************************************
* sram_write
2008-07-22 14:16:34 +04:00
* writes a number of bytes to the Edgeport device ' s sram starting at the
2005-04-17 02:20:36 +04:00
* given address .
* If successful returns the number of bytes written , otherwise it returns
* a negative error number of the problem .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int sram_write ( struct usb_serial * serial , __u16 extAddr , __u16 addr ,
__u16 length , const __u8 * data )
2005-04-17 02:20:36 +04:00
{
int result ;
__u16 current_length ;
unsigned char * transfer_buffer ;
2012-09-18 12:33:23 +04:00
dev_dbg ( & serial - > dev - > dev , " %s - %x, %x, %d \n " , __func__ , extAddr , addr , length ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
transfer_buffer = kmalloc ( 64 , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
/* need to split these writes up into 64 byte chunks */
result = 0 ;
while ( length > 0 ) {
2008-07-22 14:16:34 +04:00
if ( length > 64 )
2005-04-17 02:20:36 +04:00
current_length = 64 ;
2008-07-22 14:16:34 +04:00
else
2005-04-17 02:20:36 +04:00
current_length = length ;
2008-07-22 14:16:34 +04:00
2012-09-18 12:33:23 +04:00
/* dev_dbg(&serial->dev->dev, "%s - writing %x, %x, %d\n", __func__, extAddr, addr, current_length); */
2008-07-22 14:16:34 +04:00
memcpy ( transfer_buffer , data , current_length ) ;
result = usb_control_msg ( serial - > dev ,
usb_sndctrlpipe ( serial - > dev , 0 ) ,
USB_REQUEST_ION_WRITE_RAM ,
0x40 , addr , extAddr , transfer_buffer ,
current_length , 300 ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 )
break ;
length - = current_length ;
addr + = current_length ;
data + = current_length ;
2008-07-22 14:16:34 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/****************************************************************************
* rom_write
* writes a number of bytes to the Edgeport device ' s ROM starting at the
* given address .
* If successful returns the number of bytes written , otherwise it returns
* a negative error number of the problem .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int rom_write ( struct usb_serial * serial , __u16 extAddr , __u16 addr ,
__u16 length , const __u8 * data )
2005-04-17 02:20:36 +04:00
{
int result ;
__u16 current_length ;
unsigned char * transfer_buffer ;
2008-07-22 14:16:34 +04:00
transfer_buffer = kmalloc ( 64 , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
/* need to split these writes up into 64 byte chunks */
result = 0 ;
while ( length > 0 ) {
2008-07-22 14:16:34 +04:00
if ( length > 64 )
2005-04-17 02:20:36 +04:00
current_length = 64 ;
2008-07-22 14:16:34 +04:00
else
2005-04-17 02:20:36 +04:00
current_length = length ;
2008-07-22 14:16:34 +04:00
memcpy ( transfer_buffer , data , current_length ) ;
result = usb_control_msg ( serial - > dev ,
usb_sndctrlpipe ( serial - > dev , 0 ) ,
USB_REQUEST_ION_WRITE_ROM , 0x40 ,
addr , extAddr ,
transfer_buffer , current_length , 300 ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 )
break ;
length - = current_length ;
addr + = current_length ;
data + = current_length ;
2008-07-22 14:16:34 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/****************************************************************************
* rom_read
* reads a number of bytes from the Edgeport device starting at the given
* address .
* If successful returns the number of bytes read , otherwise it returns
* a negative error number of the problem .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int rom_read ( struct usb_serial * serial , __u16 extAddr ,
__u16 addr , __u16 length , __u8 * data )
2005-04-17 02:20:36 +04:00
{
int result ;
__u16 current_length ;
unsigned char * transfer_buffer ;
2008-07-22 14:16:34 +04:00
transfer_buffer = kmalloc ( 64 , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! transfer_buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
/* need to split these reads up into 64 byte chunks */
result = 0 ;
while ( length > 0 ) {
2008-07-22 14:16:34 +04:00
if ( length > 64 )
2005-04-17 02:20:36 +04:00
current_length = 64 ;
2008-07-22 14:16:34 +04:00
else
2005-04-17 02:20:36 +04:00
current_length = length ;
2008-07-22 14:16:34 +04:00
result = usb_control_msg ( serial - > dev ,
usb_rcvctrlpipe ( serial - > dev , 0 ) ,
USB_REQUEST_ION_READ_ROM ,
0xC0 , addr , extAddr , transfer_buffer ,
current_length , 300 ) ;
2005-04-17 02:20:36 +04:00
if ( result < 0 )
break ;
2008-07-22 14:16:34 +04:00
memcpy ( data , transfer_buffer , current_length ) ;
2005-04-17 02:20:36 +04:00
length - = current_length ;
addr + = current_length ;
data + = current_length ;
2008-07-22 14:16:34 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
kfree ( transfer_buffer ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/****************************************************************************
* send_iosp_ext_cmd
* Is used to send a IOSP message to the Edgeport device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int send_iosp_ext_cmd ( struct edgeport_port * edge_port ,
__u8 command , __u8 param )
2005-04-17 02:20:36 +04:00
{
unsigned char * buffer ;
unsigned char * currentCommand ;
int length = 0 ;
int status = 0 ;
2008-07-22 14:16:34 +04:00
buffer = kmalloc ( 10 , GFP_ATOMIC ) ;
2013-12-29 22:22:56 +04:00
if ( ! buffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
currentCommand = buffer ;
2013-06-06 21:32:00 +04:00
MAKE_CMD_EXT_CMD ( & currentCommand , & length , edge_port - > port - > port_number ,
command , param ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
status = write_cmd_usb ( edge_port , buffer , length ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
/* something bad happened, let's free up the memory */
kfree ( buffer ) ;
}
return status ;
}
/*****************************************************************************
* write_cmd_usb
* this function writes the given buffer out to the bulk write endpoint .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int write_cmd_usb ( struct edgeport_port * edge_port ,
unsigned char * buffer , int length )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:16:34 +04:00
struct edgeport_serial * edge_serial =
usb_get_serial_data ( edge_port - > port - > serial ) ;
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
int status = 0 ;
struct urb * urb ;
2012-09-18 12:58:57 +04:00
usb_serial_debug_data ( dev , __func__ , length , buffer ) ;
2005-04-17 02:20:36 +04:00
/* Allocate our next urb */
2008-07-22 14:16:34 +04:00
urb = usb_alloc_urb ( 0 , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! urb )
return - ENOMEM ;
2007-03-15 17:27:17 +03:00
atomic_inc ( & CmdUrbs ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - ALLOCATE URB %p (outstanding %d) \n " ,
__func__ , urb , atomic_read ( & CmdUrbs ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
usb_fill_bulk_urb ( urb , edge_serial - > serial - > dev ,
usb_sndbulkpipe ( edge_serial - > serial - > dev ,
edge_serial - > bulk_out_endpoint ) ,
buffer , length , edge_bulk_out_cmd_callback , edge_port ) ;
2005-04-17 02:20:36 +04:00
2007-03-17 03:35:53 +03:00
edge_port - > commandPending = true ;
2005-04-17 02:20:36 +04:00
status = usb_submit_urb ( urb , GFP_ATOMIC ) ;
if ( status ) {
/* something went wrong */
2012-09-18 12:33:23 +04:00
dev_err ( dev , " %s - usb_submit_urb(write command) failed, status = %d \n " ,
__func__ , status ) ;
2005-04-17 02:20:36 +04:00
usb_kill_urb ( urb ) ;
usb_free_urb ( urb ) ;
2007-03-15 17:27:17 +03:00
atomic_dec ( & CmdUrbs ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
#if 0
2008-07-22 14:16:34 +04:00
wait_event ( & edge_port - > wait_command , ! edge_port - > commandPending ) ;
2005-04-17 02:20:36 +04:00
2007-03-17 03:35:53 +03:00
if ( edge_port - > commandPending ) {
2005-04-17 02:20:36 +04:00
/* command timed out */
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - command timed out \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
status = - EINVAL ;
}
# endif
return status ;
}
/*****************************************************************************
* send_cmd_write_baud_rate
* this function sends the proper command to change the baud rate of the
* specified port .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int send_cmd_write_baud_rate ( struct edgeport_port * edge_port ,
int baudRate )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:16:34 +04:00
struct edgeport_serial * edge_serial =
usb_get_serial_data ( edge_port - > port - > serial ) ;
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
unsigned char * cmdBuffer ;
unsigned char * currCmd ;
int cmdLen = 0 ;
int divisor ;
int status ;
2013-06-06 21:32:00 +04:00
u32 number = edge_port - > port - > port_number ;
2005-04-17 02:20:36 +04:00
2007-07-29 19:03:29 +04:00
if ( edge_serial - > is_epic & &
! edge_serial - > epic_descriptor . Supports . IOSPSetBaudRate ) {
2013-06-06 21:32:00 +04:00
dev_dbg ( dev , " SendCmdWriteBaudRate - NOT Setting baud rate for port, baud = %d \n " ,
baudRate ) ;
2007-01-18 11:20:19 +03:00
return 0 ;
}
2013-06-06 21:32:00 +04:00
dev_dbg ( dev , " %s - baud = %d \n " , __func__ , baudRate ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
status = calc_baud_rate_divisor ( dev , baudRate , & divisor ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev , " %s - bad baud rate \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
2008-07-22 14:16:34 +04:00
/* Alloc memory for the string of commands. */
cmdBuffer = kmalloc ( 0x100 , GFP_ATOMIC ) ;
2013-12-29 22:22:56 +04:00
if ( ! cmdBuffer )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2013-12-29 22:22:56 +04:00
2005-04-17 02:20:36 +04:00
currCmd = cmdBuffer ;
2008-07-22 14:16:34 +04:00
/* Enable access to divisor latch */
MAKE_CMD_WRITE_REG ( & currCmd , & cmdLen , number , LCR , LCR_DL_ENABLE ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* Write the divisor itself */
MAKE_CMD_WRITE_REG ( & currCmd , & cmdLen , number , DLL , LOW8 ( divisor ) ) ;
MAKE_CMD_WRITE_REG ( & currCmd , & cmdLen , number , DLM , HIGH8 ( divisor ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* Restore original value to disable access to divisor latch */
MAKE_CMD_WRITE_REG ( & currCmd , & cmdLen , number , LCR ,
edge_port - > shadowLCR ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
status = write_cmd_usb ( edge_port , cmdBuffer , cmdLen ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
/* something bad happened, let's free up the memory */
2008-07-22 14:16:34 +04:00
kfree ( cmdBuffer ) ;
2005-04-17 02:20:36 +04:00
}
return status ;
}
/*****************************************************************************
* calc_baud_rate_divisor
* this function calculates the proper baud rate divisor for the specified
* baud rate .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-09-18 12:33:23 +04:00
static int calc_baud_rate_divisor ( struct device * dev , int baudrate , int * divisor )
2005-04-17 02:20:36 +04:00
{
int i ;
__u16 custom ;
2005-12-11 18:20:08 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( divisor_table ) ; i + + ) {
2008-07-22 14:16:34 +04:00
if ( divisor_table [ i ] . BaudRate = = baudrate ) {
2005-04-17 02:20:36 +04:00
* divisor = divisor_table [ i ] . Divisor ;
return 0 ;
}
}
2008-07-22 14:16:34 +04:00
/* We have tried all of the standard baud rates
* lets try to calculate the divisor for this baud rate
* Make sure the baud rate is reasonable */
2005-04-17 02:20:36 +04:00
if ( baudrate > 50 & & baudrate < 230400 ) {
2008-07-22 14:16:34 +04:00
/* get divisor */
2005-04-17 02:20:36 +04:00
custom = ( __u16 ) ( ( 230400L + baudrate / 2 ) / baudrate ) ;
* divisor = custom ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - Baud %d = %d \n " , __func__ , baudrate , custom ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
return - 1 ;
}
/*****************************************************************************
* send_cmd_write_uart_register
2009-07-16 19:13:03 +04:00
* this function builds up a uart register message and sends to the device .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int send_cmd_write_uart_register ( struct edgeport_port * edge_port ,
__u8 regNum , __u8 regValue )
2005-04-17 02:20:36 +04:00
{
2008-07-22 14:16:34 +04:00
struct edgeport_serial * edge_serial =
usb_get_serial_data ( edge_port - > port - > serial ) ;
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2005-04-17 02:20:36 +04:00
unsigned char * cmdBuffer ;
unsigned char * currCmd ;
unsigned long cmdLen = 0 ;
int status ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - write to %s register 0x%02x \n " ,
( regNum = = MCR ) ? " MCR " : " LCR " , __func__ , regValue ) ;
2005-04-17 02:20:36 +04:00
2007-07-29 19:03:29 +04:00
if ( edge_serial - > is_epic & &
! edge_serial - > epic_descriptor . Supports . IOSPWriteMCR & &
regNum = = MCR ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " SendCmdWriteUartReg - Not writing to MCR Register \n " ) ;
2007-01-18 11:20:19 +03:00
return 0 ;
}
2007-07-29 19:03:29 +04:00
if ( edge_serial - > is_epic & &
! edge_serial - > epic_descriptor . Supports . IOSPWriteLCR & &
regNum = = LCR ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " SendCmdWriteUartReg - Not writing to LCR Register \n " ) ;
2007-01-18 11:20:19 +03:00
return 0 ;
}
2008-07-22 14:16:34 +04:00
/* Alloc memory for the string of commands. */
cmdBuffer = kmalloc ( 0x10 , GFP_ATOMIC ) ;
if ( cmdBuffer = = NULL )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
currCmd = cmdBuffer ;
2008-07-22 14:16:34 +04:00
/* Build a cmd in the buffer to write the given register */
2013-06-06 21:32:00 +04:00
MAKE_CMD_WRITE_REG ( & currCmd , & cmdLen , edge_port - > port - > port_number ,
regNum , regValue ) ;
2005-04-17 02:20:36 +04:00
status = write_cmd_usb ( edge_port , cmdBuffer , cmdLen ) ;
if ( status ) {
/* something bad happened, let's free up the memory */
2008-07-22 14:16:34 +04:00
kfree ( cmdBuffer ) ;
2005-04-17 02:20:36 +04:00
}
return status ;
}
/*****************************************************************************
* change_port_settings
2008-07-22 14:16:34 +04:00
* This routine is called to set the UART on the device to match the
* specified new settings .
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:09:07 +04:00
static void change_port_settings ( struct tty_struct * tty ,
struct edgeport_port * edge_port , struct ktermios * old_termios )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_port - > port - > dev ;
2008-07-22 14:16:34 +04:00
struct edgeport_serial * edge_serial =
usb_get_serial_data ( edge_port - > port - > serial ) ;
2005-04-17 02:20:36 +04:00
int baud ;
unsigned cflag ;
__u8 mask = 0xff ;
__u8 lData ;
__u8 lParity ;
__u8 lStop ;
__u8 rxFlow ;
__u8 txFlow ;
int status ;
2007-03-17 03:35:53 +03:00
if ( ! edge_port - > open & &
! edge_port - > openPending ) {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - port not opened \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2012-07-14 18:31:47 +04:00
cflag = tty - > termios . c_cflag ;
2005-04-17 02:20:36 +04:00
switch ( cflag & CSIZE ) {
2008-07-22 14:16:34 +04:00
case CS5 :
lData = LCR_BITS_5 ; mask = 0x1f ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - data bits = 5 \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
break ;
case CS6 :
lData = LCR_BITS_6 ; mask = 0x3f ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - data bits = 6 \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
break ;
case CS7 :
lData = LCR_BITS_7 ; mask = 0x7f ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - data bits = 7 \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
break ;
default :
case CS8 :
lData = LCR_BITS_8 ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - data bits = 8 \n " , __func__ ) ;
2008-07-22 14:16:34 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
lParity = LCR_PAR_NONE ;
if ( cflag & PARENB ) {
if ( cflag & CMSPAR ) {
if ( cflag & PARODD ) {
lParity = LCR_PAR_MARK ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - parity = mark \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
} else {
lParity = LCR_PAR_SPACE ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - parity = space \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
} else if ( cflag & PARODD ) {
lParity = LCR_PAR_ODD ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - parity = odd \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
} else {
lParity = LCR_PAR_EVEN ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - parity = even \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - parity = none \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
if ( cflag & CSTOPB ) {
lStop = LCR_STOP_2 ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - stop bits = 2 \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
} else {
lStop = LCR_STOP_1 ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - stop bits = 1 \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
/* figure out the flow control settings */
rxFlow = txFlow = 0x00 ;
if ( cflag & CRTSCTS ) {
rxFlow | = IOSP_RX_FLOW_RTS ;
txFlow | = IOSP_TX_FLOW_CTS ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - RTS/CTS is enabled \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - RTS/CTS is disabled \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-22 14:16:34 +04:00
/* if we are implementing XON/XOFF, set the start and stop character
in the device */
2005-04-17 02:20:36 +04:00
if ( I_IXOFF ( tty ) | | I_IXON ( tty ) ) {
unsigned char stop_char = STOP_CHAR ( tty ) ;
unsigned char start_char = START_CHAR ( tty ) ;
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPSetXChar ) ) ) {
2008-07-22 14:16:34 +04:00
send_iosp_ext_cmd ( edge_port ,
IOSP_CMD_SET_XON_CHAR , start_char ) ;
send_iosp_ext_cmd ( edge_port ,
IOSP_CMD_SET_XOFF_CHAR , stop_char ) ;
2007-01-18 11:20:19 +03:00
}
2005-04-17 02:20:36 +04:00
/* if we are implementing INBOUND XON/XOFF */
if ( I_IXOFF ( tty ) ) {
rxFlow | = IOSP_RX_FLOW_XON_XOFF ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x \n " ,
__func__ , start_char , stop_char ) ;
2005-04-17 02:20:36 +04:00
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - INBOUND XON/XOFF is disabled \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
/* if we are implementing OUTBOUND XON/XOFF */
if ( I_IXON ( tty ) ) {
txFlow | = IOSP_TX_FLOW_XON_XOFF ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x \n " ,
__func__ , start_char , stop_char ) ;
2005-04-17 02:20:36 +04:00
} else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - OUTBOUND XON/XOFF is disabled \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
}
/* Set flow control to the configured value */
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPSetRxFlow ) ) )
send_iosp_ext_cmd ( edge_port , IOSP_CMD_SET_RX_FLOW , rxFlow ) ;
if ( ( ! edge_serial - > is_epic ) | |
( ( edge_serial - > is_epic ) & &
( edge_serial - > epic_descriptor . Supports . IOSPSetTxFlow ) ) )
send_iosp_ext_cmd ( edge_port , IOSP_CMD_SET_TX_FLOW , txFlow ) ;
2005-04-17 02:20:36 +04:00
edge_port - > shadowLCR & = ~ ( LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK ) ;
edge_port - > shadowLCR | = ( lData | lParity | lStop ) ;
edge_port - > validDataMask = mask ;
/* Send the updated LCR value to the EdgePort */
2008-07-22 14:16:34 +04:00
status = send_cmd_write_uart_register ( edge_port , LCR ,
edge_port - > shadowLCR ) ;
if ( status ! = 0 )
2005-04-17 02:20:36 +04:00
return ;
/* set up the MCR register and send it to the EdgePort */
edge_port - > shadowMCR = MCR_MASTER_IE ;
2008-07-22 14:16:34 +04:00
if ( cflag & CBAUD )
2005-04-17 02:20:36 +04:00
edge_port - > shadowMCR | = ( MCR_DTR | MCR_RTS ) ;
2008-07-22 14:16:34 +04:00
status = send_cmd_write_uart_register ( edge_port , MCR ,
edge_port - > shadowMCR ) ;
if ( status ! = 0 )
2005-04-17 02:20:36 +04:00
return ;
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate ( tty ) ;
if ( ! baud ) {
/* pick a default, any default... */
baud = 9600 ;
}
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s - baud rate = %d \n " , __func__ , baud ) ;
2008-07-22 14:16:34 +04:00
status = send_cmd_write_baud_rate ( edge_port , baud ) ;
2007-10-18 12:24:25 +04:00
if ( status = = - 1 ) {
/* Speed change was not possible - put back the old speed */
baud = tty_termios_baud_rate ( old_termios ) ;
tty_encode_baud_rate ( tty , baud , baud ) ;
}
2005-04-17 02:20:36 +04:00
}
/****************************************************************************
* unicode_to_ascii
* Turns a string from Unicode into ASCII .
* Doesn ' t do a good job with any characters that are outside the normal
* ASCII range , but it ' s only for debugging . . .
* NOTE : expects the unicode in LE format
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void unicode_to_ascii ( char * string , int buflen ,
__le16 * unicode , int unicode_size )
2005-04-17 02:20:36 +04:00
{
int i ;
2006-05-23 08:49:44 +04:00
if ( buflen < = 0 ) /* never happens, but... */
2005-04-17 02:20:36 +04:00
return ;
2006-05-23 08:49:44 +04:00
- - buflen ; /* space for nul */
2005-04-17 02:20:36 +04:00
2006-05-23 08:49:44 +04:00
for ( i = 0 ; i < unicode_size ; i + + ) {
if ( i > = buflen )
break ;
2005-04-17 02:20:36 +04:00
string [ i ] = ( char ) ( le16_to_cpu ( unicode [ i ] ) ) ;
2006-05-23 08:49:44 +04:00
}
string [ i ] = 0x00 ;
2005-04-17 02:20:36 +04:00
}
/****************************************************************************
* get_manufacturing_desc
2008-07-22 14:16:34 +04:00
* reads in the manufacturing descriptor and stores it into the serial
2005-04-17 02:20:36 +04:00
* structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void get_manufacturing_desc ( struct edgeport_serial * edge_serial )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2005-04-17 02:20:36 +04:00
int response ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " getting manufacturer descriptor \n " ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
response = rom_read ( edge_serial - > serial ,
( EDGE_MANUF_DESC_ADDR & 0xffff0000 ) > > 16 ,
( __u16 ) ( EDGE_MANUF_DESC_ADDR & 0x0000ffff ) ,
EDGE_MANUF_DESC_LEN ,
( __u8 * ) ( & edge_serial - > manuf_descriptor ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
if ( response < 1 )
2012-09-18 12:33:23 +04:00
dev_err ( dev , " error in getting manufacturer descriptor \n " ) ;
2008-07-22 14:16:34 +04:00
else {
2005-04-17 02:20:36 +04:00
char string [ 30 ] ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " **Manufacturer Descriptor \n " ) ;
dev_dbg ( dev , " RomSize: %dK \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . RomSize ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " RamSize: %dK \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . RamSize ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " CpuRev: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . CpuRev ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " BoardRev: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . BoardRev ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " NumPorts: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . NumPorts ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " DescDate: %d/%d/%d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . DescDate [ 0 ] ,
edge_serial - > manuf_descriptor . DescDate [ 1 ] ,
edge_serial - > manuf_descriptor . DescDate [ 2 ] + 1900 ) ;
2006-06-07 05:18:33 +04:00
unicode_to_ascii ( string , sizeof ( string ) ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . SerialNumber ,
edge_serial - > manuf_descriptor . SerNumLength / 2 ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " SerialNumber: %s \n " , string ) ;
2006-06-07 05:18:33 +04:00
unicode_to_ascii ( string , sizeof ( string ) ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . AssemblyNumber ,
edge_serial - > manuf_descriptor . AssemblyNumLength / 2 ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " AssemblyNumber: %s \n " , string ) ;
2006-06-07 05:18:33 +04:00
unicode_to_ascii ( string , sizeof ( string ) ,
2006-05-23 08:49:44 +04:00
edge_serial - > manuf_descriptor . OemAssyNumber ,
edge_serial - > manuf_descriptor . OemAssyNumLength / 2 ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " OemAssyNumber: %s \n " , string ) ;
dev_dbg ( dev , " UartType: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . UartType ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " IonPid: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . IonPid ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " IonConfig: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > manuf_descriptor . IonConfig ) ;
2005-04-17 02:20:36 +04:00
}
}
/****************************************************************************
* get_boot_desc
2008-07-22 14:16:34 +04:00
* reads in the bootloader descriptor and stores it into the serial
2005-04-17 02:20:36 +04:00
* structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void get_boot_desc ( struct edgeport_serial * edge_serial )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2005-04-17 02:20:36 +04:00
int response ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " getting boot descriptor \n " ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
response = rom_read ( edge_serial - > serial ,
( EDGE_BOOT_DESC_ADDR & 0xffff0000 ) > > 16 ,
( __u16 ) ( EDGE_BOOT_DESC_ADDR & 0x0000ffff ) ,
EDGE_BOOT_DESC_LEN ,
( __u8 * ) ( & edge_serial - > boot_descriptor ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
if ( response < 1 )
2012-09-18 12:33:23 +04:00
dev_err ( dev , " error in getting boot descriptor \n " ) ;
2008-07-22 14:16:34 +04:00
else {
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " **Boot Descriptor: \n " ) ;
dev_dbg ( dev , " BootCodeLength: %d \n " ,
le16_to_cpu ( edge_serial - > boot_descriptor . BootCodeLength ) ) ;
dev_dbg ( dev , " MajorVersion: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > boot_descriptor . MajorVersion ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " MinorVersion: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > boot_descriptor . MinorVersion ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " BuildNumber: %d \n " ,
2008-07-22 14:16:34 +04:00
le16_to_cpu ( edge_serial - > boot_descriptor . BuildNumber ) ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " Capabilities: 0x%x \n " ,
2008-07-22 14:16:34 +04:00
le16_to_cpu ( edge_serial - > boot_descriptor . Capabilities ) ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " UConfig0: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > boot_descriptor . UConfig0 ) ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " UConfig1: %d \n " ,
2008-07-22 14:16:34 +04:00
edge_serial - > boot_descriptor . UConfig1 ) ;
2005-04-17 02:20:36 +04:00
}
}
/****************************************************************************
* load_application_firmware
* This is called to load the application firmware to the device
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static void load_application_firmware ( struct edgeport_serial * edge_serial )
2005-04-17 02:20:36 +04:00
{
2012-09-18 12:33:23 +04:00
struct device * dev = & edge_serial - > serial - > dev - > dev ;
2008-07-03 15:30:23 +04:00
const struct ihex_binrec * rec ;
const struct firmware * fw ;
const char * fw_name ;
const char * fw_info ;
2005-04-17 02:20:36 +04:00
int response ;
2008-07-03 15:30:23 +04:00
__u32 Operaddr ;
__u16 build ;
2005-04-17 02:20:36 +04:00
switch ( edge_serial - > product_info . iDownloadFile ) {
case EDGE_DOWNLOAD_FILE_I930 :
2008-07-03 15:30:23 +04:00
fw_info = " downloading firmware version (930) " ;
fw_name = " edgeport/down.fw " ;
2005-04-17 02:20:36 +04:00
break ;
case EDGE_DOWNLOAD_FILE_80251 :
2008-07-03 15:30:23 +04:00
fw_info = " downloading firmware version (80251) " ;
fw_name = " edgeport/down2.fw " ;
2005-04-17 02:20:36 +04:00
break ;
case EDGE_DOWNLOAD_FILE_NONE :
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " No download file specified, skipping download \n " ) ;
2005-04-17 02:20:36 +04:00
return ;
default :
return ;
}
2008-07-03 15:30:23 +04:00
response = request_ihex_firmware ( & fw , fw_name ,
& edge_serial - > serial - > dev - > dev ) ;
if ( response ) {
2012-09-18 12:33:23 +04:00
dev_err ( dev , " Failed to load image \" %s \" err %d \n " ,
2008-07-03 15:30:23 +04:00
fw_name , response ) ;
return ;
}
rec = ( const struct ihex_binrec * ) fw - > data ;
build = ( rec - > data [ 2 ] < < 8 ) | rec - > data [ 3 ] ;
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " %s %d.%d.%d \n " , fw_info , rec - > data [ 0 ] , rec - > data [ 1 ] , build ) ;
2008-07-03 15:30:23 +04:00
2011-01-17 16:19:37 +03:00
edge_serial - > product_info . FirmwareMajorVersion = rec - > data [ 0 ] ;
edge_serial - > product_info . FirmwareMinorVersion = rec - > data [ 1 ] ;
2008-07-03 15:30:23 +04:00
edge_serial - > product_info . FirmwareBuildNumber = cpu_to_le16 ( build ) ;
2005-04-17 02:20:36 +04:00
2008-07-03 15:30:23 +04:00
for ( rec = ihex_next_binrec ( rec ) ; rec ;
rec = ihex_next_binrec ( rec ) ) {
Operaddr = be32_to_cpu ( rec - > addr ) ;
response = sram_write ( edge_serial - > serial ,
Operaddr > > 16 ,
Operaddr & 0xFFFF ,
be16_to_cpu ( rec - > len ) ,
& rec - > data [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
if ( response < 0 ) {
2008-07-03 15:30:23 +04:00
dev_err ( & edge_serial - > serial - > dev - > dev ,
" sram_write failed (%x, %x, %d) \n " ,
Operaddr > > 16 , Operaddr & 0xFFFF ,
be16_to_cpu ( rec - > len ) ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2012-09-18 12:33:23 +04:00
dev_dbg ( dev , " sending exec_dl_code \n " ) ;
response = usb_control_msg ( edge_serial - > serial - > dev ,
usb_sndctrlpipe ( edge_serial - > serial - > dev , 0 ) ,
USB_REQUEST_ION_EXEC_DL_CODE ,
2005-04-17 02:20:36 +04:00
0x40 , 0x4000 , 0x0001 , NULL , 0 , 3000 ) ;
2008-07-03 15:30:23 +04:00
release_firmware ( fw ) ;
2005-04-17 02:20:36 +04:00
}
/****************************************************************************
* edge_startup
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-07-22 14:16:34 +04:00
static int edge_startup ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
struct edgeport_serial * edge_serial ;
struct usb_device * dev ;
2012-09-18 12:33:23 +04:00
struct device * ddev = & serial - > dev - > dev ;
2012-10-17 15:34:57 +04:00
int i ;
2007-01-18 11:20:19 +03:00
int response ;
2007-03-17 03:35:53 +03:00
bool interrupt_in_found ;
bool bulk_in_found ;
bool bulk_out_found ;
2007-01-18 11:20:19 +03:00
static __u32 descriptor [ 3 ] = { EDGE_COMPATIBILITY_MASK0 ,
EDGE_COMPATIBILITY_MASK1 ,
EDGE_COMPATIBILITY_MASK2 } ;
2005-04-17 02:20:36 +04:00
dev = serial - > dev ;
/* create our private serial structure */
2006-02-27 23:29:43 +03:00
edge_serial = kzalloc ( sizeof ( struct edgeport_serial ) , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! edge_serial )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2013-12-29 22:22:56 +04:00
2005-04-17 02:20:36 +04:00
spin_lock_init ( & edge_serial - > es_lock ) ;
edge_serial - > serial = serial ;
usb_set_serial_data ( serial , edge_serial ) ;
/* get the name for the device from the device */
2010-01-25 14:53:33 +03:00
i = usb_string ( dev , dev - > descriptor . iManufacturer ,
2006-05-23 08:49:44 +04:00
& edge_serial - > name [ 0 ] , MAX_NAME_LEN + 1 ) ;
2010-01-25 14:53:33 +03:00
if ( i < 0 )
i = 0 ;
2006-05-23 08:49:44 +04:00
edge_serial - > name [ i + + ] = ' ' ;
2010-01-25 14:53:33 +03:00
usb_string ( dev , dev - > descriptor . iProduct ,
2006-05-23 08:49:44 +04:00
& edge_serial - > name [ i ] , MAX_NAME_LEN + 2 - i ) ;
2005-04-17 02:20:36 +04:00
dev_info ( & serial - > dev - > dev , " %s detected \n " , edge_serial - > name ) ;
2007-01-18 11:20:19 +03:00
/* Read the epic descriptor */
if ( get_epic_descriptor ( edge_serial ) < = 0 ) {
/* memcpy descriptor to Supports structures */
memcpy ( & edge_serial - > epic_descriptor . Supports , descriptor ,
sizeof ( struct edge_compatibility_bits ) ) ;
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
/* get the manufacturing descriptor for this device */
2008-07-22 14:16:34 +04:00
get_manufacturing_desc ( edge_serial ) ;
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
/* get the boot descriptor */
2008-07-22 14:16:34 +04:00
get_boot_desc ( edge_serial ) ;
2007-01-18 11:20:19 +03:00
get_product_info ( edge_serial ) ;
}
2005-04-17 02:20:36 +04:00
/* set the number of ports from the manufacturing description */
/* serial->num_ports = serial->product_info.NumPorts; */
2007-01-18 11:20:19 +03:00
if ( ( ! edge_serial - > is_epic ) & &
( edge_serial - > product_info . NumPorts ! = serial - > num_ports ) ) {
2012-09-18 12:33:23 +04:00
dev_warn ( ddev ,
" Device Reported %d serial ports vs. core thinking we have %d ports, email greg@kroah.com this information. \n " ,
2007-01-18 11:20:19 +03:00
edge_serial - > product_info . NumPorts ,
serial - > num_ports ) ;
2005-04-17 02:20:36 +04:00
}
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " %s - time 1 %ld \n " , __func__ , jiffies ) ;
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
/* If not an EPiC device */
if ( ! edge_serial - > is_epic ) {
/* now load the application firmware into this device */
2008-07-22 14:16:34 +04:00
load_application_firmware ( edge_serial ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " %s - time 2 %ld \n " , __func__ , jiffies ) ;
2005-04-17 02:20:36 +04:00
2007-01-18 11:20:19 +03:00
/* Check current Edgeport EEPROM and update if necessary */
2008-07-22 14:16:34 +04:00
update_edgeport_E2PROM ( edge_serial ) ;
2005-04-17 02:20:36 +04:00
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " %s - time 3 %ld \n " , __func__ , jiffies ) ;
2007-01-18 11:20:19 +03:00
/* set the configuration to use #1 */
2012-09-18 12:33:23 +04:00
/* dev_dbg(ddev, "set_configuration 1\n"); */
2008-07-22 14:16:34 +04:00
/* usb_set_configuration (dev, 1); */
2007-01-18 11:20:19 +03:00
}
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " FirmwareMajorVersion %d.%d.%d \n " ,
2008-07-03 15:30:23 +04:00
edge_serial - > product_info . FirmwareMajorVersion ,
edge_serial - > product_info . FirmwareMinorVersion ,
le16_to_cpu ( edge_serial - > product_info . FirmwareBuildNumber ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
/* we set up the pointers to the endpoints in the edge_open function,
2005-04-17 02:20:36 +04:00
* as the structures aren ' t created yet . */
2007-01-18 11:20:19 +03:00
response = 0 ;
if ( edge_serial - > is_epic ) {
2008-07-22 14:16:34 +04:00
/* EPIC thing, set up our interrupt polling now and our read
* urb , so that the device knows it really is connected . */
2007-03-17 03:35:53 +03:00
interrupt_in_found = bulk_in_found = bulk_out_found = false ;
2008-07-22 14:16:34 +04:00
for ( i = 0 ; i < serial - > interface - > altsetting [ 0 ]
. desc . bNumEndpoints ; + + i ) {
2007-01-18 11:20:19 +03:00
struct usb_endpoint_descriptor * endpoint ;
int buffer_size ;
2008-07-22 14:16:34 +04:00
endpoint = & serial - > interface - > altsetting [ 0 ] .
endpoint [ i ] . desc ;
2011-08-23 14:12:03 +04:00
buffer_size = usb_endpoint_maxp ( endpoint ) ;
2007-03-17 03:35:53 +03:00
if ( ! interrupt_in_found & &
2007-01-18 11:20:19 +03:00
( usb_endpoint_is_int_in ( endpoint ) ) ) {
/* we found a interrupt in endpoint */
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " found interrupt in \n " ) ;
2007-01-18 11:20:19 +03:00
/* not set up yet, so do it now */
2008-07-22 14:16:34 +04:00
edge_serial - > interrupt_read_urb =
usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! edge_serial - > interrupt_read_urb )
2007-01-18 11:20:19 +03:00
return - ENOMEM ;
2013-12-29 22:22:56 +04:00
2008-07-22 14:16:34 +04:00
edge_serial - > interrupt_in_buffer =
kmalloc ( buffer_size , GFP_KERNEL ) ;
2007-01-18 11:20:19 +03:00
if ( ! edge_serial - > interrupt_in_buffer ) {
usb_free_urb ( edge_serial - > interrupt_read_urb ) ;
return - ENOMEM ;
}
2008-07-22 14:16:34 +04:00
edge_serial - > interrupt_in_endpoint =
endpoint - > bEndpointAddress ;
2007-01-18 11:20:19 +03:00
/* set up our interrupt urb */
2008-07-22 14:16:34 +04:00
usb_fill_int_urb (
edge_serial - > interrupt_read_urb ,
dev ,
usb_rcvintpipe ( dev ,
endpoint - > bEndpointAddress ) ,
edge_serial - > interrupt_in_buffer ,
buffer_size ,
edge_interrupt_callback ,
edge_serial ,
endpoint - > bInterval ) ;
2007-01-18 11:20:19 +03:00
2007-03-17 03:35:53 +03:00
interrupt_in_found = true ;
2007-01-18 11:20:19 +03:00
}
2007-03-17 03:35:53 +03:00
if ( ! bulk_in_found & &
2008-07-22 14:16:34 +04:00
( usb_endpoint_is_bulk_in ( endpoint ) ) ) {
2007-01-18 11:20:19 +03:00
/* we found a bulk in endpoint */
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " found bulk in \n " ) ;
2007-01-18 11:20:19 +03:00
/* not set up yet, so do it now */
2008-07-22 14:16:34 +04:00
edge_serial - > read_urb =
usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2013-12-29 22:22:56 +04:00
if ( ! edge_serial - > read_urb )
2007-01-18 11:20:19 +03:00
return - ENOMEM ;
2013-12-29 22:22:56 +04:00
2008-07-22 14:16:34 +04:00
edge_serial - > bulk_in_buffer =
kmalloc ( buffer_size , GFP_KERNEL ) ;
2007-01-18 11:20:19 +03:00
if ( ! edge_serial - > bulk_in_buffer ) {
usb_free_urb ( edge_serial - > read_urb ) ;
return - ENOMEM ;
}
2008-07-22 14:16:34 +04:00
edge_serial - > bulk_in_endpoint =
endpoint - > bEndpointAddress ;
2007-01-18 11:20:19 +03:00
/* set up our bulk in urb */
usb_fill_bulk_urb ( edge_serial - > read_urb , dev ,
2008-07-22 14:16:34 +04:00
usb_rcvbulkpipe ( dev ,
endpoint - > bEndpointAddress ) ,
edge_serial - > bulk_in_buffer ,
2011-08-23 14:12:03 +04:00
usb_endpoint_maxp ( endpoint ) ,
2008-07-22 14:16:34 +04:00
edge_bulk_in_callback ,
edge_serial ) ;
2007-03-17 03:35:53 +03:00
bulk_in_found = true ;
2007-01-18 11:20:19 +03:00
}
2007-03-17 03:35:53 +03:00
if ( ! bulk_out_found & &
2007-01-18 11:20:19 +03:00
( usb_endpoint_is_bulk_out ( endpoint ) ) ) {
/* we found a bulk out endpoint */
2012-09-18 12:33:23 +04:00
dev_dbg ( ddev , " found bulk out \n " ) ;
2008-07-22 14:16:34 +04:00
edge_serial - > bulk_out_endpoint =
endpoint - > bEndpointAddress ;
2007-03-17 03:35:53 +03:00
bulk_out_found = true ;
2007-01-18 11:20:19 +03:00
}
}
2007-03-17 03:35:53 +03:00
if ( ! interrupt_in_found | | ! bulk_in_found | | ! bulk_out_found ) {
2012-09-18 12:33:23 +04:00
dev_err ( ddev , " Error - the proper endpoints were not found! \n " ) ;
2007-01-18 11:20:19 +03:00
return - ENODEV ;
}
/* start interrupt read for this edgeport this interrupt will
* continue as long as the edgeport is connected */
2008-07-22 14:16:34 +04:00
response = usb_submit_urb ( edge_serial - > interrupt_read_urb ,
GFP_KERNEL ) ;
2007-01-18 11:20:19 +03:00
if ( response )
2012-09-18 12:33:23 +04:00
dev_err ( ddev , " %s - Error %d submitting control urb \n " ,
2008-08-21 03:56:34 +04:00
__func__ , response ) ;
2007-01-18 11:20:19 +03:00
}
return response ;
2005-04-17 02:20:36 +04:00
}
/****************************************************************************
2009-06-02 19:53:55 +04:00
* edge_disconnect
2005-04-17 02:20:36 +04:00
* This function is called whenever the device is removed from the usb bus .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-02 19:53:55 +04:00
static void edge_disconnect ( struct usb_serial * serial )
2005-04-17 02:20:36 +04:00
{
2007-01-18 11:20:19 +03:00
struct edgeport_serial * edge_serial = usb_get_serial_data ( serial ) ;
2005-04-17 02:20:36 +04:00
/* stop reads and writes on all ports */
2007-01-18 11:20:19 +03:00
/* free up our endpoint stuff */
if ( edge_serial - > is_epic ) {
2007-06-13 20:50:41 +04:00
usb_kill_urb ( edge_serial - > interrupt_read_urb ) ;
2007-01-18 11:20:19 +03:00
usb_free_urb ( edge_serial - > interrupt_read_urb ) ;
kfree ( edge_serial - > interrupt_in_buffer ) ;
2007-06-13 20:50:41 +04:00
usb_kill_urb ( edge_serial - > read_urb ) ;
2007-01-18 11:20:19 +03:00
usb_free_urb ( edge_serial - > read_urb ) ;
kfree ( edge_serial - > bulk_in_buffer ) ;
}
2009-06-02 19:53:55 +04:00
}
/****************************************************************************
* edge_release
* This function is called when the device structure is deallocated .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void edge_release ( struct usb_serial * serial )
{
struct edgeport_serial * edge_serial = usb_get_serial_data ( serial ) ;
2007-01-18 11:20:19 +03:00
kfree ( edge_serial ) ;
2005-04-17 02:20:36 +04:00
}
2012-10-17 15:34:57 +04:00
static int edge_port_probe ( struct usb_serial_port * port )
{
struct edgeport_port * edge_port ;
edge_port = kzalloc ( sizeof ( * edge_port ) , GFP_KERNEL ) ;
if ( ! edge_port )
return - ENOMEM ;
spin_lock_init ( & edge_port - > ep_lock ) ;
edge_port - > port = port ;
usb_set_serial_port_data ( port , edge_port ) ;
return 0 ;
}
static int edge_port_remove ( struct usb_serial_port * port )
{
struct edgeport_port * edge_port ;
edge_port = usb_get_serial_port_data ( port ) ;
kfree ( edge_port ) ;
return 0 ;
}
2012-05-09 02:46:14 +04:00
module_usb_serial_driver ( serial_drivers , id_table_combined ) ;
2005-04-17 02:20:36 +04:00
2008-07-22 14:16:34 +04:00
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2008-07-03 15:30:23 +04:00
MODULE_FIRMWARE ( " edgeport/boot.fw " ) ;
MODULE_FIRMWARE ( " edgeport/boot2.fw " ) ;
MODULE_FIRMWARE ( " edgeport/down.fw " ) ;
MODULE_FIRMWARE ( " edgeport/down2.fw " ) ;