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