aboutsummaryrefslogtreecommitdiffstats
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2009-01-28 14:09:51 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-28 14:09:51 -0800
commit0d6d1070903c4cae7f7782ef3cafb7f0295fa2d3 (patch)
tree5c3dcb0a9b9d5446b272dd2af8d0c25da8393437
parent9037c1ff433a050075b49abe85b78e5d5bee6414 (diff)
downloadpatches-0d6d1070903c4cae7f7782ef3cafb7f0295fa2d3.tar.gz
2.6.29-rc2-git4 resync
also add a bunch of staging patches
-rw-r--r--driver-core.current/debugfs-fix-up-debugfs_create_size_t-inline-function.patch36
-rw-r--r--series46
-rw-r--r--staging/staging-add-aten2011-usb-to-serial-converter-driver.patch4143
-rw-r--r--staging/staging-add-b3dfg-driver.patch1070
-rw-r--r--staging/staging-b3dfg-fixups-and-improvements.patch1416
-rw-r--r--staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch277
-rw-r--r--staging/staging-poch-fix-verification-of-memory-area.patch29
-rw-r--r--staging/staging-sxg-add-multicast-support-for-sahara-sxg-driver.patch320
-rw-r--r--version2
9 files changed, 7264 insertions, 75 deletions
diff --git a/driver-core.current/debugfs-fix-up-debugfs_create_size_t-inline-function.patch b/driver-core.current/debugfs-fix-up-debugfs_create_size_t-inline-function.patch
deleted file mode 100644
index fbe673cb2f265c..00000000000000
--- a/driver-core.current/debugfs-fix-up-debugfs_create_size_t-inline-function.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From foo@baz Mon Jan 26 17:24:33 PST 2009
-Date: Mon, 26 Jan 2009 17:24:33 -0800
-To: Greg KH <greg@kroah.com>
-From: Greg Kroah-Hartman <gregkh@suse.de>
-Subject: debugfs: fix up debugfs_create_size_t() inline function
-
-From: Greg Kroah-Hartman <gregkh@suse.de>
-
-If CONFIG_DEBUGFS is disabled, the fixup patch from Inaky will still
-keep the debugfs.h file from compiling properly.
-
-This should now be resolved with this patch.
-
-Cc: Inaky Perez-Gonzalez <inaky@linux.intel.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-
----
- include/linux/debugfs.h | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
---- a/include/linux/debugfs.h
-+++ b/include/linux/debugfs.h
-@@ -162,9 +162,10 @@ static inline struct dentry *debugfs_cre
- return ERR_PTR(-ENODEV);
- }
-
--struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
-- struct dentry *parent,
-- size_t *value)
-+static inline struct dentry *debugfs_create_size_t(const char *name,
-+ mode_t mode,
-+ struct dentry *parent,
-+ size_t *value)
- {
- return ERR_PTR(-ENODEV);
- }
diff --git a/series b/series
index fc947c98bfa72f..b2c1a239e4fbc0 100644
--- a/series
+++ b/series
@@ -11,7 +11,6 @@ gregkh.pre/detect-atomic-counter-underflows.patch
#################################
# Driver core patches for 2.6.29
#################################
-driver-core.current/debugfs-fix-up-debugfs_create_size_t-inline-function.patch
driver-core.current/sync-patch-for-jp_jp-stable_kernel_rules.txt.patch
driver-core.current/uio-add-missing-documentation-of-features-added-recently.patch
driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch
@@ -19,43 +18,6 @@ driver-core.current/driver-core-fix-kernel-doc-parameter-name.patch
#################################
# USB patches for 2.6.29
#################################
-usb.current/usb-cp2101-add-fasttrax-gps-evaluation-kit-vendor-product-id.patch
-usb.current/usb-fix-toggle-mismatch-in-disable_endpoint-paths.patch
-usb.current/usb-storage-add-unusual-devs-entry.patch
-usb.current/usb-don-t-enable-wakeup-by-default-for-pci-host-controllers.patch
-usb.current/usb-fix-suspend-resume-of-pci-usb-controllers.patch
-usb.current/usb-fix-char-device-disconnect-handling.patch
-usb.current/usb-omap1-ohci-buildfix.patch
-usb.current/usb-musb-davinci-buildfix.patch
-usb.current/usb-musb_hdrc-another-davinci-buildfix.patch
-usb.current/usb-musb-free_irq-bugfix.patch
-usb.current/usb-musb-tusb6010-buildfix.patch
-usb.current/usb-musb-uses-endpoint-functions.patch
-usb.current/usb-musb-cppi-bugfixes.patch
-usb.current/usb-musb-cppi-dma-fix.patch
-usb.current/usb-musb-kconfig-fix.patch
-usb.current/usb-composite-fix-bug-should-test-set_alt-function-pointer-before-use-it.patch
-usb.current/usb-composite-fix-bug-low-byte-of-w_index-is-the-usb-interface-number-not-the-whole-2-bytes-of-w_index.patch
-usb.current/usb-cdc-acm-support-some-gps-data-loggers.patch
-usb.current/usb-cdc-acm-quirk-for-mtk-gps.patch
-usb.current/usb-remove-vernier-labpro-from-ldusb.patch
-usb.current/usb-usblp.c-add-usblp_quirk_bidir-to-brother-hl-1440.patch
-usb.current/usb-cp2101-device.patch
-usb.current/usb-ftdi_sio-added-alti-2-vid-and-neptune-3-pid.patch
-usb.current/usb-ftdi_sio-driver-support-of-bar-code-scanner-from-diebold.patch
-usb.current/usb-add-kernel-doc-for-wusb_dev-in-struct-usb_device.patch
-usb.current/usb-usbmon-implement-compat_ioctl.patch
-usb.current/usb-storage-support-of-dane-elec-mediatouch-usb-device.patch
-usb.current/usb-remove-zte-modem-from-unusual_devices.patch
-usb.current/usb-option-driver-onda-device-mt503hs-has-wrong-id.patch
-usb.current/usb-cdc-acm-add-another-conexant-modem-to-the-quirks.patch
-usb.current/usb-new-id-for-ti_usb_3410_5052-driver.patch
-usb.current/usb-gadget-fix-x-y.patch
-usb.current/usb-unusual_dev-usb-storage-needs-to-ignore-a-device.patch
-usb.current/usb-storage-add-another-unusual_dev-for-off-by-one-bug.patch
-usb.current/usb-option-add-quanta-hsdpa-data-card-device-ids.patch
-
-usb.current/usb-driver-for-freescale-quicc-engine-usb-host-controller.patch
#####################################################################
@@ -157,6 +119,7 @@ staging/staging-android-add-lowmemorykiller-documentation.patch
staging/staging-android-task_get_unused_fd_flags-fix-the-wrong-usage-of-tsk-signal.patch
staging/staging-agnx-drivers-staging-agnx-agnx.h-needs-linux-io.h.patch
staging/staging-usbip-usbip_start_threads-handle-kernel_thread-failure.patch
+staging/staging-poch-fix-verification-of-memory-area.patch
# for after .29:
@@ -175,6 +138,7 @@ staging/staging-sxg-fix-build-warnings-in-sxg_ethtool.patch
staging/staging-sxg-remove-firmware-files-from-sgx_ethtool.c.patch
staging/staging-sxg-fix-build-warnings-in-downloadb-firmware-files.patch
staging/staging-sxg-fix-build-warnings-in-sxg.c.patch
+staging/staging-sxg-add-multicast-support-for-sahara-sxg-driver.patch
staging/staging-asus_oled-fix-sparse-warnings-about-using-plain-integer-as-null-pointer.patch
staging/staging-asus_oled-do-not-initialise-statics-to-0-or-null.patch
@@ -272,3 +236,9 @@ staging/staging-dst-fix-build-dependancy.patch
staging/staging-add-stlc45xx-wi-fi-driver-for-stlc4550-4560.patch
+staging/staging-add-aten2011-usb-to-serial-converter-driver.patch
+
+staging/staging-add-b3dfg-driver.patch
+staging/staging-b3dfg-fixups-and-improvements.patch
+staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch
+
diff --git a/staging/staging-add-aten2011-usb-to-serial-converter-driver.patch b/staging/staging-add-aten2011-usb-to-serial-converter-driver.patch
new file mode 100644
index 00000000000000..190509522f1284
--- /dev/null
+++ b/staging/staging-add-aten2011-usb-to-serial-converter-driver.patch
@@ -0,0 +1,4143 @@
+From dfa82523e32a8b1fa87f236f2d4167f7bb252b58 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@suse.de>
+Date: Tue, 27 Jan 2009 23:28:27 -0800
+Subject: 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>
+
+---
+ drivers/staging/Kconfig | 2
+ drivers/staging/Makefile | 1
+ drivers/staging/uc2322/Kconfig | 10
+ drivers/staging/uc2322/Makefile | 1
+ drivers/staging/uc2322/TODO | 8
+ drivers/staging/uc2322/aten2011.c | 3625 ++++++++++++++++++++++++++++++++
+ drivers/staging/uc2322/aten2011.h | 383 +++
+ drivers/staging/uc2322/aten2011_16C50.h | 58
+ 8 files changed, 4088 insertions(+)
+
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -99,5 +99,7 @@ source "drivers/staging/dst/Kconfig"
+
+ source "drivers/staging/stlc45xx/Kconfig"
+
++source "drivers/staging/uc2322/Kconfig"
++
+ endif # !STAGING_EXCLUDE_BUILD
+ endif # STAGING
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -32,3 +32,4 @@ obj-$(CONFIG_EPL) += epl/
+ obj-$(CONFIG_ANDROID) += android/
+ obj-$(CONFIG_DST) += dst/
+ obj-$(CONFIG_STLC45XX) += stlc45xx/
++obj-$(CONFIG_USB_SERIAL_ATEN2011) += uc2322/
+--- /dev/null
++++ b/drivers/staging/uc2322/aten2011_16C50.h
+@@ -0,0 +1,58 @@
++/*
++ * 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
++ */
++
++
++#if !defined(_16C50_H)
++#define _16C50_H
++
++/*************************************
++ * Bit definitions for each register *
++ *************************************/
++#define LCR_BITS_5 0x00 /* 5 bits/char */
++#define LCR_BITS_6 0x01 /* 6 bits/char */
++#define LCR_BITS_7 0x02 /* 7 bits/char */
++#define LCR_BITS_8 0x03 /* 8 bits/char */
++#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
++
++#define LCR_STOP_1 0x00 /* 1 stop bit */
++#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
++#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
++#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
++
++#define LCR_PAR_NONE 0x00 /* No parity */
++#define LCR_PAR_ODD 0x08 /* Odd parity */
++#define LCR_PAR_EVEN 0x18 /* Even parity */
++#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
++#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
++#define LCR_PAR_MASK 0x38 /* Mask for parity field */
++
++#define LCR_SET_BREAK 0x40 /* Set Break condition */
++#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
++
++#define MCR_DTR 0x01 /* Assert DTR */
++#define MCR_RTS 0x02 /* Assert RTS */
++#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
++#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
++#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
++#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
++
++#define ATEN2011_MSR_CTS 0x10 /* Current state of CTS */
++#define ATEN2011_MSR_DSR 0x20 /* Current state of DSR */
++#define ATEN2011_MSR_RI 0x40 /* Current state of RI */
++#define ATEN2011_MSR_CD 0x80 /* Current state of CD */
++
++#endif /* if !defined(_16C50_H) */
++
+--- /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.
++ ////////////////////////////////////
++ // 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");
++
+--- /dev/null
++++ b/drivers/staging/uc2322/aten2011.h
+@@ -0,0 +1,383 @@
++/*
++ * 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
++ */
++
++
++#if !defined(_ATEN_CIP_H_)
++#define _ATEN_CIP_H_
++
++
++#define MAX_RS232_PORTS 2 /* Max # of RS-232 ports per device */
++
++#include <linux/version.h>
++
++/*
++ * All typedef goes here
++ */
++
++
++/* typedefs that the insideout headers need */
++
++#ifndef TRUE
++ #define TRUE (1)
++#endif
++
++#ifndef FALSE
++ #define FALSE (0)
++#endif
++
++#ifndef LOW8
++ #define LOW8(val) ((unsigned char)(val & 0xff))
++#endif
++
++#ifndef HIGH8
++ #define HIGH8(val) ((unsigned char)((val & 0xff00) >> 8))
++#endif
++
++#ifndef NUM_ENTRIES
++ #define NUM_ENTRIES(x) (sizeof(x)/sizeof((x)[0]))
++#endif
++
++#define MAX_SERIALNUMBER_LEN 12
++
++/* The following table is used to map the USBx port number to
++ * the device serial number (or physical USB path), */
++
++#define MAX_ATENPORTS 2
++#define MAX_NAME_LEN 64
++
++#define RAID_REG1 0x30
++#define RAID_REG2 0x31
++
++#define ZLP_REG1 0x3A //Zero_Flag_Reg1 58
++#define ZLP_REG2 0x3B //Zero_Flag_Reg2 59
++#define ZLP_REG3 0x3C //Zero_Flag_Reg3 60
++#define ZLP_REG4 0x3D //Zero_Flag_Reg4 61
++#define ZLP_REG5 0x3E //Zero_Flag_Reg5 62
++
++#define THRESHOLD_VAL_SP1_1 0x3F
++#define THRESHOLD_VAL_SP1_2 0x40
++#define THRESHOLD_VAL_SP2_1 0x41
++#define THRESHOLD_VAL_SP2_2 0x42
++
++#define THRESHOLD_VAL_SP3_1 0x43
++#define THRESHOLD_VAL_SP3_2 0x44
++#define THRESHOLD_VAL_SP4_1 0x45
++#define THRESHOLD_VAL_SP4_2 0x46
++
++
++/* For higher baud Rates use TIOCEXBAUD */
++#define TIOCEXBAUD 0x5462
++
++#define BAUD_1152 0 /* 115200bps * 1 */
++#define BAUD_2304 1 /* 230400bps * 2 */
++#define BAUD_4032 2 /* 403200bps * 3.5 */
++#define BAUD_4608 3 /* 460800bps * 4 */
++#define BAUD_8064 4 /* 806400bps * 7 */
++#define BAUD_9216 5 /* 921600bps * 8 */
++
++#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */
++#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */
++#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */
++
++#ifndef SERIAL_MAGIC
++ #define SERIAL_MAGIC 0x6702
++#endif
++
++#define PORT_MAGIC 0x7301
++
++
++
++/* vendor id and device id defines */
++
++#define USB_VENDOR_ID_ATENINTL 0x0557
++#define ATENINTL_DEVICE_ID_2011 0x2011
++#define ATENINTL_DEVICE_ID_7820 0x7820
++
++/* Product information read from the ATENINTL. Provided for later upgrade */
++
++/* Interrupt Rotinue Defines */
++
++#define SERIAL_IIR_RLS 0x06
++#define SERIAL_IIR_RDA 0x04
++#define SERIAL_IIR_CTI 0x0c
++#define SERIAL_IIR_THR 0x02
++#define SERIAL_IIR_MS 0x00
++
++/*
++ * Emulation of the bit mask on the LINE STATUS REGISTER.
++ */
++#define SERIAL_LSR_DR 0x0001
++#define SERIAL_LSR_OE 0x0002
++#define SERIAL_LSR_PE 0x0004
++#define SERIAL_LSR_FE 0x0008
++#define SERIAL_LSR_BI 0x0010
++#define SERIAL_LSR_THRE 0x0020
++#define SERIAL_LSR_TEMT 0x0040
++#define SERIAL_LSR_FIFOERR 0x0080
++
++//MSR bit defines(place holders)
++#define ATEN_MSR_CTS 0x01
++#define ATEN_MSR_DSR 0x02
++#define ATEN_MSR_RI 0x04
++#define ATEN_MSR_CD 0x08
++#define ATEN_MSR_DELTA_CTS 0x10
++#define ATEN_MSR_DELTA_DSR 0x20
++#define ATEN_MSR_DELTA_RI 0x40
++#define ATEN_MSR_DELTA_CD 0x80
++
++// Serial Port register Address
++#define RECEIVE_BUFFER_REGISTER ((__u16)(0x00))
++#define TRANSMIT_HOLDING_REGISTER ((__u16)(0x00))
++#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
++#define INTERRUPT_IDENT_REGISTER ((__u16)(0x02))
++#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
++#define LINE_CONTROL_REGISTER ((__u16)(0x03))
++#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
++#define LINE_STATUS_REGISTER ((__u16)(0x05))
++#define MODEM_STATUS_REGISTER ((__u16)(0x06))
++#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
++#define DIVISOR_LATCH_LSB ((__u16)(0x00))
++#define DIVISOR_LATCH_MSB ((__u16)(0x01))
++
++#define SP_REGISTER_BASE ((__u16)(0x08))
++#define CONTROL_REGISTER_BASE ((__u16)(0x09))
++#define DCR_REGISTER_BASE ((__u16)(0x16))
++
++#define SP1_REGISTER ((__u16)(0x00))
++#define CONTROL1_REGISTER ((__u16)(0x01))
++#define CLK_MULTI_REGISTER ((__u16)(0x02))
++#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
++#define DCR1_REGISTER ((__u16)(0x04))
++#define GPIO_REGISTER ((__u16)(0x07))
++
++#define CLOCK_SELECT_REG1 ((__u16)(0x13))
++#define CLOCK_SELECT_REG2 ((__u16)(0x14))
++
++#define SERIAL_LCR_DLAB ((__u16)(0x0080))
++
++/*
++ * URB POOL related defines
++ */
++#define NUM_URBS 16 /* URB Count */
++#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
++
++struct ATENINTL_product_info
++{
++ __u16 ProductId; /* Product Identifier */
++ __u8 NumPorts; /* Number of ports on ATENINTL */
++ __u8 ProdInfoVer; /* What version of structure is this? */
++
++ __u32 IsServer :1; /* Set if Server */
++ __u32 IsRS232 :1; /* Set if RS-232 ports exist */
++ __u32 IsRS422 :1; /* Set if RS-422 ports exist */
++ __u32 IsRS485 :1; /* Set if RS-485 ports exist */
++ __u32 IsReserved :28; /* Reserved for later expansion */
++
++ __u8 CpuRev; /* CPU revision level (chg only if s/w visible) */
++ __u8 BoardRev; /* PCB revision level (chg only if s/w visible) */
++
++ __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */
++ __u8 Unused1[1]; /* Available */
++};
++
++// different USB-serial Adapter's ID's table
++static struct usb_device_id ATENINTL_port_id_table [] = {
++ { USB_DEVICE(USB_VENDOR_ID_ATENINTL,ATENINTL_DEVICE_ID_2011) },
++ { USB_DEVICE(USB_VENDOR_ID_ATENINTL,ATENINTL_DEVICE_ID_7820) },
++ { } /* terminating entry */
++};
++
++static __devinitdata struct usb_device_id id_table_combined [] = {
++ { USB_DEVICE(USB_VENDOR_ID_ATENINTL,ATENINTL_DEVICE_ID_2011) },
++ { USB_DEVICE(USB_VENDOR_ID_ATENINTL,ATENINTL_DEVICE_ID_7820) },
++ { } /* terminating entry */
++};
++
++MODULE_DEVICE_TABLE (usb, id_table_combined);
++
++/* This structure holds all of the local port information */
++struct ATENINTL_port
++{
++ int port_num; /*Actual port number in the device(1,2,etc)*/
++ __u8 bulk_out_endpoint; /* the bulk out endpoint handle */
++ unsigned char *bulk_out_buffer; /* buffer used for the bulk out endpoint */
++ struct urb *write_urb; /* write URB for this port */
++ __u8 bulk_in_endpoint; /* the bulk in endpoint handle */
++ unsigned char *bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
++ struct urb *read_urb; /* read URB for this port */
++ __s16 rxBytesAvail;/*the number of bytes that we need to read from this device */
++ __s16 rxBytesRemaining; /* the number of port bytes left to read */
++ char write_in_progress; /* TRUE while a write URB is outstanding */
++ __u8 shadowLCR; /* last LCR value received */
++ __u8 shadowMCR; /* last MCR value received */
++ __u8 shadowMSR; /* last MSR value received */
++ __u8 shadowLSR; /* last LSR value received */
++ __u8 shadowXonChar; /* last value set as XON char in ATENINTL */
++ __u8 shadowXoffChar; /* last value set as XOFF char in ATENINTL */
++ __u8 validDataMask;
++ __u32 baudRate;
++ char open;
++ char openPending;
++ char commandPending;
++ char closePending;
++ char chaseResponsePending;
++ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
++ wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
++ wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
++ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
++ int delta_msr_cond;
++ struct async_icount icount;
++ struct usb_serial_port *port; /* loop back to the owner of this object */
++ /*Offsets*/
++ __u16 AppNum;
++ __u8 SpRegOffset;
++ __u8 ControlRegOffset;
++ __u8 DcrRegOffset;
++ __u8 ClkSelectRegOffset;
++ //for processing control URBS in interrupt context
++ struct urb *control_urb;
++ // __le16 rx_creg;
++ char *ctrl_buf;
++ int MsrLsr;
++
++ struct urb *write_urb_pool[NUM_URBS];
++ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
++ struct ktermios tmp_termios; /* stores the old termios settings */
++ spinlock_t lock; /* private lock */
++};
++
++
++/* This structure holds all of the individual serial device information */
++struct ATENINTL_serial
++{
++ char name[MAX_NAME_LEN+1]; /* string name of this device */
++ struct ATENINTL_product_info product_info; /* Product Info */
++ __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */
++ unsigned char *interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */
++ struct urb * interrupt_read_urb; /* our interrupt urb */
++ __u8 bulk_in_endpoint; /* the bulk in endpoint handle */
++ unsigned char *bulk_in_buffer; /* the buffer we use for the bulk in endpoint */
++ struct urb *read_urb; /* our bulk read urb */
++ __u8 bulk_out_endpoint; /* the bulk out endpoint handle */
++ __s16 rxBytesAvail; /* the number of bytes that we need to read from this device */
++ __u8 rxPort; /* the port that we are currently receiving data for */
++ __u8 rxStatusCode; /* the receive status code */
++ __u8 rxStatusParam; /* the receive status paramater */
++ __s16 rxBytesRemaining; /* the number of port bytes left to read */
++ struct usb_serial *serial; /* loop back to the owner of this object */
++ int ATEN2011_spectrum_2or4ports; //this says the number of ports in the device
++ // Indicates about the no.of opened ports of an individual USB-serial adapater.
++ unsigned int NoOfOpenPorts;
++ // a flag for Status endpoint polling
++ unsigned char status_polling_started;
++};
++
++/* baud rate information */
++struct ATEN2011_divisor_table_entry
++{
++ __u32 BaudRate;
++ __u16 Divisor;
++};
++
++/* Define table of divisors for ATENINTL 2011 hardware *
++ * These assume a 3.6864MHz crystal, the standard /16, and *
++ * MCR.7 = 0. */
++#ifdef NOTATEN2011
++static struct ATEN2011_divisor_table_entry ATEN2011_divisor_table[] = {
++ { 50, 2304},
++ { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */
++ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */
++ { 150, 768},
++ { 300, 384},
++ { 600, 192},
++ { 1200, 96},
++ { 1800, 64},
++ { 2400, 48},
++ { 4800, 24},
++ { 7200, 16},
++ { 9600, 12},
++ { 19200, 6},
++ { 38400, 3},
++ { 57600, 2},
++ { 115200, 1},
++};
++#endif
++
++/* local function prototypes */
++/* function prototypes for all URB callbacks */
++static void ATEN2011_interrupt_callback(struct urb *urb);
++static void ATEN2011_bulk_in_callback(struct urb *urb);
++static void ATEN2011_bulk_out_data_callback(struct urb *urb);
++static void ATEN2011_control_callback(struct urb *urb);
++static int ATEN2011_get_reg(struct ATENINTL_port *ATEN,__u16 Wval, __u16 reg, __u16 * val);
++int handle_newMsr(struct ATENINTL_port *port,__u8 newMsr);
++int handle_newLsr(struct ATENINTL_port *port,__u8 newLsr);
++/* function prototypes for the usbserial callbacks */
++
++#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);
++static void ATEN2011_close(struct tty_struct *tty, struct usb_serial_port *port, struct file *filp);
++static int ATEN2011_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count);
++static int ATEN2011_write_room(struct tty_struct *tty);
++static int ATEN2011_chars_in_buffer(struct tty_struct *tty);
++static void ATEN2011_throttle(struct tty_struct *tty);
++static void ATEN2011_unthrottle(struct tty_struct *tty);
++static void ATEN2011_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios);
++static int ATEN2011_tiocmset(struct tty_struct *tty, struct file *file,
++ unsigned int set, unsigned int clear);
++static int ATEN2011_tiocmget(struct tty_struct *tty, struct file *file);
++static int ATEN2011_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
++static void ATEN2011_break(struct tty_struct *tty, int break_state);
++#else
++static int ATEN2011_open(struct usb_serial_port *port, struct file *filp);
++static void ATEN2011_close(struct usb_serial_port *port, struct file *filp);
++static int ATEN2011_write(struct usb_serial_port *port, const unsigned char *data, int count);
++static int ATEN2011_write_room(struct usb_serial_port *port);
++static int ATEN2011_chars_in_buffer(struct usb_serial_port *port);
++static void ATEN2011_throttle(struct usb_serial_port *port);
++static void ATEN2011_unthrottle(struct usb_serial_port *port);
++static void ATEN2011_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
++static int ATEN2011_tiocmset(struct usb_serial_port *port, struct file *file,
++ unsigned int set, unsigned int clear);
++static int ATEN2011_tiocmget(struct usb_serial_port *port, struct file *file);
++static int ATEN2011_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg);
++static void ATEN2011_break(struct usb_serial_port *port, int break_state);
++#endif
++
++//static void ATEN2011_break_ctl(struct usb_serial_port *port, int break_state );
++
++static int ATEN2011_startup(struct usb_serial *serial);
++static void ATEN2011_shutdown(struct usb_serial *serial);
++//static int ATEN2011_serial_probe(struct usb_serial *serial, const struct usb_device_id *id);
++static int ATEN2011_calc_num_ports(struct usb_serial *serial);
++
++/* function prototypes for all of our local functions */
++static int ATEN2011_calc_baud_rate_divisor(int baudRate, int *divisor,__u16 *clk_sel_val);
++static int ATEN2011_send_cmd_write_baud_rate(struct ATENINTL_port *ATEN2011_port, int baudRate);
++#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);
++static void ATEN2011_block_until_chase_response(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port);
++static void ATEN2011_block_until_tx_empty(struct tty_struct *tty, struct ATENINTL_port *ATEN2011_port);
++#else
++static void ATEN2011_change_port_settings(struct ATENINTL_port *ATEN2011_port, struct ktermios *old_termios);
++static void ATEN2011_block_until_chase_response(struct ATENINTL_port *ATEN2011_port);
++static void ATEN2011_block_until_tx_empty(struct ATENINTL_port *ATEN2011_port);
++#endif
++
++int __init ATENINTL2011_init(void);
++void __exit ATENINTL2011_exit(void);
++
++#endif
+--- /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.
+--- /dev/null
++++ b/drivers/staging/uc2322/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_USB_SERIAL_ATEN2011) += aten2011.o
+--- /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/staging/staging-add-b3dfg-driver.patch b/staging/staging-add-b3dfg-driver.patch
new file mode 100644
index 00000000000000..bc16553ccf9828
--- /dev/null
+++ b/staging/staging-add-b3dfg-driver.patch
@@ -0,0 +1,1070 @@
+From a14d86995e4a1f5ce4de8801b35ca4b5d24723bd Mon Sep 17 00:00:00 2001
+From: Daniel Drake <dsd@gentoo.org>
+Date: Wed, 28 Jan 2009 09:38:07 -0500
+Subject: Staging: add b3dfg driver
+
+From: Daniel Drake <ddrake@brontes3d.com>
+
+Initial b3dfg driver development as preformed by Daniel Drake. All
+basic functionality is completed.
+
+Signed-off-by: Justin Bronder <jsbronder@brontes3d.com>
+Cc: Daniel Drake <ddrake@brontes3d.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/b3dfg/b3dfg.c | 1049 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1049 insertions(+)
+
+--- /dev/null
++++ b/drivers/staging/b3dfg/b3dfg.c
+@@ -0,0 +1,1049 @@
++ /*
++ * Brontes PCI frame grabber driver
++ *
++ * Copyright (C) 2008 3M Company
++ * Contact: Daniel Drake <ddrake@brontes3d.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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
++ */
++
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/ioctl.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++#include <linux/cdev.h>
++#include <linux/list.h>
++#include <linux/poll.h>
++#include <linux/wait.h>
++#include <linux/mm.h>
++#include <linux/version.h>
++#include <linux/mutex.h>
++
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++/* TODO:
++ * locking
++ * queue/wait buffer presents filltime results for each frame?
++ * counting of dropped frames
++ * review endianness
++ */
++
++#ifdef DEBUG
++#define dbg(msg...) printk(msg)
++#else
++#define dbg(msg...)
++#endif
++
++#define DRIVER_NAME "b3dfg"
++#define PFX DRIVER_NAME ": "
++#define B3DFG_MAX_DEVS 4
++#define B3DFG_NR_TRIPLET_BUFFERS 4
++#define B3DFG_NR_FRAME_BUFFERS (B3DFG_NR_TRIPLET_BUFFERS * 3)
++#define B3DFG_FRAMES_PER_BUFFER 3
++
++#define B3DFG_BAR_REGS 0
++#define B3DFG_REGS_LENGTH 0x10000
++
++#define B3DFG_IOC_MAGIC 0xb3 /* dfg :-) */
++#define B3DFG_IOCGFRMSZ _IOR(B3DFG_IOC_MAGIC, 1, int)
++#define B3DFG_IOCTNUMBUFS _IO(B3DFG_IOC_MAGIC, 2)
++#define B3DFG_IOCTTRANS _IO(B3DFG_IOC_MAGIC, 3)
++#define B3DFG_IOCTQUEUEBUF _IO(B3DFG_IOC_MAGIC, 4)
++#define B3DFG_IOCTPOLLBUF _IOWR(B3DFG_IOC_MAGIC, 5, struct b3dfg_poll)
++#define B3DFG_IOCTWAITBUF _IOWR(B3DFG_IOC_MAGIC, 6, struct b3dfg_wait)
++#define B3DFG_IOCGWANDSTAT _IOR(B3DFG_IOC_MAGIC, 7, int)
++
++enum {
++ /* number of 4kb pages per frame */
++ B3D_REG_FRM_SIZE = 0x0,
++
++ /* bit 0: set to enable interrupts */
++ B3D_REG_HW_CTRL = 0x4,
++
++ /* bit 0-1 - 1-based ID of next pending frame transfer (0 = nothing pending)
++ * bit 2 indicates the previous DMA transfer has completed
++ * bit 8:15 - counter of number of discarded triplets */
++ B3D_REG_DMA_STS = 0x8,
++
++ /* bit 0: wand status (1 = present, 0 = disconnected) */
++ B3D_REG_WAND_STS = 0xc,
++
++ /* bus address for DMA transfers. lower 2 bits must be zero because DMA
++ * works with 32 bit word size. */
++ B3D_REG_EC220_DMA_ADDR = 0x8000,
++
++ /* bit 20:0 - number of 32 bit words to be transferred
++ * bit 21:31 - reserved */
++ B3D_REG_EC220_TRF_SIZE = 0x8004,
++
++ /* bit 0 - error bit
++ * bit 1 - interrupt bit (set to generate interrupt at end of transfer)
++ * bit 2 - start bit (set to start transfer)
++ * bit 3 - direction (0 = DMA_TO_DEVICE, 1 = DMA_FROM_DEVICE
++ * bit 4:31 - reserved */
++ B3D_REG_EC220_DMA_STS = 0x8008,
++};
++
++enum b3dfg_buffer_state {
++ B3DFG_BUFFER_POLLED = 0,
++ B3DFG_BUFFER_PENDING,
++ B3DFG_BUFFER_POPULATED,
++};
++
++struct b3dfg_buffer {
++ unsigned char *frame[B3DFG_FRAMES_PER_BUFFER];
++ u8 state;
++ struct list_head list;
++};
++
++struct b3dfg_dev {
++ /* no protection needed: all finalized at initialization time */
++ struct pci_dev *pdev;
++ struct cdev chardev;
++ struct class_device *classdev;
++ void __iomem *regs;
++ unsigned int frame_size;
++
++ /* we want to serialize some ioctl operations */
++ struct mutex ioctl_mutex;
++
++ /* preallocated frame buffers */
++ unsigned char *frame_buffer[B3DFG_NR_FRAME_BUFFERS];
++
++ /* buffers_lock protects num_buffers, buffers, buffer_queue */
++ spinlock_t buffer_lock;
++ int num_buffers;
++ struct b3dfg_buffer *buffers;
++ struct list_head buffer_queue;
++
++ wait_queue_head_t buffer_waitqueue;
++
++ atomic_t mapping_count;
++
++ spinlock_t triplets_dropped_lock;
++ unsigned int triplets_dropped;
++
++ /* FIXME: we need some locking here. this could be accessed in parallel
++ * from the queue_buffer ioctl and the interrupt handler. */
++ int cur_dma_frame_idx;
++ dma_addr_t cur_dma_frame_addr;
++
++ unsigned int transmission_enabled:1;
++ unsigned int triplet_ready:1;
++};
++
++static u8 b3dfg_devices[B3DFG_MAX_DEVS];
++
++static struct class *b3dfg_class;
++static dev_t b3dfg_devt;
++
++static const struct pci_device_id b3dfg_ids[] __devinitdata = {
++ { PCI_DEVICE(0x0b3d, 0x0001) },
++
++ /* FIXME: remove this ID once all boards have been moved to 0xb3d.
++ * this is Eureka's vendor ID that we borrowed before we bought our own. */
++ { PCI_DEVICE(0x1901, 0x0001) },
++ { },
++};
++
++/***** user-visible types *****/
++
++struct b3dfg_poll {
++ int buffer_idx;
++ unsigned int triplets_dropped;
++};
++
++struct b3dfg_wait {
++ int buffer_idx;
++ unsigned int timeout;
++ unsigned int triplets_dropped;
++};
++
++/**** register I/O ****/
++
++static u32 b3dfg_read32(struct b3dfg_dev *fgdev, u16 reg)
++{
++ return ioread32(fgdev->regs + reg);
++}
++
++static void b3dfg_write32(struct b3dfg_dev *fgdev, u16 reg, u32 value)
++{
++ iowrite32(value, fgdev->regs + reg);
++}
++
++/**** buffer management ****/
++
++/* program EC220 for transfer of a specific frame */
++static void setup_frame_transfer(struct b3dfg_dev *fgdev,
++ struct b3dfg_buffer *buf, int frame, int acknowledge)
++{
++ unsigned char *frm_addr;
++ dma_addr_t frm_addr_dma;
++ struct device *dev = &fgdev->pdev->dev;
++ unsigned int frame_size = fgdev->frame_size;
++ unsigned char dma_sts = 0xd;
++
++ frm_addr = buf->frame[frame];
++ frm_addr_dma = dma_map_single(dev, frm_addr, frame_size, DMA_FROM_DEVICE);
++ fgdev->cur_dma_frame_addr = frm_addr_dma;
++ fgdev->cur_dma_frame_idx = frame;
++
++ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR, cpu_to_le32(frm_addr_dma));
++ b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE, cpu_to_le32(frame_size >> 2));
++
++ if (likely(acknowledge))
++ dma_sts |= 0x2;
++ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0xf);
++}
++
++/* retrieve a buffer pointer from a buffer index. also checks that the
++ * requested buffer actually exists. buffer_lock should be held by caller */
++static inline struct b3dfg_buffer *buffer_from_idx(struct b3dfg_dev *fgdev,
++ int idx)
++{
++ if (unlikely(idx >= fgdev->num_buffers))
++ return NULL;
++ return &fgdev->buffers[idx];
++}
++
++/* caller should hold buffer lock */
++static void free_all_buffers(struct b3dfg_dev *fgdev)
++{
++ kfree(fgdev->buffers);
++ fgdev->buffers = NULL;
++ fgdev->num_buffers = 0;
++}
++
++static void dequeue_all_buffers(struct b3dfg_dev *fgdev)
++{
++ int i;
++ for (i = 0; i < fgdev->num_buffers; i++) {
++ struct b3dfg_buffer *buf = &fgdev->buffers[i];
++ buf->state = B3DFG_BUFFER_POLLED;
++ list_del_init(&buf->list);
++ }
++}
++
++/* initialize a buffer: allocate its frames, set default values */
++static void init_buffer(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf,
++ int idx)
++{
++ unsigned int addr_offset = idx * B3DFG_FRAMES_PER_BUFFER;
++ int i;
++
++ memset(buf, 0, sizeof(struct b3dfg_buffer));
++ for (i = 0; i < B3DFG_FRAMES_PER_BUFFER; i++)
++ buf->frame[i] = fgdev->frame_buffer[addr_offset + i];
++
++ INIT_LIST_HEAD(&buf->list);
++}
++
++/* adjust the number of buffers, growing or shrinking the pool appropriately. */
++static int set_num_buffers(struct b3dfg_dev *fgdev, int num_buffers)
++{
++ int i;
++ struct b3dfg_buffer *buffers;
++ unsigned long flags;
++
++ printk(KERN_INFO PFX "set %d buffers\n", num_buffers);
++ if (fgdev->transmission_enabled) {
++ printk(KERN_ERR PFX
++ "cannot set buffer count while transmission is enabled\n");
++ return -EBUSY;
++ }
++
++ if (atomic_read(&fgdev->mapping_count) > 0) {
++ printk(KERN_ERR PFX
++ "cannot set buffer count while memory mappings are active\n");
++ return -EBUSY;
++ }
++
++ if (num_buffers > B3DFG_NR_TRIPLET_BUFFERS) {
++ printk(KERN_ERR PFX "limited to %d triplet buffers\n",
++ B3DFG_NR_TRIPLET_BUFFERS);
++ return -E2BIG;
++ }
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ if (num_buffers == fgdev->num_buffers) {
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return 0;
++ }
++
++ /* free all buffers then allocate new ones */
++ dequeue_all_buffers(fgdev);
++ free_all_buffers(fgdev);
++
++ /* must unlock to allocate GFP_KERNEL memory */
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ if (num_buffers == 0)
++ return 0;
++
++ buffers = kmalloc(num_buffers * sizeof(struct b3dfg_buffer),
++ GFP_KERNEL);
++ if (!buffers)
++ return -ENOMEM;
++
++ for (i = 0; i < num_buffers; i++)
++ init_buffer(fgdev, &buffers[i], i);
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ fgdev->buffers = buffers;
++ fgdev->num_buffers = num_buffers;
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ return 0;
++}
++
++/* queue a buffer to receive data */
++static int queue_buffer(struct b3dfg_dev *fgdev, int bufidx)
++{
++ struct b3dfg_buffer *buf;
++ unsigned long flags;
++ int r = 0;
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ buf = buffer_from_idx(fgdev, bufidx);
++ if (unlikely(!buf)) {
++ r = -ENOENT;
++ goto out;
++ }
++
++ if (unlikely(buf->state == B3DFG_BUFFER_PENDING)) {
++ printk(KERN_ERR PFX "buffer %d is already queued", bufidx);
++ r = -EINVAL;
++ goto out;
++ }
++
++ buf->state = B3DFG_BUFFER_PENDING;
++ list_add_tail(&buf->list, &fgdev->buffer_queue);
++
++ if (fgdev->transmission_enabled && fgdev->triplet_ready) {
++ dbg("triplet is ready, so pushing immediately\n");
++ fgdev->triplet_ready = 0;
++ setup_frame_transfer(fgdev, buf, 0, 0);
++ }
++
++out:
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return r;
++}
++
++/* non-blocking buffer poll. returns 1 if data is present in the buffer,
++ * 0 otherwise */
++static int poll_buffer(struct b3dfg_dev *fgdev, void __user *arg)
++{
++ struct b3dfg_poll p;
++ struct b3dfg_buffer *buf;
++ unsigned long flags;
++ int r = 1;
++
++ if (copy_from_user(&p, arg, sizeof(p)))
++ return -EFAULT;
++
++ if (unlikely(!fgdev->transmission_enabled)) {
++ printk(KERN_ERR PFX
++ "cannot poll buffers when transmission is disabled\n");
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ buf = buffer_from_idx(fgdev, p.buffer_idx);
++ if (unlikely(!buf)) {
++ r = -ENOENT;
++ goto out;
++ }
++
++ if (buf->state != B3DFG_BUFFER_POPULATED) {
++ r = 0;
++ goto out;
++ }
++
++ if (likely(buf->state == B3DFG_BUFFER_POPULATED)) {
++ buf->state = B3DFG_BUFFER_POLLED;
++ spin_lock(&fgdev->triplets_dropped_lock);
++ p.triplets_dropped = fgdev->triplets_dropped;
++ fgdev->triplets_dropped = 0;
++ spin_unlock(&fgdev->triplets_dropped_lock);
++ if (copy_to_user(arg, &p, sizeof(p)))
++ r = -EFAULT;
++ }
++
++out:
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return r;
++}
++
++static u8 buffer_state(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf)
++{
++ unsigned long flags;
++ u8 state;
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ state = buf->state;
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return state;
++}
++
++/* sleep until a specific buffer becomes populated */
++static int wait_buffer(struct b3dfg_dev *fgdev, void __user *arg)
++{
++ struct b3dfg_wait w;
++ struct b3dfg_buffer *buf;
++ unsigned long flags;
++ int r;
++
++ if (copy_from_user(&w, arg, sizeof(w)))
++ return -EFAULT;
++
++ if (unlikely(!fgdev->transmission_enabled)) {
++ printk(KERN_ERR PFX
++ "cannot wait on buffers when transmission is disabled\n");
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ buf = buffer_from_idx(fgdev, w.buffer_idx);
++ if (unlikely(!buf)) {
++ r = -ENOENT;
++ goto out;
++ }
++
++ if (buf->state == B3DFG_BUFFER_POPULATED) {
++ r = 0;
++ goto out_triplets_dropped;
++ }
++
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ /* FIXME: what prevents the buffer going away at this time? */
++
++ if (w.timeout > 0) {
++ r = wait_event_interruptible_timeout(fgdev->buffer_waitqueue,
++ buffer_state(fgdev, buf) == B3DFG_BUFFER_POPULATED,
++ (w.timeout * HZ) / 1000);
++ if (unlikely(r < 0))
++ return r;
++ else if (unlikely(buffer_state(fgdev, buf)
++ != B3DFG_BUFFER_POPULATED))
++ return -ETIMEDOUT;
++ w.timeout = r * 1000 / HZ;
++ } else {
++ r = wait_event_interruptible(fgdev->buffer_waitqueue,
++ buffer_state(fgdev, buf) == B3DFG_BUFFER_POPULATED);
++ if (unlikely(r))
++ return -ERESTARTSYS;
++ }
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ /* FIXME: rediscover buffer? it might have changed during the unlocked
++ * time */
++ buf->state = B3DFG_BUFFER_POLLED;
++
++out_triplets_dropped:
++ spin_lock(&fgdev->triplets_dropped_lock);
++ w.triplets_dropped = fgdev->triplets_dropped;
++ fgdev->triplets_dropped = 0;
++ spin_unlock(&fgdev->triplets_dropped_lock);
++ if (copy_to_user(arg, &w, sizeof(w)))
++ r = -EFAULT;
++out:
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return r;
++}
++
++/**** virtual memory mapping ****/
++
++static void b3dfg_vma_open(struct vm_area_struct *vma)
++{
++ struct b3dfg_dev *fgdev = vma->vm_file->private_data;
++ atomic_inc(&fgdev->mapping_count);
++}
++
++static void b3dfg_vma_close(struct vm_area_struct *vma)
++{
++ struct b3dfg_dev *fgdev = vma->vm_file->private_data;
++ atomic_dec(&fgdev->mapping_count);
++}
++
++/* page fault handler */
++static unsigned long b3dfg_vma_nopfn(struct vm_area_struct *vma,
++ unsigned long address)
++{
++ struct b3dfg_dev *fgdev = vma->vm_file->private_data;
++ unsigned long off = address - vma->vm_start;
++ unsigned int frame_size = fgdev->frame_size;
++ unsigned int buf_size = frame_size * B3DFG_FRAMES_PER_BUFFER;
++ unsigned long flags;
++ unsigned char *addr;
++
++ /* determine which buffer the offset lies within */
++ unsigned int buf_idx = off / buf_size;
++ /* and the offset into the buffer */
++ unsigned int buf_off = off % buf_size;
++
++ /* determine which frame inside the buffer the offset lies in */
++ unsigned int frm_idx = buf_off / frame_size;
++ /* and the offset into the frame */
++ unsigned int frm_off = buf_off % frame_size;
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ if (unlikely(buf_idx > fgdev->num_buffers)) {
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return NOPFN_SIGBUS;
++ }
++
++ addr = fgdev->buffers[buf_idx].frame[frm_idx] + frm_off;
++ vm_insert_pfn(vma, vma->vm_start + off,
++ virt_to_phys(addr) >> PAGE_SHIFT);
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ return NOPFN_REFAULT;
++}
++
++static struct vm_operations_struct b3dfg_vm_ops = {
++ .open = b3dfg_vma_open,
++ .close = b3dfg_vma_close,
++ .nopfn = b3dfg_vma_nopfn,
++};
++
++static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
++{
++ u32 wndstat = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
++ dbg("wand status %x\n", wndstat);
++ return __put_user(wndstat & 0x1, arg);
++}
++
++static int enable_transmission(struct b3dfg_dev *fgdev)
++{
++ u16 command;
++ unsigned long flags;
++
++ printk(KERN_INFO PFX "enable transmission\n");
++
++ /* check we're a bus master */
++ pci_read_config_word(fgdev->pdev, PCI_COMMAND, &command);
++ if (!(command & PCI_COMMAND_MASTER)) {
++ printk(KERN_ERR PFX "not a bus master, force-enabling\n");
++ /* FIXME: why did we lose it in the first place? */
++ pci_write_config_word(fgdev->pdev, PCI_COMMAND,
++ command | PCI_COMMAND_MASTER);
++ }
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ if (fgdev->num_buffers == 0) {
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ printk(KERN_ERR PFX "cannot start transmission to 0 buffers\n");
++ return -EINVAL;
++ }
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ spin_lock_irqsave(&fgdev->triplets_dropped_lock, flags);
++ fgdev->triplets_dropped = 0;
++ spin_unlock_irqrestore(&fgdev->triplets_dropped_lock, flags);
++
++ fgdev->triplet_ready = 0;
++ fgdev->transmission_enabled = 1;
++ fgdev->cur_dma_frame_idx = -1;
++ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 1);
++ return 0;
++}
++
++static void disable_transmission(struct b3dfg_dev *fgdev)
++{
++ unsigned long flags;
++ u32 tmp;
++
++ printk(KERN_INFO PFX "disable transmission\n");
++
++ /* guarantee that no more interrupts will be serviced */
++ fgdev->transmission_enabled = 0;
++ synchronize_irq(fgdev->pdev->irq);
++
++ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
++
++ /* FIXME: temporary debugging only. if the board stops transmitting,
++ * hitting ctrl+c and seeing this message is useful for determining
++ * the state of the board. */
++ tmp = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
++ dbg("brontes DMA_STS reads %x after TX stopped\n", tmp);
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ dequeue_all_buffers(fgdev);
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++}
++
++static int set_transmission(struct b3dfg_dev *fgdev, int enabled)
++{
++ if (enabled && !fgdev->transmission_enabled)
++ return enable_transmission(fgdev);
++ else if (!enabled && fgdev->transmission_enabled)
++ disable_transmission(fgdev);
++ return 0;
++}
++
++static irqreturn_t b3dfg_intr(int irq, void *dev_id)
++{
++ struct b3dfg_dev *fgdev = dev_id;
++ struct device *dev;
++ struct b3dfg_buffer *buf = NULL;
++ unsigned int frame_size;
++ u32 sts;
++ u8 dropped;
++ int next_trf;
++ int need_ack = 1;
++
++ if (unlikely(!fgdev->transmission_enabled)) {
++ printk("ignore interrupt, TX disabled\n");
++ /* FIXME should return IRQ_NONE when we are stable */
++ goto out;
++ }
++
++ sts = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
++ if (unlikely(sts == 0)) {
++ printk("ignore interrupt, brontes DMA status is 0\n");
++ /* FIXME should return IRQ_NONE when we are stable */
++ goto out;
++ }
++
++ dropped = (sts >> 8) & 0xff;
++ dbg(KERN_INFO PFX "got intr, brontes DMASTS=%08x (dropped=%d comp=%d next_trf=%d)\n", sts, dropped, !!(sts & 0x4), sts & 0x3);
++
++ if (unlikely(dropped > 0)) {
++ spin_lock(&fgdev->triplets_dropped_lock);
++ fgdev->triplets_dropped += dropped;
++ spin_unlock(&fgdev->triplets_dropped_lock);
++ }
++
++ dev = &fgdev->pdev->dev;
++ frame_size = fgdev->frame_size;
++
++ spin_lock(&fgdev->buffer_lock);
++ if (unlikely(list_empty(&fgdev->buffer_queue))) {
++ /* FIXME need more sanity checking here */
++ dbg("driver has no buffer ready --> cannot program any more transfers\n");
++ fgdev->triplet_ready = 1;
++ goto out_unlock;
++ }
++
++ next_trf = sts & 0x3;
++
++ if (sts & 0x4) {
++ u32 tmp;
++
++ tmp = b3dfg_read32(fgdev, B3D_REG_EC220_DMA_STS);
++ /* last DMA completed */
++ if (unlikely(tmp & 0x1)) {
++ printk(KERN_ERR PFX "EC220 reports error (%08x)\n", tmp);
++ /* FIXME flesh out error handling */
++ goto out_unlock;
++ }
++ if (unlikely(fgdev->cur_dma_frame_idx == -1)) {
++ printk("ERROR completed but no last idx?\n");
++ /* FIXME flesh out error handling */
++ goto out_unlock;
++ }
++ dma_unmap_single(dev, fgdev->cur_dma_frame_addr, frame_size,
++ DMA_FROM_DEVICE);
++
++ buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
++ if (likely(buf)) {
++ dbg("handle frame completion\n");
++ if (fgdev->cur_dma_frame_idx == B3DFG_FRAMES_PER_BUFFER - 1) {
++ /* last frame of that triplet completed */
++ dbg("triplet completed\n");
++ buf->state = B3DFG_BUFFER_POPULATED;
++ list_del_init(&buf->list);
++ wake_up_interruptible(&fgdev->buffer_waitqueue);
++ }
++ } else {
++ printk("got frame but no buffer!\n");
++ }
++ }
++
++ if (next_trf) {
++ next_trf--;
++
++ buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
++ dbg("program DMA transfer for frame %d\n", next_trf + 1);
++ if (likely(buf)) {
++ if (next_trf != fgdev->cur_dma_frame_idx + 1) {
++ printk("ERROR mismatch, next_trf %d vs cur_dma_frame_idx %d\n",
++ next_trf, fgdev->cur_dma_frame_idx);
++ /* FIXME this is where we should handle dropped triplets */
++ goto out_unlock;
++ }
++ setup_frame_transfer(fgdev, buf, next_trf, 1);
++ need_ack = 0;
++ } else {
++ printk("cannot setup next DMA due to no buffer\n");
++ }
++ } else {
++ fgdev->cur_dma_frame_idx = -1;
++ }
++
++out_unlock:
++ spin_unlock(&fgdev->buffer_lock);
++out:
++ if (need_ack) {
++ dbg("acknowledging interrupt\n");
++ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0x0b);
++ }
++ return IRQ_HANDLED;
++}
++
++static int b3dfg_open(struct inode *inode, struct file *filp)
++{
++ struct b3dfg_dev *fgdev =
++ container_of(inode->i_cdev, struct b3dfg_dev, chardev);
++
++ printk(KERN_INFO PFX "open\n");
++ filp->private_data = fgdev;
++ return 0;
++}
++
++static int b3dfg_release(struct inode *inode, struct file *filp)
++{
++ struct b3dfg_dev *fgdev = filp->private_data;
++ printk(KERN_INFO PFX "release\n");
++ set_transmission(fgdev, 0);
++
++ /* no buffer locking needed, this is serialized */
++ dequeue_all_buffers(fgdev);
++ return set_num_buffers(fgdev, 0);
++}
++
++static long b3dfg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ struct b3dfg_dev *fgdev = filp->private_data;
++ int r;
++
++ switch (cmd) {
++ case B3DFG_IOCGFRMSZ:
++ return __put_user(fgdev->frame_size, (int __user *) arg);
++ case B3DFG_IOCGWANDSTAT:
++ return get_wand_status(fgdev, (int __user *) arg);
++ case B3DFG_IOCTNUMBUFS:
++ mutex_lock(&fgdev->ioctl_mutex);
++ r = set_num_buffers(fgdev, (int) arg);
++ mutex_unlock(&fgdev->ioctl_mutex);
++ return r;
++ case B3DFG_IOCTTRANS:
++ mutex_lock(&fgdev->ioctl_mutex);
++ r = set_transmission(fgdev, (int) arg);
++ mutex_unlock(&fgdev->ioctl_mutex);
++ return r;
++ case B3DFG_IOCTQUEUEBUF:
++ return queue_buffer(fgdev, (int) arg);
++ case B3DFG_IOCTPOLLBUF:
++ return poll_buffer(fgdev, (void __user *) arg);
++ case B3DFG_IOCTWAITBUF:
++ return wait_buffer(fgdev, (void __user *) arg);
++ default:
++ printk(KERN_ERR PFX "unrecognised ioctl %x\n", cmd);
++ return -EINVAL;
++ }
++}
++
++static unsigned int b3dfg_poll(struct file *filp, poll_table *poll_table)
++{
++ struct b3dfg_dev *fgdev = filp->private_data;
++ unsigned long flags;
++ int i;
++ int r = 0;
++
++ /* don't let the user mess with buffer allocations etc. while polling */
++ mutex_lock(&fgdev->ioctl_mutex);
++
++ if (unlikely(!fgdev->transmission_enabled)) {
++ printk(KERN_ERR PFX "cannot poll() when transmission is disabled\n");
++ r = POLLERR;
++ goto out;
++ }
++
++ poll_wait(filp, &fgdev->buffer_waitqueue, poll_table);
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ for (i = 0; i < fgdev->num_buffers; i++) {
++ if (fgdev->buffers[i].state == B3DFG_BUFFER_POPULATED) {
++ r = POLLIN | POLLRDNORM;
++ goto out_buffer_unlock;
++ }
++ }
++
++out_buffer_unlock:
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++out:
++ mutex_unlock(&fgdev->ioctl_mutex);
++ return r;
++}
++
++static int b3dfg_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct b3dfg_dev *fgdev = filp->private_data;
++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++ unsigned long vsize = vma->vm_end - vma->vm_start;
++ unsigned long bufdatalen;
++ unsigned long psize;
++ unsigned long flags;
++ int r = 0;
++
++ /* don't let user mess with buffer allocations during mmap */
++ mutex_lock(&fgdev->ioctl_mutex);
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
++ bufdatalen = fgdev->num_buffers * fgdev->frame_size * 3;
++ psize = bufdatalen - offset;
++
++ if (fgdev->num_buffers == 0) {
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ r = -ENOENT;
++ goto out;
++ }
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ if (vsize > psize) {
++ r = -EINVAL;
++ goto out;
++ }
++
++ vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR | VM_PFNMAP;
++ vma->vm_ops = &b3dfg_vm_ops;
++ b3dfg_vma_open(vma);
++
++out:
++ mutex_unlock(&fgdev->ioctl_mutex);
++ return r;
++}
++
++static struct file_operations b3dfg_fops = {
++ .owner = THIS_MODULE,
++ .open = b3dfg_open,
++ .release = b3dfg_release,
++ .unlocked_ioctl = b3dfg_ioctl,
++ .poll = b3dfg_poll,
++ .mmap = b3dfg_mmap,
++};
++
++static void free_all_frame_buffers(struct b3dfg_dev *fgdev)
++{
++ int i;
++ for (i = 0; i < B3DFG_NR_FRAME_BUFFERS; i++)
++ kfree(fgdev->frame_buffer[i]);
++}
++
++/* initialize device and any data structures. called before any interrupts
++ * are enabled. */
++static int b3dfg_init_dev(struct b3dfg_dev *fgdev)
++{
++ int i;
++ u32 frm_size = b3dfg_read32(fgdev, B3D_REG_FRM_SIZE);
++
++ /* disable interrupts. in abnormal circumstances (e.g. after a crash) the
++ * board may still be transmitting from the previous session. if we ensure
++ * that interrupts are disabled before we later enable them, we are sure
++ * to capture a triplet from the start, rather than starting from frame
++ * 2 or 3. disabling interrupts causes the FG to throw away all buffered
++ * data and stop buffering more until interrupts are enabled again. */
++ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
++
++ fgdev->frame_size = frm_size * 4096;
++ for (i = 0; i < B3DFG_NR_FRAME_BUFFERS; i++) {
++ fgdev->frame_buffer[i] = kmalloc(fgdev->frame_size, GFP_KERNEL);
++ if (!fgdev->frame_buffer[i])
++ goto err_no_mem;
++ }
++
++ INIT_LIST_HEAD(&fgdev->buffer_queue);
++ init_waitqueue_head(&fgdev->buffer_waitqueue);
++ spin_lock_init(&fgdev->buffer_lock);
++ spin_lock_init(&fgdev->triplets_dropped_lock);
++ atomic_set(&fgdev->mapping_count, 0);
++ mutex_init(&fgdev->ioctl_mutex);
++ return 0;
++
++err_no_mem:
++ free_all_frame_buffers(fgdev);
++ return -ENOMEM;
++}
++
++/* find next free minor number, returns -1 if none are availabile */
++static int get_free_minor(void)
++{
++ int i;
++ for (i = 0; i < B3DFG_MAX_DEVS; i++) {
++ if (b3dfg_devices[i] == 0)
++ return i;
++ }
++ return -1;
++}
++
++static int __devinit b3dfg_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct b3dfg_dev *fgdev = kzalloc(sizeof(*fgdev), GFP_KERNEL);
++ int r = 0;
++ int minor = get_free_minor();
++ dev_t devno = MKDEV(MAJOR(b3dfg_devt), minor);
++
++ if (fgdev == NULL)
++ return -ENOMEM;
++
++ if (minor < 0) {
++ printk(KERN_ERR PFX "too many devices found!\n");
++ return -EIO;
++ }
++
++ b3dfg_devices[minor] = 1;
++ printk(KERN_INFO PFX "probe device at %s with IRQ %d\n",
++ pci_name(pdev), pdev->irq);
++
++ cdev_init(&fgdev->chardev, &b3dfg_fops);
++ fgdev->chardev.owner = THIS_MODULE;
++
++ r = cdev_add(&fgdev->chardev, devno, 1);
++ if (r)
++ goto err1;
++
++ fgdev->classdev = class_device_create(b3dfg_class, NULL, devno, &pdev->dev,
++ DRIVER_NAME "%d", minor);
++ if (IS_ERR(fgdev->classdev)) {
++ r = PTR_ERR(fgdev->classdev);
++ goto err2;
++ }
++
++ r = pci_enable_device(pdev);
++ if (r)
++ goto err3;
++
++ if (pci_resource_len(pdev, B3DFG_BAR_REGS) != B3DFG_REGS_LENGTH) {
++ printk(KERN_ERR PFX "invalid register resource size\n");
++ goto err4;
++ }
++
++ if (pci_resource_flags(pdev, B3DFG_BAR_REGS) != IORESOURCE_MEM) {
++ printk(KERN_ERR PFX "invalid resource flags");
++ goto err4;
++ }
++
++ fgdev->regs = ioremap_nocache(pci_resource_start(pdev, B3DFG_BAR_REGS),
++ B3DFG_REGS_LENGTH);
++ if (!fgdev->regs) {
++ printk(KERN_ERR PFX "regs ioremap failed\n");
++ goto err4;
++ }
++
++ fgdev->pdev = pdev;
++ pci_set_drvdata(pdev, fgdev);
++ r = b3dfg_init_dev(fgdev);
++ if (r < 0) {
++ printk(KERN_ERR PFX "failed to initalize device\n");
++ goto err5;
++ }
++
++ r = request_irq(pdev->irq, b3dfg_intr, IRQF_SHARED, DRIVER_NAME, fgdev);
++ if (r) {
++ printk(KERN_ERR PFX "couldn't request irq %d\n", pdev->irq);
++ goto err6;
++ }
++
++ return 0;
++
++err6:
++ free_all_frame_buffers(fgdev);
++err5:
++ iounmap(fgdev->regs);
++err4:
++ pci_disable_device(pdev);
++err3:
++ class_device_unregister(fgdev->classdev);
++err2:
++ cdev_del(&fgdev->chardev);
++err1:
++ kfree(fgdev);
++ if (minor >= 0)
++ b3dfg_devices[minor] = 0;
++ return r;
++}
++
++static void __devexit b3dfg_remove(struct pci_dev *pdev)
++{
++ struct b3dfg_dev *fgdev = pci_get_drvdata(pdev);
++ unsigned int minor = MINOR(fgdev->chardev.dev);
++
++ printk(KERN_INFO PFX "remove\n");
++
++ free_irq(pdev->irq, fgdev);
++ iounmap(fgdev->regs);
++ pci_disable_device(pdev);
++ class_device_unregister(fgdev->classdev);
++ cdev_del(&fgdev->chardev);
++ free_all_frame_buffers(fgdev);
++ kfree(fgdev);
++ b3dfg_devices[minor] = 0;
++}
++
++static struct pci_driver b3dfg_driver = {
++ .name = DRIVER_NAME,
++ .id_table = b3dfg_ids,
++ .probe = b3dfg_probe,
++ .remove = b3dfg_remove,
++};
++
++static int __init b3dfg_module_init(void)
++{
++ int r;
++
++ printk(KERN_INFO PFX "loaded\n");
++
++ b3dfg_class = class_create(THIS_MODULE, DRIVER_NAME);
++ if (IS_ERR(b3dfg_class))
++ return PTR_ERR(b3dfg_class);
++
++ r = alloc_chrdev_region(&b3dfg_devt, 0, B3DFG_MAX_DEVS, DRIVER_NAME);
++ if (r)
++ goto err1;
++
++ r = pci_register_driver(&b3dfg_driver);
++ if (r)
++ goto err2;
++
++ return r;
++
++err2:
++ unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
++err1:
++ class_destroy(b3dfg_class);
++ return r;
++}
++
++static void __exit b3dfg_module_exit(void)
++{
++ printk(KERN_INFO PFX "unloaded\n");
++ pci_unregister_driver(&b3dfg_driver);
++ unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
++ class_destroy(b3dfg_class);
++}
++
++module_init(b3dfg_module_init);
++module_exit(b3dfg_module_exit);
++MODULE_AUTHOR("Daniel Drake <ddrake@brontes3d.com>");
++MODULE_DESCRIPTION("Brontes frame grabber driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, b3dfg_ids);
++
diff --git a/staging/staging-b3dfg-fixups-and-improvements.patch b/staging/staging-b3dfg-fixups-and-improvements.patch
new file mode 100644
index 00000000000000..1ba4a9c7ec9e56
--- /dev/null
+++ b/staging/staging-b3dfg-fixups-and-improvements.patch
@@ -0,0 +1,1416 @@
+From 0e6d6eecf80c82be2e3d881dbd4cffbdd846f727 Mon Sep 17 00:00:00 2001
+From: Duane Griffin <duaneg@dghda.com>
+Date: Wed, 28 Jan 2009 09:50:37 -0500
+Subject: Staging: b3dfg: fixups and improvements
+
+From: Duane Griffin <duaneg@dghda.com>
+
+ - Added support for cable plug/unplug detection.
+ - Improvements to error handling.
+ - Switch to the pci_* DMA API.
+ - Removed set_num_buffers functionality.
+ - Locking review.
+ - Unconditionally disable transmission when releasing device.
+
+Signed-off-by: Justin Bronder <jsbronder@brontes3d.com>
+Cc: Duane Griffin <duaneg@dghda.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/b3dfg/b3dfg.c | 884 ++++++++++++++++++++++--------------------
+ 1 file changed, 480 insertions(+), 404 deletions(-)
+
+--- a/drivers/staging/b3dfg/b3dfg.c
++++ b/drivers/staging/b3dfg/b3dfg.c
+@@ -34,52 +34,52 @@
+ #include <linux/wait.h>
+ #include <linux/mm.h>
+ #include <linux/version.h>
+-#include <linux/mutex.h>
+
+-#include <asm/atomic.h>
+ #include <asm/uaccess.h>
+
+ /* TODO:
+- * locking
+ * queue/wait buffer presents filltime results for each frame?
+ * counting of dropped frames
+ * review endianness
+ */
+
+-#ifdef DEBUG
+-#define dbg(msg...) printk(msg)
+-#else
+-#define dbg(msg...)
+-#endif
++static unsigned int b3dfg_nbuf = 2;
++
++module_param_named(buffer_count, b3dfg_nbuf, uint, 0444);
++
++MODULE_PARM_DESC(buffer_count, "Number of buffers (min 2, default 2)\n");
++
++MODULE_AUTHOR("Daniel Drake <ddrake@brontes3d.com>");
++MODULE_DESCRIPTION("Brontes frame grabber driver");
++MODULE_LICENSE("GPL");
+
+ #define DRIVER_NAME "b3dfg"
+-#define PFX DRIVER_NAME ": "
+ #define B3DFG_MAX_DEVS 4
+-#define B3DFG_NR_TRIPLET_BUFFERS 4
+-#define B3DFG_NR_FRAME_BUFFERS (B3DFG_NR_TRIPLET_BUFFERS * 3)
+ #define B3DFG_FRAMES_PER_BUFFER 3
+
+ #define B3DFG_BAR_REGS 0
+ #define B3DFG_REGS_LENGTH 0x10000
+
+-#define B3DFG_IOC_MAGIC 0xb3 /* dfg :-) */
+-#define B3DFG_IOCGFRMSZ _IOR(B3DFG_IOC_MAGIC, 1, int)
+-#define B3DFG_IOCTNUMBUFS _IO(B3DFG_IOC_MAGIC, 2)
+-#define B3DFG_IOCTTRANS _IO(B3DFG_IOC_MAGIC, 3)
+-#define B3DFG_IOCTQUEUEBUF _IO(B3DFG_IOC_MAGIC, 4)
+-#define B3DFG_IOCTPOLLBUF _IOWR(B3DFG_IOC_MAGIC, 5, struct b3dfg_poll)
+-#define B3DFG_IOCTWAITBUF _IOWR(B3DFG_IOC_MAGIC, 6, struct b3dfg_wait)
+-#define B3DFG_IOCGWANDSTAT _IOR(B3DFG_IOC_MAGIC, 7, int)
++#define B3DFG_IOC_MAGIC 0xb3 /* dfg :-) */
++#define B3DFG_IOCGFRMSZ _IOR(B3DFG_IOC_MAGIC, 1, int)
++#define B3DFG_IOCTNUMBUFS _IO(B3DFG_IOC_MAGIC, 2)
++#define B3DFG_IOCTTRANS _IO(B3DFG_IOC_MAGIC, 3)
++#define B3DFG_IOCTQUEUEBUF _IO(B3DFG_IOC_MAGIC, 4)
++#define B3DFG_IOCTPOLLBUF _IOWR(B3DFG_IOC_MAGIC, 5, struct b3dfg_poll)
++#define B3DFG_IOCTWAITBUF _IOWR(B3DFG_IOC_MAGIC, 6, struct b3dfg_wait)
++#define B3DFG_IOCGWANDSTAT _IOR(B3DFG_IOC_MAGIC, 7, int)
+
+ enum {
+ /* number of 4kb pages per frame */
+ B3D_REG_FRM_SIZE = 0x0,
+
+- /* bit 0: set to enable interrupts */
++ /* bit 0: set to enable interrupts
++ * bit 1: set to enable cable status change interrupts */
+ B3D_REG_HW_CTRL = 0x4,
+
+- /* bit 0-1 - 1-based ID of next pending frame transfer (0 = nothing pending)
++ /* bit 0-1 - 1-based ID of next pending frame transfer (0 = none)
+ * bit 2 indicates the previous DMA transfer has completed
++ * bit 3 indicates wand cable status change
+ * bit 8:15 - counter of number of discarded triplets */
+ B3D_REG_DMA_STS = 0x8,
+
+@@ -110,41 +110,48 @@ enum b3dfg_buffer_state {
+
+ struct b3dfg_buffer {
+ unsigned char *frame[B3DFG_FRAMES_PER_BUFFER];
+- u8 state;
+ struct list_head list;
++ u8 state;
+ };
+
+ struct b3dfg_dev {
++
+ /* no protection needed: all finalized at initialization time */
+ struct pci_dev *pdev;
+- struct cdev chardev;
+- struct class_device *classdev;
++ struct cdev chardev;
++ struct class_device *classdev;
+ void __iomem *regs;
+ unsigned int frame_size;
+
+- /* we want to serialize some ioctl operations */
+- struct mutex ioctl_mutex;
+-
+- /* preallocated frame buffers */
+- unsigned char *frame_buffer[B3DFG_NR_FRAME_BUFFERS];
+-
+- /* buffers_lock protects num_buffers, buffers, buffer_queue */
++ /*
++ * Protects buffer state, including buffer_queue, triplet_ready,
++ * cur_dma_frame_idx & cur_dma_frame_addr.
++ */
+ spinlock_t buffer_lock;
+- int num_buffers;
+ struct b3dfg_buffer *buffers;
+ struct list_head buffer_queue;
+
+- wait_queue_head_t buffer_waitqueue;
++ /* Last frame in triplet transferred (-1 if none). */
++ int cur_dma_frame_idx;
+
+- atomic_t mapping_count;
++ /* Current frame's address for DMA. */
++ dma_addr_t cur_dma_frame_addr;
+
++ /*
++ * Protects cstate_tstamp.
++ * Nests inside buffer_lock.
++ */
++ spinlock_t cstate_lock;
++ unsigned long cstate_tstamp;
++
++ /*
++ * Protects triplets_dropped.
++ * Nests inside buffers_lock.
++ */
+ spinlock_t triplets_dropped_lock;
+ unsigned int triplets_dropped;
+
+- /* FIXME: we need some locking here. this could be accessed in parallel
+- * from the queue_buffer ioctl and the interrupt handler. */
+- int cur_dma_frame_idx;
+- dma_addr_t cur_dma_frame_addr;
++ wait_queue_head_t buffer_waitqueue;
+
+ unsigned int transmission_enabled:1;
+ unsigned int triplet_ready:1;
+@@ -159,11 +166,13 @@ static const struct pci_device_id b3dfg_
+ { PCI_DEVICE(0x0b3d, 0x0001) },
+
+ /* FIXME: remove this ID once all boards have been moved to 0xb3d.
+- * this is Eureka's vendor ID that we borrowed before we bought our own. */
++ * Eureka's vendor ID that we borrowed before we bought our own. */
+ { PCI_DEVICE(0x1901, 0x0001) },
+ { },
+ };
+
++MODULE_DEVICE_TABLE(pci, b3dfg_ids);
++
+ /***** user-visible types *****/
+
+ struct b3dfg_poll {
+@@ -191,145 +200,61 @@ static void b3dfg_write32(struct b3dfg_d
+
+ /**** buffer management ****/
+
+-/* program EC220 for transfer of a specific frame */
+-static void setup_frame_transfer(struct b3dfg_dev *fgdev,
+- struct b3dfg_buffer *buf, int frame, int acknowledge)
++/*
++ * Program EC220 for transfer of a specific frame.
++ * Called with buffer_lock held.
++ */
++static int setup_frame_transfer(struct b3dfg_dev *fgdev,
++ struct b3dfg_buffer *buf, int frame)
+ {
+ unsigned char *frm_addr;
+ dma_addr_t frm_addr_dma;
+- struct device *dev = &fgdev->pdev->dev;
+- unsigned int frame_size = fgdev->frame_size;
+- unsigned char dma_sts = 0xd;
++ unsigned int frm_size = fgdev->frame_size;
+
+ frm_addr = buf->frame[frame];
+- frm_addr_dma = dma_map_single(dev, frm_addr, frame_size, DMA_FROM_DEVICE);
++ frm_addr_dma = pci_map_single(fgdev->pdev, frm_addr,
++ frm_size, PCI_DMA_FROMDEVICE);
++ if (pci_dma_mapping_error(frm_addr_dma))
++ return -ENOMEM;
++
+ fgdev->cur_dma_frame_addr = frm_addr_dma;
+ fgdev->cur_dma_frame_idx = frame;
+
+ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR, cpu_to_le32(frm_addr_dma));
+- b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE, cpu_to_le32(frame_size >> 2));
+-
+- if (likely(acknowledge))
+- dma_sts |= 0x2;
++ b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE, cpu_to_le32(frm_size >> 2));
+ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0xf);
+-}
+-
+-/* retrieve a buffer pointer from a buffer index. also checks that the
+- * requested buffer actually exists. buffer_lock should be held by caller */
+-static inline struct b3dfg_buffer *buffer_from_idx(struct b3dfg_dev *fgdev,
+- int idx)
+-{
+- if (unlikely(idx >= fgdev->num_buffers))
+- return NULL;
+- return &fgdev->buffers[idx];
+-}
+
+-/* caller should hold buffer lock */
+-static void free_all_buffers(struct b3dfg_dev *fgdev)
+-{
+- kfree(fgdev->buffers);
+- fgdev->buffers = NULL;
+- fgdev->num_buffers = 0;
++ return 0;
+ }
+
++/* Caller should hold buffer lock */
+ static void dequeue_all_buffers(struct b3dfg_dev *fgdev)
+ {
+ int i;
+- for (i = 0; i < fgdev->num_buffers; i++) {
++ for (i = 0; i < b3dfg_nbuf; i++) {
+ struct b3dfg_buffer *buf = &fgdev->buffers[i];
+ buf->state = B3DFG_BUFFER_POLLED;
+ list_del_init(&buf->list);
+ }
+ }
+
+-/* initialize a buffer: allocate its frames, set default values */
+-static void init_buffer(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf,
+- int idx)
+-{
+- unsigned int addr_offset = idx * B3DFG_FRAMES_PER_BUFFER;
+- int i;
+-
+- memset(buf, 0, sizeof(struct b3dfg_buffer));
+- for (i = 0; i < B3DFG_FRAMES_PER_BUFFER; i++)
+- buf->frame[i] = fgdev->frame_buffer[addr_offset + i];
+-
+- INIT_LIST_HEAD(&buf->list);
+-}
+-
+-/* adjust the number of buffers, growing or shrinking the pool appropriately. */
+-static int set_num_buffers(struct b3dfg_dev *fgdev, int num_buffers)
+-{
+- int i;
+- struct b3dfg_buffer *buffers;
+- unsigned long flags;
+-
+- printk(KERN_INFO PFX "set %d buffers\n", num_buffers);
+- if (fgdev->transmission_enabled) {
+- printk(KERN_ERR PFX
+- "cannot set buffer count while transmission is enabled\n");
+- return -EBUSY;
+- }
+-
+- if (atomic_read(&fgdev->mapping_count) > 0) {
+- printk(KERN_ERR PFX
+- "cannot set buffer count while memory mappings are active\n");
+- return -EBUSY;
+- }
+-
+- if (num_buffers > B3DFG_NR_TRIPLET_BUFFERS) {
+- printk(KERN_ERR PFX "limited to %d triplet buffers\n",
+- B3DFG_NR_TRIPLET_BUFFERS);
+- return -E2BIG;
+- }
+-
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- if (num_buffers == fgdev->num_buffers) {
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- return 0;
+- }
+-
+- /* free all buffers then allocate new ones */
+- dequeue_all_buffers(fgdev);
+- free_all_buffers(fgdev);
+-
+- /* must unlock to allocate GFP_KERNEL memory */
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+-
+- if (num_buffers == 0)
+- return 0;
+-
+- buffers = kmalloc(num_buffers * sizeof(struct b3dfg_buffer),
+- GFP_KERNEL);
+- if (!buffers)
+- return -ENOMEM;
+-
+- for (i = 0; i < num_buffers; i++)
+- init_buffer(fgdev, &buffers[i], i);
+-
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- fgdev->buffers = buffers;
+- fgdev->num_buffers = num_buffers;
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+-
+- return 0;
+-}
+-
+ /* queue a buffer to receive data */
+ static int queue_buffer(struct b3dfg_dev *fgdev, int bufidx)
+ {
++ struct device *dev = &fgdev->pdev->dev;
+ struct b3dfg_buffer *buf;
+ unsigned long flags;
+ int r = 0;
+
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- buf = buffer_from_idx(fgdev, bufidx);
+- if (unlikely(!buf)) {
++ if (bufidx < 0 || bufidx >= b3dfg_nbuf) {
+ r = -ENOENT;
+ goto out;
+ }
++ buf = &fgdev->buffers[bufidx];
+
+ if (unlikely(buf->state == B3DFG_BUFFER_PENDING)) {
+- printk(KERN_ERR PFX "buffer %d is already queued", bufidx);
++ dev_dbg(dev, "buffer %d is already queued\n", bufidx);
+ r = -EINVAL;
+ goto out;
+ }
+@@ -338,9 +263,11 @@ static int queue_buffer(struct b3dfg_dev
+ list_add_tail(&buf->list, &fgdev->buffer_queue);
+
+ if (fgdev->transmission_enabled && fgdev->triplet_ready) {
+- dbg("triplet is ready, so pushing immediately\n");
++ dev_dbg(dev, "triplet is ready, pushing immediately\n");
+ fgdev->triplet_ready = 0;
+- setup_frame_transfer(fgdev, buf, 0, 0);
++ r = setup_frame_transfer(fgdev, buf, 0);
++ if (r)
++ dev_err(dev, "unable to map DMA buffer\n");
+ }
+
+ out:
+@@ -352,139 +279,159 @@ out:
+ * 0 otherwise */
+ static int poll_buffer(struct b3dfg_dev *fgdev, void __user *arg)
+ {
++ struct device *dev = &fgdev->pdev->dev;
+ struct b3dfg_poll p;
+ struct b3dfg_buffer *buf;
+ unsigned long flags;
+ int r = 1;
++ int arg_out = 0;
+
+ if (copy_from_user(&p, arg, sizeof(p)))
+ return -EFAULT;
+
+ if (unlikely(!fgdev->transmission_enabled)) {
+- printk(KERN_ERR PFX
+- "cannot poll buffers when transmission is disabled\n");
++ dev_dbg(dev, "cannot poll, transmission disabled\n");
+ return -EINVAL;
+ }
+
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- buf = buffer_from_idx(fgdev, p.buffer_idx);
+- if (unlikely(!buf)) {
+- r = -ENOENT;
+- goto out;
+- }
++ if (p.buffer_idx < 0 || p.buffer_idx >= b3dfg_nbuf)
++ return -ENOENT;
+
+- if (buf->state != B3DFG_BUFFER_POPULATED) {
+- r = 0;
+- goto out;
+- }
++ buf = &fgdev->buffers[p.buffer_idx];
++
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+
+ if (likely(buf->state == B3DFG_BUFFER_POPULATED)) {
++ arg_out = 1;
+ buf->state = B3DFG_BUFFER_POLLED;
++
++ /* IRQs already disabled by spin_lock_irqsave above. */
+ spin_lock(&fgdev->triplets_dropped_lock);
+ p.triplets_dropped = fgdev->triplets_dropped;
+ fgdev->triplets_dropped = 0;
+ spin_unlock(&fgdev->triplets_dropped_lock);
+- if (copy_to_user(arg, &p, sizeof(p)))
+- r = -EFAULT;
++ } else {
++ r = 0;
+ }
+
+-out:
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ if (arg_out && copy_to_user(arg, &p, sizeof(p)))
++ r = -EFAULT;
++
+ return r;
+ }
+
+-static u8 buffer_state(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf)
++static unsigned long get_cstate_change(struct b3dfg_dev *fgdev)
++{
++ unsigned long flags, when;
++
++ spin_lock_irqsave(&fgdev->cstate_lock, flags);
++ when = fgdev->cstate_tstamp;
++ spin_unlock_irqrestore(&fgdev->cstate_lock, flags);
++ return when;
++}
++
++static int is_event_ready(struct b3dfg_dev *fgdev, struct b3dfg_buffer *buf,
++ unsigned long when)
+ {
++ int result;
+ unsigned long flags;
+- u8 state;
+
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- state = buf->state;
++ spin_lock(&fgdev->cstate_lock);
++ result = (!fgdev->transmission_enabled ||
++ buf->state == B3DFG_BUFFER_POPULATED ||
++ when != fgdev->cstate_tstamp);
++ spin_unlock(&fgdev->cstate_lock);
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- return state;
++
++ return result;
+ }
+
+ /* sleep until a specific buffer becomes populated */
+ static int wait_buffer(struct b3dfg_dev *fgdev, void __user *arg)
+ {
++ struct device *dev = &fgdev->pdev->dev;
+ struct b3dfg_wait w;
+ struct b3dfg_buffer *buf;
+- unsigned long flags;
++ unsigned long flags, when;
+ int r;
+
+ if (copy_from_user(&w, arg, sizeof(w)))
+ return -EFAULT;
+
+- if (unlikely(!fgdev->transmission_enabled)) {
+- printk(KERN_ERR PFX
+- "cannot wait on buffers when transmission is disabled\n");
++ if (!fgdev->transmission_enabled) {
++ dev_dbg(dev, "cannot wait, transmission disabled\n");
+ return -EINVAL;
+ }
+
++ if (w.buffer_idx < 0 || w.buffer_idx >= b3dfg_nbuf)
++ return -ENOENT;
++
++ buf = &fgdev->buffers[w.buffer_idx];
++
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- buf = buffer_from_idx(fgdev, w.buffer_idx);
+- if (unlikely(!buf)) {
+- r = -ENOENT;
+- goto out;
+- }
+
+ if (buf->state == B3DFG_BUFFER_POPULATED) {
+- r = 0;
++ r = w.timeout;
+ goto out_triplets_dropped;
+ }
+
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- /* FIXME: what prevents the buffer going away at this time? */
+
++ when = get_cstate_change(fgdev);
+ if (w.timeout > 0) {
+ r = wait_event_interruptible_timeout(fgdev->buffer_waitqueue,
+- buffer_state(fgdev, buf) == B3DFG_BUFFER_POPULATED,
++ is_event_ready(fgdev, buf, when),
+ (w.timeout * HZ) / 1000);
++
+ if (unlikely(r < 0))
+- return r;
+- else if (unlikely(buffer_state(fgdev, buf)
+- != B3DFG_BUFFER_POPULATED))
+- return -ETIMEDOUT;
++ goto out;
++
+ w.timeout = r * 1000 / HZ;
+ } else {
+ r = wait_event_interruptible(fgdev->buffer_waitqueue,
+- buffer_state(fgdev, buf) == B3DFG_BUFFER_POPULATED);
+- if (unlikely(r))
+- return -ERESTARTSYS;
++ is_event_ready(fgdev, buf, when));
++
++ if (unlikely(r)) {
++ r = -ERESTARTSYS;
++ goto out;
++ }
++ }
++
++ /* TODO: Inform the user via field(s) in w? */
++ if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev)) {
++ r = -EINVAL;
++ goto out;
+ }
+
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- /* FIXME: rediscover buffer? it might have changed during the unlocked
+- * time */
++
++ if (buf->state != B3DFG_BUFFER_POPULATED) {
++ r = -ETIMEDOUT;
++ goto out_unlock;
++ }
++
+ buf->state = B3DFG_BUFFER_POLLED;
+
+ out_triplets_dropped:
++
++ /* IRQs already disabled by spin_lock_irqsave above. */
+ spin_lock(&fgdev->triplets_dropped_lock);
+ w.triplets_dropped = fgdev->triplets_dropped;
+ fgdev->triplets_dropped = 0;
+ spin_unlock(&fgdev->triplets_dropped_lock);
++
++out_unlock:
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+ if (copy_to_user(arg, &w, sizeof(w)))
+ r = -EFAULT;
+ out:
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+ return r;
+ }
+
+-/**** virtual memory mapping ****/
+-
+-static void b3dfg_vma_open(struct vm_area_struct *vma)
+-{
+- struct b3dfg_dev *fgdev = vma->vm_file->private_data;
+- atomic_inc(&fgdev->mapping_count);
+-}
+-
+-static void b3dfg_vma_close(struct vm_area_struct *vma)
+-{
+- struct b3dfg_dev *fgdev = vma->vm_file->private_data;
+- atomic_dec(&fgdev->mapping_count);
+-}
+-
+-/* page fault handler */
++/* mmap page fault handler */
+ static unsigned long b3dfg_vma_nopfn(struct vm_area_struct *vma,
+ unsigned long address)
+ {
+@@ -492,7 +439,6 @@ static unsigned long b3dfg_vma_nopfn(str
+ unsigned long off = address - vma->vm_start;
+ unsigned int frame_size = fgdev->frame_size;
+ unsigned int buf_size = frame_size * B3DFG_FRAMES_PER_BUFFER;
+- unsigned long flags;
+ unsigned char *addr;
+
+ /* determine which buffer the offset lies within */
+@@ -505,29 +451,24 @@ static unsigned long b3dfg_vma_nopfn(str
+ /* and the offset into the frame */
+ unsigned int frm_off = buf_off % frame_size;
+
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- if (unlikely(buf_idx > fgdev->num_buffers)) {
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ if (unlikely(buf_idx >= b3dfg_nbuf))
+ return NOPFN_SIGBUS;
+- }
+
+ addr = fgdev->buffers[buf_idx].frame[frm_idx] + frm_off;
+ vm_insert_pfn(vma, vma->vm_start + off,
+- virt_to_phys(addr) >> PAGE_SHIFT);
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++ virt_to_phys(addr) >> PAGE_SHIFT);
++
+ return NOPFN_REFAULT;
+ }
+
+ static struct vm_operations_struct b3dfg_vm_ops = {
+- .open = b3dfg_vma_open,
+- .close = b3dfg_vma_close,
+ .nopfn = b3dfg_vma_nopfn,
+ };
+
+ static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
+ {
+ u32 wndstat = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
+- dbg("wand status %x\n", wndstat);
++ dev_dbg(&fgdev->pdev->dev, "wand status %x\n", wndstat);
+ return __put_user(wndstat & 0x1, arg);
+ }
+
+@@ -535,47 +476,63 @@ static int enable_transmission(struct b3
+ {
+ u16 command;
+ unsigned long flags;
++ struct device *dev = &fgdev->pdev->dev;
+
+- printk(KERN_INFO PFX "enable transmission\n");
++ dev_dbg(dev, "enable transmission\n");
+
+- /* check we're a bus master */
++ /* check the cable is plugged in. */
++ if (!b3dfg_read32(fgdev, B3D_REG_WAND_STS)) {
++ dev_dbg(dev, "cannot start transmission without wand\n");
++ return -EINVAL;
++ }
++
++ /*
++ * Check we're a bus master.
++ * TODO: I think we can remove this having added the pci_set_master call
++ */
+ pci_read_config_word(fgdev->pdev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_MASTER)) {
+- printk(KERN_ERR PFX "not a bus master, force-enabling\n");
+- /* FIXME: why did we lose it in the first place? */
++ dev_err(dev, "not a bus master, force-enabling\n");
+ pci_write_config_word(fgdev->pdev, PCI_COMMAND,
+ command | PCI_COMMAND_MASTER);
+ }
+
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- if (fgdev->num_buffers == 0) {
++
++ /* Handle racing enable_transmission calls. */
++ if (fgdev->transmission_enabled) {
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- printk(KERN_ERR PFX "cannot start transmission to 0 buffers\n");
+- return -EINVAL;
++ goto out;
+ }
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+
+- spin_lock_irqsave(&fgdev->triplets_dropped_lock, flags);
++ spin_lock(&fgdev->triplets_dropped_lock);
+ fgdev->triplets_dropped = 0;
+- spin_unlock_irqrestore(&fgdev->triplets_dropped_lock, flags);
++ spin_unlock(&fgdev->triplets_dropped_lock);
+
+ fgdev->triplet_ready = 0;
+- fgdev->transmission_enabled = 1;
+ fgdev->cur_dma_frame_idx = -1;
+- b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 1);
++ fgdev->transmission_enabled = 1;
++
++ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ /* Enable DMA and cable status interrupts. */
++ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0x03);
++
++out:
+ return 0;
+ }
+
+ static void disable_transmission(struct b3dfg_dev *fgdev)
+ {
++ struct device *dev = &fgdev->pdev->dev;
+ unsigned long flags;
+ u32 tmp;
+
+- printk(KERN_INFO PFX "disable transmission\n");
++ dev_dbg(dev, "disable transmission\n");
+
+ /* guarantee that no more interrupts will be serviced */
++ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+ fgdev->transmission_enabled = 0;
+- synchronize_irq(fgdev->pdev->irq);
+
+ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
+
+@@ -583,130 +540,238 @@ static void disable_transmission(struct
+ * hitting ctrl+c and seeing this message is useful for determining
+ * the state of the board. */
+ tmp = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
+- dbg("brontes DMA_STS reads %x after TX stopped\n", tmp);
++ dev_dbg(dev, "DMA_STS reads %x after TX stopped\n", tmp);
+
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+ dequeue_all_buffers(fgdev);
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
++
++ wake_up_interruptible(&fgdev->buffer_waitqueue);
+ }
+
+ static int set_transmission(struct b3dfg_dev *fgdev, int enabled)
+ {
++ int res = 0;
++
+ if (enabled && !fgdev->transmission_enabled)
+- return enable_transmission(fgdev);
++ res = enable_transmission(fgdev);
+ else if (!enabled && fgdev->transmission_enabled)
+ disable_transmission(fgdev);
+- return 0;
++
++ return res;
++}
++
++/* Called in interrupt context. */
++static void handle_cstate_unplug(struct b3dfg_dev *fgdev)
++{
++ /* Disable all interrupts. */
++ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
++
++ /* Stop transmission. */
++ spin_lock(&fgdev->buffer_lock);
++ fgdev->transmission_enabled = 0;
++
++ fgdev->cur_dma_frame_idx = -1;
++ fgdev->triplet_ready = 0;
++ if (fgdev->cur_dma_frame_addr) {
++ pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
++ fgdev->frame_size, PCI_DMA_FROMDEVICE);
++ fgdev->cur_dma_frame_addr = 0;
++ }
++ dequeue_all_buffers(fgdev);
++ spin_unlock(&fgdev->buffer_lock);
++}
++
++/* Called in interrupt context. */
++static void handle_cstate_change(struct b3dfg_dev *fgdev)
++{
++ u32 cstate = b3dfg_read32(fgdev, B3D_REG_WAND_STS);
++ unsigned long when;
++ struct device *dev = &fgdev->pdev->dev;
++
++ dev_dbg(dev, "cable state change: %u\n", cstate);
++
++ /*
++ * When the wand is unplugged we reset our state. The hardware will
++ * have done the same internally.
++ *
++ * Note we should never see a cable *plugged* event, as interrupts
++ * should only be enabled when transmitting, which requires the cable
++ * to be plugged. If we do see one it probably means the cable has been
++ * unplugged and re-plugged very rapidly. Possibly because it has a
++ * broken wire and is momentarily losing contact.
++ *
++ * TODO: At the moment if you plug in the cable then enable transmission
++ * the hardware will raise a couple of spurious interrupts, so
++ * just ignore them for now.
++ *
++ * Once the hardware is fixed we should complain and treat it as an
++ * unplug. Or at least track how frequently it is happening and do
++ * so if too many come in.
++ */
++ if (cstate) {
++ dev_warn(dev, "ignoring unexpected plug event\n");
++ return;
++ }
++ handle_cstate_unplug(fgdev);
++
++ /*
++ * Record cable state change timestamp & wake anyone waiting
++ * on a cable state change. Be paranoid about ensuring events
++ * are not missed if we somehow get two interrupts in a jiffy.
++ */
++ spin_lock(&fgdev->cstate_lock);
++ when = jiffies_64;
++ if (when <= fgdev->cstate_tstamp)
++ when = fgdev->cstate_tstamp + 1;
++ fgdev->cstate_tstamp = when;
++ wake_up_interruptible(&fgdev->buffer_waitqueue);
++ spin_unlock(&fgdev->cstate_lock);
++}
++
++/* Called with buffer_lock held. */
++static void transfer_complete(struct b3dfg_dev *fgdev)
++{
++ struct b3dfg_buffer *buf;
++ struct device *dev = &fgdev->pdev->dev;
++
++ pci_unmap_single(fgdev->pdev, fgdev->cur_dma_frame_addr,
++ fgdev->frame_size, PCI_DMA_FROMDEVICE);
++ fgdev->cur_dma_frame_addr = 0;
++
++ buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
++ if (buf) {
++ dev_dbg(dev, "handle frame completion\n");
++ if (fgdev->cur_dma_frame_idx == B3DFG_FRAMES_PER_BUFFER - 1) {
++
++ /* last frame of that triplet completed */
++ dev_dbg(dev, "triplet completed\n");
++ buf->state = B3DFG_BUFFER_POPULATED;
++ list_del_init(&buf->list);
++ wake_up_interruptible(&fgdev->buffer_waitqueue);
++ }
++ } else {
++ dev_err(dev, "got frame but no buffer!\n");
++ }
++}
++
++/*
++ * Called with buffer_lock held.
++ *
++ * Note that idx is the (1-based) *next* frame to be transferred, while
++ * cur_dma_frame_idx is the (0-based) *last* frame to have been transferred (or
++ * -1 if none). Thus there should be a difference of 2 between them.
++ */
++static bool setup_next_frame_transfer(struct b3dfg_dev *fgdev, int idx)
++{
++ struct b3dfg_buffer *buf;
++ struct device *dev = &fgdev->pdev->dev;
++ bool need_ack = 1;
++
++ dev_dbg(dev, "program DMA transfer for next frame: %d\n", idx);
++
++ buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
++ if (buf) {
++ if (idx == fgdev->cur_dma_frame_idx + 2) {
++ if (setup_frame_transfer(fgdev, buf, idx - 1))
++ dev_err(dev, "unable to map DMA buffer\n");
++ need_ack = 0;
++ } else {
++ dev_err(dev, "frame mismatch, got %d, expected %d\n",
++ idx, fgdev->cur_dma_frame_idx + 2);
++
++ /* FIXME: handle dropped triplets here */
++ }
++ } else {
++ dev_err(dev, "cannot setup DMA, no buffer\n");
++ }
++
++ return need_ack;
+ }
+
+ static irqreturn_t b3dfg_intr(int irq, void *dev_id)
+ {
+ struct b3dfg_dev *fgdev = dev_id;
+- struct device *dev;
+- struct b3dfg_buffer *buf = NULL;
+- unsigned int frame_size;
++ struct device *dev = &fgdev->pdev->dev;
+ u32 sts;
+ u8 dropped;
+- int next_trf;
+- int need_ack = 1;
++ bool need_ack = 1;
++ irqreturn_t res = IRQ_HANDLED;
+
+- if (unlikely(!fgdev->transmission_enabled)) {
+- printk("ignore interrupt, TX disabled\n");
+- /* FIXME should return IRQ_NONE when we are stable */
++ sts = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
++ if (unlikely(sts == 0)) {
++ dev_warn(dev, "ignore interrupt, DMA status is 0\n");
++ res = IRQ_NONE;
+ goto out;
+ }
+
+- sts = b3dfg_read32(fgdev, B3D_REG_DMA_STS);
+- if (unlikely(sts == 0)) {
+- printk("ignore interrupt, brontes DMA status is 0\n");
+- /* FIXME should return IRQ_NONE when we are stable */
++ if (unlikely(!fgdev->transmission_enabled)) {
++ dev_warn(dev, "ignore interrupt, TX disabled\n");
++ res = IRQ_HANDLED;
+ goto out;
+ }
+
++ /* Handle dropped frames, as reported by the hardware. */
+ dropped = (sts >> 8) & 0xff;
+- dbg(KERN_INFO PFX "got intr, brontes DMASTS=%08x (dropped=%d comp=%d next_trf=%d)\n", sts, dropped, !!(sts & 0x4), sts & 0x3);
+-
++ dev_dbg(dev, "intr: DMA_STS=%08x (drop=%d comp=%d next=%d)\n",
++ sts, dropped, !!(sts & 0x4), sts & 0x3);
+ if (unlikely(dropped > 0)) {
+ spin_lock(&fgdev->triplets_dropped_lock);
+ fgdev->triplets_dropped += dropped;
+ spin_unlock(&fgdev->triplets_dropped_lock);
+ }
+
+- dev = &fgdev->pdev->dev;
+- frame_size = fgdev->frame_size;
++ /* Handle a cable state change (i.e. the wand being unplugged). */
++ if (sts & 0x08) {
++ handle_cstate_change(fgdev);
++ goto out;
++ }
+
+ spin_lock(&fgdev->buffer_lock);
+ if (unlikely(list_empty(&fgdev->buffer_queue))) {
++
+ /* FIXME need more sanity checking here */
+- dbg("driver has no buffer ready --> cannot program any more transfers\n");
++ dev_info(dev, "buffer not ready for next transfer\n");
+ fgdev->triplet_ready = 1;
+ goto out_unlock;
+ }
+
+- next_trf = sts & 0x3;
+-
++ /* Has a frame transfer been completed? */
+ if (sts & 0x4) {
+- u32 tmp;
++ u32 dma_status = b3dfg_read32(fgdev, B3D_REG_EC220_DMA_STS);
++
++ /* Check for DMA errors reported by the hardware. */
++ if (unlikely(dma_status & 0x1)) {
++ dev_err(dev, "EC220 error: %08x\n", dma_status);
+
+- tmp = b3dfg_read32(fgdev, B3D_REG_EC220_DMA_STS);
+- /* last DMA completed */
+- if (unlikely(tmp & 0x1)) {
+- printk(KERN_ERR PFX "EC220 reports error (%08x)\n", tmp);
+ /* FIXME flesh out error handling */
+ goto out_unlock;
+ }
++
++ /* Sanity check, we should have a frame index at this point. */
+ if (unlikely(fgdev->cur_dma_frame_idx == -1)) {
+- printk("ERROR completed but no last idx?\n");
++ dev_err(dev, "completed but no last idx?\n");
++
+ /* FIXME flesh out error handling */
+ goto out_unlock;
+ }
+- dma_unmap_single(dev, fgdev->cur_dma_frame_addr, frame_size,
+- DMA_FROM_DEVICE);
+
+- buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
+- if (likely(buf)) {
+- dbg("handle frame completion\n");
+- if (fgdev->cur_dma_frame_idx == B3DFG_FRAMES_PER_BUFFER - 1) {
+- /* last frame of that triplet completed */
+- dbg("triplet completed\n");
+- buf->state = B3DFG_BUFFER_POPULATED;
+- list_del_init(&buf->list);
+- wake_up_interruptible(&fgdev->buffer_waitqueue);
+- }
+- } else {
+- printk("got frame but no buffer!\n");
+- }
++ transfer_complete(fgdev);
+ }
+
+- if (next_trf) {
+- next_trf--;
+-
+- buf = list_entry(fgdev->buffer_queue.next, struct b3dfg_buffer, list);
+- dbg("program DMA transfer for frame %d\n", next_trf + 1);
+- if (likely(buf)) {
+- if (next_trf != fgdev->cur_dma_frame_idx + 1) {
+- printk("ERROR mismatch, next_trf %d vs cur_dma_frame_idx %d\n",
+- next_trf, fgdev->cur_dma_frame_idx);
+- /* FIXME this is where we should handle dropped triplets */
+- goto out_unlock;
+- }
+- setup_frame_transfer(fgdev, buf, next_trf, 1);
+- need_ack = 0;
+- } else {
+- printk("cannot setup next DMA due to no buffer\n");
+- }
+- } else {
++ /* Is there another frame transfer pending? */
++ if (sts & 0x3)
++ need_ack = setup_next_frame_transfer(fgdev, sts & 0x3);
++ else
+ fgdev->cur_dma_frame_idx = -1;
+- }
+
+ out_unlock:
+ spin_unlock(&fgdev->buffer_lock);
+ out:
+ if (need_ack) {
+- dbg("acknowledging interrupt\n");
++ dev_dbg(dev, "acknowledging interrupt\n");
+ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0x0b);
+ }
+- return IRQ_HANDLED;
++ return res;
+ }
+
+ static int b3dfg_open(struct inode *inode, struct file *filp)
+@@ -714,7 +779,7 @@ static int b3dfg_open(struct inode *inod
+ struct b3dfg_dev *fgdev =
+ container_of(inode->i_cdev, struct b3dfg_dev, chardev);
+
+- printk(KERN_INFO PFX "open\n");
++ dev_dbg(&fgdev->pdev->dev, "open\n");
+ filp->private_data = fgdev;
+ return 0;
+ }
+@@ -722,18 +787,14 @@ static int b3dfg_open(struct inode *inod
+ static int b3dfg_release(struct inode *inode, struct file *filp)
+ {
+ struct b3dfg_dev *fgdev = filp->private_data;
+- printk(KERN_INFO PFX "release\n");
+- set_transmission(fgdev, 0);
+-
+- /* no buffer locking needed, this is serialized */
+- dequeue_all_buffers(fgdev);
+- return set_num_buffers(fgdev, 0);
++ dev_dbg(&fgdev->pdev->dev, "release\n");
++ disable_transmission(fgdev);
++ return 0;
+ }
+
+ static long b3dfg_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+ {
+ struct b3dfg_dev *fgdev = filp->private_data;
+- int r;
+
+ switch (cmd) {
+ case B3DFG_IOCGFRMSZ:
+@@ -741,15 +802,11 @@ static long b3dfg_ioctl(struct file *fil
+ case B3DFG_IOCGWANDSTAT:
+ return get_wand_status(fgdev, (int __user *) arg);
+ case B3DFG_IOCTNUMBUFS:
+- mutex_lock(&fgdev->ioctl_mutex);
+- r = set_num_buffers(fgdev, (int) arg);
+- mutex_unlock(&fgdev->ioctl_mutex);
+- return r;
++
++ /* TODO: Remove once userspace stops using this. */
++ return 0;
+ case B3DFG_IOCTTRANS:
+- mutex_lock(&fgdev->ioctl_mutex);
+- r = set_transmission(fgdev, (int) arg);
+- mutex_unlock(&fgdev->ioctl_mutex);
+- return r;
++ return set_transmission(fgdev, (int) arg);
+ case B3DFG_IOCTQUEUEBUF:
+ return queue_buffer(fgdev, (int) arg);
+ case B3DFG_IOCTPOLLBUF:
+@@ -757,7 +814,7 @@ static long b3dfg_ioctl(struct file *fil
+ case B3DFG_IOCTWAITBUF:
+ return wait_buffer(fgdev, (void __user *) arg);
+ default:
+- printk(KERN_ERR PFX "unrecognised ioctl %x\n", cmd);
++ dev_dbg(&fgdev->pdev->dev, "unrecognised ioctl %x\n", cmd);
+ return -EINVAL;
+ }
+ }
+@@ -765,32 +822,26 @@ static long b3dfg_ioctl(struct file *fil
+ static unsigned int b3dfg_poll(struct file *filp, poll_table *poll_table)
+ {
+ struct b3dfg_dev *fgdev = filp->private_data;
+- unsigned long flags;
++ unsigned long flags, when;
+ int i;
+ int r = 0;
+
+- /* don't let the user mess with buffer allocations etc. while polling */
+- mutex_lock(&fgdev->ioctl_mutex);
+-
+- if (unlikely(!fgdev->transmission_enabled)) {
+- printk(KERN_ERR PFX "cannot poll() when transmission is disabled\n");
+- r = POLLERR;
+- goto out;
+- }
+-
++ when = get_cstate_change(fgdev);
+ poll_wait(filp, &fgdev->buffer_waitqueue, poll_table);
++
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- for (i = 0; i < fgdev->num_buffers; i++) {
++ for (i = 0; i < b3dfg_nbuf; i++) {
+ if (fgdev->buffers[i].state == B3DFG_BUFFER_POPULATED) {
+ r = POLLIN | POLLRDNORM;
+- goto out_buffer_unlock;
++ break;
+ }
+ }
+-
+-out_buffer_unlock:
+ spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+-out:
+- mutex_unlock(&fgdev->ioctl_mutex);
++
++ /* TODO: Confirm this is how we want to communicate the change. */
++ if (!fgdev->transmission_enabled || when != get_cstate_change(fgdev))
++ r = POLLERR;
++
+ return r;
+ }
+
+@@ -799,35 +850,18 @@ static int b3dfg_mmap(struct file *filp,
+ struct b3dfg_dev *fgdev = filp->private_data;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long vsize = vma->vm_end - vma->vm_start;
+- unsigned long bufdatalen;
+- unsigned long psize;
+- unsigned long flags;
++ unsigned long bufdatalen = b3dfg_nbuf * fgdev->frame_size * 3;
++ unsigned long psize = bufdatalen - offset;
+ int r = 0;
+
+- /* don't let user mess with buffer allocations during mmap */
+- mutex_lock(&fgdev->ioctl_mutex);
+-
+- spin_lock_irqsave(&fgdev->buffer_lock, flags);
+- bufdatalen = fgdev->num_buffers * fgdev->frame_size * 3;
+- psize = bufdatalen - offset;
+-
+- if (fgdev->num_buffers == 0) {
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- r = -ENOENT;
+- goto out;
+- }
+- spin_unlock_irqrestore(&fgdev->buffer_lock, flags);
+- if (vsize > psize) {
++ if (vsize <= psize) {
++ vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR |
++ VM_PFNMAP;
++ vma->vm_ops = &b3dfg_vm_ops;
++ } else {
+ r = -EINVAL;
+- goto out;
+ }
+
+- vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR | VM_PFNMAP;
+- vma->vm_ops = &b3dfg_vm_ops;
+- b3dfg_vma_open(vma);
+-
+-out:
+- mutex_unlock(&fgdev->ioctl_mutex);
+ return r;
+ }
+
+@@ -842,43 +876,55 @@ static struct file_operations b3dfg_fops
+
+ static void free_all_frame_buffers(struct b3dfg_dev *fgdev)
+ {
+- int i;
+- for (i = 0; i < B3DFG_NR_FRAME_BUFFERS; i++)
+- kfree(fgdev->frame_buffer[i]);
++ int i, j;
++ for (i = 0; i < b3dfg_nbuf; i++)
++ for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++)
++ kfree(fgdev->buffers[i].frame[j]);
++ kfree(fgdev->buffers);
+ }
+
+ /* initialize device and any data structures. called before any interrupts
+ * are enabled. */
+ static int b3dfg_init_dev(struct b3dfg_dev *fgdev)
+ {
+- int i;
++ int i, j;
+ u32 frm_size = b3dfg_read32(fgdev, B3D_REG_FRM_SIZE);
+
+- /* disable interrupts. in abnormal circumstances (e.g. after a crash) the
+- * board may still be transmitting from the previous session. if we ensure
+- * that interrupts are disabled before we later enable them, we are sure
+- * to capture a triplet from the start, rather than starting from frame
+- * 2 or 3. disabling interrupts causes the FG to throw away all buffered
+- * data and stop buffering more until interrupts are enabled again. */
++ /* Disable interrupts. In abnormal circumstances (e.g. after a crash)
++ * the board may still be transmitting from the previous session. If we
++ * ensure that interrupts are disabled before we later enable them, we
++ * are sure to capture a triplet from the start, rather than starting
++ * from frame 2 or 3. Disabling interrupts causes the FG to throw away
++ * all buffered data and stop buffering more until interrupts are
++ * enabled again.
++ */
+ b3dfg_write32(fgdev, B3D_REG_HW_CTRL, 0);
+
+ fgdev->frame_size = frm_size * 4096;
+- for (i = 0; i < B3DFG_NR_FRAME_BUFFERS; i++) {
+- fgdev->frame_buffer[i] = kmalloc(fgdev->frame_size, GFP_KERNEL);
+- if (!fgdev->frame_buffer[i])
+- goto err_no_mem;
++ fgdev->buffers = kzalloc(sizeof(struct b3dfg_buffer) * b3dfg_nbuf,
++ GFP_KERNEL);
++ if (!fgdev->buffers)
++ goto err_no_buf;
++ for (i = 0; i < b3dfg_nbuf; i++) {
++ struct b3dfg_buffer *buf = &fgdev->buffers[i];
++ for (j = 0; j < B3DFG_FRAMES_PER_BUFFER; j++) {
++ buf->frame[j] = kmalloc(fgdev->frame_size, GFP_KERNEL);
++ if (!buf->frame[j])
++ goto err_no_mem;
++ }
++ INIT_LIST_HEAD(&buf->list);
+ }
+
+ INIT_LIST_HEAD(&fgdev->buffer_queue);
+ init_waitqueue_head(&fgdev->buffer_waitqueue);
+ spin_lock_init(&fgdev->buffer_lock);
++ spin_lock_init(&fgdev->cstate_lock);
+ spin_lock_init(&fgdev->triplets_dropped_lock);
+- atomic_set(&fgdev->mapping_count, 0);
+- mutex_init(&fgdev->ioctl_mutex);
+ return 0;
+
+ err_no_mem:
+ free_all_frame_buffers(fgdev);
++err_no_buf:
+ return -ENOMEM;
+ }
+
+@@ -900,84 +946,112 @@ static int __devinit b3dfg_probe(struct
+ int r = 0;
+ int minor = get_free_minor();
+ dev_t devno = MKDEV(MAJOR(b3dfg_devt), minor);
++ unsigned long res_len;
++ resource_size_t res_base;
+
+ if (fgdev == NULL)
+ return -ENOMEM;
+
+ if (minor < 0) {
+- printk(KERN_ERR PFX "too many devices found!\n");
+- return -EIO;
++ dev_err(&pdev->dev, "too many devices found!\n");
++ r = -EIO;
++ goto err_free;
+ }
+
+ b3dfg_devices[minor] = 1;
+- printk(KERN_INFO PFX "probe device at %s with IRQ %d\n",
+- pci_name(pdev), pdev->irq);
++ dev_info(&pdev->dev, "probe device with IRQ %d\n", pdev->irq);
+
+ cdev_init(&fgdev->chardev, &b3dfg_fops);
+ fgdev->chardev.owner = THIS_MODULE;
+
+ r = cdev_add(&fgdev->chardev, devno, 1);
+- if (r)
+- goto err1;
++ if (r) {
++ dev_err(&pdev->dev, "cannot add char device\n");
++ goto err_release_minor;
++ }
+
+- fgdev->classdev = class_device_create(b3dfg_class, NULL, devno, &pdev->dev,
+- DRIVER_NAME "%d", minor);
++ fgdev->classdev = class_device_create(b3dfg_class, NULL, devno,
++ &pdev->dev, DRIVER_NAME "%d",
++ minor);
+ if (IS_ERR(fgdev->classdev)) {
++ dev_err(&pdev->dev, "cannot create class device\n");
+ r = PTR_ERR(fgdev->classdev);
+- goto err2;
++ goto err_del_cdev;
+ }
+
+ r = pci_enable_device(pdev);
+- if (r)
+- goto err3;
++ if (r) {
++ dev_err(&pdev->dev, "cannot enable PCI device\n");
++ goto err_dev_unreg;
++ }
+
+- if (pci_resource_len(pdev, B3DFG_BAR_REGS) != B3DFG_REGS_LENGTH) {
+- printk(KERN_ERR PFX "invalid register resource size\n");
+- goto err4;
++ res_len = pci_resource_len(pdev, B3DFG_BAR_REGS);
++ if (res_len != B3DFG_REGS_LENGTH) {
++ dev_err(&pdev->dev, "invalid register resource size\n");
++ r = -EIO;
++ goto err_disable;
+ }
+
+ if (pci_resource_flags(pdev, B3DFG_BAR_REGS) != IORESOURCE_MEM) {
+- printk(KERN_ERR PFX "invalid resource flags");
+- goto err4;
++ dev_err(&pdev->dev, "invalid resource flags\n");
++ r = -EIO;
++ goto err_disable;
+ }
+
+- fgdev->regs = ioremap_nocache(pci_resource_start(pdev, B3DFG_BAR_REGS),
+- B3DFG_REGS_LENGTH);
++ r = pci_request_regions(pdev, DRIVER_NAME);
++ if (r) {
++ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
++ goto err_disable;
++ }
++
++ pci_set_master(pdev);
++
++ r = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++ if (r) {
++ dev_err(&pdev->dev, "no usable DMA configuration\n");
++ goto err_free_res;
++ }
++
++ res_base = pci_resource_start(pdev, B3DFG_BAR_REGS);
++ fgdev->regs = ioremap_nocache(res_base, res_len);
+ if (!fgdev->regs) {
+- printk(KERN_ERR PFX "regs ioremap failed\n");
+- goto err4;
++ dev_err(&pdev->dev, "regs ioremap failed\n");
++ r = -EIO;
++ goto err_free_res;
+ }
+
+ fgdev->pdev = pdev;
+ pci_set_drvdata(pdev, fgdev);
+ r = b3dfg_init_dev(fgdev);
+ if (r < 0) {
+- printk(KERN_ERR PFX "failed to initalize device\n");
+- goto err5;
++ dev_err(&pdev->dev, "failed to initalize device\n");
++ goto err_unmap;
+ }
+
+ r = request_irq(pdev->irq, b3dfg_intr, IRQF_SHARED, DRIVER_NAME, fgdev);
+ if (r) {
+- printk(KERN_ERR PFX "couldn't request irq %d\n", pdev->irq);
+- goto err6;
++ dev_err(&pdev->dev, "couldn't request irq %d\n", pdev->irq);
++ goto err_free_bufs;
+ }
+
+ return 0;
+
+-err6:
++err_free_bufs:
+ free_all_frame_buffers(fgdev);
+-err5:
++err_unmap:
+ iounmap(fgdev->regs);
+-err4:
++err_free_res:
++ pci_release_regions(pdev);
++err_disable:
+ pci_disable_device(pdev);
+-err3:
++err_dev_unreg:
+ class_device_unregister(fgdev->classdev);
+-err2:
++err_del_cdev:
+ cdev_del(&fgdev->chardev);
+-err1:
++err_release_minor:
++ b3dfg_devices[minor] = 0;
++err_free:
+ kfree(fgdev);
+- if (minor >= 0)
+- b3dfg_devices[minor] = 0;
+ return r;
+ }
+
+@@ -986,10 +1060,11 @@ static void __devexit b3dfg_remove(struc
+ struct b3dfg_dev *fgdev = pci_get_drvdata(pdev);
+ unsigned int minor = MINOR(fgdev->chardev.dev);
+
+- printk(KERN_INFO PFX "remove\n");
++ dev_dbg(&pdev->dev, "remove\n");
+
+ free_irq(pdev->irq, fgdev);
+ iounmap(fgdev->regs);
++ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ class_device_unregister(fgdev->classdev);
+ cdev_del(&fgdev->chardev);
+@@ -1002,14 +1077,20 @@ static struct pci_driver b3dfg_driver =
+ .name = DRIVER_NAME,
+ .id_table = b3dfg_ids,
+ .probe = b3dfg_probe,
+- .remove = b3dfg_remove,
++ .remove = __devexit_p(b3dfg_remove),
+ };
+
+ static int __init b3dfg_module_init(void)
+ {
+ int r;
+
+- printk(KERN_INFO PFX "loaded\n");
++ if (b3dfg_nbuf < 2) {
++ printk(KERN_ERR DRIVER_NAME
++ ": buffer_count is out of range (must be >= 2)");
++ return -EINVAL;
++ }
++
++ printk(KERN_INFO DRIVER_NAME ": loaded\n");
+
+ b3dfg_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(b3dfg_class))
+@@ -1034,7 +1115,7 @@ err1:
+
+ static void __exit b3dfg_module_exit(void)
+ {
+- printk(KERN_INFO PFX "unloaded\n");
++ printk(KERN_INFO DRIVER_NAME ": unloaded\n");
+ pci_unregister_driver(&b3dfg_driver);
+ unregister_chrdev_region(b3dfg_devt, B3DFG_MAX_DEVS);
+ class_destroy(b3dfg_class);
+@@ -1042,8 +1123,3 @@ static void __exit b3dfg_module_exit(voi
+
+ module_init(b3dfg_module_init);
+ module_exit(b3dfg_module_exit);
+-MODULE_AUTHOR("Daniel Drake <ddrake@brontes3d.com>");
+-MODULE_DESCRIPTION("Brontes frame grabber driver");
+-MODULE_LICENSE("GPL");
+-MODULE_DEVICE_TABLE(pci, b3dfg_ids);
+-
diff --git a/staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch b/staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch
new file mode 100644
index 00000000000000..aeccba7acb24f3
--- /dev/null
+++ b/staging/staging-b3dfg-prepare-b3dfg-for-submission-upstream.patch
@@ -0,0 +1,277 @@
+From 20e673d4a906066336a6a45036918fcb7833e611 Mon Sep 17 00:00:00 2001
+From: Justin Bronder <jsbronder@brontes3d.com>
+Date: Wed, 28 Jan 2009 10:06:42 -0500
+Subject: Staging: b3dfg: Prepare b3dfg for submission upstream.
+
+From: Justin Bronder <jsbronder@brontes3d.com>
+
+- Basically, update driver to run with 2.6.28
+ - Conversion from struct class_device to struct device.
+ - Conversion from .nopfn to .fault in vm_operations_struct.
+ - Update use of pci_resource_flags to check for IORESOURCE_SIZEALIGN.
+ - Update use of pci_dma_mapping_error.
+- Minor code cleanup and integration with kernel build system.
+
+Signed-off-by: Justin Bronder <jsbronder@brontes3d.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/Kconfig | 2
+ drivers/staging/Makefile | 1
+ drivers/staging/b3dfg/Kconfig | 9 ++++
+ drivers/staging/b3dfg/Makefile | 1
+ drivers/staging/b3dfg/TODO | 4 +
+ drivers/staging/b3dfg/b3dfg.c | 86 +++++++++++++++++++----------------------
+ 6 files changed, 57 insertions(+), 46 deletions(-)
+
+--- a/drivers/staging/b3dfg/b3dfg.c
++++ b/drivers/staging/b3dfg/b3dfg.c
+@@ -2,7 +2,9 @@
+ * Brontes PCI frame grabber driver
+ *
+ * Copyright (C) 2008 3M Company
+- * Contact: Daniel Drake <ddrake@brontes3d.com>
++ * Contact: Justin Bronder <jsbronder@brontes3d.com>
++ * Original Authors: Daniel Drake <ddrake@brontes3d.com>
++ * Duane Griffin <duaneg@dghda.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -34,14 +36,7 @@
+ #include <linux/wait.h>
+ #include <linux/mm.h>
+ #include <linux/version.h>
+-
+-#include <asm/uaccess.h>
+-
+-/* TODO:
+- * queue/wait buffer presents filltime results for each frame?
+- * counting of dropped frames
+- * review endianness
+- */
++#include <linux/uaccess.h>
+
+ static unsigned int b3dfg_nbuf = 2;
+
+@@ -119,7 +114,7 @@ struct b3dfg_dev {
+ /* no protection needed: all finalized at initialization time */
+ struct pci_dev *pdev;
+ struct cdev chardev;
+- struct class_device *classdev;
++ struct device *dev;
+ void __iomem *regs;
+ unsigned int frame_size;
+
+@@ -164,10 +159,6 @@ static dev_t b3dfg_devt;
+
+ static const struct pci_device_id b3dfg_ids[] __devinitdata = {
+ { PCI_DEVICE(0x0b3d, 0x0001) },
+-
+- /* FIXME: remove this ID once all boards have been moved to 0xb3d.
+- * Eureka's vendor ID that we borrowed before we bought our own. */
+- { PCI_DEVICE(0x1901, 0x0001) },
+ { },
+ };
+
+@@ -213,15 +204,17 @@ static int setup_frame_transfer(struct b
+
+ frm_addr = buf->frame[frame];
+ frm_addr_dma = pci_map_single(fgdev->pdev, frm_addr,
+- frm_size, PCI_DMA_FROMDEVICE);
+- if (pci_dma_mapping_error(frm_addr_dma))
++ frm_size, PCI_DMA_FROMDEVICE);
++ if (pci_dma_mapping_error(fgdev->pdev, frm_addr_dma))
+ return -ENOMEM;
+
+ fgdev->cur_dma_frame_addr = frm_addr_dma;
+ fgdev->cur_dma_frame_idx = frame;
+
+- b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR, cpu_to_le32(frm_addr_dma));
+- b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE, cpu_to_le32(frm_size >> 2));
++ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_ADDR,
++ cpu_to_le32(frm_addr_dma));
++ b3dfg_write32(fgdev, B3D_REG_EC220_TRF_SIZE,
++ cpu_to_le32(frm_size >> 2));
+ b3dfg_write32(fgdev, B3D_REG_EC220_DMA_STS, 0xf);
+
+ return 0;
+@@ -248,6 +241,7 @@ static int queue_buffer(struct b3dfg_dev
+
+ spin_lock_irqsave(&fgdev->buffer_lock, flags);
+ if (bufidx < 0 || bufidx >= b3dfg_nbuf) {
++ dev_dbg(dev, "Invalid buffer index, %d\n", bufidx);
+ r = -ENOENT;
+ goto out;
+ }
+@@ -432,11 +426,11 @@ out:
+ }
+
+ /* mmap page fault handler */
+-static unsigned long b3dfg_vma_nopfn(struct vm_area_struct *vma,
+- unsigned long address)
++static int b3dfg_vma_fault(struct vm_area_struct *vma,
++ struct vm_fault *vmf)
+ {
+ struct b3dfg_dev *fgdev = vma->vm_file->private_data;
+- unsigned long off = address - vma->vm_start;
++ unsigned long off = vmf->pgoff << PAGE_SHIFT;
+ unsigned int frame_size = fgdev->frame_size;
+ unsigned int buf_size = frame_size * B3DFG_FRAMES_PER_BUFFER;
+ unsigned char *addr;
+@@ -452,17 +446,17 @@ static unsigned long b3dfg_vma_nopfn(str
+ unsigned int frm_off = buf_off % frame_size;
+
+ if (unlikely(buf_idx >= b3dfg_nbuf))
+- return NOPFN_SIGBUS;
++ return VM_FAULT_SIGBUS;
+
+ addr = fgdev->buffers[buf_idx].frame[frm_idx] + frm_off;
+- vm_insert_pfn(vma, vma->vm_start + off,
+- virt_to_phys(addr) >> PAGE_SHIFT);
++ vm_insert_pfn(vma, (unsigned long)vmf->virtual_address,
++ virt_to_phys(addr) >> PAGE_SHIFT);
+
+- return NOPFN_REFAULT;
++ return VM_FAULT_NOPAGE;
+ }
+
+ static struct vm_operations_struct b3dfg_vm_ops = {
+- .nopfn = b3dfg_vma_nopfn,
++ .fault = b3dfg_vma_fault,
+ };
+
+ static int get_wand_status(struct b3dfg_dev *fgdev, int __user *arg)
+@@ -601,12 +595,12 @@ static void handle_cstate_change(struct
+ * broken wire and is momentarily losing contact.
+ *
+ * TODO: At the moment if you plug in the cable then enable transmission
+- * the hardware will raise a couple of spurious interrupts, so
+- * just ignore them for now.
++ * the hardware will raise a couple of spurious interrupts, so
++ * just ignore them for now.
+ *
+- * Once the hardware is fixed we should complain and treat it as an
+- * unplug. Or at least track how frequently it is happening and do
+- * so if too many come in.
++ * Once the hardware is fixed we should complain and treat it as an
++ * unplug. Or at least track how frequently it is happening and do
++ * so if too many come in.
+ */
+ if (cstate) {
+ dev_warn(dev, "ignoring unexpected plug event\n");
+@@ -801,10 +795,6 @@ static long b3dfg_ioctl(struct file *fil
+ return __put_user(fgdev->frame_size, (int __user *) arg);
+ case B3DFG_IOCGWANDSTAT:
+ return get_wand_status(fgdev, (int __user *) arg);
+- case B3DFG_IOCTNUMBUFS:
+-
+- /* TODO: Remove once userspace stops using this. */
+- return 0;
+ case B3DFG_IOCTTRANS:
+ return set_transmission(fgdev, (int) arg);
+ case B3DFG_IOCTQUEUEBUF:
+@@ -970,12 +960,16 @@ static int __devinit b3dfg_probe(struct
+ goto err_release_minor;
+ }
+
+- fgdev->classdev = class_device_create(b3dfg_class, NULL, devno,
+- &pdev->dev, DRIVER_NAME "%d",
+- minor);
+- if (IS_ERR(fgdev->classdev)) {
+- dev_err(&pdev->dev, "cannot create class device\n");
+- r = PTR_ERR(fgdev->classdev);
++ fgdev->dev = device_create(
++ b3dfg_class,
++ &pdev->dev,
++ devno,
++ dev_get_drvdata(&pdev->dev),
++ DRIVER_NAME "%d", minor);
++
++ if (IS_ERR(fgdev->dev)) {
++ dev_err(&pdev->dev, "cannot create device\n");
++ r = PTR_ERR(fgdev->dev);
+ goto err_del_cdev;
+ }
+
+@@ -992,12 +986,12 @@ static int __devinit b3dfg_probe(struct
+ goto err_disable;
+ }
+
+- if (pci_resource_flags(pdev, B3DFG_BAR_REGS) != IORESOURCE_MEM) {
++ if (pci_resource_flags(pdev, B3DFG_BAR_REGS)
++ != (IORESOURCE_MEM | IORESOURCE_SIZEALIGN)) {
+ dev_err(&pdev->dev, "invalid resource flags\n");
+ r = -EIO;
+ goto err_disable;
+ }
+-
+ r = pci_request_regions(pdev, DRIVER_NAME);
+ if (r) {
+ dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+@@ -1045,7 +1039,7 @@ err_free_res:
+ err_disable:
+ pci_disable_device(pdev);
+ err_dev_unreg:
+- class_device_unregister(fgdev->classdev);
++ device_destroy(b3dfg_class, devno);
+ err_del_cdev:
+ cdev_del(&fgdev->chardev);
+ err_release_minor:
+@@ -1066,7 +1060,7 @@ static void __devexit b3dfg_remove(struc
+ iounmap(fgdev->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+- class_device_unregister(fgdev->classdev);
++ device_destroy(b3dfg_class, MKDEV(MAJOR(b3dfg_devt), minor));
+ cdev_del(&fgdev->chardev);
+ free_all_frame_buffers(fgdev);
+ kfree(fgdev);
+@@ -1086,7 +1080,7 @@ static int __init b3dfg_module_init(void
+
+ if (b3dfg_nbuf < 2) {
+ printk(KERN_ERR DRIVER_NAME
+- ": buffer_count is out of range (must be >= 2)");
++ ": buffer_count is out of range (must be >= 2)");
+ return -EINVAL;
+ }
+
+--- /dev/null
++++ b/drivers/staging/b3dfg/Kconfig
+@@ -0,0 +1,9 @@
++config B3DFG
++ tristate "Brontes 3d Frame Framegrabber"
++ default n
++ ---help---
++ This driver provides support for the Brontes 3d Framegrabber
++ PCI card.
++
++ To compile this driver as a module, choose M here. The module
++ will be called b3dfg.
+--- /dev/null
++++ b/drivers/staging/b3dfg/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_B3DFG) += b3dfg.o
+--- /dev/null
++++ b/drivers/staging/b3dfg/TODO
+@@ -0,0 +1,4 @@
++
++ - queue/wait buffer presents filltime results for each frame?
++ - counting of dropped frames
++ - review endianness
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -101,5 +101,7 @@ source "drivers/staging/stlc45xx/Kconfig
+
+ source "drivers/staging/uc2322/Kconfig"
+
++source "drivers/staging/b3dfg/Kconfig"
++
+ endif # !STAGING_EXCLUDE_BUILD
+ endif # STAGING
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -33,3 +33,4 @@ obj-$(CONFIG_ANDROID) += android/
+ obj-$(CONFIG_DST) += dst/
+ obj-$(CONFIG_STLC45XX) += stlc45xx/
+ obj-$(CONFIG_USB_SERIAL_ATEN2011) += uc2322/
++obj-$(CONFIG_B3DFG) += b3dfg/
diff --git a/staging/staging-poch-fix-verification-of-memory-area.patch b/staging/staging-poch-fix-verification-of-memory-area.patch
new file mode 100644
index 00000000000000..07c9a8fa2f7264
--- /dev/null
+++ b/staging/staging-poch-fix-verification-of-memory-area.patch
@@ -0,0 +1,29 @@
+From roel.kluin@gmail.com Wed Jan 28 14:00:58 2009
+From: Roel Kluin <roel.kluin@gmail.com>
+Date: Wed, 28 Jan 2009 22:14:17 +0100
+Subject: Staging: poch: fix verification of memory area
+To: Greg KH <gregkh@suse.de>
+Cc: lkml <linux-kernel@vger.kernel.org>
+Message-ID: <4980CAA9.1060301@gmail.com>
+
+
+fix verification of memory area
+
+Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/poch/poch.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/staging/poch/poch.c
++++ b/drivers/staging/poch/poch.c
+@@ -1026,7 +1026,7 @@ static int poch_ioctl(struct inode *inod
+ }
+ break;
+ case POCH_IOC_GET_COUNTERS:
+- if (access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters)))
++ if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters)))
+ return -EFAULT;
+
+ spin_lock_irq(&channel->counters_lock);
diff --git a/staging/staging-sxg-add-multicast-support-for-sahara-sxg-driver.patch b/staging/staging-sxg-add-multicast-support-for-sahara-sxg-driver.patch
new file mode 100644
index 00000000000000..1f65a89233ea66
--- /dev/null
+++ b/staging/staging-sxg-add-multicast-support-for-sahara-sxg-driver.patch
@@ -0,0 +1,320 @@
+From mithlesh@linsyssoft.com Wed Jan 28 13:57:57 2009
+From: Mithlesh Thukral <mithlesh@linsyssoft.com>
+Date: Wed, 28 Jan 2009 07:08:11 +0530 (IST)
+Subject: Staging: sxg: Add multicast support for Sahara SXG driver
+To: Greg Kroah-Hartman <gregkh@suse.de>
+Cc: Sahara Project <saharaproj@linsyssoft.com>, Michael Miles <mmiles@alacritech.com>, Christopher Harrer <charrer@alacritech.com>
+Message-ID: <alpine.LFD.2.00.0901280706290.18077@localhost.localdomain>
+
+From: Mithlesh Thukral <mithlesh@linsyssoft.com>
+
+* Add multicast support for SXG driver for Alacritech's 10Gbe products.
+
+Signed-off-by: LinSysSoft Sahara Team <saharaproj@linsyssoft.com>
+Signed-off-by: Mithlesh Thukral <mithlesh@linsyssoft.com>
+Cc: Michael Miles <mmiles@alacritech.com>
+Cc: Christopher Harrer <charrer@alacritech.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/staging/sxg/sxg.c | 127 ++++++++++++++------------------------
+ drivers/staging/sxg/sxg_ethtool.c | 4 -
+ 2 files changed, 52 insertions(+), 79 deletions(-)
+
+--- a/drivers/staging/sxg/sxg.c
++++ b/drivers/staging/sxg/sxg.c
+@@ -119,10 +119,8 @@ static void sxg_complete_slow_send(struc
+ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter,
+ struct sxg_event *Event);
+ static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus);
+-/* See if we need sxg_mac_filter() in future. If not remove it
+ static bool sxg_mac_filter(struct adapter_t *adapter,
+ struct ether_header *EtherHdr, ushort length);
+-*/
+ static struct net_device_stats *sxg_get_stats(struct net_device * dev);
+ void sxg_free_resources(struct adapter_t *adapter);
+ void sxg_free_rcvblocks(struct adapter_t *adapter);
+@@ -155,6 +153,7 @@ static int sxg_write_mdio_reg(struct ada
+ u32 DevAddr, u32 RegAddr, u32 Value);
+ static int sxg_read_mdio_reg(struct adapter_t *adapter,
+ u32 DevAddr, u32 RegAddr, u32 *pValue);
++static void sxg_set_mcast_addr(struct adapter_t *adapter);
+
+ static unsigned int sxg_first_init = 1;
+ static char *sxg_banner =
+@@ -1609,16 +1608,14 @@ static struct sk_buff *sxg_slow_receive(
+ #endif
+ /* Dumb-nic frame. See if it passes our mac filter and update stats */
+
+- /*
+- * ASK if (!sxg_mac_filter(adapter,
+- * SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
+- * Event->Length)) {
+- * SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr",
+- * Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
+- * Event->Length, 0);
+- * goto drop;
+- * }
+- */
++ if (!sxg_mac_filter(adapter,
++ (struct ether_header *)(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)),
++ Event->Length)) {
++ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr",
++ Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
++ Event->Length, 0);
++ goto drop;
++ }
+
+ Packet = RcvDataBufferHdr->SxgDumbRcvPacket;
+ SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event);
+@@ -1728,7 +1725,6 @@ static void sxg_process_rcv_error(struct
+ }
+ }
+
+-#if 0 /* Find out if this code will be needed in future */
+ /*
+ * sxg_mac_filter
+ *
+@@ -1743,6 +1739,7 @@ static bool sxg_mac_filter(struct adapte
+ struct ether_header *EtherHdr, ushort length)
+ {
+ bool EqualAddr;
++ struct net_device *dev = adapter->netdev;
+
+ if (SXG_MULTICAST_PACKET(EtherHdr)) {
+ if (SXG_BROADCAST_PACKET(EtherHdr)) {
+@@ -1750,8 +1747,6 @@ static bool sxg_mac_filter(struct adapte
+ if (adapter->MacFilter & MAC_BCAST) {
+ adapter->Stats.DumbRcvBcastPkts++;
+ adapter->Stats.DumbRcvBcastBytes += length;
+- adapter->Stats.DumbRcvPkts++;
+- adapter->Stats.DumbRcvBytes += length;
+ return (TRUE);
+ }
+ } else {
+@@ -1759,15 +1754,12 @@ static bool sxg_mac_filter(struct adapte
+ if (adapter->MacFilter & MAC_ALLMCAST) {
+ adapter->Stats.DumbRcvMcastPkts++;
+ adapter->Stats.DumbRcvMcastBytes += length;
+- adapter->Stats.DumbRcvPkts++;
+- adapter->Stats.DumbRcvBytes += length;
+ return (TRUE);
+ }
+ if (adapter->MacFilter & MAC_MCAST) {
+- struct sxg_multicast_address *MulticastAddrs =
+- adapter->MulticastAddrs;
+- while (MulticastAddrs) {
+- ETHER_EQ_ADDR(MulticastAddrs->Address,
++ struct dev_mc_list *mclist = dev->mc_list;
++ while (mclist) {
++ ETHER_EQ_ADDR(mclist->da_addr,
+ EtherHdr->ether_dhost,
+ EqualAddr);
+ if (EqualAddr) {
+@@ -1775,12 +1767,9 @@ static bool sxg_mac_filter(struct adapte
+ DumbRcvMcastPkts++;
+ adapter->Stats.
+ DumbRcvMcastBytes += length;
+- adapter->Stats.DumbRcvPkts++;
+- adapter->Stats.DumbRcvBytes +=
+- length;
+ return (TRUE);
+ }
+- MulticastAddrs = MulticastAddrs->Next;
++ mclist = mclist->next;
+ }
+ }
+ }
+@@ -1792,20 +1781,15 @@ static bool sxg_mac_filter(struct adapte
+ */
+ adapter->Stats.DumbRcvUcastPkts++;
+ adapter->Stats.DumbRcvUcastBytes += length;
+- adapter->Stats.DumbRcvPkts++;
+- adapter->Stats.DumbRcvBytes += length;
+ return (TRUE);
+ }
+ if (adapter->MacFilter & MAC_PROMISC) {
+ /* Whatever it is, keep it. */
+- adapter->Stats.DumbRcvPkts++;
+- adapter->Stats.DumbRcvBytes += length;
+ return (TRUE);
+ }
+- adapter->Stats.RcvDiscards++;
+ return (FALSE);
+ }
+-#endif
++
+ static int sxg_register_interrupt(struct adapter_t *adapter)
+ {
+ if (!adapter->intrregistered) {
+@@ -1885,24 +1869,24 @@ static int sxg_if_init(struct adapter_t
+ ASSERT(adapter->linkstate == LINK_DOWN);
+
+ adapter->devflags_prev = dev->flags;
+- adapter->macopts = MAC_DIRECTED;
++ adapter->MacFilter = MAC_DIRECTED;
+ if (dev->flags) {
+ DBG_ERROR("sxg: %s (%s) Set MAC options: ", __func__,
+ adapter->netdev->name);
+ if (dev->flags & IFF_BROADCAST) {
+- adapter->macopts |= MAC_BCAST;
++ adapter->MacFilter |= MAC_BCAST;
+ DBG_ERROR("BCAST ");
+ }
+ if (dev->flags & IFF_PROMISC) {
+- adapter->macopts |= MAC_PROMISC;
++ adapter->MacFilter |= MAC_PROMISC;
+ DBG_ERROR("PROMISC ");
+ }
+ if (dev->flags & IFF_ALLMULTI) {
+- adapter->macopts |= MAC_ALLMCAST;
++ adapter->MacFilter |= MAC_ALLMCAST;
+ DBG_ERROR("ALL_MCAST ");
+ }
+ if (dev->flags & IFF_MULTICAST) {
+- adapter->macopts |= MAC_MCAST;
++ adapter->MacFilter |= MAC_MCAST;
+ DBG_ERROR("MCAST ");
+ }
+ DBG_ERROR("\n");
+@@ -3036,9 +3020,7 @@ static int sxg_read_mdio_reg(struct adap
+ * complemented), we must then transpose the value and return bits 30-23.
+ */
+ static u32 sxg_crc_table[256];/* Table of CRC's for all possible byte values */
+-#if XXXTODO
+ static u32 sxg_crc_init; /* Is table initialized */
+-#endif
+
+ /* Contruct the CRC32 table */
+ static void sxg_mcast_init_crc32(void)
+@@ -3063,7 +3045,6 @@ static void sxg_mcast_init_crc32(void)
+ }
+ }
+
+-#if XXXTODO
+ /*
+ * Return the MAC hast as described above.
+ */
+@@ -3091,13 +3072,12 @@ static unsigned char sxg_mcast_get_mac_h
+
+ return (machash);
+ }
+-#endif
+
+ static void sxg_mcast_set_mask(struct adapter_t *adapter)
+ {
+ struct sxg_ucode_regs *sxg_regs = adapter->UcodeRegs;
+
+- DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__,
++ DBG_ERROR("%s ENTER (%s) MacFilter[%x] mask[%llx]\n", __FUNCTION__,
+ adapter->netdev->name, (unsigned int)adapter->MacFilter,
+ adapter->MulticastMask);
+
+@@ -3107,7 +3087,7 @@ static void sxg_mcast_set_mask(struct ad
+ * promiscuous mode as well as ALLMCAST mode. It saves the
+ * Microcode from having keep state about the MAC configuration
+ */
+- /* DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n
++ /* DBG_ERROR("sxg: %s MacFilter = MAC_ALLMCAST | MAC_PROMISC\n \
+ * SLUT MODE!!!\n",__func__);
+ */
+ WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH);
+@@ -3135,39 +3115,6 @@ static void sxg_mcast_set_mask(struct ad
+ }
+ }
+
+-#if XXXTODO
+-/*
+- * Allocate a mcast_address structure to hold the multicast address.
+- * Link it in.
+- */
+-static int sxg_mcast_add_list(struct adapter_t *adapter, char *address)
+-{
+- struct mcast_address *mcaddr, *mlist;
+- bool equaladdr;
+-
+- /* Check to see if it already exists */
+- mlist = adapter->mcastaddrs;
+- while (mlist) {
+- ETHER_EQ_ADDR(mlist->address, address, equaladdr);
+- if (equaladdr) {
+- return (STATUS_SUCCESS);
+- }
+- mlist = mlist->next;
+- }
+-
+- /* Doesn't already exist. Allocate a structure to hold it */
+- mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC);
+- if (mcaddr == NULL)
+- return 1;
+-
+- memcpy(mcaddr->address, address, 6);
+-
+- mcaddr->next = adapter->mcastaddrs;
+- adapter->mcastaddrs = mcaddr;
+-
+- return (STATUS_SUCCESS);
+-}
+-
+ static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address)
+ {
+ unsigned char crcpoly;
+@@ -3184,7 +3131,25 @@ static void sxg_mcast_set_bit(struct ada
+ /* OR in the new bit into our 64 bit mask. */
+ adapter->MulticastMask |= (u64) 1 << crcpoly;
+ }
+-#endif
++
++/*
++ * Function takes MAC addresses from dev_mc_list and generates the Mask
++ */
++
++static void sxg_set_mcast_addr(struct adapter_t *adapter)
++{
++ struct dev_mc_list *mclist;
++ struct net_device *dev = adapter->netdev;
++ int i;
++
++ if (adapter->MacFilter & (MAC_ALLMCAST | MAC_MCAST)) {
++ for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
++ i++, mclist = mclist->next) {
++ sxg_mcast_set_bit(adapter,mclist->da_addr);
++ }
++ }
++ sxg_mcast_set_mask(adapter);
++}
+
+ static void sxg_mcast_set_list(struct net_device *dev)
+ {
+@@ -3194,8 +3159,16 @@ static void sxg_mcast_set_list(struct ne
+ if (dev->flags & IFF_PROMISC) {
+ adapter->MacFilter |= MAC_PROMISC;
+ }
++
++ if (dev->flags & IFF_MULTICAST)
++ adapter->MacFilter |= MAC_MCAST;
++
++ if (dev->flags & IFF_ALLMULTI) {
++ adapter->MacFilter |= MAC_ALLMCAST;
++ }
++
+ //XXX handle other flags as well
+- sxg_mcast_set_mask(adapter);
++ sxg_set_mcast_addr(adapter);
+ }
+
+ #if XXXTODO
+--- a/drivers/staging/sxg/sxg_ethtool.c
++++ b/drivers/staging/sxg/sxg_ethtool.c
+@@ -99,9 +99,9 @@ static struct sxg_nic_stats sxg_nic_gstr
+ /* May be need in future */
+ /* {"dumb_rcv_broadcast_packets", SXG_NIC_STATS(Stats.DumbRcvBcastPkts)},
+ {"dumb_rcv_broadcast_bytes", SXG_NIC_STATS(Stats.DumbRcvBcastBytes)},
+- {"dumb_rcv_multicast_packets", SXG_NIC_STATS(Stats.DumbRcvMcastPkts)},
++*/ {"dumb_rcv_multicast_packets", SXG_NIC_STATS(Stats.DumbRcvMcastPkts)},
+ {"dumb_rcv_multicast_bytes", SXG_NIC_STATS(Stats.DumbRcvMcastBytes)},
+- {"dumb_rcv_unicast_packets", SXG_NIC_STATS(Stats.DumbRcvUcastPkts)},
++/* {"dumb_rcv_unicast_packets", SXG_NIC_STATS(Stats.DumbRcvUcastPkts)},
+ {"dumb_rcv_unicast_bytes", SXG_NIC_STATS(Stats.DumbRcvUcastBytes)},
+ */
+ {"no_sgl_buffer", SXG_NIC_STATS(Stats.NoSglBuf)},
diff --git a/version b/version
index 89084549b8288c..9ab72e41eb9399 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.6.29-rc2-git2
+2.6.29-rc2-git4