Hi Greg

Kind of Driver: Driver for a dongle usb-> serial 
Manufacturer: Io-Data
Device: USB-RSA (based on EZUSB-CHip)
Goal: Port the driver that was working on kernel version 3.17 to current
kernel version
Problem Description:
- The driver initializes properly, and downloads the firmware.
- When issuing echo "0123456789" > /dev/ttyUSB0, the data is sent downstream
to the device. echo then blocks for 30 seconds. usbrsa_close is then called.
With it, also echo terminates (return code = 0)
- When issuing stty -F /dev/ttyUSB0 300, the command is apparently executed.
stty however blocks (as it seems indefinitely). usbrsa_close is only called
once I cancel stty with CTRL-C

Remark: From what I can see, the driver does not block within the driver
code but somewhere else.

For log and source code, please look below (As you suggested, I scanned the
source with checkpatch.pl. I have removed all errors). 

gkh> Why not post the updated
gkh> code so that everyone can see it and possibly help out with it? 
No issue with that -- just wanted to save everybody from utterly long postings.


=====

command: echo "0123456789" > /dev/ttyUSB0
SYSLOG:

[105791.355511] tty ttyUSB0: usbrsa_init_termios()
[105791.355528] usbrsa_open; priv=ffff880307620e00
[105791.355533] usbrsa ttyUSB0: usbrsa_open - port 0
[105791.355536] usbrsa ttyUSB0: usbrsa_set_termios - port 0
[105791.355539] usbrsa ttyUSB0: usbrsa_set_termios - baudrate = 300
[105791.355543] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207
SPEED=300 ep=2
[105791.355547] usbrsa ttyUSB0: send_baudrate_lcr_register()
ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3
[105791.355615] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0,
ep=0xc0010f00
[105791.355656] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving
[105791.355669] usbrsa ttyUSB0: usbrsa_open - port 0: leaving
[105791.355712] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint
[105791.355724] usbrsa_write; private struct =ffff880307620e00
[105791.355729] usbrsa ttyUSB0: usbrsa_write - port 0; bytes=11 := count=11
: nofTxBytesFree=4063
[105791.355734] usbrsa ttyUSB0: usbrsa_write - poolsize  10, urb_index 0
[105791.355739] usbrsa ttyUSB0: usbrsa_write - port 0;URB allocated=0
[105791.355744] usbrsa ttyUSB0: usbrsa_write - port 0;bytes in urb=11
[105791.355748] usbrsa ttyUSB0: usbrsa_write - length = 11, data = 30 31 32
33 34 35 36 37 38 39 0a
[105791.355753] usbrsa ttyUSB0: usbrsa_write - port 0;sent=11;count=0;
nof_bytes_to_be_sent=0;bytes=11
[105791.355756] usbrsa ttyUSB0: usbrsa_write() End - sent=11
[105791.355801] usbrsa ttyUSB0: usbrsa_write_callback() - port = 0, ep
=0xc0018f80
[105791.355809] usbrsa ttyUSB0: usbrsa_write_callback - length = 11, data =
30 31 32 33 34 35 36 37 38 39 0a
[105791.355817] usbrsa ttyUSB0: usbrsa_write_callback(): Returned URB 0
[105791.355958] usbrsa_status_callback: nofTxBytesFree=4052,nofRxBytesReceived=0

... (here the blocking of "echo" starts)

[105793.353318] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint
[105795.353432] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint

... (repeats every 2 seconds for around 30 seconds)

usbrsa_status_callback(): usb_serial_port_softint
[105821.354309] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint
[105821.766319] usbrsa_close - start
[105821.766328] usbrsa ttyUSB0: usbrsa_close - port 0 start
[105821.766334] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207
SPEED=300 ep=5
[105821.766338] usbrsa ttyUSB0: send_baudrate_lcr_register()
ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3
[105821.766380] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0,
ep=0xc0028f00
[105821.766392] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving
[105821.766395] usbrsa ttyUSB0: usbrsa_close - #retries=3
[105821.766397] usbrsa_close - end
[105821.766399] usbrsa ttyUSB0: usbrsa_close - end 
[105821.766416] usbrsa ttyUSB0: usbrsa_status_callback(): wake_up

... (echo terminates).....

command: stty -F /dev/ttyUSB0 300
SYSLOG:

[106202.139819] usbrsa_open; priv=ffff880307620e00
[106202.139824] usbrsa ttyUSB0: usbrsa_open - port 0
[106202.139827] usbrsa ttyUSB0: usbrsa_set_termios - port 0
[106202.139830] usbrsa ttyUSB0: usbrsa_set_termios - baudrate = 300
[106202.139834] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207
SPEED=300 ep=2
[106202.139838] usbrsa ttyUSB0: send_baudrate_lcr_register()
ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3
[106202.139924] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0,
ep=0xc0010f00
[106202.139949] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving
[106202.139958] usbrsa ttyUSB0: usbrsa_open - port 0: leaving
[106202.139978] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5401
[106202.139982] usbrsa ttyUSB0: usbrsa_ioctl(): TCGETS -- not implemented
[106202.139986] usbrsa ttyUSB0: usbrsa_ioctl() leaving
[106202.139996] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint
[106202.140016] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5401
[106202.140021] usbrsa ttyUSB0: usbrsa_ioctl(): TCGETS -- not implemented
[106202.140025] usbrsa ttyUSB0: usbrsa_ioctl() leaving
[106202.140030] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5403
[106202.140035] usbrsa ttyUSB0: usbrsa_ioctl(): 0x5403 not supported
[106202.140038] usbrsa ttyUSB0: usbrsa_ioctl() leaving
[106204.139545] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint

.... (stty waits blocked on the command line) ....

[106206.139617] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint

... (repeats every 2 seconds until CTRL-C  is sent to the stty command)


[106428.147311] usbrsa ttyUSB0: usbrsa_status_callback():
usb_serial_port_softint
[106428.665722] usbrsa_close - start
[106428.665733] usbrsa ttyUSB0: usbrsa_close - port 0 start
[106428.665740] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207
SPEED=300 ep=5
[106428.665744] usbrsa ttyUSB0: send_baudrate_lcr_register()
ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3
[106428.665782] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0,
ep=0xc0028f00
[106428.665794] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving
[106428.665797] usbrsa ttyUSB0: usbrsa_close - #retries=3
[106428.665799] usbrsa_close - end
[106428.665801] usbrsa ttyUSB0: usbrsa_close - end 
[106428.665824] usbrsa ttyUSB0: usbrsa_status_callback(): wake_up

... (stty returns to command line. return code = 130)




SOURCE CODE:

/*
 * Driver for IO-Data's USB RSA serial dongle
 *      Copyright (C) 2012
 *         Tilman Glotzner(tilmanglotz...@gmail.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.
 *
 *
 *
 *  USB-RSA by IO-DATA
 *  USB to serial converter
 *  =======================
 *
 *  Remark: The device uses an AN2131Q (Eazy USB) and a ST16C550(UART)
 *
 *  End Points:
 *  ============
 *
 *  End Point:  EP1OUT
 *  Direction:  Host to Device
 *  Type:               Bulk Transfer
 *  Size:               64 bytes
 *  Desc:               Data to be transmitted
 *  Format:             64 bytes of data
 *
 *
 *  End Point:  EP2OUT
 *  Direction:  Host to Device
 *  Type:               Bulk Transfer
 *  Size:               3 bytes
 *  Desc:               Set baud rate counter and Line Control Register
 *                              of the ST16C550. Receiver Interrupts are turned
 *                              ON, i.e.  Modem status IR, RX line status IR,
 *                              and     RX holding register IR
 *  Format:
 *              Byte0:  Low Byte of counter (DLL)
 *              Byte1:  High Byte of counter (DLM)
 *              Byte2:  Line Control Register (LCR)
 *                              - Bit 0: Word Length 0
 *                              - Bit 1: Word Length 1
 *                              - Bit 2: Stop Bits
 *                              - Bit 3: Parity Enable
 *                              - Bit 4: Parity Even
 *                              - Bit 5: Set Parity
 *                              - Bit 6: Set Break
 *                              - Bit 7: Counter Register Enable
 *                                              (needs to be set to '0')
 *
 *
 *      End Point:      EP3OUT
 *  Direction:  Host to Device
 *  Type:               Bulk Transfer
 *  Size:               1 bytes
 *  Desc:               Set modem control register of the ST16C550
 *  Format:
 *              Byte0:  Modem Control Register
 *                              - Bit0: DTR
 *                              - Bit1: RTS
 *                              - Bit2: OP1
 *                              - Bit3: OP2
 *                              - Bit4: Diagnostics mode
 *
 *
 *  End Point:  EP4OUT
 *  Direction:  Host to Device
 *  Type:               Bulk Transfer
 *  Size:               0 bytes
 *  Desc:               Reset EP1OUT and EP1IN (Tx/Rx pipes)
 *  Format:             n.a.
 *
 *
 *  End Point:  EP5OUT
 *  Direction:  Host to Device
 *  Type:               Bulk Transfer
 *  Size:               3 bytes
 *  Desc:               Set baud rate counter and Line Control Register
 *                              of the ST16C550. Receiver Interrupts are turned
 *                              OFF, i.e.  Modem status IR, RX line status IR,
 *                              and     RX holding register IR
 *  Format:
 *              Byte0:  Low Byte of counter (DLL)
 *              Byte1:  High Byte of counter (DLM)
 *              Byte2:  Line Control Register (LCR)
 *                              - Bit 0: Word Length 0
 *                              - Bit 1: Word Length 1
 *                              - Bit 2: Stop Bits
 *                              - Bit 3: Parity Enable
 *                              - Bit 4: Parity Even
 *                              - Bit 5: Set Parity
 *                              - Bit 6: Set Break
 *                              - Bit 7: Counter Register Enable
 *                                      (needs to be set to '0')
 *
 *
 *  End Point:  EP1IN
 *  Direction:  Device to Host
 *  Type:               Bulk Transfer
 *  Size:               64 bytes
 *  Desc:               Data received by USB-RSA
 *  Format:             64 bytes of data
 *
 *
 *  End Point:  EP2IN
 *  Direction:  Device to Host
 *  Type:               Bulk Transfer
 *  Size:               1 byte
 *  Desc:               Read Modem Status Register of ST16C550
 *  Format:
 *              Byte0:  Modem Status Register
 *                              - Bit0: Delta CTS
 *                              - Bit1: Delta DSR
 *                              - Bit2: Delta RI
 *                              - Bit3: Delta CD
 *                              - Bit4: CTS
 *                              - Bit5: DSR
 *                              - Bit6: RI
 *                              - Bit7: CD
 *
 *
 *  End Point:  EP3IN
 *  Direction:  Device to Host
 *  Type:               Bulk Transfer
 *  Size:               4 bytes
 *  Desc:               Read RX/TX Pipe Status
 *  Format:
 *              Byte0:  Byte available in TX Buffer of USB-RSA (Low Byte)
 *              Byte1:  Byte available in TX Buffer of USB-RSA (High Byte)
 *              Byte2:  Byte received and stored in RX Buffer
 *                                      of USB-RSA (Low Byte)
 *              Byte3:  Byte received and stored in RX Buffer
 *                                      of USB-RSA (High Byte)
 *
 *
 *  todo:
 *  use of status urb information (status urb returns tx_bytes_available
 *        on usbrsa) (done)
 *  debug: write blocks if more than 9 URBs (done)
 *  debug  rx pipe (first urb read is always empty)
 *  CTS, and DSR: do these need to be enabled OP1/OP2 ? (no)
 *  xon/xoff correctly implemented ?
 *  write function to issue lcr und divisor urb (EPOUT2 and EPOUT5)
 *        + waits for completion (done)
 *  reflect lcr, dll, dlm in usbrsa_port_private (done)
 *  send break
 *  buffering effect: when writing to USB-RSA not all characters are
 *        transferred at once (done)
 *  Are parent_serial,parent_port in usbrsa_port_private
 *              really necessary?
 *      Load kernel modules on which this driver depends.
 *
 */

#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/mutex.h>
#include <linux/uaccess.h>
#include <asm/termbits.h>
#include <linux/usb.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
#include <linux/usb/serial.h>
#include <linux/usb/ezusb.h>
#include <linux/firmware.h>
#include <linux/ihex.h>
#include <linux/usb/ezusb.h>
#include "usbrsa.h"



#define CONFIG_USB_SERIAL_DEBUG 1
#ifdef CONFIG_USB_SERIAL_DEBUG
        int debug = 1;
#else
        int debug = 0;
#endif

/*
 * Version Information
 */
#define DRIVER_VERSION "v0.1"
#define DRIVER_AUTHOR "Tilman Glotzner <tilman.gloetz...@gmail.com>"
#define DRIVER_DESC "Driver for IODATA's USBRSA serial dongle"


#define IODATA_VENDOR_ID                        0x4bb
#define IODATA_USBRSA_PREENUM_ID        0xa01
#define IODATA_USBRSA_ID                        0xa02


#define COMMAND_TIMEOUT         (2*HZ)  /* 2 second timeout for a command */

/*
 * Taken whiteheat driver as role model:
 * ID tables for usb-rsa are unusual, because we want to different
 * things for different versions of the device.  Eventually, this
 * will be doable from a single table.  But, for now, we define two
 * separate ID tables, and then a third table that combines them
 * just for the purpose of exporting the autoloading information.
*/
static const struct usb_device_id id_table_std[] = {
                { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) },
                { }                             /* Terminating entry */
};

static const struct usb_device_id id_table_prerenumeration[] = {
                { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) },
                { }                             /* Terminating entry */
};

static const struct usb_device_id id_table_combined[] = {
                { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) },
                { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) },
                { }                             /* Terminating entry */
};


MODULE_DEVICE_TABLE(usb, id_table_combined);







/***********************************************************************
*                   Preenumeration device
************************************************************************/


/***********************************************************************
*                   Function Prototypes
***********************************************************************/
static int usbrsa_firmware_download(struct usb_serial *serial,
                const struct usb_device_id *id);
static int usbrsa_firmware_attach(struct usb_serial *serial);


/***********************************************************************
*                   Driver object declaration
***********************************************************************/
static struct usb_serial_driver usbrsa_preenum_device = {
                .driver = {
                                .owner =        THIS_MODULE,
                                .name =         "usbrsanofirm",
                },
                .description =          "IO-DATA - USB-RSA - (prerenumeration)",
                .id_table =             id_table_prerenumeration,
                .num_ports =            1,
                .probe =                usbrsa_firmware_download,
                .attach =               usbrsa_firmware_attach,
};


/***********************************************************************
*                    Functions
************************************************************************/


/***********************************************************************
* Name: usbrsa_firmware_download
* Purpose: Downloads firmware to AN2134Q
*
***********************************************************************/
static int usbrsa_firmware_download(struct usb_serial *serial,
                const struct usb_device_id *id)
{
        int response;

        dev_dbg(&serial->dev->dev, "%s", __func__);
        response = ezusb_fx1_ihex_firmware_download(serial->dev, "usbrsa.fw");

        if (response >= 0) {
                dev_dbg(&serial->dev->dev, "%s(): Firmware downloaded.",
                                __func__);
                /* The USB-RSA does not reenumerate without
                 *  toggeling the reset bit
                 */
                udelay(1000);
                response = ezusb_fx1_set_reset(serial->dev, 1);
                udelay(10000);
                if (response >= 0) {
                        response = ezusb_fx1_set_reset(serial->dev, 0);
                        if (response >= 0) {
                                dev_dbg(&serial->dev->dev,
                                                "%s(): Device with new firmware 
reset.",
                                                __func__);
                                return 0;
                        }
                }
                dev_err(&serial->dev->dev,
                                "%s(): Status register of EZUSB not 
accessible.",
                                __func__);
        }
        dev_err(&serial->dev->dev,
                        "%s(): Firmware download or subsequent reset failed",
                        __func__);
        return -ENOENT;
}

/***********************************************************************
* Name: usbrsa_firmware_attach
* Purpose: Prevents the driver from attaching, so that can attach
*          to the reenumerated device
*
***********************************************************************/
static int usbrsa_firmware_attach(struct usb_serial *serial)
{
        /* We want this device to fail to have the driver
         * assigned to the reenumerated device
         */
        return 1;
}


/***********************************************************************/

/***********************************************************************
*                  REENUMERATED DEVICE
***********************************************************************/

/***********************************************************************
*                   Function Prototypes
***********************************************************************/
static int  usbrsa_attach(struct usb_serial *serial);
static void  usbrsa_release(struct usb_serial *serial);
static int usbrsa_probe(struct usb_serial_port *port);
static int usbrsa_remove(struct usb_serial_port *port);
static int  usbrsa_open(struct tty_struct *tty,
        struct usb_serial_port *port);

static void usbrsa_close(struct usb_serial_port *port);
static void usbrsa_set_termios(struct tty_struct *tty,
        struct usb_serial_port *port,
        struct ktermios *old);
static void usbrsa_init_termios(struct tty_struct *tty);
static int  usbrsa_write(struct tty_struct *tty,
        struct usb_serial_port *port,
        const unsigned char *buf, int count);
static int  usbrsa_ioctl(struct tty_struct *tty,
        unsigned int cmd,
        unsigned long arg);
static int usbrsa_write_room(struct tty_struct *tty);
static int usbrsa_chars_in_buffer(struct tty_struct *tty);
static void usbrsa_unthrottle(struct tty_struct *tty);
static void usbrsa_throttle(struct tty_struct *tty);
static int usbrsa_tiocmset(struct tty_struct *tty,
        unsigned int set,
        unsigned int clear);
static int usbrsa_tiocmget(struct tty_struct *tty);

/***********************************************************************
*              Completion Handler Prototypes
***********************************************************************/
static void usbrsa_baudrate_lcr_callback(struct urb *urb);
static void  usbrsa_reset_callback(struct urb *urb);
static void  usbrsa_status_callback(struct urb *urb);
static void  usbrsa_write_callback(struct urb *urb);
static void  usbrsa_read_callback(struct urb *urb);
static void  usbrsa_mcr_callback(struct urb *urb);
static void  usbrsa_msr_callback(struct urb *urb);

/***********************************************************************
*                   Driver object declaration
***********************************************************************/
static struct usb_serial_driver usbrsa_enumerated_device = {
                .driver = {
                                .owner =        THIS_MODULE,
                                .name =         "usbrsa",
                },
                .description =          "IO-DATA - USB-RSA",
                .id_table =             id_table_std,
                .num_ports =            1,
                .attach =               usbrsa_attach,
                .release =                              usbrsa_release,
                .port_probe =               usbrsa_probe,
                .port_remove =                  usbrsa_remove,
                .open =                                 usbrsa_open,
                .close =                                usbrsa_close,
                .write =                                usbrsa_write,
                .write_bulk_callback =  usbrsa_write_callback,
                .read_bulk_callback =   usbrsa_read_callback,
                .set_termios =                  usbrsa_set_termios,
                .tiocmset =                             usbrsa_tiocmset,
                .tiocmget =                             usbrsa_tiocmget,
                .init_termios =                 usbrsa_init_termios,
                .ioctl =                                usbrsa_ioctl,
                .write_room =                   usbrsa_write_room,
                .chars_in_buffer =              usbrsa_chars_in_buffer,
                .throttle =                             usbrsa_throttle,
                .unthrottle =                   usbrsa_unthrottle
};



/***********************************************************************
*                   Function Prototypes of help functions
***********************************************************************/
static int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data);
static int allocate_read_urbs(struct usbrsa_port_private *priv_data);
static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data);
static int allocate_reset_urb(struct usbrsa_port_private *priv_data);
static int allocate_status_urb(struct usbrsa_port_private *priv_data);
static int allocate_mcr_urb(struct usbrsa_port_private *priv_data);
static int allocate_msr_urb(struct usbrsa_port_private *priv_data);

static void release_write_urbs(struct usbrsa_port_private *priv_data);
static void release_read_urbs(struct usbrsa_port_private *priv_data);
static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data);
static void release_reset_urb(struct usbrsa_port_private *priv_data);
static void release_status_urb(struct usbrsa_port_private *priv_data);
static void release_mcr_urb(struct usbrsa_port_private *priv_data);
static void release_msr_urb(struct usbrsa_port_private *priv_data);



static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate,
                        int endpoint, struct usb_serial_port *port);
static int send_mcr_register(struct usb_serial_port *port);
static int fetch_msr_register(struct usb_serial_port *port);
static int get_serial_info(struct usb_serial_port  *port,
                        struct serial_struct __user *retinfo);
static int send_reset(struct usb_serial_port *port);
static int wait_modem_info(struct usb_serial_port *port, unsigned int arg);

/***********************************************************************
*                   Functions
***********************************************************************/


/***********************************************************************
* Name: usbrsa_attach
* Purpose:
*
*
***********************************************************************/
static int  usbrsa_attach(struct usb_serial *serial)
{
        int                                                     ret = 0;

        printk(KERN_DEBUG "%s start", __func__);
        dev_dbg(&serial->dev->dev, "%s", __func__);

        return ret;
}

/***********************************************************************
* Name: usbrsa_release
* Purpose:
*
*
***********************************************************************/
static void  usbrsa_release(struct usb_serial *serial)
{

        printk("%s: start: numberOfPorts=%d", __func__, serial->num_ports);
        dev_dbg(&serial->dev->dev, "%s()", __func__);

}

/***********************************************************************
* Name: usbrsa_probe
* Purpose: Creates private data structures of driver
*
*
*
***********************************************************************/
static int usbrsa_probe(struct usb_serial_port *port)
{
        int                                                     ret = 0;
        struct usbrsa_port_private *priv = NULL;


        printk("%s", __func__);
/*      struct usbrsa_private *info;
*
*       info = kzalloc(sizeof(*info), GFP_KERNEL);
*       if (!info)
*               return -ENOMEM;
*
*       usb_set_serial_port_data(port, info);
*/


        dev_dbg(&port->dev, "%s", __func__);
        if (!port) {
                dev_err(&port->dev, "%s(): Invalid handler", __func__);
                return -ENODEV;
        }


        /* allocate struct for driver's private data */
        priv = kmalloc(sizeof(struct usbrsa_port_private), GFP_KERNEL);
        if (priv == NULL) {
                dev_err(&port->dev,
                                "%s: Out of memory for port structures\n",
                                __func__);
                goto out_no_private;
        }


        priv->parent_serial     = port->serial;
        priv->parent_port       = port;
        priv->read_running      = USBRSA_READ_STOP;
        priv->urb_pool_size     = NUM_URBS;
        priv->nofTxMaxBytes     = USBRSA_TX_MAX_BYTES;
        mutex_init(&priv->mutex);
        priv->debugTimeStamp = jiffies;

        spin_lock_init(&priv->lock);
        init_waitqueue_head(&priv->wait_flag);
        printk("%s: private struct at %p\n", __func__, priv);
        usb_set_serial_port_data(port, priv);
        printk("%s: private struct at %p\n", __func__,
                        usb_get_serial_port_data(port));


        /* allocate  urbs */
        printk("%s about to enter 'usbrsa_allocate_write_urbs'\n", __func__);
        ret = usbrsa_allocate_write_urbs(priv);
        if (ret != 0)
                goto out_no_alloc_write;
        printk("%s allocate_read_urbs", __func__);
        ret = allocate_read_urbs(priv);
        if (ret != 0)
                goto out_no_alloc_read;
        printk("%s allocate_baudrate_lcr_urb\n", __func__);
        ret = allocate_baudrate_lcr_urb(priv);
        if (ret != 0)
                goto out_no_alloc_baudrate_lcr;
        printk("%s allocate_reset_urb\n", __func__);
        ret = allocate_reset_urb(priv);
        if (ret != 0)
                goto out_no_alloc_reset;
        printk("%s allocate_status_urb\n", __func__);
        ret = allocate_status_urb(priv);
        if (ret != 0)
                goto out_no_alloc_status;
        printk("%s allocate_mcr_urb\n", __func__);
        ret = allocate_mcr_urb(priv);
        if (ret != 0)
                goto out_no_alloc_mcr;
        printk("%s allocate_msr_urb\n", __func__);
        ret = allocate_msr_urb(priv);
        if (ret != 0)
                goto out_no_alloc_msr;

        printk("%s send_reset", __func__);
        /* sent reset */
        ret = send_reset(port);
        if (ret != 0) {
                dev_err(&port->dev, "%s(): Failed to issue reset command. "
                                " Error=%d\n", __func__, ret);
                ret = ENODEV;
                goto out_no_device;
        }
        printk("%s reset successful sent (ret=%d)", __func__, ret);

        printk("%s end", __func__);
        return 0;

out_no_device:
        release_msr_urb(priv);
out_no_alloc_msr:
        release_mcr_urb(priv);
out_no_alloc_mcr:
        release_status_urb(priv);
out_no_alloc_status:
        release_reset_urb(priv);
out_no_alloc_reset:
        release_baudrate_lcr_urb(priv);
out_no_alloc_baudrate_lcr:
        release_read_urbs(priv);
out_no_alloc_read:
        release_write_urbs(priv);
out_no_alloc_write:
        kfree(priv);
out_no_private:

        printk("%s end error", __func__);
        return ret;
}

/***********************************************************************
* Name: usbrsa_remove
* Purpose: Cleans up private data structures of driver
*
*
*
***********************************************************************/
static int usbrsa_remove(struct usb_serial_port *port)
{

        struct usbrsa_port_private      *priv;
        struct usb_serial_port          *serport;

        printk("%s", __func__);
        dev_dbg(&port->dev, "%s()", __func__);


        printk("%s: Mark1\n", __func__);
        serport = port;
        priv = usb_get_serial_port_data(serport);
        printk("%s: Mark2\n", __func__);
        printk("%s: private struct at %p\n", __func__, priv);
        release_msr_urb(priv);
        printk("%s: Mark2b ", __func__);
        release_mcr_urb(priv);
        printk("%s: Mark2c ", __func__);
        release_status_urb(priv);
        printk("%s: Mark2d ", __func__);
        release_reset_urb(priv);
        printk("%s: Mark2a ", __func__);
        release_baudrate_lcr_urb(priv);
        release_read_urbs(priv);
        printk("%s: Mark3", __func__);
        release_write_urbs(priv);
        printk("%s: Mark4", __func__);
        kfree(priv);
        printk("%s: Mark5", __func__);

        return 0;
}


/***********************************************************************
* Name: usbrsa_open
* Purpose: Open USB device. Sets termios, tty, and starts to sent
*          status queries to EP3IN.
*
*
***********************************************************************/
static int  usbrsa_open(struct tty_struct *tty,
                                                struct usb_serial_port *port)
{
        struct ktermios                         tmp_termios;
        int                                                     retval = 0;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;

        printk("%s; priv=%p\n", __func__, priv);
        dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number);

        /* flush buffer of USB-RSA by sending reset */
        /*retval = send_reset(port);

        if (retval != 0) {
                dev_err(&port->dev,
                                "%s(): usb_submit_urb() failed with error %d\n",
                                __func__, retval);
                return -ENODEV;
        }
        */

        if (tty) {
                /* usbrsa_set_termios will sent to endpoint 2 of the USB-RSA 
thereby
                * turning on the RX interrupt
                */
                usbrsa_set_termios(tty, port, &tmp_termios);
        }

        /* start reading from USB-RSA */
        spin_lock_irqsave(&priv->lock, flags);
        if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) {
                set_bit(LOCK_STATUS, &priv->urb_lock);

                /* enable continuous reading */
                priv->read_running = USBRSA_READ_RUNNING;
                spin_unlock_irqrestore(&priv->lock, flags);
                retval = usb_submit_urb(priv->status_urb, GFP_KERNEL);
         } else {
                spin_unlock_irqrestore(&priv->lock, flags);
         }

         dev_dbg(&port->dev, "%s - port %d: leaving", __func__, 
port->port_number);
         return 0;
}

/***********************************************************************
* Name: usbrsa_close
* Purpose: closes USB-RSA device
*
*
***********************************************************************/
static void usbrsa_close(struct usb_serial_port *port)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int                                                     retries = 3;
        unsigned long                           flags;
        int                                                     retval;


        printk("%s - start", __func__);
        dev_dbg(&port->dev, "%s - port %d start", __func__, port->port_number);

        /* turn off  RX interrupt of USB-RSA by sending to EP5) */
        while (retries > 0) {
                /* turn off RX interrupt of USB-RSA by sending to EP5.*/
                retval = send_baudrate_lcr_register(priv->c_flag,
                                 priv->baudrate, EP5OUT, port);
                if (retval != 0) {
                        dev_err(&port->dev, "%s(): usb_submit_urb() failed"
                                        " with error %d\n", __func__, retval);
                } else {
                        dev_dbg(&port->dev, "%s - #retries=%d", __func__, 
retries);
                        break;
                }
                retries--;
        }

        /* disable continuous reading */
        spin_lock_irqsave(&priv->lock, flags);
        priv->read_running = USBRSA_READ_STOP;
        spin_unlock_irqrestore(&priv->lock, flags);

        printk("%s - end", __func__);
        dev_dbg(&port->dev, "%s - end ", __func__);
}

/***********************************************************************
* Name: usbrsa_init_termios
* Purpose: Initialize termios of tty
*
*
***********************************************************************/
static void usbrsa_init_termios(struct tty_struct *tty)
{

        dev_dbg(tty->dev, "%s()", __func__);

/*      tty->termios = tty_std_termios;
        tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        tty->termios.c_ispeed = 9600;
        tty->termios.c_ospeed = 9600;
*/
}


/***********************************************************************
* Name: usbrsa_set_termios
* Purpose: Initialize USB-RSA with terminal settings
*
*
***********************************************************************/
static void usbrsa_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned int                            cflag;
        speed_t                                         baud_rate;
        int                                             retval;
        int                                                     retries = 3;

        dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number);


        if (!tty) {
                dev_err(&port->dev, "%s(): no tty structures", __func__);
                return;
        }

        if (I_IXOFF(tty) || I_IXON(tty)) {
                priv->xon = START_CHAR(tty);
                priv->xoff = STOP_CHAR(tty);
                dev_dbg(&port->dev, "%s - XON = %2x, XOFF = %2x",
                                __func__, priv->xon, priv->xoff);
        }
        cflag = tty->termios.c_cflag;
        priv->c_flag = cflag;
        /* get the baud rate wanted */
        baud_rate       = tty_get_baud_rate(tty);
        priv->baudrate = baud_rate;
        dev_dbg(&port->dev, "%s - baudrate = %u", __func__, baud_rate);

        /* if baud rate is B0, drop DTR */
        if ((baud_rate & CBAUD) == B0) {
                priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR);
                retval = send_mcr_register(port);
                if (retval != 0)
                        return;
        }

        while (retries > 0) {
                retval = send_baudrate_lcr_register(cflag, baud_rate,
                                EP2OUT, port);

                if (retval != 0) {
                        dev_err(&port->dev, "%s(): send_baudrate_lcr_register() 
failed"
                                        " with error %d\n", __func__, retval);
                        retries--;
                } else {
                        /* bail out */
                        retries = 0;
                }
        }
}

/***********************************************************************
* Name: usbrsa_write
* Purpose: copies data from user space, packs it into urbs, and sents
*          urbs downstream to USB-RSA
*
*
***********************************************************************/
static int usbrsa_write(struct tty_struct *tty,
        struct usb_serial_port *port,
        const unsigned char *buf, int count)
{
        struct usb_serial                       *serial = port->serial;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;
        int                                                     retval;
        int                                                     
nof_bytes_to_be_sent;
        int                                                     bytes;
        int                                                     urb_index;
        int                                                     sent = 0;
        struct urb                                      *urb;

        dev_dbg(&port->dev, "%s - port %d START", __func__, port->port_number);
        printk("%s; private struct =%p\n", __func__, priv);


        while (count > 0) {
                /* transfer only as many bytes as USB-RSA can take */
                nof_bytes_to_be_sent = (count > priv->nofTxBytesFree) ?
                                priv->nofTxBytesFree : count;
                dev_dbg(&port->dev, "%s - port %d; bytes=%d := count=%d : 
nofTxBytesFree=%d",
                                __func__, port->port_number,
                                nof_bytes_to_be_sent, count,
                                priv->nofTxBytesFree);

                while (nof_bytes_to_be_sent > 0) {
                        /* check for empty urb in write pool */
                        spin_lock_irqsave(&priv->lock, flags);
                        urb_index =
                                find_first_zero_bit(&priv->write_urb_pool_lock,
                                                        priv->urb_pool_size);

                        dev_dbg(&port->dev, "%s - poolsize  %d, urb_index 
%d\n", __func__,
priv->urb_pool_size, urb_index);
                        if (urb_index >= priv->urb_pool_size) {
                                /* no more urbs available */
                                spin_unlock_irqrestore(&priv->lock, flags);
                                goto out_write_no_urbs;
                        }

                        dev_dbg(&port->dev, "%s - port %d;URB allocated=%d", 
__func__,
port->port_number, urb_index);
                        /* reserve urb */
                        set_bit(urb_index, &priv->write_urb_pool_lock);
                        urb = priv->write_urb_pool[urb_index];

                        spin_unlock_irqrestore(&priv->lock, flags);

                        /* copy data from userspace into urb transfer buffer */
                        bytes = (nof_bytes_to_be_sent > port->bulk_out_size) ?
                                        port->bulk_out_size : 
nof_bytes_to_be_sent;
                        memcpy(urb->transfer_buffer, buf + sent, bytes);

                        dev_dbg(&port->dev, "%s - port %d;bytes in urb=%d", 
__func__,
port->port_number, bytes);
                        usb_serial_debug_data(&port->dev,
                                        __func__, bytes, urb->transfer_buffer);
                        urb->dev = serial->dev;
                        urb->transfer_buffer_length = bytes;

                        /* sent urb to USB-RSA */
                        retval = usb_submit_urb(urb, GFP_ATOMIC);

                        if (retval) {
                                /* return urb to pool */
                                spin_lock_irqsave(&priv->lock, flags);
                                clear_bit(urb_index, 
&priv->write_urb_pool_lock);
                                spin_unlock_irqrestore(&priv->lock, flags);
                                dev_err(&port->dev,
                                                "%s - failed submitting write 
urb, error %d\n",
                                                __func__, retval);
                                sent = retval;

                                /* bail out */
                                goto out_write_submit_failed;
                        } else {
                                sent += bytes;
                                count -= bytes;
                                nof_bytes_to_be_sent -= bytes;
                                dev_dbg(&port->dev, "%s - port 
%d;sent=%d;count=%d;
nof_bytes_to_be_sent=%d;bytes=%d",
                                                __func__, port->port_number, 
sent, count, nof_bytes_to_be_sent,
                                                bytes);
                        }
                }
        }
out_write_no_urbs:
out_write_submit_failed:
        dev_dbg(&port->dev, "%s() End - sent=%d\n", __func__, sent);
        usb_serial_port_softint(port);
        return sent;
}

/***********************************************************************
* Name: usbrsa_ioctl
* Purpose: copies data from user space, packs it into urbs, and sents
*          urbs downstream to USB-RSA
*
*
***********************************************************************/
static int  usbrsa_ioctl(struct tty_struct *tty,
                                        unsigned int cmd, unsigned long arg)
{

        struct usb_serial_port *port = tty->driver_data;

        dev_dbg(&port->dev, "%s() cmd 0x%.4x", __func__, cmd);

        switch (cmd) {
        case TIOCGSERIAL:
                return get_serial_info(port,
                                (struct serial_struct __user *) arg);
                break;
        case TIOCMIWAIT:
                dev_dbg(&port->dev, "%s(): TIOCMIWAIT", __func__);
                return wait_modem_info(port, arg);
                break;
        case TCGETS:
                dev_dbg(&port->dev, "%s(): TCGETS -- not implemented", 
__func__);
                break;
        case TCSETS:
                dev_dbg(&port->dev, "%s(): TCSETS -- not implemented", 
__func__);
                break;
        case TCFLSH:
                dev_dbg(&port->dev, "%s(): TCFLSH -- not implemented", 
__func__);
                break;
        default:
                dev_dbg(&port->dev, "%s(): 0x%04x not supported", __func__, 
cmd);
                break;
        }
        dev_dbg(&port->dev, "%s() leaving", __func__);
        return -ENOIOCTLCMD;
}


/***********************************************************************
* Name: usbrsa_write_room
* Purpose: Returns fill level of the tx queue. The tx queue consists
*          of 2 parts: A pool of URBs, and a buffer in the USB-RSA.
*                       Mostly, the fill level of the pool will be returned.
*                       Only if there is less memory available in the USB-RSA's
*                       buffer than in the the pool, the fill level of the 
USB-RSA
*                       will be returned to prevent clogging the tx queue.
*
*
*
***********************************************************************/
static int usbrsa_write_room(struct tty_struct *tty)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int                                                     room = 0;
        int                                                     i = 0;
        long                                            t;
        unsigned long                           flags;
        int                                                     retval;

        /*dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number);*/

        /* if no current fill level information is available, issue status 
update */
        if (priv->read_running != USBRSA_READ_RUNNING) {
                /* start reading from USB-RSA */
                spin_lock_irqsave(&priv->lock, flags);
                if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) {
                        set_bit(LOCK_STATUS, &priv->urb_lock);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        retval = usb_submit_urb(priv->status_urb, GFP_KERNEL);
                        if (retval != 0) {
                                return -ENODEV;
                        }
                        /* wait for the command to complete
                        * (waits, until timeout or condition==true)
                        */
                        t = wait_event_timeout(priv->wait_flag,
                                        (test_bit(LOCK_STATUS, &priv->urb_lock) 
== 0), COMMAND_TIMEOUT);
                        if (!t) {
                                /* fetching of msr */
                                usb_kill_urb(priv->status_urb);
                                dev_dbg(&port->dev, "%s - status urb timed 
out.", __func__);
                                return -ETIMEDOUT;
                                /*goto send_reset_exit; */
                        }
                } else {
                        spin_unlock_irqrestore(&priv->lock, flags);
                }
        }


        spin_lock_irqsave(&priv->lock, flags);
        for (i = 0; i < priv->urb_pool_size; i++)       {
                if (test_bit(i, &priv->write_urb_pool_lock) == 0) {
                        room++;
                }
        }
        spin_unlock_irqrestore(&priv->lock, flags);

        /*compute bytes  available in write URB pool */
        room *= port->bulk_out_size;

        dev_dbg(&port->dev, "%s(): Pool=%d;usbrsa.tx=%d",
                        __func__, room, priv->nofTxBytesFree);
        /* if usbrsa has fewer bytes available than URB pool return available 
bytes
in USBRSA */
        room = (room > priv->nofTxBytesFree) ?  priv->nofTxBytesFree : room;

        /*dev_dbg(&port->dev, "%s(): %d", __func__, room); */
        return room;
}


/***********************************************************************
* Name: usbrsa_chars_in_buffer
* Purpose: Return the number of bytes still waiting to be sent
*                       stored in the USBRSA as well as in the buffer of the
*                       driver (URB pool).
*                       The tty layer thereby calls the close function only
*                       after all bytes are sent.
*
*
*
*
***********************************************************************/
static int usbrsa_chars_in_buffer(struct tty_struct *tty)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int                                             chars = 0;
        int                                                     i = 0;
        unsigned long                           flags;
        long                                            t;
        int                                                     retval;

        /*dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number);*/

        if (priv->read_running != USBRSA_READ_RUNNING) {
                /* start reading from USB-RSA */
                spin_lock_irqsave(&priv->lock, flags);
                if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) {
                        set_bit(LOCK_STATUS, &priv->urb_lock);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        retval = usb_submit_urb(priv->status_urb, GFP_KERNEL);
                        if (retval != 0) {
                                chars =  -ENODEV;
                                goto chars_in_buffer_exit;
                        }
                        /* wait for the command to complete
                         * (waits, until timeout or condition==true)
                         */
                        t = wait_event_timeout(priv->wait_flag,
                                        (test_bit(LOCK_STATUS, &priv->urb_lock) 
== 0), COMMAND_TIMEOUT);
                        if (!t) {
                                /* fetching of msr */
                                usb_kill_urb(priv->status_urb);
                                dev_dbg(&port->dev, "%s - status urb timed 
out.", __func__);
                                chars =  -ETIMEDOUT;
                                goto chars_in_buffer_exit;
                        }
                } else {
                        spin_unlock_irqrestore(&priv->lock, flags);
                }
        }
        spin_lock_irqsave(&priv->lock, flags);

        /*bytes in TX buffer of USBRSA */
        chars = priv->nofTxMaxBytes - priv->nofTxBytesFree;

        /* account for URBs in the pool and not yet transferred to the USB-RSA 
*/
        for (i = 0; i < priv->urb_pool_size; i++) {
                if (test_bit(i, &priv->write_urb_pool_lock) != 0) {
                        chars += 
priv->write_urb_pool[i]->transfer_buffer_length;
                }
        }

        spin_unlock_irqrestore(&priv->lock, flags);

chars_in_buffer_exit:
        /*dev_dbg(&port->dev,"%s(): %d", __func__, chars);*/
        return chars;
}


/***********************************************************************
* Name: usbrsa_throttle
* Purpose:
*
*
*
***********************************************************************/
static void usbrsa_throttle(struct tty_struct *tty)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int status;

        dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number);


        /* if we are implementing XON/XOFF, send the stop character
         */
        if (I_IXOFF(tty)) {
                unsigned char stop_char = STOP_CHAR(tty);

                status = usbrsa_write(tty, port, &stop_char, 1);
                if (status <= 0)
                        return;
        }

        /* if we are implementing RTS/CTS, toggle that line */
        if (tty->termios.c_cflag & CRTSCTS)     {
                priv->mcr &= ~USBRSA_ST16C550_MCR_RTS;
                status = send_mcr_register(port);
                if (status != 0)
                        return;
        }
}


/***********************************************************************
* Name: usbrsa_unthrottle
* Purpose:
*
*
*
***********************************************************************/
static void usbrsa_unthrottle(struct tty_struct *tty)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int status;

        dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number);



        /* if we are implementing XON/XOFF, send the start character */
        if (I_IXOFF(tty)) {
                unsigned char start_char = START_CHAR(tty);

                status = usbrsa_write(tty, port, &start_char, 1);
                if (status <= 0)
                        return;
        }
        /* if we are implementing RTS/CTS, toggle that line */
        if (tty->termios.c_cflag & CRTSCTS)     {
                priv->mcr |= USBRSA_ST16C550_MCR_RTS;
                send_mcr_register(port);
        }
}


/***********************************************************************
* Name: usbrsa_tiocmset
* Purpose:
*
*
*
***********************************************************************/
static int  usbrsa_tiocmset(struct tty_struct *tty,
                        unsigned int set, unsigned int clear)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;
        int                                                     retval;

        if (port == NULL)
                return -ENODEV;


        dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number);

        spin_lock_irqsave(&priv->lock, flags);

        if (set & TIOCM_RTS)
                priv->mcr |= USBRSA_ST16C550_MCR_RTS;
        if (set & TIOCM_DTR)
                priv->mcr |= USBRSA_ST16C550_MCR_DTR;
        if (set & TIOCM_LOOP) {
                priv->mcr |= USBRSA_ST16C550_MCR_DIAG;
                priv->lloop = 1;
        }

        if (clear & TIOCM_RTS)
                priv->mcr &= ~USBRSA_ST16C550_MCR_RTS;
        if (clear & TIOCM_DTR)
                priv->mcr &= ~USBRSA_ST16C550_MCR_DTR;
        if (clear & TIOCM_LOOP) {
                priv->mcr &= ~USBRSA_ST16C550_MCR_DIAG;
                priv->lloop = 0;
        }

        /* bring OP1 and OP2 to defined states */
        priv->mcr &= ~USBRSA_ST16C550_MCR_OP1;
        priv->mcr &= ~USBRSA_ST16C550_MCR_OP2;

        spin_unlock_irqrestore(&priv->lock, flags);


        retval = send_mcr_register(port);
        dev_dbg(&port->dev, "%s: %d=send_mcr_register", __func__, retval);
        return retval;
}


/***********************************************************************
* Name: usbrsa_tiocmget
* Purpose:
*
*
*
***********************************************************************/
static int  usbrsa_tiocmget(struct tty_struct *tty)
{
        struct usb_serial_port          *port = tty->driver_data;
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        int                                                     retval;


        if (port == NULL)
                return -ENODEV;

        dev_dbg(&port->dev, "%s() - port %d", __func__, port->port_number);


        retval = fetch_msr_register(port);
        dev_dbg(&port->dev, "%s: %d=fetch_msr_register", __func__, retval);

        if (retval == 0) {
                retval = ((priv->mcr &  USBRSA_ST16C550_MCR_DTR) ? TIOCM_DTR : 
0)
                        | ((priv->mcr &  USBRSA_ST16C550_MCR_RTS) ? TIOCM_RTS : 
0)
                        | ((priv->mcr &  USBRSA_ST16C550_MCR_DIAG) ? TIOCM_LOOP 
: 0)
                        | ((priv->msr &  USBRSA_ST16C550_MSR_CTS) ? TIOCM_CTS : 
0)
                        | ((priv->msr &  USBRSA_ST16C550_MSR_CD) ? TIOCM_CD : 0)
                        | ((priv->msr &  USBRSA_ST16C550_MSR_RI) ? TIOCM_RI : 0)
                        | ((priv->msr &  USBRSA_ST16C550_MSR_DSR) ? TIOCM_DSR : 
0);

        }

        return retval;
}


/***********************************************************************
*                C O M P L E T I O N   H A N D L E R S
***********************************************************************/

/***********************************************************************
* Name: usbrsa_baudrate_lcr_callback
* Purpose:
*
*
***********************************************************************/
static void usbrsa_baudrate_lcr_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        unsigned long                           flags;

        dev_dbg(&port->dev, "%s() - port = %d, ep=0x%x", __func__, 
port->port_number,
                        priv->baudrate_lcr_urb->pipe);

        /* unlock urb */
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        if (status)     {
                dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, 
status);
        }
        wake_up(&priv->wait_flag);
}


/***********************************************************************
* Name: usbrsa_reset_callback
* Purpose:
*
*
***********************************************************************/
static void  usbrsa_reset_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        unsigned long                           flags;

        dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__, 
port->port_number,
                        priv->reset_urb->pipe);

        /* unlock urb */
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_RESET, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        if (status) {
                dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, 
status);

        }
        wake_up(&priv->wait_flag);
}


/***********************************************************************
* Name: usbrsa_status_callback
* Purpose:
*
*
***********************************************************************/
static void  usbrsa_status_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        __u8                                            *ep3in   = 
urb->transfer_buffer;
        unsigned long                           flags;
        int                                                     retval;
        int                                                     
read_urbs_needed = 0;
        int                                                     urb_index;
        unsigned int                            i;


/*      dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__,
port->port_number,
*                       priv->status_urb->pipe);
*/

        spin_lock_irqsave(&priv->lock, flags);
        /* read payload data of urb, i.e. bytes received and bytes
        * available in tx queue of USB-RSA
        */
        priv->nofTxBytesFree            = ep3in[0] + (256 * ep3in[1]);
        priv->nofRxBytesReceived        = ep3in[2] + (256 * ep3in[3]);
        /* unlock urb */
        clear_bit(LOCK_STATUS, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        if ((priv->debugNofTxBytesFree != priv->nofTxBytesFree) ||
                        (priv->debugRxBytesReceived !=  
priv->nofRxBytesReceived)) {
                printk("%s: nofTxBytesFree=%d,nofRxBytesReceived=%d\n",
                                __func__, priv->nofTxBytesFree, 
priv->nofRxBytesReceived);
        }
        priv->debugNofTxBytesFree =  priv->nofTxBytesFree;
        priv->debugRxBytesReceived = priv->nofRxBytesReceived;

        /* if coutinuous read enabled, either
        * -- issue next status request (USBRSA did not receive
        *    anything)
        * -- issue a read urb (if rx queue is filled)
        */
        if (priv->read_running == USBRSA_READ_RUNNING) {
                if (priv->nofRxBytesReceived != 0) {
                        /* USB-RSA received data */

                        /* compute urbs needed */
                        read_urbs_needed  = 
priv->nofRxBytesReceived/port->bulk_in_size;
                        if (priv->nofRxBytesReceived%port->bulk_in_size)
                                read_urbs_needed++;
                        dev_dbg(&port->dev, "%s(): EP1IN: rx=%d, 
urbs_needed=%d,size_of_urb=%d",
                                        __func__,
                                        priv->nofRxBytesReceived,
                                        read_urbs_needed,
                                        port->bulk_in_size);


                        /* issue read urbs */
                        if (read_urbs_needed > priv->urb_pool_size)
                                read_urbs_needed = priv->urb_pool_size;
                        for (i = 0; i < read_urbs_needed; i++) {
                                spin_lock_irqsave(&priv->lock, flags);
                                urb_index = 
find_first_zero_bit(&priv->read_urb_pool_lock,
                                                priv->urb_pool_size);
                                if (urb_index < priv->urb_pool_size) {
                                        set_bit(urb_index, 
&priv->read_urb_pool_lock);
                                        spin_unlock_irqrestore(&priv->lock, 
flags);

                                        /* submit read */
                                        dev_dbg(&port->dev, "%s(): submit read 
urb[%d]", __func__, urb_index);
                                        retval = 
usb_submit_urb(priv->read_urb_pool[urb_index], GFP_KERNEL);
                                        if (retval)     {
                                                /* return urb to read pool */
                                                spin_lock_irqsave(&priv->lock, 
flags);
                                                clear_bit(urb_index, 
&priv->read_urb_pool_lock);
                                                
spin_unlock_irqrestore(&priv->lock, flags);
                                                dev_dbg(&port->dev, "%s(): 
nonzero urb status: 0x%x", __func__, status);
                                                return;
                                        }
                                } else {
                                        spin_unlock_irqrestore(&priv->lock, 
flags);
                                        i = read_urbs_needed;
                                }
                        }
                }
                spin_lock_irqsave(&priv->lock, flags);
                set_bit(LOCK_STATUS, &priv->urb_lock);
                spin_unlock_irqrestore(&priv->lock, flags);
                retval = usb_submit_urb(priv->status_urb, GFP_KERNEL);
                if (retval != 0) {
                        dev_err(&port->dev, "%s(): usb_submit_urb() failed"
                                        " with error %d\n", __func__, retval);
                        spin_lock_irqsave(&priv->lock, flags);
                        clear_bit(LOCK_STATUS, &priv->urb_lock);
                        spin_unlock_irqrestore(&priv->lock, flags);
                }
        } else {
                /* reading from device ceased -- do nothing
                *dev_dbg(&port->dev,"%s(): reading stopped: 
tx_free=%d;rx_recv=%d",
                *               __func__, 
priv->nofTxBytesFree,priv->nofRxBytesReceived); */
        }
        if (status)     {
                dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, 
status);
        }
        if (priv->read_running == USBRSA_READ_RUNNING) {
                if ((jiffies - priv->debugTimeStamp)/HZ  > 1 )  {
                        dev_dbg(&port->dev,"%s(): usb_serial_port_softint", 
__func__);
                         priv->debugTimeStamp = jiffies;
                }
                usb_serial_port_softint(port);
        } else {
                dev_dbg(&port->dev, "%s(): wake_up", __func__);
                wake_up(&priv->wait_flag);
        }
        return;
}


/***********************************************************************
* Name: usbrsa_write_callback
* Purpose:
*
*
***********************************************************************/
static void  usbrsa_write_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        unsigned long                           flags;
        int                                                     urb_index;

        dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__, 
port->port_number,
                                priv->status_urb->pipe);

        usb_serial_debug_data(&port->dev, __func__,
                                urb->actual_length, urb->transfer_buffer);
        /* find urb in write pool */
        for (urb_index = 0; urb_index < priv->urb_pool_size; urb_index++) {
                if (urb == priv->write_urb_pool[urb_index])     {
                        /* urb found; return urb to pool */
                        spin_lock_irqsave(&priv->lock, flags);
                        clear_bit(urb_index, &priv->write_urb_pool_lock);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        break;
                }
        }

        if (urb != priv->write_urb_pool[urb_index])     {
                /* urb not found -- this points to a bug */
                dev_err(&port->dev, "%s(): urb not in pool",
                                __func__);
        }
        dev_dbg(&port->dev, "%s(): Returned URB %d", __func__, urb_index);
        if (status)     {
                dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, 
status);
        }
        usb_serial_port_softint(port);
}


/***********************************************************************
* Name: usbrsa_read_callback
* Purpose:
*
*
***********************************************************************/
static void  usbrsa_read_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        struct tty_struct                       *tty;
        int                                                     status  = 
urb->status;
        unsigned char                           *data   = urb->transfer_buffer;
        int                                                     urb_index;
        unsigned long                           flags;

        dev_dbg(&port->dev, "%s() - port = %d, ep=0x%x", __func__, 
port->port_number,
                                priv->status_urb->pipe);
        usb_serial_debug_data(&port->dev, __func__,
                        urb->actual_length, data);


        /* find urb in read pool */
        for (urb_index = 0; urb_index < priv->urb_pool_size; urb_index++) {
                if (urb == priv->read_urb_pool[urb_index]) {
                        /* urb found; */
                        break;
                }
        }
        if (urb != priv->read_urb_pool[urb_index]) {
                /* urb not found -- this points to a bug */
                dev_err(&port->dev, "%s(): urb not in pool",
                                __func__);
                return;
        }
        dev_dbg(&port->dev, "%s() - port = %d: urb_index=%d",
                        __func__, port->port_number, urb_index);

        tty = tty_port_tty_get(&port->port);
        if (tty != NULL && urb->actual_length > 0) {
                tty_insert_flip_string(tty->port, data, urb->actual_length);
                tty_flip_buffer_push(tty->port);
        }
        tty_kref_put(tty);

        /* return urb to pool */
        dev_dbg(&port->dev, "%s: return URB %d", __func__, urb_index);
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(urb_index, &priv->read_urb_pool_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        if (status)     {
                dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, 
status);
        }
        usb_serial_port_softint(port);
}


/***********************************************************************
* Name: usbrsa_mcr_callbacks
* Purpose:
*
*
***********************************************************************/
static void usbrsa_mcr_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        unsigned long                           flags;

        dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x, status=%d", __func__,
port->port_number,
                                        priv->mcr_urb->pipe, status);

        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_MCR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);


        if (status)     {
                dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, 
status);
        }
        wake_up(&priv->wait_flag);
}


/***********************************************************************
* Name: usbrsa_msr_callbackS
* Purpose:
*
*
***********************************************************************/
static void usbrsa_msr_callback(struct urb *urb)
{
        struct usb_serial_port          *port   = urb->context;
        struct usbrsa_port_private      *priv   = 
usb_get_serial_port_data(port);
        int                                                     status  = 
urb->status;
        unsigned long                           flags;
        __u8                                            *msr;

        dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x, status=%d", __func__,
port->port_number,
                                        priv->msr_urb->pipe, status);

        spin_lock_irqsave(&priv->lock, flags);
        msr = urb->transfer_buffer;
        priv->msr = msr[0];
        clear_bit(LOCK_MSR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        dev_dbg(&port->dev, "%s() - msr =%02x", __func__, priv->msr);

        if (status)     {
                dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, 
status);
        }
        wake_up(&priv->wait_flag);
}


/***********************************************************************
*                  Help Functions
***********************************************************************/

/***********************************************************************
* Name: usbrsa_allocate_write_urbs
* Purpose: Allocates and initializes pool of write urbs to EP1OUT
*
*
***********************************************************************/
int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data)
{
        int i;
        unsigned long flags;
        struct urb *urb;
        void *buf = NULL;

        printk("%s() Mark 1\n", __func__);
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); */
        printk("%s() Mark 2\n", __func__);

        for (i = 0; i < priv_data->urb_pool_size; i++) {
                printk("%s; i=%d\n", __func__, i);
                urb = usb_alloc_urb(0, GFP_KERNEL);
                printk("%s; urb=%p\n", __func__, urb);
                printk("%s: pre priv_data->write_urb_pool[%d]=%p\n", __func__, 
i,
priv_data->write_urb_pool[i]);
                priv_data->write_urb_pool[i] = urb;
                printk("%s: post priv_data->write_urb_pool[%d]=%p\n", __func__, 
i,
priv_data->write_urb_pool[i]);
                if (priv_data->write_urb_pool[i] == NULL) {
                        goto out_alloc_write_urb_pool;
                }
                printk("%s: pre 
priv_data->write_urb_pool[%d]->transfer_buffer=%p\n",
                                __func__, i, 
priv_data->write_urb_pool[i]->transfer_buffer);
                buf = kmalloc(priv_data->parent_port->bulk_out_size, 
GFP_KERNEL);
                printk("%s: post buf=%p\n", __func__, buf);
                priv_data->write_urb_pool[i]->transfer_buffer = buf;

                printk("%s: post 
priv_data->write_urb_pool[%d]->transfer_buffer=%p\n",
                                __func__, i, 
priv_data->write_urb_pool[i]->transfer_buffer);
                if (priv_data->write_urb_pool[i]->transfer_buffer == NULL) {
                        goto out_alloc_write_urb_pool;
                }
                printk("%s; Mark3\n", __func__);
                usb_fill_bulk_urb(priv_data->write_urb_pool[i],
                                        priv_data->parent_serial->dev,
                                        
usb_sndbulkpipe(priv_data->parent_serial->dev, EP1OUT),
                                        
priv_data->write_urb_pool[i]->transfer_buffer,
                                        priv_data->parent_port->bulk_out_size,
                                        usbrsa_write_callback, 
priv_data->parent_port);
                printk("%s; Mark4\n", __func__);

                printk("%s -- clear_bit\n", __func__);
                spin_lock_irqsave(&priv_data->lock, flags);
                clear_bit(i, &priv_data->write_urb_pool_lock);
                spin_unlock_irqrestore(&priv_data->lock, flags);
                printk("%s -- clear_bit end\n", __func__);
        }
        printk("%s end", __func__);
        return 0;

        out_alloc_write_urb_pool:
                while (i > 0) {
                        if (priv_data->write_urb_pool[i] != NULL) {
                                if 
(priv_data->write_urb_pool[i]->transfer_buffer != NULL) {
                                        
kfree(priv_data->write_urb_pool[i]->transfer_buffer);
                                }
                                usb_free_urb(priv_data->write_urb_pool[i]);
                        }
                i--;
                }
                printk("%s end error", __func__);
                return -ENOMEM;
}

/***********************************************************************
* Name: allocate_read_urbs
* Purpose: Allocates and initializes pool of read urbs to EP1IN
*
*
***********************************************************************/
int allocate_read_urbs(struct usbrsa_port_private *priv_data)
{
        int i;
        unsigned long flags;
        struct urb *urb;
        void *buf = NULL;

        printk("%s start", __func__);
/*      dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/

        for (i = 0; i < priv_data->urb_pool_size; i++)  {
                urb = usb_alloc_urb(0, GFP_KERNEL);
                priv_data->read_urb_pool[i]  = urb;
                if (priv_data->read_urb_pool[i] == NULL) {
                        goto out_alloc_read_urb_pool;
                }
                buf = kmalloc(priv_data->parent_port->bulk_in_size, GFP_KERNEL);
                priv_data->read_urb_pool[i]->transfer_buffer = buf;
                if (priv_data->read_urb_pool[i]->transfer_buffer == NULL) {
                        goto out_alloc_read_urb_pool;
                }

                usb_fill_bulk_urb(priv_data->read_urb_pool[i],
                                        priv_data->parent_serial->dev,
                                        
usb_rcvbulkpipe(priv_data->parent_serial->dev, EP1OUT),
                                        
priv_data->read_urb_pool[i]->transfer_buffer,
                                        priv_data->parent_port->bulk_in_size,
                                        usbrsa_read_callback, 
priv_data->parent_port);

                spin_lock_irqsave(&priv_data->lock, flags);
                clear_bit(i, &priv_data->read_urb_pool_lock);
                spin_unlock_irqrestore(&priv_data->lock, flags);
        }
        printk("%s end", __func__);
        return 0;

out_alloc_read_urb_pool:
                while (i > 0) {
                        if (priv_data->read_urb_pool[i] != NULL) {
                                if 
(priv_data->read_urb_pool[i]->transfer_buffer != NULL) {
                                        
kfree(priv_data->read_urb_pool[i]->transfer_buffer);
                                }
                                usb_free_urb(priv_data->read_urb_pool[i]);
                        }
                i--;
                }
                printk("%s end error", __func__);
                return -ENOMEM;
}

/***********************************************************************
* Name: allocate_baudrate_lcr_urb
* Purpose: Allocates and initializes urb to set baudrate and LCR
*          to EP2OUT or EP5OUT
*
*
***********************************************************************/
static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;

/*      dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); */
        printk("%s: Start priv_data=%p\n", __func__, priv_data);
        priv_data->baudrate_lcr_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (priv_data->baudrate_lcr_urb == NULL) {
                goto out_alloc_baudrate_lcr;
        }
        printk("%s: urb successfully allocated @ %p\n", __func__,
priv_data->baudrate_lcr_urb);
        priv_data->baudrate_lcr_urb->transfer_buffer = kmalloc(EP3OUTLEN, 
GFP_KERNEL);
        if (priv_data->baudrate_lcr_urb->transfer_buffer == NULL) {
                goto out_alloc_baudrate_lcr;
        }
        printk("%s: transfer buffer successfully allocated @ %p\n",
                        __func__, priv_data->baudrate_lcr_urb->transfer_buffer);
        /* sent to EP2OUT by default thereby disabling  the rx handling of 
USB-RSA.
        * The USB-RSA does no longer process or forward the data it receives */
        usb_fill_bulk_urb(priv_data->baudrate_lcr_urb, 
priv_data->parent_serial->dev,
                        usb_sndbulkpipe(priv_data->parent_serial->dev,
                        EP5OUT),
                        priv_data->baudrate_lcr_urb->transfer_buffer, EP5OUTLEN,
                        usbrsa_baudrate_lcr_callback, priv_data->parent_port);

        spin_lock_irqsave(&priv_data->lock, flags);
        clear_bit(LOCK_BAUDRATE_LCR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);

        return 0;

out_alloc_baudrate_lcr:
        spin_lock_irqsave(&priv_data->lock, flags);
        set_bit(LOCK_BAUDRATE_LCR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);
        dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate
memory\n", __func__);
        return -ENOMEM;
}

/***********************************************************************
* Name: allocate_reset_urb
* Purpose: Allocates and initializes reset urb to EP4OUT
*
*
***********************************************************************/
static int allocate_reset_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;

        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s() start\n", __func__);

        priv_data->reset_urb = usb_alloc_urb(0, GFP_KERNEL);
        printk("%s() reset_urb=%p\n", __func__, priv_data->reset_urb);
        if (priv_data->reset_urb == NULL) {
                goto out_alloc_reset;
        }

        priv_data->reset_urb->transfer_buffer = NULL;
        printk("%s() reset_urb->transfer_buffer=%p\n", __func__, 
priv_data->reset_urb);

        usb_fill_bulk_urb(priv_data->reset_urb, priv_data->parent_serial->dev,
                        usb_sndbulkpipe(priv_data->parent_serial->dev, EP4OUT),
                        priv_data->reset_urb->transfer_buffer, EP4OUTLEN,
                        usbrsa_reset_callback, priv_data->parent_port);

        spin_lock_irqsave(&priv_data->lock, flags);
        clear_bit(LOCK_RESET, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);

        return 0;

out_alloc_reset:
        spin_lock_irqsave(&priv_data->lock, flags);
        set_bit(LOCK_RESET, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);
        dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate 
memory",
__func__);
        return -ENOMEM;
}

/***********************************************************************
* Name: allocate_status_urb
* Purpose: Allocates and initializes status urb from EP3IN
*
*
***********************************************************************/
static int allocate_status_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;

        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s() -- start\n", __func__);

        priv_data->status_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (priv_data->status_urb == NULL) {
                goto out_alloc_status;
        }
        printk("%s()  priv_data->status_urb =%p\n", __func__, 
priv_data->status_urb);
        priv_data->status_urb->transfer_buffer = kmalloc(EP3INLEN, GFP_KERNEL);
        if (priv_data->status_urb->transfer_buffer == NULL)     {
                goto out_alloc_status;
        }
        printk("%s()  priv_data->status_urb->transfer_buffer =%p\n", __func__,
                        priv_data->status_urb->transfer_buffer);
        usb_fill_bulk_urb(priv_data->status_urb, priv_data->parent_serial->dev,
                        usb_rcvbulkpipe(priv_data->parent_serial->dev, EP3IN),
                        priv_data->status_urb->transfer_buffer, EP3INLEN,
                        usbrsa_status_callback, priv_data->parent_port);
        spin_lock_irqsave(&priv_data->lock, flags);
        clear_bit(LOCK_STATUS, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);

        return 0;

out_alloc_status:
        spin_lock_irqsave(&priv_data->lock, flags);
        set_bit(LOCK_STATUS, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);
        dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate 
memory",
__func__);
        return -ENOMEM;
}


/***********************************************************************
* Name: allocate_mcr_urb
* Purpose: Allocates and initializes modem control register urb
*                       to EP3OUT
*
***********************************************************************/
static int allocate_mcr_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;

        printk("%s() -- start\n", __func__);
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        priv_data->mcr_urb = usb_alloc_urb(0, GFP_KERNEL);
        printk("%s() priv_data->mcr_urb = %p\n", __func__, priv_data->mcr_urb);

        if (priv_data->mcr_urb == NULL) {
                goto out_alloc_mcr;
        }

        priv_data->mcr_urb->transfer_buffer = kmalloc(EP3OUTLEN, GFP_KERNEL);
        if (priv_data->mcr_urb->transfer_buffer == NULL) {
                goto out_alloc_mcr;
        }
        printk("%s() priv_data->mcr_urb->transfer_buffer = %p\n", __func__,
                        priv_data->mcr_urb->transfer_buffer);

        usb_fill_bulk_urb(priv_data->mcr_urb, priv_data->parent_serial->dev,
                        usb_sndbulkpipe(priv_data->parent_serial->dev, EP3OUT),
                        priv_data->mcr_urb->transfer_buffer, EP3OUTLEN,
                        usbrsa_mcr_callback, priv_data->parent_port);
        spin_lock_irqsave(&priv_data->lock, flags);
        clear_bit(LOCK_MCR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);

        return 0;

out_alloc_mcr:
        spin_lock_irqsave(&priv_data->lock, flags);
        set_bit(LOCK_MCR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);
        dev_dbg(&(priv_data->parent_port->dev),
                        "%s(): Could not allocate memory", __func__);
        return -ENOMEM;
}


/***********************************************************************
* Name: allocate_msr_urb
* Purpose: Allocates and initializes modem status register urb
*                       to EP3IN
*
***********************************************************************/
static int allocate_msr_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;

        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s() -- start \n", __func__);

        priv_data->msr_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (priv_data->msr_urb == NULL) {
                goto out_alloc_msr;
        }
        printk("%s() priv_data->msr_urb=%p \n", __func__, priv_data->msr_urb);

        priv_data->msr_urb->transfer_buffer = kmalloc(EP3OUTLEN, GFP_KERNEL);
        if (priv_data->msr_urb->transfer_buffer == NULL) {
                goto out_alloc_msr;
        }
        printk("%s() priv_data->msr_urb->transfer_buffer=%p \n",
                        __func__, priv_data->msr_urb->transfer_buffer);

        usb_fill_bulk_urb(priv_data->msr_urb, priv_data->parent_serial->dev,
                        usb_rcvbulkpipe(priv_data->parent_serial->dev, EP2IN),
                        priv_data->msr_urb->transfer_buffer, EP2INLEN,
                        usbrsa_msr_callback, priv_data->parent_port);
        spin_lock_irqsave(&priv_data->lock, flags);
        clear_bit(LOCK_MSR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);

        return 0;

out_alloc_msr:
        spin_lock_irqsave(&priv_data->lock, flags);
        set_bit(LOCK_MSR, &priv_data->urb_lock);
        spin_unlock_irqrestore(&priv_data->lock, flags);
        dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate 
memory",
__func__);
        return -ENOMEM;
}


/***********************************************************************
* Name: release_write_urbs
* Purpose: Deallocate resource pool for EP1OUT
*
*
***********************************************************************/
static void release_write_urbs(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;
        int                     i;

        /*dev_dbg(&(priv_data->parent_port->dev),"%s():
pool_size=%d",__func__,priv_data->urb_pool_size);*/
        printk("%s(): pool_size=%d\n", __func__, priv_data->urb_pool_size);
        for (i = 0; i < priv_data->urb_pool_size; i++) {
                printk("%s: post priv_data->write_urb_pool[%d]=%p\n",
                                __func__, i, priv_data->write_urb_pool[i]);
                if (priv_data->write_urb_pool[i] != NULL) {
                        printk("%s: post 
priv_data->write_urb_pool[%d]->transfer_buffer=%p\n",
__func__, i,
                                                                        
priv_data->write_urb_pool[i]->transfer_buffer);
                        if (priv_data->write_urb_pool[i]->transfer_buffer != 
NULL) {
                                
kfree(priv_data->write_urb_pool[i]->transfer_buffer);
                        }
                        usb_free_urb(priv_data->write_urb_pool[i]);
                }
                spin_lock_irqsave(&priv_data->lock, flags);
                set_bit(i, &priv_data->write_urb_pool_lock);
                spin_unlock_irqrestore(&priv_data->lock, flags);
        }
}

/***********************************************************************
* Name: release_read_urbs
* Purpose: Deallocate resource pool for EP1IN
*
*
***********************************************************************/
static void release_read_urbs(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;
        int             i;

        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s()\n", __func__);
        for (i = 0; i < priv_data->urb_pool_size; i++) {
                if (priv_data->read_urb_pool[i] != NULL) {
                        if (priv_data->read_urb_pool[i]->transfer_buffer != 
NULL) {
                                
kfree(priv_data->read_urb_pool[i]->transfer_buffer);
                        }
                        usb_free_urb(priv_data->read_urb_pool[i]);
                }

                spin_lock_irqsave(&priv_data->lock, flags);
                set_bit(i, &priv_data->read_urb_pool_lock);
                spin_unlock_irqrestore(&priv_data->lock, flags);
        }
}

/***********************************************************************
* Name: release_baudrate_lcr_urb
* Purpose: Remove baudrate_lcr_urb
*
*
***********************************************************************/
static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data)
{
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s: Start", __func__);
        if (priv_data->baudrate_lcr_urb != NULL) {
                if (priv_data->baudrate_lcr_urb->transfer_buffer != NULL) {
                        kfree(priv_data->baudrate_lcr_urb->transfer_buffer);
                }
                usb_free_urb(priv_data->baudrate_lcr_urb);
                priv_data->baudrate_lcr_urb = NULL;
        }
}

/***********************************************************************
* Name: release_reset_urb
* Purpose: Remove release_reset_urb
*
*
***********************************************************************/
static void release_reset_urb(struct usbrsa_port_private *priv_data)
{
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s()\n", __func__);
        if (priv_data->reset_urb != NULL) {
                usb_free_urb(priv_data->reset_urb);
                priv_data->reset_urb = NULL;
        }
}

/***********************************************************************
* Name: release_status_urb
* Purpose: Remove release_status_urb
*
*
***********************************************************************/
static void release_status_urb(struct usbrsa_port_private *priv_data)
{
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s()\n", __func__);
        if (priv_data->status_urb != NULL) {
                if (priv_data->status_urb->transfer_buffer != NULL)     {
                        kfree(priv_data->status_urb->transfer_buffer);
                }
                usb_free_urb(priv_data->status_urb);
                priv_data->status_urb = NULL;
        }
}

/***********************************************************************
* Name: release_mcr_urb
* Purpose: Remove release_mcr_urb
*
*
***********************************************************************/
static void release_mcr_urb(struct usbrsa_port_private *priv_data)
{
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s()\n", __func__);
        if (priv_data->mcr_urb != NULL) {
                if (priv_data->mcr_urb->transfer_buffer != NULL) {
                        kfree(priv_data->mcr_urb->transfer_buffer);
                }
                usb_free_urb(priv_data->mcr_urb);
                priv_data->mcr_urb = NULL;
        }
}


/***********************************************************************
* Name: release_msr_urb
* Purpose: deallocate msr_urb
*
*
***********************************************************************/
static void release_msr_urb(struct usbrsa_port_private *priv_data)
{
        /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/
        printk("%s()\n", __func__);
        if (priv_data->msr_urb != NULL) {
                if (priv_data->msr_urb->transfer_buffer != NULL) {
                        kfree(priv_data->msr_urb->transfer_buffer);
                }
                usb_free_urb(priv_data->msr_urb);
                priv_data->msr_urb = NULL;
        }
}


/***********************************************************************
* Name: prepare_baudrate_lcr_urb
* Purpose: Computes urb setting Line Control Regsister (LCR) and
*                       divider register (DLL+DLM) to determine baud rate of
*                       ST16c550. The urb is sent to either EP2OUT and EP5OUT.
*                       An urb to EP2OUT sets the registers of the USB-RSA and
*                       enables receive interrupts. An urb to EP5OUT only sets
*                       the register.
*
*
*                       Format of EP2OUT/EP5OUT
*                       Byte 0: DLL of ST16c550
*                       Byte 1: DLM of ST16c550
*                       Byte 2: LCR of ST16c550
*
***********************************************************************/
static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate,
                        int endpoint, struct usb_serial_port *port)
{
        struct usbrsa_port_private      *priv           = 
usb_get_serial_port_data(port);
        unsigned long                           flags;
        long                                            t;
        int                                                     retval;
        __u8                                            lcr                     
= 0;
        __u16                                           divisor         = 0;
        __u8                                            *buffer_ptr     = 
priv->baudrate_lcr_urb->transfer_buffer;

        dev_dbg(&port->dev, "%s() CFLAG=%u SPEED=%u ep=%d", __func__,
                        cflag, baud_rate, endpoint);
        /* if word length is 5 bit, stop bit length is 1,5 bit times
        * else 2 bit times
        */

        /* restrict baud_rate to boundaries determined by
        * USB-RSA hardware
        */
        if (baud_rate < 75)
                baud_rate = 75;
        if (baud_rate > 460800)
                baud_rate = 460800;


        divisor = USBRSA_ST16C550_CLOCK / (16 * baud_rate);
        priv->dll = divisor & 0xFF;
        priv->dlm = (divisor & 0xFF00) >> 8;



        switch (cflag & CSIZE) {
        case CS5:
                lcr = USBRSA_ST16C550_LCR_CS5;
                break;
        case CS6:
                lcr = USBRSA_ST16C550_LCR_CS6;
                break;
        case CS7:
                lcr = USBRSA_ST16C550_LCR_CS7;
                break;
        default:
        case CS8:
                lcr = USBRSA_ST16C550_LCR_CS8;
                break;
        }

        /* determine the parity */
        if (cflag & PARENB)
                if (cflag & CMSPAR)
                        if (cflag & PARODD)
                                lcr |= USBRSA_ST16C550_LCR_MARK;
                        else
                                lcr |= USBRSA_ST16C550_LCR_SPACE;
                else
                        if (cflag & PARODD)
                                lcr |= USBRSA_ST16C550_LCR_ODD;
                        else
                                lcr |= USBRSA_ST16C550_LCR_EVEN;
        else
                lcr |= USBRSA_ST16C550_LCR_NONE;


        /* figure out the stop bits requested */
        if (cflag & CSTOPB)
                lcr |= USBRSA_ST16C550_LCR_STOP2;
        else
                lcr |= USBRSA_ST16C550_LCR_STOP1;

        /* FW of USB-RSA expects bit 7 (Baud Rate Counter Latch) to be 0 */

        lcr &= 0x7F;
        priv->lcr = lcr;

        *buffer_ptr = priv->dll;
        buffer_ptr++;
        *buffer_ptr = priv->dlm;
        buffer_ptr++;
        *buffer_ptr = priv->lcr;


        dev_dbg(&port->dev, "%s() 
ST16C550.DLL=%d;ST16C550.DLM=%d;ST16C550.LCR=%d",
                        __func__, priv->dll, priv->dlm, priv->lcr);

        spin_lock_irqsave(&priv->lock, flags);
        if (!(test_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock))) {
                set_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock);
                priv->baudrate_lcr_urb->pipe =
                        usb_sndbulkpipe(priv->parent_serial->dev, endpoint);
                spin_unlock_irqrestore(&priv->lock, flags);

                retval  = usb_submit_urb(priv->baudrate_lcr_urb, GFP_ATOMIC);
        } else {
                /* urb already in use */
                spin_unlock_irqrestore(&priv->lock, flags);
                dev_dbg(&port->dev, "%s(): Cannot reserve baudrate_lcr_urb", 
__func__);
                /* fix me: return appropriate return code */
                retval = -1;
                /* end fix me */
                goto send_baudrate_lcr_exit;
        }

        if (retval) {
                /* something bad happened, let's free up the urb */
                dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, 
retval);
                goto send_baudrate_lcr_exit;
        }

   /* wait for the command to complete
        * (waits, until timeout or condition==true)
        */
        t = wait_event_timeout(priv->wait_flag,
                (test_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock) == 0), 
COMMAND_TIMEOUT);

        if (!t) {
                /* timeout. Dequeue urb */
                usb_kill_urb(priv->baudrate_lcr_urb);
                dev_dbg(&port->dev, "%s - sending baudrate_lcr_urb timed out.", 
__func__);
                retval = -ETIMEDOUT;
                goto send_baudrate_lcr_exit;
        }

send_baudrate_lcr_exit:
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        dev_dbg(&port->dev, "%s() leaving", __func__);
        return retval;
}


/***********************************************************************
* Name: send_mcr_register
* Purpose: Sends MCR value in private data structure of device
*                       to USBRSA
*
*                       Format of EP3OUT
*                       USB Message Length: 1 Byte
*                       Bit0: DTR
*                       Bit1: RTS
*                       Bit2: OP1
*                       Bit3: OP2
*                       Bit4: Diagnostics mode
*
***********************************************************************/
static int send_mcr_register(struct usb_serial_port *port)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                   flags;
        long                                    t;
        int retval;

        dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->mcr);


        spin_lock_irqsave(&priv->lock, flags);
        set_bit(LOCK_MCR, &priv->urb_lock);
        memcpy(priv->mcr_urb->transfer_buffer, &priv->mcr, 1);
        spin_unlock_irqrestore(&priv->lock, flags);

        retval  = usb_submit_urb(priv->mcr_urb, GFP_ATOMIC);

        if (retval) {
        /* something bad happened, let's free up the urb */
                dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, 
retval);
                goto send_mcr_exit;
        }

        /* wait for the command to complete
        * (waits, until timeout or condition==true)
        */
        t = wait_event_timeout(priv->wait_flag,
                        (test_bit(LOCK_MCR, &priv->urb_lock) == 0), 
COMMAND_TIMEOUT);
        if (!t) {
                /* fetching of msr */
                usb_kill_urb(priv->mcr_urb);
                dev_dbg(&port->dev, "%s - sending mcr timed out.", __func__);
                retval = -ETIMEDOUT;
                goto send_mcr_exit;
        }

send_mcr_exit:
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_MCR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        return retval;
}


/***********************************************************************
* Name: fetch_msr_register
* Purpose: Get MSR value from USBRSA and stores it in private data
*          structure
*
*                       Format of EP2IN
*                       USB Message Length: 1 Byte
*                       Bit0: Delta CTS (1 indicates a change on the line)
*                       Bit1: Delta DTS (1 indicates a change on the line)
*                       Bit2: Delta RI (1 indicates a change on the line)
*                       Bit3: Delta CD (1 indicates a change on the line)
*                       Bit4: CTS
*                       Bit5: DTS
*                       Bit6: RI
*                       Bit7: CD
*
***********************************************************************/
static int fetch_msr_register(struct usb_serial_port *port)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;
        long                                            t;
        int retval;

        dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->msr);


        spin_lock_irqsave(&priv->lock, flags);
        set_bit(LOCK_MSR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        retval  = usb_submit_urb(priv->msr_urb, GFP_ATOMIC);

        if (retval)     {
                /* something bad happened, let's free up the urb */
                dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, 
retval);
                goto send_msr_exit;
        }

        /* wait for the command to complete
         * (waits, until timeout or condition==true)
        */
        t = wait_event_timeout(priv->wait_flag,
                        (test_bit(LOCK_MSR, &priv->urb_lock) == 0), 
COMMAND_TIMEOUT);
        if (!t) {
                /* fetching of msr */
                usb_kill_urb(priv->msr_urb);
                dev_dbg(&port->dev, "%s - fetching msr timed out.", __func__);
                retval = -ETIMEDOUT;
                goto send_msr_exit;
        }


send_msr_exit:
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_MSR, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->msr);
        return retval;
}


/***********************************************************************
* Name: send_reset
* Purpose: sent reset urb to USBRSA and wait for completion
*
*
***********************************************************************/
static int send_reset(struct usb_serial_port *port)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;
        long                                            t;
        int                                             retval;

        dev_dbg(&port->dev, "%s: ", __func__);


        spin_lock_irqsave(&priv->lock, flags);
        set_bit(LOCK_RESET, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        retval  = usb_submit_urb(priv->reset_urb, GFP_ATOMIC);

        if (retval)     {
                /* something bad happened, let's free up the urb */
                dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, 
retval);
                goto send_reset_exit;
        }

        /* wait for the command to complete
         * (waits, until timeout or condition==true) */
        t = wait_event_timeout(priv->wait_flag,
                        (test_bit(LOCK_RESET, &priv->urb_lock) == 0), 
COMMAND_TIMEOUT);
        if (!t) {
                /* fetching of msr */
                usb_kill_urb(priv->reset_urb);
                dev_dbg(&port->dev, "%s - reset timed out.", __func__);
                retval = -ETIMEDOUT;
                goto send_reset_exit;
        }


send_reset_exit:
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_RESET, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);
        return retval;
}


/***********************************************************************
* Name: wait_modem_info
* Purpose: waits until a line reflected in the MSR (modem status
*                       register) changes. Lines that can be tested are:
*                       - CTS
*                       - DSR
*                       - RI
*                       - CD
*
*
***********************************************************************/
static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        unsigned long                           flags;
        unsigned int                            prev, status;
        unsigned int                            changed;
        int                                             retval;

        spin_lock_irqsave(&priv->lock, flags);

        retval = fetch_msr_register(port);
        if (retval != 0) {
                goto bailout_wait_modem_info;
        }
        spin_lock_irqsave(&priv->lock, flags);
        prev = priv->msr;
        spin_unlock_irqrestore(&priv->lock, flags);

        while (1) {
                retval = fetch_msr_register(port);
                if (retval != 0) {
                        goto bailout_wait_modem_info;
                }
                spin_lock_irqsave(&priv->lock, flags);
                status = priv->msr;
                spin_unlock_irqrestore(&priv->lock, flags);

                if (signal_pending(current))
                        return -ERESTARTSYS;

                spin_lock_irqsave(&priv->lock, flags);
                changed = prev ^ status;
                prev = status;
                spin_unlock_irqrestore(&priv->lock, flags);

                if (((arg & TIOCM_RNG) && (changed & USBRSA_ST16C550_MSR_RI)) ||
                        ((arg & TIOCM_DSR) && (changed & 
USBRSA_ST16C550_MSR_DSR)) ||
                        ((arg & TIOCM_CD)  && (changed & 
USBRSA_ST16C550_MSR_CD)) ||
                        ((arg & TIOCM_CTS) && (changed & 
USBRSA_ST16C550_MSR_CTS)))
                        return 0;

        }

bailout_wait_modem_info:
        /* NOTREACHED */
        return retval;
}


/***********************************************************************
* Name: get_serial_info
* Purpose: fills a struct containing information about the serial
*                       port.
*
*
***********************************************************************/
static int get_serial_info(struct usb_serial_port  *port,
        struct serial_struct __user *retinfo)
{
        struct usbrsa_port_private      *priv = usb_get_serial_port_data(port);
        struct serial_struct            tmp;

        if (!retinfo)
                return -EFAULT;

        memset(&tmp, 0, sizeof(tmp));

        tmp.type                = PORT_16550A;
        tmp.line                = port->minor;
        tmp.port                = port->port_number;
        tmp.irq                 = 0;
        tmp.flags               = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
        tmp.xmit_fifo_size      = priv->urb_pool_size * port->bulk_out_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;
}



static struct usb_serial_driver * const serial_drivers[] = {
        &usbrsa_preenum_device, &usbrsa_enumerated_device, NULL
};

module_usb_serial_driver(serial_drivers, id_table_combined);


/*
 * request_module("ezusb");
 * request_module("usbserial");
*/

MODULE_FIRMWARE("usbrsa.fw");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");


module_param(debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debug");


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to