Re: usb serial driver: private data already deallocated when release function is called

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Greg

  
> Do you have a pointer to your code anywhere?  That would be the easiest
> way to help you out here.  Otherwise we are just guessing as to the
> issues involved.

Not really -- I hence pasted it into this posting. I hope that is OK and does
violate some etiquette of this list.
Btw. are there repositories that would be suitable to make highly experimental
code available ? 
 
Thanks

Tilman
/* File: usbrsatest.c
 * Driver for IO-Data's USB RSA serial dongle (test driver)
 *      Copyright (C) 2012
 *         Tilman Glotzner
 *
 *
 *      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.
 *
 *
 *
 */


#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/firmware.h>
#include <linux/device.h>
#include <linux/usb/ezusb.h>
//#include <linux/ihex.h>
#include "usbrsa.h"

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

char buffer_tx[65];
char buffer_rx[65];

/*
 * Version Information
 */
#define DRIVER_VERSION "v0.1"
#define DRIVER_AUTHOR "Tilman Gloetzner <tilmanglotzner@xxxxxxxxx>"
#define DRIVER_DESC "IO-Data USB-RSA test driver"


#define IODATA_VENDOR_ID                        0x4bb
#define IODATA_USBRSA_PREENUM_ID        0xa01
#define IODATA_USBRSA_ID                        0xa03
#define IODATA_USBRSA_FW_STRING         "USB-RSA Test-FW"

#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_test_firmware_download(struct usb_serial *serial,
                                        const struct usb_device_id *id);
static int usbrsa_test_firmware_attach(struct usb_serial *serial);
////////////////////////////////////////////////////////////////////////
//                   Driver object declaration
////////////////////////////////////////////////////////////////////////
static struct usb_serial_driver usbrsa_test_preenum_device = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "usbrsanofirm",
        },
        .description =          "IO-DATA - USB-RSA - (test prerenumeration)",
        .id_table =             id_table_prerenumeration,
        .num_ports =            1,
        .probe =                usbrsa_test_firmware_download,
        .attach =               usbrsa_test_firmware_attach,
};


////////////////////////////////////////////////////////////////////////
//                   Functions
////////////////////////////////////////////////////////////////////////


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

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

        response = ezusb_fx1_ihex_firmware_download(serial->dev, "usbrsatest.fw");

        if (response < 0)
                goto fwdownload_out0;


        // The USB-RSA does not reenumerate without toggeling the reset bit
        // one more time
     //   response = ezusb_fx1_set_reset(serial->dev, 1);
     //   response = ezusb_fx1_set_reset(serial->dev, 0);
        dev_dbg(&serial->dev->dev,"%s(): Firmware downloaded.",__func__);

        return 0;
 fwdownload_out0:
        return -ENOENT;;
}


//////////////////////////////////////////////////////////////////////
// Name: usbrsa_firmware_attach
// Purpose: Prevents the driver from attaching, so that can attach
//          to the reenumerated device
//
//////////////////////////////////////////////////////////////////////
static int usbrsa_test_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_test_attach(struct usb_serial *serial);
static void  usbrsa_test_release(struct usb_serial *serial);
static int usbrsa_test_port_probe(struct usb_serial_port* port);
static int usbrsa_test_port_remove(struct usb_serial_port* port);
static int  usbrsa_test_open(struct tty_struct *tty,
                        struct usb_serial_port *port);

static void usbrsa_test_close(struct usb_serial_port *port);
//static void usbrsa_test_init_termios(struct tty_struct *tty);
static int  usbrsa_test_write(struct tty_struct *tty,
                        struct usb_serial_port *port,
                        const unsigned char *buf, int count);
static int usbrsa_test_write_room(struct tty_struct *tty);
static int usbrsa_test_chars_in_buffer(struct tty_struct *tty);
static void usbrsa_test_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);

static int fetch_status(struct usb_serial_port *port);
////////////////////////////////////////////////////////////////////////
//              Completion Handler Prototypes
////////////////////////////////////////////////////////////////////////
static void  usbrsa_test_write_callback(struct urb *urb);
static void  usbrsa_test_read_callback(struct urb *urb);
static void  usbrsa_test_status_callback(struct urb *urb);

///l/////////////////////////////////////////////////////////////////////
//                   Driver object declaration
////////////////////////////////////////////////////////////////////////
static struct usb_serial_driver usbrsa_test_enumerated_device =
{
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "usbrsa_test",
        },
        .description =          "IO-DATA - USB-RSA test",
        .id_table =             id_table_std,
        .num_ports =            1,
        .attach =               usbrsa_test_attach,
        .release =                              usbrsa_test_release,
        .port_probe =                   usbrsa_test_port_probe,
        .port_remove =                  usbrsa_test_port_remove,
        .open =                                 usbrsa_test_open,
        .close =                                usbrsa_test_close,
        .write =                                usbrsa_test_write,
        .write_bulk_callback =  usbrsa_test_write_callback,
        .read_bulk_callback =   usbrsa_test_read_callback,
        .set_termios =          usbrsa_test_set_termios,
        .write_room =                   usbrsa_test_write_room,
        .chars_in_buffer =              usbrsa_test_chars_in_buffer
};

////////////////////////////////////////////////////////////////////////
//                   Function Prototypes of help functions
////////////////////////////////////////////////////////////////////////
static int allocate_write_urb(struct usbrsa_port_private *priv_data);
static int allocate_read_urb(struct usbrsa_port_private *priv_data);
static int allocate_status_urb(struct usbrsa_port_private *priv_data);

static void release_write_urb(struct usbrsa_port_private *priv_data);
static void release_read_urb(struct usbrsa_port_private *priv_data);
static void release_status_urb(struct usbrsa_port_private *priv_data);
////////////////////////////////////////////////////////////////////////
//                   Functions
////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
// Name: usbrsa_attach
// Purpose: Creates private data structures of driver
//
//
//////////////////////////////////////////////////////////////////////
static int  usbrsa_test_attach(struct usb_serial *serial)
{
       int                                             i;
        int                                                     ret = 0;
        struct usb_serial_port*         serport;
        struct usbrsa_port_private*     priv = NULL;


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

        // if usbrsa does not contain the gpl firmware, download firmware
        if (strncmp(serial->dev->serial,
                        IODATA_USBRSA_FW_STRING,
                        strlen(IODATA_USBRSA_FW_STRING)) != 0 )
        {
                dev_dbg(&serial->dev->dev,"%s(): Unexpected firmware: %s
",__func__, serial->dev->serial);
                if (usbrsa_test_firmware_download(serial,NULL) != 0)
                {
                        dev_dbg(&serial->dev->dev,"%s(): Firmware download
failed ",__func__);
                }
                return -1;
        }

        for (i = 0; i < serial->num_ports; i++)
        {
            // allocate struct for driver's private data
                priv = kmalloc(sizeof(struct usbrsa_port_private), GFP_KERNEL);
                if (priv == NULL)
                {
                        dev_err(&serport->dev,
                                        "%s: Out of memory for port structures\n",
                                        serial->type->description);
                        goto out_no_private;
                }

                usb_set_serial_port_data(serial->port[i],priv);
                priv->parent_serial  = serial;
                priv->parent_port    = serial->port[i];
                priv->read_running   = USBRSA_READ_STOP;
                priv->urb_pool_size  = 1;
                priv->nofTxMaxBytes  = 64;
                init_waitqueue_head(&priv->wait_flag);
                dev_dbg(&serial->dev->dev,"%s(): wait queue initialized",__func__);

                // allocate  urbs
                ret = allocate_write_urb(priv);
                if (ret != 0)
                        goto out_no_alloc_write;
                ret = allocate_read_urb(priv);
                if (ret != 0)
                        goto out_no_alloc_read;
                ret =  allocate_status_urb(priv);
                if (ret != 0)
                        goto out_no_alloc_status;
                printk("%s(): Manufacturer: %s\n",__func__,
serial->dev->manufacturer);
                printk("%s(): Product: %s\n",__func__,serial->dev->product);
                printk("%s(): Serial: %s\n",__func__,serial->dev->serial);
        }
        return 0;

        while (i >=  0)
        {
                priv = usb_get_serial_port_data(serial->port[i]);
                release_status_urb(priv);
                out_no_alloc_status:
                        release_read_urb(priv);
                out_no_alloc_read:
                        release_write_urb(priv);
                out_no_alloc_write:
                        kfree(priv);
                out_no_private:
                i--;
        }
        return ret;
}

//////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_release
// Purpose: Cleans up private data structures of driver
//
//
//////////////////////////////////////////////////////////////////////
static void  usbrsa_test_release(struct usb_serial *serial)
{
        int                             i;
        struct usbrsa_port_private*     priv;


        dev_dbg(&serial->dev->dev,"%s():entered\n",__func__);
        printk("%s():entered\n",__func__);

        for (i = 0; i < serial->num_ports; i++)
        {
                pr_debug("%s():portnum=%d\n",__func__,i);
                printk("%s():portnum=%d\n",__func__,i);
                priv = usb_get_serial_port_data(serial->port[i]);
                if (priv == NULL)
                {
                                        printk("%s: ERROR: priv ==
NULL\n",__func__);
                }
                else
                {
                        release_status_urb(priv);
                        release_write_urb(priv);
                        release_read_urb(priv);
                        kfree(priv);
                }
        }
}

//////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_port_probe
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static int usbrsa_test_port_probe(struct usb_serial_port* port)
{

        return 0;
}


//////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_port_remove
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static int usbrsa_test_port_remove(struct usb_serial_port* port)
{

        return 0;
}

//////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_set_termios
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static void usbrsa_test_set_termios(struct tty_struct *tty,
        struct usb_serial_port *port, struct ktermios *old_termios)
{
        struct device*                                  dev = &port->dev;
    speed_t                         baud_rate;

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


        if (!tty)
        {
               dev_dbg(dev,"%s(): no tty structures", __func__);
               return;
        }
        baud_rate       = tty_get_baud_rate(tty);
}


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

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

        if   (priv == NULL)
        {
                printk("%s: priv == NULL\n",__func__);
                return 0;
        }

         // start reading from USB-RSA
         spin_lock_irqsave(&priv->lock, flags);
         priv->read_running = USBRSA_READ_RUNNING;
         spin_unlock_irqrestore(&priv->lock, flags);

         ret_val = fetch_status(port);
         dev_dbg(&port->dev,"%s: fetch_status returned %d",__func__,ret_val);
         dev_dbg(&port->dev,"%s - port %d: leaving", __func__, port->number);
         return 0;
}

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

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

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

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

/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_write
// Purpose: copies data from user space, packs it into urbs, and sents
//          urbs downstream to USB-RSA
//
//
//////////////////////////////////////////////////////////////////////
static int  usbrsa_test_write(struct tty_struct *tty,
                        struct usb_serial_port *port,
                   const unsigned char *buf, int count)
{
        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;
        long                                    t;

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

        // debug
        return(count);

        // debug
        // transfer only as many bytes as USB-RSA EP1OUT can take
        nof_bytes_to_be_sent = (count > priv->nofTxMaxBytes ) ?
                        priv->nofTxMaxBytes : count;
        dev_dbg(&port->dev,"%s - port %d; nof_bytes_to_be_sent=%d := count=%d :
nofTxMaxBytes=%d",
                        __func__, port->number,
                        nof_bytes_to_be_sent,
                        count,
                        priv->nofTxMaxBytes);

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

                if ((test_bit(urb_index,&priv->write_urb_pool_lock)))
                {
                        // no more urbs available
                        spin_unlock_irqrestore(&priv->lock, flags);
                        goto out_write_no_urbs;
                }
                // reserve urb
                set_bit(urb_index,&priv->write_urb_pool_lock);
                urb = priv->write_urb_pool[urb_index];
                spin_unlock_irqrestore(&priv->lock, flags);
                dev_dbg(&port->dev,"%s - port %d;URB allocated=%d",__func__,
                        port->number,urb_index);

                // copy data from userspace into urb transfer buffer
                bytes = nof_bytes_to_be_sent;
                memcpy(urb->transfer_buffer, buf + sent, bytes);
                memcpy(buffer_tx,buf + sent, bytes);
                dev_dbg(&port->dev,"%s - port %d;bytes in urb=%d",__func__,
                        port->number, bytes);
                usb_serial_debug_data(&port->dev,
                                __func__, bytes, urb->transfer_buffer);
                urb->dev = port->serial->dev;
                urb->transfer_buffer_length = bytes;

                // sent urb to USB-RSA
                retval = 100;
                if (urb != NULL)
                        retval = usb_submit_urb(urb, GFP_ATOMIC);
                else
                        dev_err(&port->dev,"%s - urb ptr := NULL",__func__);

                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->number, sent,count,
nof_bytes_to_be_sent,
                                        bytes);
                        // wait for write urb to complete
                        t = wait_event_timeout(priv->wait_flag,
      (test_bit(urb_index, &priv->write_urb_pool_lock)==0),
                                COMMAND_TIMEOUT);
                        if (!t)
                        {
                        //      usb_kill_urb(priv->read_urb_pool[urb_index]);
                                dev_dbg(&port->dev,"%s - write urb timed out.",
__func__);
                                return -ETIMEDOUT;                             
                                //goto send_reset_exit;
                        }
                        // issue read urb
                        dev_dbg(&port->dev,"%s(): submitting read urb",__func__);
                        spin_lock_irqsave(&priv->lock, flags);
                        urb_index = 0;
                        set_bit(urb_index, &priv->read_urb_pool_lock);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        retval = usb_submit_urb(priv->read_urb_pool[urb_index],
                                GFP_ATOMIC);
                        if (retval != 0)
                        {
                                spin_lock_irqsave(&priv->lock, flags);
                                clear_bit(urb_index, &priv->read_urb_pool_lock);
                                spin_unlock_irqrestore(&priv->lock, flags);
                                return -ENODEV;
                        }
                        // wait for urb to complete
                      t = wait_event_timeout(priv->wait_flag,
                           (test_bit(urb_index, &priv->read_urb_pool_lock)==0),
                                COMMAND_TIMEOUT);
                        if (!t)
                        {
                        //      usb_kill_urb(priv->read_urb_pool[urb_index]);
                                dev_dbg(&port->dev,"%s - read urb timed out.",
__func__);
                                return -ETIMEDOUT;                             
                                //goto send_reset_exit;
                        }
                        if (strncmp(buffer_rx, buffer_tx,bytes))
                        {
                                printk(KERN_INFO "%s: Test Failed: %s(tx) !=
%s(rx)",
                                __func__, buffer_tx,buffer_rx);
                        }
                        else
                        {
                                printk(KERN_INFO "%s: Test Ok:
%s",__func__,buffer_rx);
                        }
                }
        }
        out_write_no_urbs:
        out_write_submit_failed:
        dev_dbg(&port->dev,"%s() End - sent=%d\n",__func__,sent);
        return sent;
}


/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_write_room
//
//////////////////////////////////////////////////////////////////////
static int usbrsa_test_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;
        unsigned long                           flags;


        dev_dbg(&port->dev,"%s() port = %d", __func__, port->number);
       spin_lock_irqsave(&priv->lock, flags);
        i = 0;
        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(): %d", __func__, room);
        return room;
}

/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_chars_in_buffer
//////////////////////////////////////////////////////////////////////
static int usbrsa_test_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;


        dev_dbg(&port->dev,"%s() port = %d", __func__, port->number);
        // account for URBs in the pool and not yet transferred to the USB-RSA
        spin_lock_irqsave(&priv->lock, flags);
        i = 0;
        chars = 0;
        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: fetch_status
// Purpose: Send status urb
//
//
// todo:
//////////////////////////////////////////////////////////////////////
static int fetch_status(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(): LOCK=%ld",__func__,priv->urb_lock&LOCK_STATUS);
        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_ATOMIC);

        if (retval)
        {
                /* something bad happened, let's free up the urb */
                dev_dbg(&port->dev,"%s(): Cannot submit urb: %d",__func__, retval);
                goto fetch_status_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)
        {
                // timeout
                dev_dbg(&port->dev,"%s - fetching from ep3in timed out.", __func__);
                usb_kill_urb(priv->status_urb);
                retval = -ETIMEDOUT;
                goto fetch_status_exit;
        }

        return 0;

        fetch_status_exit:
        spin_lock_irqsave(&priv->lock, flags);
        clear_bit(LOCK_STATUS, &priv->urb_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        return -1;
}


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


/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_write_callback
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static void  usbrsa_test_write_callback(struct urb *urb)
{
        struct usb_serial_port*         port;
        struct usbrsa_port_private*     priv;
        int                             status;
        unsigned long                   flags;
        int                             urb_index;

        dev_dbg(&urb->dev->dev,"%s() ",__func__);
        if (urb == NULL)
        {
                dev_dbg(&urb->dev->dev,"%s(): urb = NULL",__func__);
                return;
        }
        port = urb->context;
        status  = urb->status;
        dev_dbg(&urb->dev->dev,"%s() status=%d",__func__,status);
        priv    = usb_get_serial_port_data(port);

        usb_serial_debug_data(&port->dev, __func__,
                                urb->actual_length, urb->transfer_buffer);

        spin_lock_irqsave(&priv->lock, flags);
        urb_index = 0;
        clear_bit(urb_index, &priv->write_urb_pool_lock);
        spin_unlock_irqrestore(&priv->lock, flags);

        dev_dbg(&urb->dev->dev,"%s(): Returned URB %d",__func__, urb_index);
        if (status)
        {
                dev_dbg(&urb->dev->dev,"%s(): nonzero urb status: 0x%d",
__func__, status);
        }

        wake_up(&priv->wait_flag);
        //usb_serial_port_softint(port);
}

/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_read_callback
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static void  usbrsa_test_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;
        const char*                     data    = urb->transfer_buffer;
        int                             urb_index;
        unsigned long                   flags;

        dev_dbg(&urb->dev->dev,"%s() - port = %d;actual_length=%d", __func__,
                port->number,urb->actual_length);
        usb_serial_debug_data(&port->dev, __func__,
                        urb->actual_length, data);


        spin_lock_irqsave(&priv->lock, flags);
        strncpy(buffer_rx, data, urb->actual_length);
        buffer_rx[urb->actual_length]='\0';
        spin_unlock_irqrestore(&priv->lock, flags);

      // copy payload to tty buffer

        if (port != NULL)
        {
                tty = tty_port_tty_get(&port->port);
                if (tty != NULL)
                {
                  if (urb->actual_length > 0)
                  {
                        if (data != NULL)
                        {
                                spin_lock_irqsave(&priv->lock, flags);
                                strncpy(buffer_rx,
                                        data,
                                        urb->actual_length);
                                buffer_rx[urb->actual_length]='\0';
                                spin_unlock_irqrestore(&priv->lock, flags);

                                dev_dbg(&urb->dev->dev,
                                                "%s() - data(%d) ok:%s",
                                        __func__,
                                        urb->actual_length,
                                        buffer_rx);
                                tty_insert_flip_string(tty,
                                        data, urb->actual_length);
                                tty_flip_buffer_push(tty);
                        }
                        else   
                        {
                                 dev_dbg(&urb->dev->dev,
                                                 "%s() - data == NULL",__func__);
                        }
                  }

                 }
                 tty_kref_put(tty);

        }
        else
        {
                dev_dbg(&urb->dev->dev,
                                "%s() - port == NULL", __func__);
        }

        // return urb to pool
        urb_index = 0;
        dev_dbg(&urb->dev->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(&urb->dev->dev,"%s: nonzero urb status: %d", __func__,
status);
        }
        //usb_serial_port_softint(port);
        wake_up(&priv->wait_flag);
}


/////////////////////////////////////////////////////////////////////
// Name: usbrsa_test_status_callback
// Purpose:
//
//
//////////////////////////////////////////////////////////////////////
static void  usbrsa_test_status_callback(struct urb *urb)
{
        struct usb_serial_port*         port;
        struct usbrsa_port_private*     priv;
        int                                             status;
        unsigned long                           flags;


        dev_dbg(&urb->dev->dev,"%s() ",__func__);
        if (urb == NULL)
        {
                dev_dbg(&urb->dev->dev,"%s(): urb = NULL",__func__);
                return;
        }
        port = urb->context;
        status  = urb->status;
        dev_dbg(&urb->dev->dev,"%s() - port =
%d,status=%d",__func__,port->number,status);
        priv    = usb_get_serial_port_data(port);

        usb_serial_debug_data(&port->dev, __func__,
                        urb->actual_length, urb->transfer_buffer);
        spin_lock_irqsave(&priv->lock, flags);

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

        dev_dbg(&urb->dev->dev,"%s(): Returned status URB",__func__);
        if (status)
        {
                dev_dbg(&urb->dev->dev,"%s(): nonzero urb status: %d", __func__,
status);
        }

        wake_up(&priv->wait_flag);
        //usb_serial_port_softint(port);
}


////////////////////////////////////////////////////////////////////////
//                  Help Functions
////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Name: allocate_write_urb
// Purpose: Allocates and initializes pool of write urbs to EP1OUT
//
//
//////////////////////////////////////////////////////////////////////
int allocate_write_urb(struct usbrsa_port_private *priv_data)
{
        int i;
        unsigned long flags;
        dev_dbg(&priv_data->parent_serial->dev->dev,"%s()",__func__);

        i = 0;

        priv_data->write_urb_pool[i] = usb_alloc_urb(0,GFP_KERNEL);
        if (priv_data->write_urb_pool[i] == NULL)
        {
                goto out_alloc_write_urb;
        }
        priv_data->write_urb_pool[i]->transfer_buffer =
                        kmalloc(priv_data->parent_port->bulk_out_size,GFP_KERNEL);
        if (priv_data->write_urb_pool[i]->transfer_buffer == NULL)
        {
                goto out_alloc_write_urb;
        }

        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_test_write_callback, priv_data->parent_port);

        spin_lock_irqsave(&priv_data->lock,flags);
        clear_bit( i,&priv_data->write_urb_pool_lock);
        spin_unlock_irqrestore(&priv_data->lock,flags);

        return 0;

        out_alloc_write_urb:

        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]);
        }

        return ENOMEM;
}

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

        dev_dbg(&priv_data->parent_serial->dev->dev,"%s()",__func__);

        i = 0;

        priv_data->read_urb_pool[i] = usb_alloc_urb(0,GFP_KERNEL);
        if (priv_data->read_urb_pool[i] == NULL)
        {
                goto out_alloc_read_urb_pool;
        }
        priv_data->read_urb_pool[i]->transfer_buffer =
                        kmalloc(priv_data->parent_port->bulk_in_size,GFP_KERNEL);
        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,EP1IN),
                        priv_data->read_urb_pool[i]->transfer_buffer,
                        priv_data->parent_port->bulk_in_size,
                        usbrsa_test_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);

        return 0;

        out_alloc_read_urb_pool:
        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]);
        }
        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_serial->dev->dev,"%s()",__func__);

        priv_data->status_urb = usb_alloc_urb(0,GFP_KERNEL);
        if (priv_data->status_urb == NULL)
        {
                goto out_alloc_status;
        }

        priv_data->status_urb->transfer_buffer=kmalloc(64,GFP_KERNEL);
        if (priv_data->status_urb->transfer_buffer == NULL)
        {
                goto out_alloc_status;
        }

        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_test_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_err("%s(): Could not allocate memory",__func__);
        return ENOMEM;
}

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



        dev_dbg(&priv_data->parent_serial->dev->dev,"%s()",__func__);
        i = 0;
        priv_data->write_urb_pool[i] = usb_alloc_urb(0,GFP_KERNEL);
        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]);
        }

        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_urb
// Purpose: Deallocate resource pool for EP1IN
//
//
//////////////////////////////////////////////////////////////////////
static void release_read_urb(struct usbrsa_port_private *priv_data)
{
        unsigned long   flags;
        int             i;

        dev_dbg(&priv_data->parent_serial->dev->dev,"%s()",__func__);
        i = 0;
        priv_data->read_urb_pool[i] = usb_alloc_urb(0,GFP_KERNEL);
        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_status_urb
// Purpose: Remove release_status_urb
//
//
//////////////////////////////////////////////////////////////////////
static void release_status_urb(struct usbrsa_port_private *priv_data)
{
        dev_dbg(&priv_data->parent_serial->dev->dev,"%s()",__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;
        }

}

/*********************************************************/
/* module infrastructure                                 */
/*********************************************************/

static struct usb_serial_driver * const serial_drivers[] = {
        &usbrsa_test_preenum_device, &usbrsa_test_enumerated_device, NULL
};

module_usb_serial_driver(serial_drivers, id_table_combined);

MODULE_AUTHOR("Tilman Glotzner <tilman.gloetzner@xxxxxxxxx>");
MODULE_DESCRIPTION("IODATA USBRSA Test driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("usbrsatest.fw");
module_param(debug, int , S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debug");

/* File: usbrsa.h
 * Driver for IO-Data's USB RSA serial dongle
 *
 *      Copyright (C) 2012
 *          Tilman Glotzner <tilmanglotzner@xxxxxxxxxxx>
 *
 *      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.
 *
 *
 */

#ifndef __LINUX_USB_SERIAL_USBRSA_H
#define __LINUX_USB_SERIAL_USBRSA_H

#include <linux/tty.h>

#define FALSE                           0
#define TRUE                            1


#define USBRSA_ST16C550_CLOCK                   7730000

#define USBRSA_ST16C550_LCR_CS5                 0x00
#define USBRSA_ST16C550_LCR_CS6                 0x01
#define USBRSA_ST16C550_LCR_CS7                 0x02
#define USBRSA_ST16C550_LCR_CS8                 0x03
#define USBRSA_ST16C550_LCR_STOP1               0x00
// if word length is 5 bit, stop bit length is 1,5 bit times
// else 2 bit times
#define USBRSA_ST16C550_LCR_STOP2               0x04

#define USBRSA_ST16C550_LCR_MARK                0x28
#define USBRSA_ST16C550_LCR_SPACE               0x38
#define USBRSA_ST16C550_LCR_ODD                 0x08
#define USBRSA_ST16C550_LCR_EVEN                0x18
#define USBRSA_ST16C550_LCR_NONE                0x00

#define USBRSA_ST16C550_LCR_BREAK               0x40
#define USBRSA_ST16C550_LCR_BREAKOFF    0x00

#define USBRSA_ST16C550_MCR_DTR                 0x01
#define USBRSA_ST16C550_MCR_RTS                 0x02
#define USBRSA_ST16C550_MCR_OP1                 0x04 // 1=enable CTS; 0=tie CTS
to 1 (deactivate hardware flow control)
#define USBRSA_ST16C550_MCR_OP2                 0x08
#define USBRSA_ST16C550_MCR_DIAG                0x10
#define USBRSA_ST16C550_MSR_CTS                 0x10
#define USBRSA_ST16C550_MSR_DSR                 0x20
#define USBRSA_ST16C550_MSR_RI                  0x40
#define USBRSA_ST16C550_MSR_CD                  0x80
#define USBRSA_ST16C550_MSR_CTS_CHD             0x01
#define USBRSA_ST16C550_MSR_DSR_CHD             0x02
#define USBRSA_ST16C550_MSR_RI_CHD              0x04
#define USBRSA_ST16C550_MSR_CD_CHD              0x08
#define NUM_URBS 10 // shall not bigger than nof bits of an unsigned long
#define USBRSA_READ_STOPPING                    0x3
#define USBRSA_READ_RUNNING                     0x1
#define USBRSA_READ_STOP                        0x0

// Tx buffer of USBRSA can takes 4096 bytes at most
#define USBRSA_TX_MAX_BYTES                             4096

#define LOCK_RESET                      0
#define LOCK_STATUS                     1
#define LOCK_BAUDRATE_LCR       2
#define LOCK_MCR                        4
#define LOCK_MSR                        5

#define EP1OUT                          1
#define EP1IN                           1

#define EP2OUT                          2
#define EP2OUTLEN                       3
#define EP3OUT                          3
#define EP3OUTLEN                       1
#define EP4OUT                          4
#define EP4OUTLEN                       0
#define EP5OUT                          5
#define EP5OUTLEN                       3

#define EP2IN                           2
#define EP2INLEN                        1
#define EP3IN                           3
#define EP3INLEN                        4
struct usbrsa_port_private
{
        struct usb_serial*              parent_serial;
        struct usb_serial_port* parent_port;
        spinlock_t              lock;
        wait_queue_head_t       wait_flag; /* for handling sleeping while
waiting for a command to finish */
        __u8                                    lcr;    /* USBRSA.ST16C550's
Line Control Register */
        __u8                                    dll;    /* USBRSA.ST16C550's
Divisor Latch LSB Register */
        __u8                                    dlm;    /* USBRSA.ST16C550's
Divisor Latch MSB Register */
        __u8                                    mcr;    /* USBRSA.ST16C550's
Modem Control Register */
        __u8                                    msr;    /* USBRSA.ST16C550's
Modem Status Register */
        __u8                                    lsr;    /* USBRSA.ST16C550's
Line Status Register */

        speed_t                                 baudrate;               //baud
rate of serial port
        unsigned int                    c_flag;                         // port
settings
        // pointers to ep1in_buffer and ep1_out buffer are stored in the
usb_serial_port struct
        struct urb*                             write_urb_pool[NUM_URBS];
        unsigned long           write_urb_pool_lock;
        struct urb*                             read_urb_pool[NUM_URBS];
        unsigned long           read_urb_pool_lock;
        __u8                                    urb_pool_size;

        unsigned long                   urb_lock;                       // bit
0: lock reset_urb
        // bit 1: lock status_urb
        // bit 2; lock baudrate_lcr_urb
        // bit 3; lock mcr_urb
      // bit 4; lock msr_urb
        struct urb*             reset_urb;                      // goes out to EP4
        struct urb*                             status_urb;                    
// comes in from EP3
        struct urb*                             baudrate_lcr_urb;       // goes
to EP2OUT or EP5OUT
        struct urb*             mcr_urb;                        // urb to modem
control register (EP3OUT)
        struct urb*             msr_urb;                        // urb from
modem status register (EP2IN)

        __u8                                    read_running;
        unsigned int                    nofRxBytesReceived;
        unsigned int                    nofTxBytesFree;
        unsigned int                    nofTxMaxBytes;

        __u8                                    xoff;           /* XOFF byte
value, default 0x13 */
        __u8                                    xon;            /* XON byte
value, default 0x11 */
        __u8                                    lloop;          /* local
loopback 0 or 1, default 0 */

} __attribute__ ((packed)); ;


#endif




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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux