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 <[email protected]>"
#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 <[email protected]>");
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 <[email protected]>
*
* 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html