diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-01-27 23:28:27 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-03 14:53:36 -0700 |
commit | e6d69d91d575d0fb573d3103e1fdff6ec98e52b6 (patch) | |
tree | a94a8b2082fe1e35842b0c6e9f9e03ebac04d7f1 /drivers/staging/uc2322 | |
parent | 793bccbd0e5d22903ab4e28a598159a9bf59a0f1 (diff) |
Staging: add aten2011 usb to serial converter driver.
Many thanks to Russell Lang <gsview@ghostgum.com.au> for his
help in getting this working on newer kernel versions and
for pointing out this driver in the first place.
Cc: Russell Lang <gsview@ghostgum.com.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/uc2322')
-rw-r--r-- | drivers/staging/uc2322/Kconfig | 10 | ||||
-rw-r--r-- | drivers/staging/uc2322/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/uc2322/TODO | 8 | ||||
-rw-r--r-- | drivers/staging/uc2322/aten2011.c | 3625 | ||||
-rw-r--r-- | drivers/staging/uc2322/aten2011.h | 383 | ||||
-rw-r--r-- | drivers/staging/uc2322/aten2011_16C50.h | 58 |
6 files changed, 4085 insertions, 0 deletions
diff --git a/drivers/staging/uc2322/Kconfig b/drivers/staging/uc2322/Kconfig new file mode 100644 index 000000000000..2e0c6e79df2b --- /dev/null +++ b/drivers/staging/uc2322/Kconfig @@ -0,0 +1,10 @@ +config USB_SERIAL_ATEN2011 + tristate "ATEN 2011 USB to serial device support" + depends on USB_SERIAL + default N + ---help--- + Say Y here if you want to use a ATEN 2011 dual port USB to serial + adapter. + + To compile this driver as a module, choose M here: the module will be + called aten2011. diff --git a/drivers/staging/uc2322/Makefile b/drivers/staging/uc2322/Makefile new file mode 100644 index 000000000000..49c18d6e579f --- /dev/null +++ b/drivers/staging/uc2322/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_SERIAL_ATEN2011) += aten2011.o diff --git a/drivers/staging/uc2322/TODO b/drivers/staging/uc2322/TODO new file mode 100644 index 000000000000..8d96ad42a43b --- /dev/null +++ b/drivers/staging/uc2322/TODO @@ -0,0 +1,8 @@ +TODO: + - checkpatch.pl cleanups + - sparse cleanups + - remove dead and useless code (auditing the tty ioctls to + verify that they really are correct and needed.) + +Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and +Russell Lang <gsview@ghostgum.com.au>. diff --git a/drivers/staging/uc2322/aten2011.c b/drivers/staging/uc2322/aten2011.c new file mode 100644 index 000000000000..2c3e477d8d73 --- /dev/null +++ b/drivers/staging/uc2322/aten2011.c @@ -0,0 +1,3625 @@ +/* + * 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. + //////////////////////////////////// |