blob: 2c3e477d8d73d7cf63ce8287c8be0b2e9b415daa [file] [log] [blame]
/*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*************************************************************************
*** --------------------------------------------------------------------
***
*** Project Name: ATENINTL
***
*** Module Name: ATEN2011
***
*** File: aten2011.c
***
***
*** File Revision: 1.2
***
*** Revision Date: 2009-01-16
***
***
*** Purpose : It gives an interface between USB to 4 Serial
*** and serves as a Serial Driver for the high
*** level layers /applications.
***
*** Change History:
*** Modified from ATEN revision 1.2 for Linux kernel 2.6.26 or later
***
*** LEGEND :
***
***
*** DBG - Code inserted due to as part of debugging
*** DPRINTK - Debug Print statement
***
*************************************************************************/
/* all file inclusion goes here */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
//#include <linux/spinlock.h>
#include <linux/serial.h>
//#include <linux/ioctl.h>
#include <linux/usb.h>
#include <asm/uaccess.h>
#define KERNEL_2_6 1
#include <linux/usb/serial.h>
#include "aten2011.h" /* ATEN2011 Defines */
#include "aten2011_16C50.h" /* 16C50 UART defines */
/* all defines goes here */
/*
* Debug related defines
*/
/* 1: Enables the debugging -- 0: Disable the debugging */
//#define printk //
#define ATEN_DEBUG 0
#ifdef ATEN_DEBUG
static int debug = 0;
#define DPRINTK(fmt, args...) printk( "%s: " fmt, __FUNCTION__ , ## args)
#else
static int debug = 0;
#define DPRINTK(fmt, args...)
#endif
//#undef DPRINTK
// #define DPRINTK(fmt, args...)
/*
* Version Information
*/
#define DRIVER_VERSION "1.3.1"
#define DRIVER_DESC "ATENINTL 2011 USB Serial Adapter"
/*
* Defines used for sending commands to port
*/
#define WAIT_FOR_EVER (HZ * 0 ) /* timeout urb is wait for ever*/
#define ATEN_WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
#define ATEN_PORT1 0x0200
#define ATEN_PORT2 0x0300
#define ATEN_VENREG 0x0000
#define ATEN_MAX_PORT 0x02
#define ATEN_WRITE 0x0E
#define ATEN_READ 0x0D
/* Requests */
#define ATEN_RD_RTYPE 0xC0
#define ATEN_WR_RTYPE 0x40
#define ATEN_RDREQ 0x0D
#define ATEN_WRREQ 0x0E
#define ATEN_CTRL_TIMEOUT 500
#define VENDOR_READ_LENGTH (0x01)
int ATEN2011_Thr_cnt;
//int ATEN2011_spectrum_2or4ports; //this says the number of ports in the device
//int NoOfOpenPorts;
int RS485mode=0; //set to 1 for RS485 mode and 0 for RS232 mode
static struct usb_serial* ATEN2011_get_usb_serial (struct usb_serial_port *port, const
char *function);
static int ATEN2011_serial_paranoia_check (struct usb_serial *serial, const char
*function);
static int ATEN2011_port_paranoia_check (struct usb_serial_port *port, const char
*function);
/* setting and get register values */
static int ATEN2011_set_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 val);
static int ATEN2011_get_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 * val);
static int ATEN2011_set_Uart_Reg(struct usb_serial_port *port, __u16 reg, __u16 val);
static int ATEN2011_get_Uart_Reg(struct usb_serial_port *port, __u16 reg, __u16 * val);
void ATEN2011_Dump_serial_port(struct ATENINTL_port *ATEN2011_port);
/************************************************************************/
/************************************************************************/
/* I N T E R F A C E F U N C T I O N S */
/* I N T E R F A C E F U N C T I O N S */
/************************************************************************/
/************************************************************************/
static inline void ATEN2011_set_serial_private(struct usb_serial *serial, struct ATENINTL_serial *data)
{
usb_set_serial_data(serial, (void *)data );
}
static inline struct ATENINTL_serial * ATEN2011_get_serial_private(struct usb_serial *serial)
{
return (struct ATENINTL_serial*) usb_get_serial_data(serial);
}
static inline void ATEN2011_set_port_private(struct usb_serial_port *port, struct ATENINTL_port *data)
{
usb_set_serial_port_data(port, (void*)data );
}
static inline struct ATENINTL_port * ATEN2011_get_port_private(struct usb_serial_port *port)
{
return (struct ATENINTL_port*) usb_get_serial_port_data(port);
}
/*
Description:- To set the Control register by calling usb_fill_control_urb function by passing usb_sndctrlpipe function as parameter.
Input Parameters:
usb_serial_port: Data Structure usb_serialport correponding to that seril port.
Reg: Register Address
Val: Value to set in the Register.
*/
static int ATEN2011_set_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 val)
{
struct usb_device *dev = port->serial->dev;
val = val & 0x00ff;
DPRINTK("ATEN2011_set_reg_sync offset is %x, value %x\n",reg,val);
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
ATEN_WR_RTYPE, val, reg, NULL, 0,ATEN_WDR_TIMEOUT);
}
/*
Description:- To set the Uart register by calling usb_fill_control_urb function by passing usb_rcvctrlpipe function as parameter.
Input Parameters:
usb_serial_port: Data Structure usb_serialport correponding to that seril port.
Reg: Register Address
Val: Value to receive from the Register.
*/
static int ATEN2011_get_reg_sync(struct usb_serial_port *port, __u16 reg, __u16 * val)
{
struct usb_device *dev = port->serial->dev;
int ret=0;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
ATEN_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,ATEN_WDR_TIMEOUT);
DPRINTK("ATEN2011_get_reg_sync offset is %x, return val %x\n",reg,*val);
*val = (*val) & 0x00ff;
return ret;
}
/*
Description:- To set the Uart register by calling usb_fill_control_urb function by passing usb_sndctrlpipe function as parameter.
Input Parameters:
usb_serial_port: Data Structure usb_serialport correponding to that seril port.
Reg: Register Address
Val: Value to set in the Register.
*/
static int ATEN2011_set_Uart_Reg(struct usb_serial_port *port, __u16 reg, __u16 val)
{
struct usb_device *dev = port->serial->dev;
struct ATENINTL_serial *ATEN2011_serial;
int minor;
ATEN2011_serial = ATEN2011_get_serial_private(port->serial);
minor = port->serial->minor;
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
val = val & 0x00ff;
// For the UART control registers, the application number need to be Or'ed
if(ATEN2011_serial->ATEN2011_spectrum_2or4ports == 4)
{
val |= (((__u16)port->number - (__u16)(minor))+1)<<8;
DPRINTK("ATEN2011_set_Uart_Reg application number is %x\n",val);
}
else
{
if( ((__u16)port->number - (__u16)(minor)) == 0)
{
// val= 0x100;
val |= (((__u16)port->number - (__u16)(minor))+1)<<8;
DPRINTK("ATEN2011_set_Uart_Reg application number is %x\n",val);
}
else
{
// val=0x300;
val |= (((__u16)port->number - (__u16)(minor))+2)<<8;
DPRINTK("ATEN2011_set_Uart_Reg application number is %x\n",val);
}
}
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ATEN_WRREQ,
ATEN_WR_RTYPE, val, reg, NULL, 0,ATEN_WDR_TIMEOUT);
}
/*
Description:- To set the Control register by calling usb_fill_control_urb function by passing usb_rcvctrlpipe function as parameter.
Input Parameters:
usb_serial_port: Data Structure usb_serialport correponding to that seril port.
Reg: Register Address
Val: Value to receive from the Register.
*/
static int ATEN2011_get_Uart_Reg(struct usb_serial_port *port, __u16 reg, __u16 * val)
{
struct usb_device *dev = port->serial->dev;
int ret=0;
__u16 Wval;
struct ATENINTL_serial *ATEN2011_serial;
int minor = port->serial->minor;
ATEN2011_serial = ATEN2011_get_serial_private(port->serial);
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
//DPRINTK("application number is %4x \n",(((__u16)port->number - (__u16)(minor))+1)<<8);
/*Wval is same as application number*/
if(ATEN2011_serial->ATEN2011_spectrum_2or4ports ==4)
{
Wval=(((__u16)port->number - (__u16)(minor))+1)<<8;
DPRINTK("ATEN2011_get_Uart_Reg application number is %x\n",Wval);
}
else
{
if( ((__u16)port->number - (__u16)(minor)) == 0)
{
// Wval= 0x100;
Wval=(((__u16)port->number - (__u16)(minor))+1)<<8;
DPRINTK("ATEN2011_get_Uart_Reg application number is %x\n",Wval);
}
else
{
// Wval=0x300;
Wval=(((__u16)port->number - (__u16)(minor))+2)<<8;
DPRINTK("ATEN2011_get_Uart_Reg application number is %x\n",Wval);
}
}
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ATEN_RDREQ,
ATEN_RD_RTYPE, Wval, reg, val,VENDOR_READ_LENGTH,ATEN_WDR_TIMEOUT);
*val = (*val) & 0x00ff;
return ret;
}
void ATEN2011_Dump_serial_port(struct ATENINTL_port *ATEN2011_port)
{
DPRINTK("***************************************\n");
DPRINTK("Application number is %4x\n",ATEN2011_port->AppNum);
DPRINTK("SpRegOffset is %2x\n",ATEN2011_port->SpRegOffset);
DPRINTK("ControlRegOffset is %2x \n",ATEN2011_port->ControlRegOffset);
DPRINTK("DCRRegOffset is %2x \n",ATEN2011_port->DcrRegOffset);
//DPRINTK("ClkSelectRegOffset is %2x \n",ATEN2011_port->ClkSelectRegOffset);
DPRINTK("***************************************\n");
}
/* all structre defination goes here */
/****************************************************************************
* ATENINTL2011_4port_device
* Structure defining ATEN2011, usb serial device
****************************************************************************/
static struct usb_serial_driver ATENINTL2011_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "ATEN2011",
},
.description = DRIVER_DESC,
.id_table = ATENINTL_port_id_table,
.open = ATEN2011_open,
.close = ATEN2011_close,
.write = ATEN2011_write,
.write_room = ATEN2011_write_room,
.chars_in_buffer = ATEN2011_chars_in_buffer,
.throttle = ATEN2011_throttle,
.unthrottle = ATEN2011_unthrottle,
.calc_num_ports = ATEN2011_calc_num_ports,
#ifdef ATENSerialProbe
.probe = ATEN2011_serial_probe,
#endif
.ioctl = ATEN2011_ioctl,
.set_termios = ATEN2011_set_termios,
.break_ctl = ATEN2011_break,
// .break_ctl = ATEN2011_break_ctl,
.tiocmget = ATEN2011_tiocmget,
.tiocmset = ATEN2011_tiocmset,
.attach = ATEN2011_startup,
.shutdown = ATEN2011_shutdown,
.read_bulk_callback = ATEN2011_bulk_in_callback,
.read_int_callback = ATEN2011_interrupt_callback,
};
static struct usb_driver io_driver = {
.name = "ATEN2011",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
};
/************************************************************************/
/************************************************************************/
/* 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 */
/************************************************************************/
/************************************************************************/
/*****************************************************************************
* ATEN2011_interrupt_callback
* this is the callback function for when we have received data on the
* interrupt endpoint.
* Input : 1 Input
* pointer to the URB packet,
*
*****************************************************************************/
//#ifdef ATEN2011
static void ATEN2011_interrupt_callback (struct urb *urb)
{
int result;
int length ;
struct ATENINTL_port *ATEN2011_port;
struct ATENINTL_serial *ATEN2011_serial;
struct usb_serial *serial;
__u16 Data;
unsigned char *data;
__u8 sp[5],st;
int i;
__u16 wval;
int minor;
//printk("in the function ATEN2011_interrupt_callback Length %d, Data %x \n",urb->actual_length,(unsigned int)urb->transfer_buffer);
DPRINTK("%s"," : Entering\n");
ATEN2011_serial= (struct ATENINTL_serial *)urb->context;
if(!urb)// || ATEN2011_serial->status_polling_started == FALSE )
{
DPRINTK("%s","Invalid Pointer !!!!:\n");
return;
}
switch (urb->status)
{
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
length = urb->actual_length;
data = urb->transfer_buffer;
//ATEN2011_serial= (struct ATENINTL_serial *)urb->context;
//serial = ATEN2011_get_usb_serial(port,__FUNCTION__);
serial = ATEN2011_serial->serial;
/* ATENINTL get 5 bytes
* Byte 1 IIR Port 1 (port.number is 0)
* Byte 2 IIR Port 2 (port.number is 1)
* Byte 3 IIR Port 3 (port.number is 2)
* Byte 4 IIR Port 4 (port.number is 3)
* Byte 5 FIFO status for both */
if(length && length>5)
{
DPRINTK("%s \n","Wrong data !!!");
return;
}
/* MATRIX */
if(ATEN2011_serial->ATEN2011_spectrum_2or4ports == 4)
{
sp[0]=(__u8)data[0];
sp[1]=(__u8)data[1];
sp[2]=(__u8)data[2];
sp[3]=(__u8)data[3];
st=(__u8)data[4];
}
else
{
sp[0]=(__u8)data[0];
sp[1]=(__u8)data[2];
//sp[2]=(__u8)data[2];
//sp[3]=(__u8)data[3];
st=(__u8)data[4];
}
// printk("%s data is sp1:%x sp2:%x sp3:%x sp4:%x status:%x\n",__FUNCTION__,sp1,sp2,sp3,sp4,st);
for(i=0;i<serial->num_ports;i++)
{
ATEN2011_port = ATEN2011_get_port_private(serial->port[i]);
minor = serial->minor;
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
if((ATEN2011_serial->ATEN2011_spectrum_2or4ports == 2) && (i != 0))
wval = (((__u16)serial->port[i]->number - (__u16)(minor))+2)<<8;
else
wval = (((__u16)serial->port[i]->number - (__u16)(minor))+1)<<8;
if(ATEN2011_port->open != FALSE)
{
//printk("%s wval is:(for 2011) %x\n",__FUNCTION__,wval);
if(sp[i] & 0x01)
{
DPRINTK("SP%d No Interrupt !!!\n",i);
}
else
{
switch(sp[i] & 0x0f)
{
case SERIAL_IIR_RLS:
DPRINTK("Serial Port %d: Receiver status error or ",i);
DPRINTK("address bit detected in 9-bit mode\n");
ATEN2011_port->MsrLsr=1;
ATEN2011_get_reg(ATEN2011_port,wval,LINE_STATUS_REGISTER,&Data);
break;
case SERIAL_IIR_MS:
DPRINTK("Serial Port %d: Modem status change\n",i);
ATEN2011_port->MsrLsr=0;
ATEN2011_get_reg(ATEN2011_port,wval, MODEM_STATUS_REGISTER, &Data);
break;
}
}
}
}
exit:
if( ATEN2011_serial->status_polling_started == FALSE )
return;
result = usb_submit_urb (urb, GFP_ATOMIC);
if (result)
{
dev_err(&urb->dev->dev, "%s - Error %d submitting interrupt urb\n", __FUNCTION__, result);
}
return;
}
//#endif
static void ATEN2011_control_callback(struct urb *urb)
{
unsigned char *data;
struct ATENINTL_port *ATEN2011_port;
__u8 regval=0x0;
if(!urb)
{
DPRINTK("%s","Invalid Pointer !!!!:\n");
return;
}
switch (urb->status)
{
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
ATEN2011_port = (struct ATENINTL_port *)urb->context;
DPRINTK("%s urb buffer size is %d\n",__FUNCTION__,urb->actual_length);
DPRINTK("%s ATEN2011_port->MsrLsr is %d port %d\n",__FUNCTION__,ATEN2011_port->MsrLsr,ATEN2011_port->port_num);
data=urb->transfer_buffer;
regval=(__u8)data[0];
DPRINTK("%s data is %x\n",__FUNCTION__,regval);
if(ATEN2011_port->MsrLsr==0)
handle_newMsr(ATEN2011_port,regval);
else if(ATEN2011_port->MsrLsr==1)
handle_newLsr(ATEN2011_port,regval);
exit:
return;
}
int handle_newMsr(struct ATENINTL_port *port,__u8 newMsr)
{
struct ATENINTL_port *ATEN2011_port;
struct async_icount *icount;
ATEN2011_port=port;
icount = &ATEN2011_port->icount;
if (newMsr & (ATEN_MSR_DELTA_CTS | ATEN_MSR_DELTA_DSR | ATEN_MSR_DELTA_RI | ATEN_MSR_DELTA_CD)) {
icount = &ATEN2011_port->icount;
/* update input line counters */
if (newMsr & ATEN_MSR_DELTA_CTS) {
icount->cts++;
}
if (newMsr & ATEN_MSR_DELTA_DSR) {
icount->dsr++;
}
if (newMsr & ATEN_MSR_DELTA_CD) {
icount->dcd++;
}
if (newMsr & ATEN_MSR_DELTA_RI) {
icount->rng++;
}
}
return 0;
}
int handle_newLsr(struct ATENINTL_port *port,__u8 newLsr)
{
struct async_icount *icount;
dbg("%s - %02x", __FUNCTION__, newLsr);
if (newLsr & SERIAL_LSR_BI) {
//
// Parity and Framing errors only count if they
// occur exclusive of a break being
// received.
//
newLsr &= (__u8)(SERIAL_LSR_OE | SERIAL_LSR_BI);
}
/* update input line counters */
icount = &port->icount;
if (newLsr & SERIAL_LSR_BI) {
icount->brk++;
}
if (newLsr & SERIAL_LSR_OE) {
icount->overrun++;
}
if (newLsr & SERIAL_LSR_PE) {
icount->parity++;
}
if (newLsr & SERIAL_LSR_FE) {
icount->frame++;
}
return 0;
}
static int ATEN2011_get_reg(struct ATENINTL_port *ATEN,__u16 Wval, __u16 reg, __u16 * val)
{
struct usb_device *dev = ATEN->port->serial->dev;
struct usb_ctrlrequest *dr=NULL;
unsigned char *buffer=NULL;
int ret=0;
buffer= (__u8 *)ATEN->ctrl_buf;
// dr=(struct usb_ctrlrequest *)(buffer);
dr=(void *)(buffer + 2);
dr->bRequestType = ATEN_RD_RTYPE;
dr->bRequest = ATEN_RDREQ;
dr->wValue = cpu_to_le16(Wval);//0;
dr->wIndex = cpu_to_le16(reg);
dr->wLength = cpu_to_le16(2);
usb_fill_control_urb(ATEN->control_urb,dev,usb_rcvctrlpipe(dev,0),(unsigned char *)dr,buffer,2,ATEN2011_control_callback,ATEN);
ATEN->control_urb->transfer_buffer_length = 2;
ret=usb_submit_urb(ATEN->control_urb,GFP_ATOMIC);
return ret;
}
/*****************************************************************************
* ATEN2011_bulk_in_callback
* this is the callback function for when we have received data on the
* bulk in endpoint.
* Input : 1 Input
* pointer to the URB packet,
*
*****************************************************************************/
static void ATEN2011_bulk_in_callback (struct urb *urb)
{
int status;
unsigned char *data ;
struct usb_serial *serial;
struct usb_serial_port *port;
struct ATENINTL_serial *ATEN2011_serial;
struct ATENINTL_port *ATEN2011_port;
struct tty_struct *tty;
if(!urb)
{
DPRINTK("%s","Invalid Pointer !!!!:\n");
return;
}
if (urb->status)
{
DPRINTK("nonzero read bulk status received: %d",urb->status);
// if(urb->status==84)
//ThreadState=1;
return;
}
ATEN2011_port= (struct ATENINTL_port*)urb->context;
if(!ATEN2011_port)
{
DPRINTK("%s","NULL ATEN2011_port pointer \n");
return ;
}
port = (struct usb_serial_port *)ATEN2011_port->port;
if (ATEN2011_port_paranoia_check (port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return;
}
serial = ATEN2011_get_usb_serial(port,__FUNCTION__);
if(!serial)
{
DPRINTK("%s\n","Bad serial pointer ");
return;
}
DPRINTK("%s\n","Entering... \n");
data = urb->transfer_buffer;
ATEN2011_serial = ATEN2011_get_serial_private(serial);
DPRINTK("%s","Entering ........... \n");
if (urb->actual_length)
{
//MATRIX
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
tty = tty_port_tty_get(&ATEN2011_port->port->port);
#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,27)
tty = ATEN2011_port->port->port.tty;
#else
tty = ATEN2011_port->port->tty;
#endif
if (tty)
{
tty_buffer_request_room(tty, urb->actual_length);
tty_insert_flip_string(tty, data, urb->actual_length);
DPRINTK(" %s \n",data);
tty_flip_buffer_push(tty);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
tty_kref_put(tty);
#endif
}
ATEN2011_port->icount.rx += urb->actual_length;
DPRINTK("ATEN2011_port->icount.rx is %d:\n",ATEN2011_port->icount.rx);
//MATRIX
}
if(!ATEN2011_port->read_urb)
{
DPRINTK("%s","URB KILLED !!!\n");
return;
}
if(ATEN2011_port->read_urb->status!=-EINPROGRESS)
{
ATEN2011_port->read_urb->dev = serial->dev;
status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
if (status)
{
DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
}
}
}
/*****************************************************************************
* ATEN2011_bulk_out_data_callback
* this is the callback function for when we have finished sending serial data
* on the bulk out endpoint.
* Input : 1 Input
* pointer to the URB packet,
*
*****************************************************************************/
static void ATEN2011_bulk_out_data_callback (struct urb *urb)
{
struct ATENINTL_port *ATEN2011_port ;
struct tty_struct *tty;
if(!urb)
{
DPRINTK("%s","Invalid Pointer !!!!:\n");
return;
}
if (urb->status)
{
DPRINTK("nonzero write bulk status received:%d\n", urb->status);
return;
}
ATEN2011_port = (struct ATENINTL_port *)urb->context;
if(!ATEN2011_port)
{
DPRINTK("%s","NULL ATEN2011_port pointer \n");
return ;
}
if (ATEN2011_port_paranoia_check (ATEN2011_port->port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return;
}
DPRINTK("%s \n","Entering .........");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
tty = tty_port_tty_get(&ATEN2011_port->port->port);
#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,6,27)
tty = ATEN2011_port->port->port.tty;
#else
tty = ATEN2011_port->port->tty;
#endif
if (tty && ATEN2011_port->open)
{
/* let the tty driver wakeup if it has a special *
* write_wakeup function */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
(tty->ldisc.write_wakeup)(tty);
}
#endif
/* tell the tty driver that something has changed */
wake_up_interruptible(&tty->write_wait);
}
/* Release the Write URB */
ATEN2011_port->write_in_progress = FALSE;
//schedule_work(&ATEN2011_port->port->work);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
tty_kref_put(tty);
#endif
}
/************************************************************************/
/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
/************************************************************************/
#ifdef ATENSerialProbe
static int ATEN2011_serial_probe(struct usb_serial *serial, const struct usb_device_id *id)
{
/*need to implement the mode_reg reading and updating\
structures usb_serial_ device_type\
(i.e num_ports, num_bulkin,bulkout etc)*/
/* Also we can update the changes attach */
return 1;
}
#endif
/*****************************************************************************
* 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.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_open(struct tty_struct *tty, struct usb_serial_port *port, struct file * filp)
#else
static int ATEN2011_open(struct usb_serial_port *port, struct file * filp)
#endif
{
int response;
int j;
struct usb_serial *serial;
// struct usb_serial_port *port0;
struct urb *urb;
__u16 Data;
int status;
struct ATENINTL_serial *ATEN2011_serial;
struct ATENINTL_port *ATEN2011_port;
struct ktermios tmp_termios;
int minor;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
struct tty_struct *tty = NULL;
#endif
if (ATEN2011_port_paranoia_check (port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return -ENODEV;
}
//ATEN2011_serial->NoOfOpenPorts++;
serial = port->serial;
if (ATEN2011_serial_paranoia_check (serial, __FUNCTION__))
{
DPRINTK("%s","Serial Paranoia failed \n");
return -ENODEV;
}
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
return -ENODEV;
/*
if (ATEN2011_port->ctrl_buf==NULL)
{
ATEN2011_port->ctrl_buf = kmalloc(16,GFP_KERNEL);
if (ATEN2011_port->ctrl_buf == NULL) {
printk(", Can't allocate ctrl buff\n");
return -ENOMEM;
}
}
if(!ATEN2011_port->control_urb)
{
ATEN2011_port->control_urb=kmalloc(sizeof(struct urb),GFP_KERNEL);
}
*/
// port0 = serial->port[0];
ATEN2011_serial = ATEN2011_get_serial_private(serial);
if (ATEN2011_serial == NULL )//|| port0 == NULL)
{
return -ENODEV;
}
// increment the number of opened ports counter here
ATEN2011_serial->NoOfOpenPorts++;
//printk("the num of ports opend is:%d\n",ATEN2011_serial->NoOfOpenPorts);
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
/* Initialising the write urb pool */
for (j = 0; j < NUM_URBS; ++j)
{
urb = usb_alloc_urb(0,GFP_ATOMIC);
ATEN2011_port->write_urb_pool[j] = urb;
if (urb == NULL)
{
err("No more urbs???");
continue;
}
urb->transfer_buffer = NULL;
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (!urb->transfer_buffer)
{
err("%s-out of memory for urb buffers.", __FUNCTION__);
continue;
}
}
/*****************************************************************************
* Initialize ATEN2011 -- Write Init values to corresponding Registers
*
* Register Index
* 1 : IER
* 2 : FCR
* 3 : LCR
* 4 : MCR
*
* 0x08 : SP1/2 Control Reg
*****************************************************************************/
//NEED to check the fallowing Block
status=0;
Data=0x0;
status=ATEN2011_get_reg_sync(port,ATEN2011_port->SpRegOffset,&Data);
if(status<0){
DPRINTK("Reading Spreg failed\n");
return -1;
}
Data |= 0x80;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->SpRegOffset,Data);
if(status<0){
DPRINTK("writing Spreg failed\n");
return -1;
}
Data &= ~0x80;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->SpRegOffset,Data);
if(status<0){
DPRINTK("writing Spreg failed\n");
return -1;
}
//End of block to be checked
//**************************CHECK***************************//
if(RS485mode==0)
Data = 0xC0;
else
Data = 0x00;
status=0;
status=ATEN2011_set_Uart_Reg(port,SCRATCH_PAD_REGISTER,Data);
if(status<0) {
DPRINTK("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
return -1;
}
else DPRINTK("SCRATCH_PAD_REGISTER Writing success status%d\n",status);
//**************************CHECK***************************//
status=0;
Data=0x0;
status=ATEN2011_get_reg_sync(port,ATEN2011_port->ControlRegOffset,&Data);
if(status<0){
DPRINTK("Reading Controlreg failed\n");
return -1;
}
Data |= 0x08;//Driver done bit
/*
status = ATEN2011_set_reg_sync(port,ATEN2011_port->ControlRegOffset,Data);
if(status<0){
DPRINTK("writing Controlreg failed\n");
return -1;
}
*/
Data |= 0x20;//rx_disable
status=0;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->ControlRegOffset,Data);
if(status<0){
DPRINTK("writing Controlreg failed\n");
return -1;
}
//do register settings here
// Set all regs to the device default values.
////////////////////////////////////
// First Disable all interrupts.
////////////////////////////////////
Data = 0x00;
status=0;
status = ATEN2011_set_Uart_Reg(port,INTERRUPT_ENABLE_REGISTER,Data);
if(status<0){
DPRINTK("disableing interrupts failed\n");
return -1;
}
// Set FIFO_CONTROL_REGISTER to the default value
Data = 0x00;
status=0;
status = ATEN2011_set_Uart_Reg(port,FIFO_CONTROL_REGISTER,Data);
if(status<0){
DPRINTK("Writing FIFO_CONTROL_REGISTER failed\n");
return -1;
}
Data = 0xcf; //chk
status=0;
status = ATEN2011_set_Uart_Reg(port,FIFO_CONTROL_REGISTER,Data);
if(status<0){
DPRINTK("Writing FIFO_CONTROL_REGISTER failed\n");
return -1;
}
Data = 0x03; //LCR_BITS_8
status=0;
status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
ATEN2011_port->shadowLCR=Data;
Data = 0x0b; // MCR_DTR|MCR_RTS|MCR_MASTER_IE
status=0;
status = ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
ATEN2011_port->shadowMCR=Data;
#ifdef Check
Data = 0x00;
status=0;
status = ATEN2011_get_Uart_Reg(port,LINE_CONTROL_REGISTER,&Data);
ATEN2011_port->shadowLCR=Data;
Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
status = 0;
status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
Data = 0x0c;
status=0;
status = ATEN2011_set_Uart_Reg(port,DIVISOR_LATCH_LSB,Data);
Data = 0x0;
status=0;
status = ATEN2011_set_Uart_Reg(port,DIVISOR_LATCH_MSB,Data);
Data = 0x00;
status=0;
status = ATEN2011_get_Uart_Reg(port,LINE_CONTROL_REGISTER,&Data);
// Data = ATEN2011_port->shadowLCR; //data latch disable
Data = Data & ~SERIAL_LCR_DLAB;
status = 0;
status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
ATEN2011_port->shadowLCR=Data;
#endif
//clearing Bulkin and Bulkout Fifo
Data = 0x0;
status = 0;
status = ATEN2011_get_reg_sync(port,ATEN2011_port->SpRegOffset,&Data);
Data = Data | 0x0c;
status = 0;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->SpRegOffset,Data);
Data = Data & ~0x0c;
status = 0;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->SpRegOffset,Data);
//Finally enable all interrupts
Data = 0x0;
Data = 0x0c;
status = 0;
status = ATEN2011_set_Uart_Reg(port,INTERRUPT_ENABLE_REGISTER,Data);
//clearing rx_disable
Data = 0x0;
status = 0;
status = ATEN2011_get_reg_sync(port,ATEN2011_port->ControlRegOffset,&Data);
Data = Data & ~0x20;
status = 0;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->ControlRegOffset,Data);
// rx_negate
Data = 0x0;
status = 0;
status = ATEN2011_get_reg_sync(port,ATEN2011_port->ControlRegOffset,&Data);
Data = Data |0x10;
status = 0;
status = ATEN2011_set_reg_sync(port,ATEN2011_port->ControlRegOffset,Data);
/* force low_latency on so that our tty_push actually forces *
* the data through,otherwise it is scheduled, and with *
* high data rates (like with OHCI) data can get lost. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = port->tty;
#endif
if (tty)
tty->low_latency = 1;
/*
printk("port number is %d \n",port->number);
printk("serial number is %d \n",port->serial->minor);
printk("Bulkin endpoint is %d \n",port->bulk_in_endpointAddress);
printk("BulkOut endpoint is %d \n",port->bulk_out_endpointAddress);
printk("Interrupt endpoint is %d \n",port->interrupt_in_endpointAddress);
printk("port's number in the device is %d\n",ATEN2011_port->port_num);
*/
////////////////////////
//#ifdef CheckStatusPipe
/* Check to see if we've set up our endpoint info yet *
* (can't set it up in ATEN2011_startup as the structures *
* were not set up at that time.) */
if(ATEN2011_serial->NoOfOpenPorts==1)
{
// start the status polling here
ATEN2011_serial->status_polling_started = TRUE;
//if (ATEN2011_serial->interrupt_in_buffer == NULL)
// {
/* If not yet set, Set here */
ATEN2011_serial->interrupt_in_buffer = serial->port[0]->interrupt_in_buffer;
ATEN2011_serial->interrupt_in_endpoint = serial->port[0]->interrupt_in_endpointAddress;
//printk(" interrupt endpoint:%d \n",ATEN2011_serial->interrupt_in_endpoint);
ATEN2011_serial->interrupt_read_urb = serial->port[0]->interrupt_in_urb;
/* set up interrupt urb */
usb_fill_int_urb( \
ATEN2011_serial->interrupt_read_urb, \
serial->dev, \
usb_rcvintpipe(serial->dev,ATEN2011_serial->interrupt_in_endpoint), \
ATEN2011_serial->interrupt_in_buffer, \
ATEN2011_serial->interrupt_read_urb->transfer_buffer_length,\
ATEN2011_interrupt_callback, ATEN2011_serial, \
ATEN2011_serial->interrupt_read_urb->interval );
/* start interrupt read for ATEN2011 *
* will continue as long as ATEN2011 is connected */
response = usb_submit_urb (ATEN2011_serial->interrupt_read_urb,GFP_KERNEL);
if (response)
{
DPRINTK("%s - Error %d submitting interrupt urb", __FUNCTION__, response);
}
// else
// printk(" interrupt URB submitted\n");
//}
}
//#endif
///////////////////////
/* see if we've set up our endpoint info yet *
* (can't set it up in ATEN2011_startup as the *
* structures were not set up at that time.) */
DPRINTK("port number is %d \n",port->number);
DPRINTK("serial number is %d \n",port->serial->minor);
DPRINTK("Bulkin endpoint is %d \n",port->bulk_in_endpointAddress);
DPRINTK("BulkOut endpoint is %d \n",port->bulk_out_endpointAddress);
DPRINTK("Interrupt endpoint is %d \n",port->interrupt_in_endpointAddress);
DPRINTK("port's number in the device is %d\n",ATEN2011_port->port_num);
ATEN2011_port->bulk_in_buffer = port->bulk_in_buffer;
ATEN2011_port->bulk_in_endpoint = port->bulk_in_endpointAddress;
ATEN2011_port->read_urb = port->read_urb;
ATEN2011_port->bulk_out_endpoint = port->bulk_out_endpointAddress;
minor = port->serial->minor;
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
/* set up our bulk in urb */
if((ATEN2011_serial->ATEN2011_spectrum_2or4ports==2)&&(((__u16)port->number - (__u16)(minor)) != 0))
{
usb_fill_bulk_urb(
ATEN2011_port->read_urb,serial->dev,\
usb_rcvbulkpipe(serial->dev, (port->bulk_in_endpointAddress+2)),\
port->bulk_in_buffer,\
ATEN2011_port->read_urb->transfer_buffer_length, \
ATEN2011_bulk_in_callback,ATEN2011_port);
}
else
usb_fill_bulk_urb(
ATEN2011_port->read_urb, \
serial->dev, \
usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),\
port->bulk_in_buffer, \
ATEN2011_port->read_urb->transfer_buffer_length, \
ATEN2011_bulk_in_callback,ATEN2011_port);
DPRINTK("ATEN2011_open: bulkin endpoint is %d\n",port->bulk_in_endpointAddress);
response = usb_submit_urb (ATEN2011_port->read_urb,GFP_KERNEL);
if (response)
{
err("%s - Error %d submitting control urb", __FUNCTION__, response);
}
/* initialize our wait queues */
init_waitqueue_head(&ATEN2011_port->wait_open);
init_waitqueue_head(&ATEN2011_port->wait_chase);
init_waitqueue_head(&ATEN2011_port->delta_msr_wait);
init_waitqueue_head(&ATEN2011_port->wait_command);
/* initialize our icount structure */
memset (&(ATEN2011_port->icount), 0x00, sizeof(ATEN2011_port->icount));
/* initialize our port settings */
ATEN2011_port->shadowMCR = MCR_MASTER_IE; /* Must set to enable ints! */
ATEN2011_port->chaseResponsePending = FALSE;
/* send a open port command */
ATEN2011_port->openPending = FALSE;
ATEN2011_port->open = TRUE;
//ATEN2011_change_port_settings(ATEN2011_port,old_termios);
/* Setup termios */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
ATEN2011_set_termios (tty, port, &tmp_termios);
#else
ATEN2011_set_termios (port, &tmp_termios);
#endif
ATEN2011_port->rxBytesAvail = 0x0;
ATEN2011_port->icount.tx=0;
ATEN2011_port->icount.rx=0;
DPRINTK("\n\nusb_serial serial:%x ATEN2011_port:%x\nATEN2011_serial:%x usb_serial_port port:%x\n\n",(unsigned int)serial,(unsigned int)ATEN2011_port,(unsigned int)ATEN2011_serial,(unsigned int)port);
return 0;
}
/*****************************************************************************
* ATEN2011_close
* this function is called by the tty driver when a port is closed
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_close(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp)
#else
static void ATEN2011_close(struct usb_serial_port *port, struct file *filp)
#endif
{
struct usb_serial *serial;
struct ATENINTL_serial *ATEN2011_serial;
struct ATENINTL_port *ATEN2011_port;
int no_urbs;
__u16 Data;
//__u16 Data1= 20;
DPRINTK("%s\n","ATEN2011_close:entering...");
/* MATRIX */
//ThreadState = 1;
/* MATRIX */
//printk("Entering... :ATEN2011_close\n");
if (ATEN2011_port_paranoia_check (port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return;
}
serial = ATEN2011_get_usb_serial (port, __FUNCTION__);
if (!serial)
{
DPRINTK("%s","Serial Paranoia failed \n");
return;
}
// take the Adpater and port's private data
ATEN2011_serial = ATEN2011_get_serial_private(serial);
ATEN2011_port = ATEN2011_get_port_private(port);
if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
{
return;
}
if (serial->dev)
{
/* flush and block(wait) until tx is empty*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
ATEN2011_block_until_tx_empty(tty, ATEN2011_port);
#else
ATEN2011_block_until_tx_empty(ATEN2011_port);
#endif
}
// kill the ports URB's
for (no_urbs = 0; no_urbs < NUM_URBS;no_urbs++)
usb_kill_urb (ATEN2011_port->write_urb_pool[no_urbs]);
/* Freeing Write URBs*/
for (no_urbs = 0; no_urbs< NUM_URBS; ++no_urbs)
{
if (ATEN2011_port->write_urb_pool[no_urbs])
{
if (ATEN2011_port->write_urb_pool[no_urbs]->transfer_buffer)
kfree(ATEN2011_port->write_urb_pool[no_urbs]->transfer_buffer);
usb_free_urb (ATEN2011_port->write_urb_pool[no_urbs]);
}
}
/* While closing port, shutdown all bulk read, write *
* and interrupt read if they exists */
if (serial->dev)
{
if (ATEN2011_port->write_urb)
{
DPRINTK("%s","Shutdown bulk write\n");
usb_kill_urb (ATEN2011_port->write_urb);
}
if (ATEN2011_port->read_urb)
{
DPRINTK("%s","Shutdown bulk read\n");
usb_kill_urb (ATEN2011_port->read_urb);
}
if((&ATEN2011_port->control_urb))
{
DPRINTK("%s","Shutdown control read\n");
// usb_kill_urb (ATEN2011_port->control_urb);
}
}
//if(ATEN2011_port->ctrl_buf != NULL)
//kfree(ATEN2011_port->ctrl_buf);
// decrement the no.of open ports counter of an individual USB-serial adapter.
ATEN2011_serial->NoOfOpenPorts--;
DPRINTK("NoOfOpenPorts in close%d:in port%d\n",ATEN2011_serial->NoOfOpenPorts,port->number);
//printk("the num of ports opend is:%d\n",ATEN2011_serial->NoOfOpenPorts);
if(ATEN2011_serial->NoOfOpenPorts==0)
{
//stop the stus polling here
//printk("disabling the status polling flag to FALSE :\n");
ATEN2011_serial->status_polling_started = FALSE;
if(ATEN2011_serial->interrupt_read_urb)
{
DPRINTK("%s","Shutdown interrupt_read_urb\n");
//ATEN2011_serial->interrupt_in_buffer=NULL;
//usb_kill_urb (ATEN2011_serial->interrupt_read_urb);
}
}
if (ATEN2011_port->write_urb)
{
/* if this urb had a transfer buffer already (old tx) free it */
if (ATEN2011_port->write_urb->transfer_buffer != NULL)
{
kfree(ATEN2011_port->write_urb->transfer_buffer);
}
usb_free_urb(ATEN2011_port->write_urb);
}
// clear the MCR & IER
Data = 0x00;
ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
Data = 0x00;
ATEN2011_set_Uart_Reg(port,INTERRUPT_ENABLE_REGISTER,Data);
//ATEN2011_get_Uart_Reg(port,MODEM_CONTROL_REGISTER,&Data1);
//printk("value of MCR after closing the port is : 0x%x\n",Data1);
ATEN2011_port->open = FALSE;
ATEN2011_port->closePending = FALSE;
ATEN2011_port->openPending = FALSE;
DPRINTK("%s \n","Leaving ............");
}
/*****************************************************************************
* SerialBreak
* this function sends a break to the port
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_break(struct tty_struct *tty, int break_state)
#else
static void ATEN2011_break(struct usb_serial_port *port, int break_state)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#endif
unsigned char data;
struct usb_serial *serial;
struct ATENINTL_serial *ATEN2011_serial;
struct ATENINTL_port *ATEN2011_port;
DPRINTK("%s \n","Entering ...........");
DPRINTK("ATEN2011_break: Start\n");
if (ATEN2011_port_paranoia_check (port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return;
}
serial = ATEN2011_get_usb_serial (port, __FUNCTION__);
if (!serial)
{
DPRINTK("%s","Serial Paranoia failed \n");
return;
}
ATEN2011_serial = ATEN2011_get_serial_private(serial);
ATEN2011_port = ATEN2011_get_port_private(port);
if ((ATEN2011_serial == NULL) || (ATEN2011_port == NULL))
{
return;
}
/* flush and chase */
ATEN2011_port->chaseResponsePending = TRUE;
if (serial->dev)
{
/* flush and block until tx is empty*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
ATEN2011_block_until_chase_response(tty, ATEN2011_port);
#else
ATEN2011_block_until_chase_response(ATEN2011_port);
#endif
}
if(break_state == -1)
{
data = ATEN2011_port->shadowLCR | LCR_SET_BREAK;
}
else
{
data = ATEN2011_port->shadowLCR & ~LCR_SET_BREAK;
}
ATEN2011_port->shadowLCR = data;
DPRINTK("ATEN2011_break ATEN2011_port->shadowLCR is %x\n",ATEN2011_port->shadowLCR);
ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,ATEN2011_port->shadowLCR);
return;
}
/************************************************************************
*
* ATEN2011_block_until_chase_response
*
* This function will block the close until one of the following:
* 1. Response to our Chase comes from ATEN2011
* 2. A timout of 10 seconds without activity has expired
* (1K of ATEN2011 data @ 2400 baud ==> 4 sec to empty)
*
************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_block_until_chase_response(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port)
#else
static void ATEN2011_block_until_chase_response(struct ATENINTL_port *ATEN2011_port)
#endif
{
int timeout = 1*HZ;
int wait = 10;
int count ;
while (1)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
count = ATEN2011_chars_in_buffer(tty);
#else
count = ATEN2011_chars_in_buffer(ATEN2011_port->port);
#endif
/* Check for Buffer status */
if(count<=0)
{
ATEN2011_port->chaseResponsePending = FALSE;
return;
}
/* Block the thread for a while */
interruptible_sleep_on_timeout (&ATEN2011_port->wait_chase, timeout);
/* No activity.. count down section */
wait--;
if (wait == 0)
{
dbg("%s - TIMEOUT", __FUNCTION__);
return;
}
else
{
/* Reset timout value back to seconds */
wait = 10;
}
}
}
/************************************************************************
*
* ATEN2011_block_until_tx_empty
*
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The ATEN2011 has stopped
* 3. A timout of 3 seconds without activity has expired
*
************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_block_until_tx_empty(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port)
#else
static void ATEN2011_block_until_tx_empty(struct ATENINTL_port *ATEN2011_port)
#endif
{
int timeout = HZ/10;
int wait = 30;
int count;
while (1)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
count = ATEN2011_chars_in_buffer(tty);
#else
count = ATEN2011_chars_in_buffer(ATEN2011_port->port);
#endif
/* Check for Buffer status */
if(count<=0)
{
return;
}
/* Block the thread for a while */
interruptible_sleep_on_timeout (&ATEN2011_port->wait_chase, timeout);
/* No activity.. count down section */
wait--;
if (wait == 0)
{
dbg("%s - TIMEOUT", __FUNCTION__);
return;
}
else
{
/* Reset timout value back to seconds */
wait = 30;
}
}
}
/*****************************************************************************
* ATEN2011_write_room
* 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
* Otherwise we return a negative error number.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_write_room (struct tty_struct *tty)
#else
static int ATEN2011_write_room (struct usb_serial_port *port)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#endif
int i;
int room = 0;
struct ATENINTL_port *ATEN2011_port;
// DPRINTK("%s \n"," ATEN2011_write_room:entering ...........");
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
DPRINTK("%s \n"," ATEN2011_write_room:leaving ...........");
return -1;
}
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
{
DPRINTK("%s \n","ATEN2011_break:leaving ...........");
return -1;
}
for (i = 0; i < NUM_URBS; ++i)
{
if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS)
{
room += URB_TRANSFER_BUFFER_SIZE;
}
}
dbg("%s - returns %d", __FUNCTION__, room);
return (room);
}
/*****************************************************************************
* ATEN2011_chars_in_buffer
* 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,
* Otherwise we return a negative error number.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_chars_in_buffer(struct tty_struct *tty)
#else
static int ATEN2011_chars_in_buffer(struct usb_serial_port *port)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#endif
int i;
int chars = 0;
struct ATENINTL_port *ATEN2011_port;
//DPRINTK("%s \n"," ATEN2011_chars_in_buffer:entering ...........");
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return -1;
}
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
{
DPRINTK("%s \n","ATEN2011_break:leaving ...........");
return -1;
}
for (i = 0; i < NUM_URBS; ++i)
{
if (ATEN2011_port->write_urb_pool[i]->status == -EINPROGRESS)
{
chars += URB_TRANSFER_BUFFER_SIZE;
}
}
dbg("%s - returns %d", __FUNCTION__, chars);
return (chars);
}
/*****************************************************************************
* SerialWrite
* 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.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_write (struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count)
#else
static int ATEN2011_write (struct usb_serial_port *port, const unsigned char *data, int count)
#endif
{
int status;
int i;
int bytes_sent = 0;
int transfer_size;
int from_user=0;
int minor;
struct ATENINTL_port *ATEN2011_port;
struct usb_serial *serial;
struct ATENINTL_serial *ATEN2011_serial;
struct urb *urb;
//__u16 Data;
const unsigned char *current_position = data;
unsigned char * data1;
DPRINTK("%s \n","entering ...........");
//DPRINTK("ATEN2011_write: ATEN2011_port->shadowLCR is %x\n",ATEN2011_port->shadowLCR);
#ifdef NOTATEN2011
Data = 0x00;
status=0;
status = ATEN2011_get_Uart_Reg(port,LINE_CONTROL_REGISTER,&Data);
ATEN2011_port->shadowLCR = Data;
DPRINTK("ATEN2011_write: LINE_CONTROL_REGISTER is %x\n",Data);
DPRINTK("ATEN2011_write: ATEN2011_port->shadowLCR is %x\n",ATEN2011_port->shadowLCR);
//Data = 0x03;
//status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
//ATEN2011_port->shadowLCR=Data;//Need to add later
Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
status = 0;
status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
//Data = 0x0c;
//status = ATEN2011_set_Uart_Reg(port,DIVISOR_LATCH_LSB,Data);
Data = 0x00;
status=0;
status = ATEN2011_get_Uart_Reg(port,DIVISOR_LATCH_LSB,&Data);
DPRINTK("ATEN2011_write:DLL value is %x\n",Data);
Data = 0x0;
status=0;
status = ATEN2011_get_Uart_Reg(port,DIVISOR_LATCH_MSB,&Data);
DPRINTK("ATEN2011_write:DLM value is %x\n",Data);
Data = Data & ~SERIAL_LCR_DLAB;
DPRINTK("ATEN2011_write: ATEN2011_port->shadowLCR is %x\n",ATEN2011_port->shadowLCR);
status = 0;
status = ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
#endif
if (ATEN2011_port_paranoia_check (port, __FUNCTION__))
{
DPRINTK("%s","Port Paranoia failed \n");
return -1;
}
serial = port->serial;
if (ATEN2011_serial_paranoia_check (serial, __FUNCTION__))
{
DPRINTK("%s","Serial Paranoia failed \n");
return -1;
}
ATEN2011_port = ATEN2011_get_port_private(port);
if(ATEN2011_port==NULL)
{
DPRINTK("%s","ATEN2011_port is NULL\n");
return -1;
}
ATEN2011_serial =ATEN2011_get_serial_private(serial);
if(ATEN2011_serial==NULL)
{
DPRINTK("%s","ATEN2011_serial is NULL \n");
return -1;
}
/* try to find a free urb in the list */
urb = NULL;
for (i = 0; i < NUM_URBS; ++i)
{
if (ATEN2011_port->write_urb_pool[i]->status != -EINPROGRESS)
{
urb = ATEN2011_port->write_urb_pool[i];
DPRINTK("\nURB:%d",i);
break;
}
}
if (urb == NULL)
{
dbg("%s - no more free urbs", __FUNCTION__);
goto exit;
}
if (urb->transfer_buffer == NULL)
{
urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (urb->transfer_buffer == NULL)
{
err("%s no more kernel memory...", __FUNCTION__);
goto exit;
}
}
transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
if (from_user)
{
if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
bytes_sent = -EFAULT;
goto exit;
}
}
else
{
memcpy (urb->transfer_buffer, current_position, transfer_size);
}
//usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer);
/* fill urb with data and submit */
minor = port->serial->minor;
if (minor == SERIAL_TTY_NO_MINOR);
minor = 0;
if((ATEN2011_serial->ATEN2011_spectrum_2or4ports==2)&&(((__u16)port->number - (__u16)(minor)) != 0))
{
usb_fill_bulk_urb (urb,
ATEN2011_serial->serial->dev,
usb_sndbulkpipe(ATEN2011_serial->serial->dev,
(port->bulk_out_endpointAddress)+2),
urb->transfer_buffer,
transfer_size,
ATEN2011_bulk_out_data_callback,
ATEN2011_port);
}
else
usb_fill_bulk_urb (urb,
ATEN2011_serial->serial->dev,
usb_sndbulkpipe(ATEN2011_serial->serial->dev,
port->bulk_out_endpointAddress),
urb->transfer_buffer,
transfer_size,
ATEN2011_bulk_out_data_callback,
ATEN2011_port);
data1=urb->transfer_buffer;
DPRINTK("\nbulkout endpoint is %d",port->bulk_out_endpointAddress);
//for(i=0;i < urb->actual_length;i++)
// DPRINTK("Data is %c\n ",data1[i]);
/* send it down the pipe */
status = usb_submit_urb(urb,GFP_ATOMIC);
if (status)
{
err("%s - usb_submit_urb(write bulk) failed with status = %d", __FUNCTION__, status);
bytes_sent = status;
goto exit;
}
bytes_sent = transfer_size;
ATEN2011_port->icount.tx += transfer_size;
DPRINTK("ATEN2011_port->icount.tx is %d:\n",ATEN2011_port->icount.tx);
exit:
return bytes_sent;
}
/*****************************************************************************
* SerialThrottle
* this function is called by the tty driver when it wants to stop the data
* being read from the port.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_throttle(struct tty_struct *tty)
#else
static void ATEN2011_throttle(struct usb_serial_port *port)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#else
struct tty_struct *tty;
#endif
struct ATENINTL_port *ATEN2011_port;
int status;
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return;
}
DPRINTK("- port %d\n", port->number);
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
return;
if (!ATEN2011_port->open)
{
DPRINTK("%s\n","port not opened");
return;
}
DPRINTK("%s","Entering .......... \n");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = port->tty;
#endif
if (!tty)
{
dbg ("%s - no tty available", __FUNCTION__);
return;
}
/* if we are implementing XON/XOFF, send the stop character */
if (I_IXOFF(tty))
{
unsigned char stop_char = STOP_CHAR(tty);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
status = ATEN2011_write(tty, port, &stop_char, 1); //FC4
#else
status = ATEN2011_write(port, &stop_char, 1); //FC4
#endif
if (status <= 0)
{
return;
}
}
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios->c_cflag & CRTSCTS)
{
ATEN2011_port->shadowMCR &= ~MCR_RTS;
status=0;
status=ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,ATEN2011_port->shadowMCR);
if (status < 0)
{
return;
}
}
return;
}
/*****************************************************************************
* ATEN2011_unthrottle
* 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)
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_unthrottle (struct tty_struct *tty)
#else
static void ATEN2011_unthrottle (struct usb_serial_port *port)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#else
struct tty_struct *tty;
#endif
int status;
struct ATENINTL_port *ATEN2011_port = ATEN2011_get_port_private(port);
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return;
}
if (ATEN2011_port == NULL)
return;
if (!ATEN2011_port->open) {
dbg("%s - port not opened", __FUNCTION__);
return;
}
DPRINTK("%s","Entering .......... \n");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = port->tty;
#endif
if (!tty)
{
dbg ("%s - no tty available", __FUNCTION__);
return;
}
/* if we are implementing XON/XOFF, send the start character */
if (I_IXOFF(tty))
{
unsigned char start_char = START_CHAR(tty);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
status = ATEN2011_write (tty, port, &start_char, 1); //FC4
#else
status = ATEN2011_write (port, &start_char, 1); //FC4
#endif
if (status <= 0)
{
return;
}
}
/* if we are implementing RTS/CTS, toggle that line */
if (tty->termios->c_cflag & CRTSCTS)
{
ATEN2011_port->shadowMCR |= MCR_RTS;
status=0;
status=ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,ATEN2011_port->shadowMCR);
if (status < 0)
{
return;
}
}
return;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_tiocmget(struct tty_struct *tty, struct file *file)
#else
static int ATEN2011_tiocmget(struct usb_serial_port *port, struct file *file)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#endif
//struct ti_port *tport = usb_get_serial_port_data(port);
struct ATENINTL_port *ATEN2011_port;
unsigned int result;
__u16 msr;
__u16 mcr;
//unsigned int mcr;
int status=0;
ATEN2011_port = ATEN2011_get_port_private(port);
DPRINTK("%s - port %d", __FUNCTION__, port->number);
if (ATEN2011_port == NULL)
return -ENODEV;
status=ATEN2011_get_Uart_Reg(port,MODEM_STATUS_REGISTER,&msr);
status=ATEN2011_get_Uart_Reg(port,MODEM_CONTROL_REGISTER,&mcr);
// mcr = ATEN2011_port->shadowMCR;
// COMMENT2: the Fallowing three line are commented for updating only MSR values
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
| ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
| ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
| ((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS : 0)
| ((msr & ATEN2011_MSR_CD) ? TIOCM_CAR : 0)
| ((msr & ATEN2011_MSR_RI) ? TIOCM_RI : 0)
| ((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR : 0);
DPRINTK("%s - 0x%04X", __FUNCTION__, result);
return result;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
#else
static int ATEN2011_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#endif
struct ATENINTL_port *ATEN2011_port;
//struct ti_port *tport = usb_get_serial_port_data(port);
unsigned int mcr;
unsigned int status;
DPRINTK("%s - port %d", __FUNCTION__, port->number);
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
return -ENODEV;
mcr = ATEN2011_port->shadowMCR;
if (clear & TIOCM_RTS)
mcr &= ~MCR_RTS;
if (clear & TIOCM_DTR)
mcr &= ~MCR_DTR;
if (clear & TIOCM_LOOP)
mcr &= ~MCR_LOOPBACK;
if (set & TIOCM_RTS)
mcr |= MCR_RTS;
if (set & TIOCM_DTR)
mcr |= MCR_DTR;
if (set & TIOCM_LOOP)
mcr |= MCR_LOOPBACK;
ATEN2011_port->shadowMCR = mcr;
status=0;
status = ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,mcr);
if(status <0)
{
DPRINTK("setting MODEM_CONTROL_REGISTER Failed\n");
return -1;
}
return 0;
}
/*****************************************************************************
* SerialSetTermios
* this function is called by the tty driver when it wants to change the termios structure
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios)
#else
static void ATEN2011_set_termios(struct usb_serial_port *port, struct ktermios *old_termios)
#endif
{
int status;
unsigned int cflag;
struct usb_serial *serial;
struct ATENINTL_port *ATEN2011_port;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
struct tty_struct *tty;
#endif
DPRINTK("ATEN2011_set_termios: START\n");
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return;
}
serial = port->serial;
if(ATEN2011_serial_paranoia_check(serial,__FUNCTION__) )
{
DPRINTK("%s","Invalid Serial \n");
return;
}
ATEN2011_port = ATEN2011_get_port_private(port);
if (ATEN2011_port == NULL)
return;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = port->tty;
if (!port->tty || !port->tty->termios)
{
dbg ("%s - no tty or termios", __FUNCTION__);
return;
}
#endif
if (!ATEN2011_port->open)
{
dbg("%s - port not opened", __FUNCTION__);
return;
}
DPRINTK("%s\n","setting termios - ");
cflag = tty->termios->c_cflag;
if (!cflag)
{
DPRINTK("%s %s\n",__FUNCTION__,"cflag is NULL");
return;
}
/* check that they really want us to change something */
if (old_termios)
{
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag)))
{
DPRINTK("%s\n","Nothing to change");
return;
}
}
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag,
RELEVANT_IFLAG(tty->termios->c_iflag));
if (old_termios)
{
dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
old_termios->c_cflag,
RELEVANT_IFLAG(old_termios->c_iflag));
}
dbg("%s - port %d", __FUNCTION__, port->number);
/* change the port settings to the new ones specified */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
ATEN2011_change_port_settings(tty, ATEN2011_port, old_termios);
#else
ATEN2011_change_port_settings(ATEN2011_port, old_termios);
#endif
if(!ATEN2011_port->read_urb)
{
DPRINTK("%s","URB KILLED !!!!!\n");
return;
}
if(ATEN2011_port->read_urb->status!=-EINPROGRESS)
{
ATEN2011_port->read_urb->dev = serial->dev;
status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
if (status)
{
DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
}
}
return;
}
/*
static void ATEN2011_break_ctl( struct usb_serial_port *port, int break_state )
{
//struct usb_serial *serial = port->serial;
// if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
// err("Set break_ctl %d", break_state);
}
*/
/*****************************************************************************
* 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
* allows an RS485 driver to be written in user space.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int get_lsr_info(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port, unsigned int *value)
#else
static int get_lsr_info(struct ATENINTL_port *ATEN2011_port, unsigned int *value)
#endif
{
int count;
unsigned int result = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
count = ATEN2011_chars_in_buffer(tty);
#else
count = ATEN2011_chars_in_buffer(ATEN2011_port->port);
#endif
if(count == 0)
{
dbg("%s -- Empty", __FUNCTION__);
result = TIOCSER_TEMT;
}
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return 0;
}
/*****************************************************************************
* get_number_bytes_avail - get number of bytes available
*
* Purpose: Let user call ioctl to get the count of number of bytes available.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int get_number_bytes_avail(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port, unsigned int *value)
#else
static int get_number_bytes_avail(struct ATENINTL_port *ATEN2011_port, unsigned int *value)
#endif
{
unsigned int result = 0;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
struct tty_struct *tty = ATEN2011_port->port->tty;
#endif
if (!tty)
return -ENOIOCTLCMD;
result = tty->read_cnt;
dbg("%s(%d) = %d", __FUNCTION__, ATEN2011_port->port->number, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return -ENOIOCTLCMD;
}
/*****************************************************************************
* set_modem_info
* function to set modem info
*****************************************************************************/
static int set_modem_info(struct ATENINTL_port *ATEN2011_port, unsigned int cmd, unsigned int *value)
{
unsigned int mcr ;
unsigned int arg;
__u16 Data;
int status;
struct usb_serial_port *port;
if (ATEN2011_port == NULL)
return -1;
port = (struct usb_serial_port*)ATEN2011_port->port;
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return -1;
}
mcr = ATEN2011_port->shadowMCR;
if (copy_from_user(&arg, value, sizeof(int)))
return -EFAULT;
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
mcr |= MCR_RTS;
if (arg & TIOCM_DTR)
mcr |= MCR_RTS;
if (arg & TIOCM_LOOP)
mcr |= MCR_LOOPBACK;
break;
case TIOCMBIC:
if (arg & TIOCM_RTS)
mcr &= ~MCR_RTS;
if (arg & TIOCM_DTR)
mcr &= ~MCR_RTS;
if (arg & TIOCM_LOOP)
mcr &= ~MCR_LOOPBACK;
break;
case TIOCMSET:
/* turn off the RTS and DTR and LOOPBACK
* and then only turn on what was asked to */
mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
break;
}
ATEN2011_port->shadowMCR = mcr;
Data = ATEN2011_port->shadowMCR;
status=0;
status = ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
if(status <0)
{
DPRINTK("setting MODEM_CONTROL_REGISTER Failed\n");
return -1;
}
return 0;
}
/*****************************************************************************
* get_modem_info
* function to get modem info
*****************************************************************************/
static int get_modem_info(struct ATENINTL_port *ATEN2011_port, unsigned int *value)
{
unsigned int result = 0;
__u16 msr;
unsigned int mcr = ATEN2011_port->shadowMCR;
int status=0;
status=ATEN2011_get_Uart_Reg(ATEN2011_port->port,MODEM_STATUS_REGISTER,&msr);
result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */
| ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */
| ((msr & ATEN2011_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */
| ((msr & ATEN2011_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */
| ((msr & ATEN2011_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */
| ((msr & ATEN2011_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
dbg("%s -- %x", __FUNCTION__, result);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return 0;
}
/*****************************************************************************
* get_serial_info
* function to get information about serial port
*****************************************************************************/
static int get_serial_info(struct ATENINTL_port *ATEN2011_port, struct serial_struct * retinfo)
{
struct serial_struct tmp;
if (ATEN2011_port == NULL)
return -1;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
tmp.line = ATEN2011_port->port->serial->minor;
if (tmp.line == SERIAL_TTY_NO_MINOR)
tmp.line = 0;
tmp.port = ATEN2011_port->port->number;
tmp.irq = 0;
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
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
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static int ATEN2011_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
#else
static int ATEN2011_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
struct usb_serial_port *port = tty->driver_data;
#else
struct tty_struct *tty;
#endif
struct ATENINTL_port *ATEN2011_port;
struct async_icount cnow;
struct async_icount cprev;
struct serial_icounter_struct icount;
int ATENret=0;
//int retval;
//struct tty_ldisc *ld;
//printk("%s - port %d, cmd = 0x%x\n", __FUNCTION__, port->number, cmd);
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return -1;
}
ATEN2011_port = ATEN2011_get_port_private(port);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = ATEN2011_port->port->tty;
#endif
if (ATEN2011_port == NULL)
return -1;
dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
switch (cmd)
{
/* return number of bytes available */
case TIOCINQ:
dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
return get_number_bytes_avail(tty, ATEN2011_port, (unsigned int *) arg);
#else
return get_number_bytes_avail(ATEN2011_port, (unsigned int *) arg);
#endif
break;
case TIOCOUTQ:
dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
return put_user(ATEN2011_chars_in_buffer(tty),
(int __user *) arg);
#else
return put_user(tty->driver->ops->chars_in_buffer ?
tty->driver->ops->chars_in_buffer(tty) : 0,
(int __user *) arg);
#endif
break;
/* //2.6.17 block
case TCFLSH:
retval = tty_check_change(tty);
if (retval)
return retval;
ld = tty_ldisc_ref(tty);
switch (arg) {
case TCIFLUSH:
if (ld && ld->flush_buffer)
ld->flush_buffer(tty);
break;
case TCIOFLUSH:
if (ld && ld->flush_buffer)
ld->flush_buffer(tty);
// fall through
case TCOFLUSH:
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
break;
default:
tty_ldisc_deref(ld);
return -EINVAL;
}
tty_ldisc_deref(ld);
return 0;
*/
case TIOCSERGETLSR:
dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
return get_lsr_info(tty, ATEN2011_port, (unsigned int *) arg);
#else
return get_lsr_info(ATEN2011_port, (unsigned int *) arg);
#endif
return 0;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number);
// printk("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, port->number);
ATENret=set_modem_info(ATEN2011_port, cmd, (unsigned int *) arg);
// printk(" %s: ret:%d\n",__FUNCTION__,ATENret);
return ATENret;
case TIOCMGET:
dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
return get_modem_info(ATEN2011_port, (unsigned int *) arg);
case TIOCGSERIAL:
dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
return get_serial_info(ATEN2011_port, (struct serial_struct *) arg);
case TIOCSSERIAL:
dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
break;
case TIOCMIWAIT:
dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
cprev = ATEN2011_port->icount;
while (1) {
//interruptible_sleep_on(&ATEN2011_port->delta_msr_wait);
// ATEN2011_port->delta_msr_cond=0;
//wait_event_interruptible(ATEN2011_port->delta_msr_wait,(ATEN2011_port->delta_msr_cond==1));
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
cnow = ATEN2011_port->icount;
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
return 0;
}
cprev = cnow;
}
/* NOTREACHED */
break;
case TIOCGICOUNT:
cnow = ATEN2011_port->icount;
icount.cts = cnow.cts;
icount.dsr = cnow.dsr;
icount.rng = cnow.rng;
icount.dcd = cnow.dcd;
icount.rx = cnow.rx;
icount.tx = cnow.tx;
icount.frame = cnow.frame;
icount.overrun = cnow.overrun;
icount.parity = cnow.parity;
icount.brk = cnow.brk;
icount.buf_overrun = cnow.buf_overrun;
dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, icount.rx, icount.tx );
if (copy_to_user((void *)arg, &icount, sizeof(icount)))
return -EFAULT;
return 0;
case TIOCEXBAUD:
return 0;
default:
break;
}
return -ENOIOCTLCMD;
}
/*****************************************************************************
* ATEN2011_send_cmd_write_baud_rate
* this function sends the proper command to change the baud rate of the
* specified port.
*****************************************************************************/
static int ATEN2011_send_cmd_write_baud_rate (struct ATENINTL_port *ATEN2011_port, int baudRate)
{
int divisor = 0;
int status;
__u16 Data;
unsigned char number ;
__u16 clk_sel_val;
struct usb_serial_port *port;
int minor;
if (ATEN2011_port == NULL)
return -1;
port = (struct usb_serial_port*)ATEN2011_port->port;
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return -1;
}
if(ATEN2011_serial_paranoia_check(port->serial,__FUNCTION__) )
{
DPRINTK("%s","Invalid Serial \n");
return -1;
}
DPRINTK("%s","Entering .......... \n");
minor = ATEN2011_port->port->serial->minor;
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
number = ATEN2011_port->port->number - minor;
dbg("%s - port = %d, baud = %d", __FUNCTION__, ATEN2011_port->port->number, baudRate);
//reset clk_uart_sel in spregOffset
if(baudRate >115200)
{
#ifdef HW_flow_control
//NOTE: need to see the pther register to modify
//setting h/w flow control bit to 1;
status=0;
//Data = ATEN2011_port->shadowMCR ;
Data = 0x2b;
ATEN2011_port->shadowMCR=Data;
status=ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
if(status<0)
{
DPRINTK("Writing spreg failed in set_serial_baud\n");
return -1;
}
#endif
}
else
{
#ifdef HW_flow_control
//setting h/w flow control bit to 0;
status=0;
//Data = ATEN2011_port->shadowMCR ;
Data = 0xb;
ATEN2011_port->shadowMCR=Data;
status=ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
if(status<0)
{
DPRINTK("Writing spreg failed in set_serial_baud\n");
return -1;
}
#endif
}
if(1)//baudRate <= 115200)
{
clk_sel_val=0x0;
Data=0x0;
status=0;
status = ATEN2011_calc_baud_rate_divisor (baudRate, &divisor,&clk_sel_val);
status= ATEN2011_get_reg_sync(port,ATEN2011_port->SpRegOffset,&Data);
if(status<0)
{
DPRINTK("reading spreg failed in set_serial_baud\n");
return -1;
}
Data = (Data & 0x8f)|clk_sel_val;
status=0;
status= ATEN2011_set_reg_sync(port,ATEN2011_port->SpRegOffset,Data);
if(status<0)
{
DPRINTK("Writing spreg failed in set_serial_baud\n");
return -1;
}
/* Calculate the Divisor */
if (status)
{
err("%s - bad baud rate", __FUNCTION__);
DPRINTK("%s\n","bad baud rate");
return status;
}
/* Enable access to divisor latch */
Data = ATEN2011_port->shadowLCR | SERIAL_LCR_DLAB;
ATEN2011_port->shadowLCR = Data;
ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
/* Write the divisor */
Data = LOW8 (divisor);//: commented to test
DPRINTK("set_serial_baud Value to write DLL is %x\n",Data);
ATEN2011_set_Uart_Reg(port,DIVISOR_LATCH_LSB,Data);
Data = HIGH8 (divisor); //: commented to test
DPRINTK("set_serial_baud Value to write DLM is %x\n",Data);
ATEN2011_set_Uart_Reg(port,DIVISOR_LATCH_MSB,Data);
/* Disable access to divisor latch */
Data = ATEN2011_port->shadowLCR & ~SERIAL_LCR_DLAB;
ATEN2011_port->shadowLCR = Data;
ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
}
return status;
}
/*****************************************************************************
* ATEN2011_calc_baud_rate_divisor
* this function calculates the proper baud rate divisor for the specified
* baud rate.
*****************************************************************************/
static int ATEN2011_calc_baud_rate_divisor (int baudRate, int *divisor,__u16 *clk_sel_val)
{
//int i;
//__u16 custom,round1, round;
dbg("%s - %d", __FUNCTION__, baudRate);
if(baudRate <=115200)
{
*divisor = 115200/baudRate;
*clk_sel_val = 0x0;
}
if((baudRate > 115200) && (baudRate <= 230400))
{
*divisor = 230400/baudRate;
*clk_sel_val=0x10;
}
else if((baudRate > 230400) && (baudRate <= 403200))
{
*divisor = 403200/baudRate;
*clk_sel_val=0x20;
}
else if((baudRate > 403200) && (baudRate <= 460800))
{
*divisor = 460800/baudRate;
*clk_sel_val=0x30;
}
else if((baudRate > 460800) && (baudRate <= 806400))
{
*divisor = 806400/baudRate;
*clk_sel_val=0x40;
}
else if((baudRate >806400) && (baudRate <= 921600))
{
*divisor = 921600/baudRate;
*clk_sel_val=0x50;
}
else if((baudRate > 921600) && (baudRate <= 1572864))
{
*divisor = 1572864/baudRate;
*clk_sel_val=0x60;
}
else if((baudRate > 1572864) && (baudRate <= 3145728))
{
*divisor = 3145728/baudRate;
*clk_sel_val=0x70;
}
return 0;
#ifdef NOTATEN2011
for (i = 0; i < NUM_ENTRIES(ATEN2011_divisor_table); i++)
{
if ( ATEN2011_divisor_table[i].BaudRate == baudrate )
{
*divisor = ATEN2011_divisor_table[i].Divisor;
return 0;
}
}
/* After trying for all the standard baud rates *
* Try calculating the divisor for this baud rate */
if (baudrate > 75 && baudrate < 230400)
{
/* get the divisor */
custom = (__u16)(230400L / baudrate);
/* Check for round off */
round1 = (__u16)(2304000L / baudrate);
round = (__u16)(round1 - (custom * 10));
if (round > 4) {
custom++;
}
*divisor = custom;
DPRINTK(" Baud %d = %d\n",baudrate, custom);
return 0;
}
DPRINTK("%s\n"," Baud calculation Failed...");
return -1;
#endif
}
/*****************************************************************************
* ATEN2011_change_port_settings
* This routine is called to set the UART on the device to match
* the specified new settings.
*****************************************************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
static void ATEN2011_change_port_settings(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port, struct ktermios *old_termios)
#else
static void ATEN2011_change_port_settings(struct ATENINTL_port *ATEN2011_port, struct ktermios *old_termios)
#endif
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
struct tty_struct *tty;
#endif
int baud;
unsigned cflag;
unsigned iflag;
__u8 mask = 0xff;
__u8 lData;
__u8 lParity;
__u8 lStop;
int status;
__u16 Data;
struct usb_serial_port *port;
struct usb_serial *serial;
if (ATEN2011_port == NULL)
return ;
port = (struct usb_serial_port *)ATEN2011_port->port;
if(ATEN2011_port_paranoia_check(port,__FUNCTION__) )
{
DPRINTK("%s","Invalid port \n");
return ;
}
if(ATEN2011_serial_paranoia_check(port->serial,__FUNCTION__) )
{
DPRINTK("%s","Invalid Serial \n");
return ;
}
serial = port->serial;
dbg("%s - port %d", __FUNCTION__, ATEN2011_port->port->number);
if ((!ATEN2011_port->open) && (!ATEN2011_port->openPending))
{
dbg("%s - port not opened", __FUNCTION__);
return;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
tty = ATEN2011_port->port->tty;
#endif
if ((!tty) || (!tty->termios))
{
dbg("%s - no tty structures", __FUNCTION__);
return;
}
DPRINTK("%s","Entering .......... \n");
lData = LCR_BITS_8;
lStop = LCR_STOP_1;
lParity = LCR_PAR_NONE;
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
/* Change the number of bits */
//COMMENT1: the below Line"if(cflag & CSIZE)" is added for the errors we get for serial loop data test i.e serial_loopback.pl -v
//if(cflag & CSIZE)
{
switch (cflag & CSIZE)
{
case CS5: lData = LCR_BITS_5;
mask = 0x1f;
break;
case CS6: lData = LCR_BITS_6;
mask = 0x3f;
break;
case CS7: lData = LCR_BITS_7;
mask = 0x7f;
break;
default:
case CS8: lData = LCR_BITS_8;
break;
}
}
/* Change the Parity bit */
if (cflag & PARENB)
{
if (cflag & PARODD)
{
lParity = LCR_PAR_ODD;
dbg("%s - parity = odd", __FUNCTION__);
}
else
{
lParity = LCR_PAR_EVEN;
dbg("%s - parity = even", __FUNCTION__);
}
}
else
{
dbg("%s - parity = none", __FUNCTION__);
}
if(cflag & CMSPAR)
{
lParity = lParity | 0x20;
}
/* Change the Stop bit */
if (cflag & CSTOPB)
{
lStop = LCR_STOP_2;
dbg("%s - stop bits = 2", __FUNCTION__);
}
else
{
lStop = LCR_STOP_1;
dbg("%s - stop bits = 1", __FUNCTION__);
}
/* Update the LCR with the correct value */
ATEN2011_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
ATEN2011_port->shadowLCR |= (lData | lParity | lStop);
ATEN2011_port->validDataMask = mask;
DPRINTK("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is %x\n",ATEN2011_port->shadowLCR);
/* Disable Interrupts */
Data = 0x00;
ATEN2011_set_Uart_Reg(port,INTERRUPT_ENABLE_REGISTER,Data);
Data = 0x00;
ATEN2011_set_Uart_Reg(port,FIFO_CONTROL_REGISTER,Data);
Data = 0xcf;
ATEN2011_set_Uart_Reg(port,FIFO_CONTROL_REGISTER,Data);
/* Send the updated LCR value to the ATEN2011 */
Data = ATEN2011_port->shadowLCR;
ATEN2011_set_Uart_Reg(port,LINE_CONTROL_REGISTER,Data);
Data = 0x00b;
ATEN2011_port->shadowMCR = Data;
ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
Data = 0x00b;
ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
/* set up the MCR register and send it to the ATEN2011 */
ATEN2011_port->shadowMCR = MCR_MASTER_IE;
if (cflag & CBAUD)
{
ATEN2011_port->shadowMCR |= (MCR_DTR | MCR_RTS);
}
if (cflag & CRTSCTS)
{
ATEN2011_port->shadowMCR |= (MCR_XON_ANY);
}
else
{
ATEN2011_port->shadowMCR &= ~(MCR_XON_ANY);
}
Data = ATEN2011_port->shadowMCR;
ATEN2011_set_Uart_Reg(port,MODEM_CONTROL_REGISTER,Data);
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate(tty);
if (!baud)
{
/* pick a default, any default... */
DPRINTK("%s\n","Picked default baud...");
baud = 9600;
}
dbg("%s - baud rate = %d", __FUNCTION__, baud);
status = ATEN2011_send_cmd_write_baud_rate (ATEN2011_port, baud);
/* Enable Interrupts */
Data = 0x0c;
ATEN2011_set_Uart_Reg(port,INTERRUPT_ENABLE_REGISTER,Data);
if(ATEN2011_port->read_urb->status!=-EINPROGRESS)
{
ATEN2011_port->read_urb->dev = serial->dev;
status = usb_submit_urb(ATEN2011_port->read_urb, GFP_ATOMIC);
if (status)
{
DPRINTK(" usb_submit_urb(read bulk) failed, status = %d", status);
}
}
//wake_up(&ATEN2011_port->delta_msr_wait);
//ATEN2011_port->delta_msr_cond=1;
DPRINTK("ATEN2011_change_port_settings ATEN2011_port->shadowLCR is End %x\n",ATEN2011_port->shadowLCR);
return;
}
static int ATEN2011_calc_num_ports(struct usb_serial *serial)
{
__u16 Data=0x00;
int ret =0;
int ATEN2011_2or4ports;
ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),\
ATEN_RDREQ,ATEN_RD_RTYPE,0,GPIO_REGISTER,&Data,VENDOR_READ_LENGTH,ATEN_WDR_TIMEOUT);
//printk("ATEN2011_calc_num_ports GPIO is %x\n",Data);
/* ghostgum: here is where the problem appears to bet */
/* Which of the following are needed? */
/* Greg used the serial->type->num_ports=2 */
/* But the code in the ATEN2011_open relies on serial->num_ports=2 */
if((Data&0x01)==0)
{
ATEN2011_2or4ports=2;
serial->type->num_ports=2;
serial->num_ports=2;
}
//else if(serial->interface->cur_altsetting->desc.bNumEndpoints == 9)
else
{
ATEN2011_2or4ports =4;
serial->type->num_ports=4;
serial->num_ports=4;
}
return ATEN2011_2or4ports;
}
/****************************************************************************
* ATEN2011_startup
****************************************************************************/
static int ATEN2011_startup (struct usb_serial *serial)
{
struct ATENINTL_serial *ATEN2011_serial;
struct ATENINTL_port *ATEN2011_port;
struct usb_device *dev;
int i,status;
int minor;
__u16 Data;
DPRINTK("%s \n"," ATEN2011_startup :entering..........");
if(!serial)
{
DPRINTK("%s\n","Invalid Handler");
return -1;
}
dev = serial->dev;
DPRINTK("%s\n","Entering...");
/* create our private serial structure */
ATEN2011_serial = kzalloc (sizeof(struct ATENINTL_serial), GFP_KERNEL);
if (ATEN2011_serial == NULL)
{
err("%s - Out of memory", __FUNCTION__);
return -ENOMEM;
}
/* resetting the private structure field values to zero */
memset (ATEN2011_serial, 0, sizeof(struct ATENINTL_serial));
ATEN2011_serial->serial = serial;
//initilize status polling flag to FALSE
ATEN2011_serial->status_polling_started = FALSE;
ATEN2011_set_serial_private(serial,ATEN2011_serial);
ATEN2011_serial->ATEN2011_spectrum_2or4ports = ATEN2011_calc_num_ports(serial);
/* we set up the pointers to the endpoints in the ATEN2011_open *
* function, as the structures aren't created yet. */
/* set up port private structures */
for (i = 0; i < serial->num_ports; ++i)
{
ATEN2011_port = kmalloc(sizeof(struct ATENINTL_port), GFP_KERNEL);
if (ATEN2011_port == NULL)
{
err("%s - Out of memory", __FUNCTION__);
ATEN2011_set_serial_private(serial,NULL);
kfree(ATEN2011_serial);
return -ENOMEM;
}
memset(ATEN2011_port, 0, sizeof(struct ATENINTL_port));
/* Initialize all port interrupt end point to port 0 int endpoint *
* Our device has only one interrupt end point comman to all port */
// serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
ATEN2011_port->port = serial->port[i];
//
ATEN2011_set_port_private(serial->port[i],ATEN2011_port);
minor = serial->port[i] ->serial->minor;
if (minor == SERIAL_TTY_NO_MINOR)
minor = 0;
ATEN2011_port->port_num=((serial->port[i]->number - minor)+1);
ATEN2011_port->AppNum = (((__u16)serial->port[i]->number - \
(__u16)(minor))+1)<<8;
if(ATEN2011_port->port_num ==1)
{
ATEN2011_port->SpRegOffset =0x0;
ATEN2011_port->ControlRegOffset =0x1;
ATEN2011_port->DcrRegOffset =0x4 ;
//ATEN2011_port->ClkSelectRegOffset = ;
}
else if((ATEN2011_port->port_num ==2)&&(ATEN2011_serial->ATEN2011_spectrum_2or4ports ==4))
{
ATEN2011_port->SpRegOffset =0x8;
ATEN2011_port->ControlRegOffset =0x9;
ATEN2011_port->DcrRegOffset =0x16;
//ATEN2011_port->ClkSelectRegOffset = ;
}
else if((ATEN2011_port->port_num ==2)&&(ATEN2011_serial->ATEN2011_spectrum_2or4ports ==2))
{
ATEN2011_port->SpRegOffset =0xa;
ATEN2011_port->ControlRegOffset =0xb;
ATEN2011_port->DcrRegOffset =0x19;
//ATEN2011_port->ClkSelectRegOffset = ;
}
else if((ATEN2011_port->port_num ==3)&&(ATEN2011_serial->ATEN2011_spectrum_2or4ports ==4))
{
ATEN2011_port->SpRegOffset =0xa;
ATEN2011_port->ControlRegOffset =0xb;
ATEN2011_port->DcrRegOffset =0x19;
//ATEN2011_port->ClkSelectRegOffset = ;
}
else if((ATEN2011_port->port_num ==4)&&(ATEN2011_serial->ATEN2011_spectrum_2or4ports ==4))
{
ATEN2011_port->SpRegOffset =0xc;
ATEN2011_port->ControlRegOffset =0xd;
ATEN2011_port->DcrRegOffset =0x1c ;
//ATEN2011_port->ClkSelectRegOffset = ;
}
ATEN2011_Dump_serial_port(ATEN2011_port);
ATEN2011_set_port_private(serial->port[i],ATEN2011_port);
//enable rx_disable bit in control register
status=ATEN2011_get_reg_sync(serial->port[i],ATEN2011_port->ControlRegOffset,&Data);
if(status<0) {
DPRINTK("Reading ControlReg failed status-0x%x\n", status);
break;
}
else DPRINTK("ControlReg Reading success val is %x, status%d\n",Data,status);
Data |= 0x08;//setting driver done bit
Data |= 0x04;//sp1_bit to have cts change reflect in modem status reg
//Data |= 0x20; //rx_disable bit
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],ATEN2011_port->ControlRegOffset,Data);
if(status<0) {
DPRINTK("Writing ControlReg failed(rx_disable) status-0x%x\n", status);
break;
}
else DPRINTK("ControlReg Writing success(rx_disable) status%d\n",status);
//Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 and 0x24 in DCR3
Data = 0x01;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],(__u16)(ATEN2011_port->DcrRegOffset+0),Data);
if(status<0) {
DPRINTK("Writing DCR0 failed status-0x%x\n", status);
break;
}
else DPRINTK("DCR0 Writing success status%d\n",status);
Data = 0x05;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],(__u16)(ATEN2011_port->DcrRegOffset+1),Data);
if(status<0) {
DPRINTK("Writing DCR1 failed status-0x%x\n", status);
break;
}
else DPRINTK("DCR1 Writing success status%d\n",status);
Data = 0x24;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],(__u16)(ATEN2011_port->DcrRegOffset+2),Data);
if(status<0) {
DPRINTK("Writing DCR2 failed status-0x%x\n", status);
break;
}
else DPRINTK("DCR2 Writing success status%d\n",status);
// write values in clkstart0x0 and clkmulti 0x20
Data = 0x0;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],CLK_START_VALUE_REGISTER,Data);
if(status<0) {
DPRINTK("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
break;
}
else DPRINTK("CLK_START_VALUE_REGISTER Writing success status%d\n",status);
Data = 0x20;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],CLK_MULTI_REGISTER,Data);
if(status<0) {
DPRINTK("Writing CLK_MULTI_REGISTER failed status-0x%x\n", status);
break;
}
else DPRINTK("CLK_MULTI_REGISTER Writing success status%d\n",status);
//write value 0x0 to scratchpad register
/*
if(RS485mode==0)
Data = 0xC0;
else
Data = 0x00;
status=0;
status=ATEN2011_set_Uart_Reg(serial->port[i],SCRATCH_PAD_REGISTER,Data);
if(status<0) {
DPRINTK("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
break;
}
else DPRINTK("SCRATCH_PAD_REGISTER Writing success status%d\n",status);
*/
/*
//Threshold Registers
if(ATEN2011_serial->ATEN2011_spectrum_2or4ports==4)
{
Data = 0x00;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
(__u16)(THRESHOLD_VAL_SP1_1+(__u16)ATEN2011_Thr_cnt),Data);
DPRINTK("THRESHOLD_VAL offset is%x\n", (__u16)(THRESHOLD_VAL_SP1_1+(__u16)ATEN2011_Thr_cnt));
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
else DPRINTK("THRESHOLD_VAL Writing success status%d\n",status);
ATEN2011_Thr_cnt++;
Data = 0x01;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
(__u16)(THRESHOLD_VAL_SP1_1+(__u16)ATEN2011_Thr_cnt),Data);
DPRINTK("THRESHOLD_VAL offsetis%x\n",(__u16)(THRESHOLD_VAL_SP1_1+(__u16)ATEN2011_Thr_cnt));
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
else DPRINTK("THRESHOLD_VAL Writing success status%d\n",status);
ATEN2011_Thr_cnt++;
}
else
{
if(ATEN2011_port->port_num==1)
{
Data = 0x00;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
0x3f,Data);
DPRINTK("THRESHOLD_VAL offset is 0x3f\n");
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
Data = 0x01;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
0x40,Data);
DPRINTK("THRESHOLD_VAL offset is 0x40\n");
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
}
else
{
Data = 0x00;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
0x43,Data);
DPRINTK("THRESHOLD_VAL offset is 0x43\n");
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
Data = 0x01;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
0x44,Data);
DPRINTK("THRESHOLD_VAL offset is 0x44\n");
if(status<0) {
DPRINTK("Writing THRESHOLD_VAL failed status-0x%x\n",status);
break;
}
}
}
*/
//Zero Length flag register
if((ATEN2011_port->port_num != 1)&&(ATEN2011_serial->ATEN2011_spectrum_2or4ports==2 ))
{
Data = 0xff;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
(__u16)(ZLP_REG1+((__u16)ATEN2011_port->port_num)),Data);
DPRINTK("ZLIP offset%x\n",(__u16)(ZLP_REG1+((__u16)ATEN2011_port->port_num)));
if(status<0) {
DPRINTK("Writing ZLP_REG%d failed status-0x%x\n",i+2,status);
break;
}
else DPRINTK("ZLP_REG%d Writing success status%d\n",i+2,status);
}
else
{
Data = 0xff;
status=0;
status=ATEN2011_set_reg_sync(serial->port[i],\
(__u16)(ZLP_REG1+((__u16)ATEN2011_port->port_num)-0x1),Data);
DPRINTK("ZLIP offset%x\n",(__u16)(ZLP_REG1+((__u16)ATEN2011_port->port_num)-0x1));
if(status<0) {
DPRINTK("Writing ZLP_REG%d failed status-0x%x\n",i+1,status);
break;
}
else DPRINTK("ZLP_REG%d Writing success status%d\n",i+1,status);
}
ATEN2011_port->control_urb = usb_alloc_urb(0,GFP_ATOMIC);
ATEN2011_port->ctrl_buf = kmalloc(16,GFP_KERNEL);
}
ATEN2011_Thr_cnt=0;
//Zero Length flag enable
Data = 0x0f;
status=0;
status=ATEN2011_set_reg_sync(serial->port[0],ZLP_REG5,Data);
if(status<0) {
DPRINTK("Writing ZLP_REG5 failed status-0x%x\n",status);
return -1;
}
else DPRINTK("ZLP_REG5 Writing success status%d\n",status);
/* setting configuration feature to one */
usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8)0x03, 0x00,0x01,0x00, 0x00, 0x00, 5*HZ);
ATEN2011_Thr_cnt =0 ;
return 0;
}
/****************************************************************************
* ATEN2011_shutdown
* This function is called whenever the device is removed from the usb bus.
****************************************************************************/
static void ATEN2011_shutdown (struct usb_serial *serial)
{
int i;
struct ATENINTL_port *ATEN2011_port;
DPRINTK("%s \n"," shutdown :entering..........");
/* MATRIX */
//ThreadState = 1;
/* MATRIX */
if(!serial)
{
DPRINTK("%s","Invalid Handler \n");
return;
}
/* check for the ports to be closed,close the ports and disconnect */
/* free private structure allocated for serial port *
* stop reads and writes on all ports */
for (i=0; i < serial->num_ports; ++i)
{
ATEN2011_port = ATEN2011_get_port_private(serial->port[i]);
kfree(ATEN2011_port->ctrl_buf);
usb_kill_urb(ATEN2011_port->control_urb);
kfree(ATEN2011_port);
ATEN2011_set_port_private(serial->port[i],NULL);
}
/* free private structure allocated for serial device */
kfree(ATEN2011_get_serial_private(serial));
ATEN2011_set_serial_private(serial,NULL);
DPRINTK("%s\n","Thank u :: ");
}
/* Inline functions to check the sanity of a pointer that is passed to us */
static int ATEN2011_serial_paranoia_check (struct usb_serial *serial, const char *function)
{
if (!serial) {
dbg("%s - serial == NULL", function);
return -1;
}
// if (serial->magic != USB_SERIAL_MAGIC) {
// dbg("%s - bad magic number for serial", function);
// return -1;
// }
if (!serial->type) {
dbg("%s - serial->type == NULL!", function);
return -1;
}
return 0;
}
static int ATEN2011_port_paranoia_check (struct usb_serial_port *port, const char *function)
{
if (!port) {
dbg("%s - port == NULL", function);
return -1;
}
// if (port->magic != USB_SERIAL_PORT_MAGIC) {
// dbg("%s - bad magic number for port", function);
// return -1;
// }
if (!port->serial) {
dbg("%s - port->serial == NULL", function);
return -1;
}
return 0;
}
static struct usb_serial* ATEN2011_get_usb_serial (struct usb_serial_port *port, const char *function) {
/* if no port was specified, or it fails a paranoia check */
if (!port ||
ATEN2011_port_paranoia_check (port, function) ||
ATEN2011_serial_paranoia_check (port->serial, function)) {
/* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */
return NULL;
}
return port->serial;
}
/****************************************************************************
* ATENINTL2011_init
* This is called by the module subsystem, or on startup to initialize us
****************************************************************************/
int __init ATENINTL2011_init(void)
{
int retval;
DPRINTK("%s \n"," ATEN2011_init :entering..........");
/* Register with the usb serial */
retval = usb_serial_register (&ATENINTL2011_4port_device);
if(retval)
goto failed_port_device_register;
/* info(DRIVER_DESC " " DRIVER_VERSION); */
printk(KERN_INFO KBUILD_MODNAME ":"
DRIVER_DESC " " DRIVER_VERSION "\n");
/* Register with the usb */
retval = usb_register(&io_driver);
if (retval)
goto failed_usb_register;
if(retval == 0)
{
DPRINTK("%s\n","Leaving...");
return 0;
}
failed_usb_register:
usb_serial_deregister(&ATENINTL2011_4port_device);
failed_port_device_register:
return retval;
}
/****************************************************************************
* ATENINTL2011_exit
* Called when the driver is about to be unloaded.
****************************************************************************/
void __exit ATENINTL2011_exit (void)
{
DPRINTK("%s \n"," ATEN2011_exit :entering..........");
usb_deregister (&io_driver);
usb_serial_deregister (&ATENINTL2011_4port_device);
DPRINTK("%s\n","End...");
}
module_init(ATENINTL2011_init);
module_exit(ATENINTL2011_exit);
/* Module information */
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debug enabled or not");