Greg KH <gregkh@...> writes: > > On Mon, Feb 15, 2016 at 11:30:43PM +0000, tilman wrote: > > Dear all > > > > a couple of years ago I wrote a driver for a serial dongle. > > I did not add it to the linux source because the dongle requires a firmware > > to be downloaded to the device (ezusb). > > The manufacturer, IO-DATA, did not want me to use > > their firmware. > > Why did they not want you to use their firmware in their device? They did not say. I would think that they feared that users would come to them in case the driver does not work. For the successor model, the offer a linux driver however. I have disassembled the firmware however. If I can make some time, I can rewrite the firmware which would avoid this issue. First step however is to get the driver working again.
> > It's impossible to say without seeing the code, sorry. Below, it comes... Thanks Tilman /// usbrsa.c /* * Driver for IO-Data's USB RSA serial dongle * Copyright (C) 2012 * Tilman Glotzner(tilmanglotz...@gmail.com) * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * * USB-RSA by IO-DATA * USB to serial convertor * ======================= * * Remark: The device uses an AN2131Q (Eazy USB) and a ST16C550(UART) * * End Points: * ============ * * End Point: EP1OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 64 bytes * Desc: Data to be transmitted * Format: 64 bytes of data * * * End Point: EP2OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 3 bytes * Desc: Set baud rate counter and Line Control Register * of the ST16C550. Receiver Interrupts are turned ON, * i.e. Modem status IR, RX line status IR, and * RX holding register IR * Format: * Byte0: Low Byte of counter (DLL) * Byte1: High Byte of counter (DLM) * Byte2: Line Control Register (LCR) * - Bit 0: Word Length 0 * - Bit 1: Word Length 1 * - Bit 2: Stop Bits * - Bit 3: Parity Enable * - Bit 4: Parity Even * - Bit 5: Set Parity * - Bit 6: Set Break * - Bit 7: Counter Register Enable (needs to be set to '0') * * * End Point: EP3OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 1 bytes * Desc: Set modem control register of the ST16C550 * Format: * Byte0: Modem Control Register * - Bit0: DTR * - Bit1: RTS * - Bit2: OP1 * - Bit3: OP2 * - Bit4: Diagnostics mode * * * End Point: EP4OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 0 bytes * Desc: Reset EP1OUT and EP1IN (Tx/Rx pipes) * Format: n.a. * * * End Point: EP5OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 3 bytes * Desc: Set baud rate counter and Line Control Register * of the ST16C550. Receiver Interrupts are turned OFF, * i.e. Modem status IR, RX line status IR, and * RX holding register IR * Format: * Byte0: Low Byte of counter (DLL) * Byte1: High Byte of counter (DLM) * Byte2: Line Control Register (LCR) * - Bit 0: Word Length 0 * - Bit 1: Word Length 1 * - Bit 2: Stop Bits * - Bit 3: Parity Enable * - Bit 4: Parity Even * - Bit 5: Set Parity * - Bit 6: Set Break * - Bit 7: Counter Register Enable (needs to be set to '0') * * * End Point: EP1IN * Direction: Device to Host * Type: Bulk Transfer * Size: 64 bytes * Desc: Data received by USB-RSA * Format: 64 bytes of data * * * End Point: EP2IN * Direction: Device to Host * Type: Bulk Transfer * Size: 1 byte * Desc: Read Modem Status Register of ST16C550 * Format: * Byte0: Modem Status Register * - Bit0: Delta CTS * - Bit1: Delta DSR * - Bit2: Delta RI * - Bit3: Delta CD * - Bit4: CTS * - Bit5: DSR * - Bit6: RI * - Bit7: CD * * * End Point: EP3IN * Direction: Device to Host * Type: Bulk Transfer * Size: 4 bytes * Desc: Read RX/TX Pipe Status * Format: * Byte0: Byte available in TX Buffer of USB-RSA (Low Byte) * Byte1: Byte available in TX Buffer of USB-RSA (High Byte) * Byte2: Byte received and stored in RX Buffer of USB-RSA (Low Byte) * Byte3: Byte received and stored in RX Buffer of USB-RSA (High Byte) * * * todo: use of status urb information (status urb returns tx_bytes_available on usbrsa) (done) * debug: write blocks if more than 9 URBs (done) * debug rx pipe (first urb read is always empty) * CTS, and DSR: do these need to be enabled OP1/OP2 ? (no) * xon/xoff correctly implemented ? * write function to issue lcr und divisor urb (EPOUT2 and EPOUT5) + waits for completion (done) * reflect lcr, dll, dlm in usbrsa_port_private (done) * send break * buffering effect: when writing to USB-RSA not all characters are transferred at once (done) * Are parent_serial,parent_port in usbrsa_port_private really necessary ? * * */ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <asm/termbits.h> #include <linux/usb.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/usb/serial.h> #include <linux/usb/ezusb.h> #include <linux/firmware.h> #include <linux/ihex.h> #include <linux/usb/ezusb.h> #include "usbrsa.h" #define CONFIG_USB_SERIAL_DEBUG 1 #ifdef CONFIG_USB_SERIAL_DEBUG static int debug = 1; #else static int debug = 0; #endif /* * Version Information */ #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Tilman Glotzner <tilman.gloetz...@gmail.com>" #define DRIVER_DESC "Driver for IODATA's USBRSA serial dongle" #define IODATA_VENDOR_ID 0x4bb #define IODATA_USBRSA_PREENUM_ID 0xa01 #define IODATA_USBRSA_ID 0xa02 #define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ /* Taken whiteheat driver as role model: ID tables for usb-rsa are unusual, because we want to different things for different versions of the device. Eventually, this will be doable from a single table. But, for now, we define two separate ID tables, and then a third table that combines them just for the purpose of exporting the autoloading information. */ static const struct usb_device_id id_table_std[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) }, { } /* Terminating entry */ }; static const struct usb_device_id id_table_prerenumeration[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) }, { } /* Terminating entry */ }; static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); struct usbrsa_private { spinlock_t lock; u8 line_control; u8 line_status; u8 line_settings[7]; }; //////////////////////////////////////////////////////////////////////// // Preenumeration device //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // Function Prototypes //////////////////////////////////////////////////////////////////////// static int usbrsa_firmware_download(struct usb_serial *serial, const struct usb_device_id *id); static int usbrsa_firmware_attach(struct usb_serial *serial); //////////////////////////////////////////////////////////////////////// // Driver object declaration //////////////////////////////////////////////////////////////////////// static struct usb_serial_driver usbrsa_preenum_device = { .driver = { .owner = THIS_MODULE, .name = "usbrsanofirm", }, .description = "IO-DATA - USB-RSA - (prerenumeration)", // .usb_driver = &usbrsa_driver, .id_table = id_table_prerenumeration, .num_ports = 1, .probe = usbrsa_firmware_download, .attach = usbrsa_firmware_attach, }; //////////////////////////////////////////////////////////////////////// // Functions //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Name: usbrsa_firmware_download // Purpose: Downloads firmware to AN2134Q // ////////////////////////////////////////////////////////////////////// static int usbrsa_firmware_download(struct usb_serial *serial, const struct usb_device_id *id) { int response; dev_dbg(&serial->dev->dev,"%s", __func__); response = ezusb_fx1_ihex_firmware_download(serial->dev, "usbrsa.fw"); if (response >= 0) { dev_dbg(&serial->dev->dev,"%s(): Firmware downloaded.",__func__); // The USB-RSA does not reenumerate without toggeling the reset bit // one more time udelay(1000); response = ezusb_fx1_set_reset(serial->dev, 1); udelay(10000); if (response >= 0) { response = ezusb_fx1_set_reset(serial->dev, 0); if (response >= 0) { dev_dbg(&serial->dev->dev,"%s(): Device with new firmware reset.",__func__); return 0; } } dev_err(&serial->dev->dev,"%s(): Status register of EZUSB not accessible.",__func__); } dev_err(&serial->dev->dev,"%s(): Firmware download or subsequent reset failed",__func__); return -ENOENT; } ////////////////////////////////////////////////////////////////////// // Name: usbrsa_firmware_attach // Purpose: Prevents the driver from attaching, so that can attach // to the reenumerated device // ////////////////////////////////////////////////////////////////////// static int usbrsa_firmware_attach(struct usb_serial *serial) { // We want this device to fail to have the driver // assigned to the reenumerated device return 1; } /***********************************************************************/ //////////////////////////////////////////////////////////////////////// // REENUMERATED DEVICE //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // Function Prototypes //////////////////////////////////////////////////////////////////////// static int usbrsa_attach(struct usb_serial *serial); static void usbrsa_release(struct usb_serial *serial); static int usbrsa_probe(struct usb_serial_port *port); static int usbrsa_remove(struct usb_serial_port *port); static int usbrsa_open(struct tty_struct *tty, struct usb_serial_port *port); static void usbrsa_close(struct usb_serial_port *port); static void usbrsa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void usbrsa_init_termios(struct tty_struct *tty); static int usbrsa_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int usbrsa_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static int usbrsa_write_room(struct tty_struct *tty); static int usbrsa_chars_in_buffer(struct tty_struct *tty); static void usbrsa_unthrottle(struct tty_struct *tty); static void usbrsa_throttle(struct tty_struct *tty); static int usbrsa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int usbrsa_tiocmget(struct tty_struct *tty); //////////////////////////////////////////////////////////////////////// // Completion Handler Prototypes //////////////////////////////////////////////////////////////////////// static void usbrsa_baudrate_lcr_callback(struct urb *urb); static void usbrsa_reset_callback(struct urb *urb); static void usbrsa_status_callback(struct urb *urb); static void usbrsa_write_callback(struct urb *urb); static void usbrsa_read_callback(struct urb *urb); static void usbrsa_mcr_callback(struct urb *urb); static void usbrsa_msr_callback(struct urb *urb); ///l///////////////////////////////////////////////////////////////////// // Driver object declaration //////////////////////////////////////////////////////////////////////// static struct usb_serial_driver usbrsa_enumerated_device = { .driver = { .owner = THIS_MODULE, .name = "usbrsa", }, .description = "IO-DATA - USB-RSA", // .usb_driver = &usbrsa_driver, .id_table = id_table_std, .num_ports = 1, .attach = usbrsa_attach, .release = usbrsa_release, .port_probe = usbrsa_probe, .port_remove = usbrsa_remove, .open = usbrsa_open, .close = usbrsa_close, .write = usbrsa_write, .write_bulk_callback = usbrsa_write_callback, .read_bulk_callback = usbrsa_read_callback, .set_termios = usbrsa_set_termios, .tiocmset = usbrsa_tiocmset, .tiocmget = usbrsa_tiocmget, // .init_termios = usbrsa_init_termios, .ioctl = usbrsa_ioctl, .write_room = usbrsa_write_room, .chars_in_buffer = usbrsa_chars_in_buffer, .throttle = usbrsa_throttle, .unthrottle = usbrsa_unthrottle }; //////////////////////////////////////////////////////////////////////// // Function Prototypes of help functions //////////////////////////////////////////////////////////////////////// static int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data); static int allocate_read_urbs(struct usbrsa_port_private *priv_data); static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data); static int allocate_reset_urb(struct usbrsa_port_private *priv_data); static int allocate_status_urb(struct usbrsa_port_private *priv_data); static int allocate_mcr_urb(struct usbrsa_port_private *priv_data); static int allocate_msr_urb(struct usbrsa_port_private *priv_data); static void release_write_urbs(struct usbrsa_port_private *priv_data); static void release_read_urbs(struct usbrsa_port_private *priv_data); static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data); static void release_reset_urb(struct usbrsa_port_private *priv_data); static void release_status_urb(struct usbrsa_port_private *priv_data); static void release_mcr_urb(struct usbrsa_port_private *priv_data); static void release_msr_urb(struct usbrsa_port_private *priv_data); static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate, int endpoint, struct usb_serial_port *port); static int send_mcr_register(struct usb_serial_port *port); static int fetch_msr_register(struct usb_serial_port *port); static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo); static int send_reset(struct usb_serial_port *port); static int wait_modem_info(struct usb_serial_port *port, unsigned int arg); //////////////////////////////////////////////////////////////////////// // Functions //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Name: usbrsa_attach // Purpose: Creates private data structures of driver // // ////////////////////////////////////////////////////////////////////// static int usbrsa_attach(struct usb_serial *serial) { int i = 0; int ret = 0; struct usb_serial_port* serport; struct usbrsa_port_private* priv = NULL; printk("%s start",__func__); dev_dbg(&serial->dev->dev,"%s", __func__); if (!serial) { dev_err(&serial->dev->dev,"%s(): Invalid handler", __func__); return -ENODEV; } for (i = 0; i < serial->num_ports; i++) { serport = serial->port[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 = serport; priv->read_running = USBRSA_READ_STOP; priv->urb_pool_size = NUM_URBS; priv->nofTxMaxBytes = USBRSA_TX_MAX_BYTES; mutex_init(&priv->mutex); init_waitqueue_head(&priv->wait_flag); // allocate urbs printk("%s about to enter 'usbrsa_allocate_write_urbs'",__func__); ret = usbrsa_allocate_write_urbs(priv); if (ret != 0) goto out_no_alloc_write; printk("%s allocate_read_urbs",__func__); ret = allocate_read_urbs(priv); if (ret != 0) goto out_no_alloc_read; printk("%s allocate_baudrate_lcr_urb",__func__); ret = allocate_baudrate_lcr_urb(priv); if (ret != 0) goto out_no_alloc_baudrate_lcr; printk("%s allocate_reset_urb",__func__); ret = allocate_reset_urb(priv); if (ret != 0) goto out_no_alloc_reset; printk("%s allocate_status_urb",__func__); ret = allocate_status_urb(priv); if (ret != 0) goto out_no_alloc_status; printk("%s allocate_mcr_urb",__func__); ret = allocate_mcr_urb(priv); if (ret != 0) goto out_no_alloc_mcr; ret = allocate_msr_urb(priv); if (ret != 0) goto out_no_alloc_msr; printk("%s send_reset",__func__); // sent reset ret = send_reset(serport); if (ret != 0) { dev_err(&serport->dev, "%s(): Failed to issue reset command. " " Error=%d\n", __func__, ret); ret = ENODEV; goto out_no_device; } printk("%s end -- debug section",__func__); // debug for (i=0; i < 5 ; i++) { priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR ); ret = send_mcr_register(serport); mdelay(200); priv->mcr |= ~(USBRSA_ST16C550_MCR_DTR ); ret = send_mcr_register(serport); mdelay(200); priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR ); ret = send_mcr_register(serport); mdelay(200); priv->mcr |= ~(USBRSA_ST16C550_MCR_DTR ); ret = send_mcr_register(serport); mdelay(200); priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR ); ret = send_mcr_register(serport); mdelay(200); } //debug end printk("%s end",__func__); return 0; } while (i >= 0) { priv = usb_get_serial_port_data(serial->port[i]); out_no_device: release_msr_urb(priv); out_no_alloc_msr: release_mcr_urb(priv); out_no_alloc_mcr: release_status_urb(priv); out_no_alloc_status: release_reset_urb(priv); out_no_alloc_reset: release_baudrate_lcr_urb(priv); out_no_alloc_baudrate_lcr: release_read_urbs(priv); out_no_alloc_read: release_write_urbs(priv); out_no_alloc_write: kfree(priv); out_no_private: i--; } printk("%s end error",__func__); return ret; } ////////////////////////////////////////////////////////////////////// // Name: usbrsa_release // Purpose: Cleans up private data structures of driver // // ////////////////////////////////////////////////////////////////////// static void usbrsa_release(struct usb_serial *serial) { int i; struct usbrsa_port_private* priv; printk("%s",__func__); dev_dbg(&serial->dev->dev,"%s()", __func__); for (i = 0; i < serial->num_ports; i++) { priv = usb_get_serial_port_data(serial->port[i]); release_msr_urb(priv); release_mcr_urb(priv); release_status_urb(priv); release_reset_urb(priv); release_baudrate_lcr_urb(priv); release_write_urbs(priv); release_read_urbs(priv); kfree(priv); } } /////////////////////////////////////////////////////////////////////// // Name: usbrsa_probe // Purpose: // // // ////////////////////////////////////////////////////////////////////// static int usbrsa_probe(struct usb_serial_port *port) { printk("%s",__func__); // struct usbrsa_private *info; // // info = kzalloc(sizeof(*info), GFP_KERNEL); // if (!info) // return -ENOMEM; // // usb_set_serial_port_data(port, info); return 0; } /////////////////////////////////////////////////////////////////////// // Name: usbrsa_remove // Purpose: // // // ////////////////////////////////////////////////////////////////////// static int usbrsa_remove(struct usb_serial_port *port) { printk("%s",__func__); // struct usbrsa_private *info; // // info = usb_get_serial_port_data(port); // kfree(info); return 0; } /////////////////////////////////////////////////////////////////////// // Name: usbrsa_open // Purpose: Open USB device. Sets termios, tty, and starts to sent // status queries to EP3IN. // // ////////////////////////////////////////////////////////////////////// static int usbrsa_open(struct tty_struct *tty, struct usb_serial_port *port) { struct ktermios tmp_termios; int retval; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; printk("%s",__func__); dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); // flush buffer of USB-RSA by sending reset retval = send_reset(port); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, retval); return ENODEV; } if (tty) { // usbrsa_set_termios will sent to endpoint 2 of the USB-RSA thereby // turning on the RX interrupt usbrsa_set_termios(tty, port, &tmp_termios); } // start reading from USB-RSA spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS,&priv->urb_lock))) { set_bit(LOCK_STATUS,&priv->urb_lock); // enable continuous reading priv->read_running = USBRSA_READ_RUNNING; spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb,GFP_KERNEL); } else { spin_unlock_irqrestore(&priv->lock, flags); } dev_dbg(&port->dev,"%s - port %d: leaving", __func__, port->port_number); printk("%s - port=%d",__func__,port->port_number); return 0; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_close // Purpose: closes USB-RSA device // // ////////////////////////////////////////////////////////////////////// static void usbrsa_close(struct usb_serial_port *port) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int retries = 3; unsigned long flags; int retval; printk("%s",__func__); dev_dbg(&port->dev,"%s - port %d", __func__, port->port_number); // turn off RX interrupt of USB-RSA by sending to EP5 while(retries > 0) { // turn off RX interrupt of USB-RSA by sending to EP5. retval = send_baudrate_lcr_register(priv->c_flag, priv->baudrate, EP5OUT, port); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, retval); } retries--; } // disable continuous reading spin_lock_irqsave(&priv->lock, flags); priv->read_running = USBRSA_READ_STOP; spin_unlock_irqrestore(&priv->lock, flags); return; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_init_termios // Purpose: Initialize termios of tty // // ////////////////////////////////////////////////////////////////////// static void usbrsa_init_termios(struct tty_struct *tty) { dev_dbg(tty->dev,"%s()", __func__); tty->termios = tty_std_termios; tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty->termios.c_ispeed = 9600; tty->termios.c_ospeed = 9600; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_set_termios // Purpose: Initialize USB-RSA with terminal settings // // ////////////////////////////////////////////////////////////////////// static void usbrsa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned int cflag; speed_t baud_rate; int retval; int retries = 3; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); if (!tty) { dev_err(&port->dev,"%s(): no tty structures", __func__); return; } if (I_IXOFF(tty) || I_IXON(tty)) { priv->xon = START_CHAR(tty); priv->xoff = STOP_CHAR(tty); dev_dbg(&port->dev,"%s - XON = %2x, XOFF = %2x", __func__, priv->xon, priv->xoff ); } cflag = tty->termios.c_cflag; priv->c_flag = cflag; /* get the baud rate wanted */ baud_rate = tty_get_baud_rate(tty); priv->baudrate = baud_rate; dev_dbg(&port->dev,"%s - baudrate = %u",__func__, baud_rate ); /* if baud rate is B0, drop DTR */ if ((baud_rate & CBAUD) == B0) { priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR ); retval = send_mcr_register(port); if (retval != 0) //return -ENODEV; return; } while(retries > 0) { retval = send_baudrate_lcr_register(cflag, baud_rate, EP2OUT, port); if (retval != 0) { dev_err(&port->dev, "%s(): send_baudrate_lcr_register() failed" " with error %d\n", __func__, retval); retries--; } else { // bail out retries = 0; } } } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_write // Purpose: copies data from user space, packs it into urbs, and sents // urbs downstream to USB-RSA // // ////////////////////////////////////////////////////////////////////// static int usbrsa_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { struct usb_serial* serial = port->serial; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; int retval; int nof_bytes_to_be_sent; int bytes; int urb_index; int sent = 0; struct urb* urb; dev_dbg(&port->dev,"%s - port %d START", __func__,port->port_number); while (count > 0) { // transfer only as many bytes as USB-RSA can take nof_bytes_to_be_sent = (count > priv->nofTxBytesFree) ? priv->nofTxBytesFree : count; dev_dbg(&port->dev,"%s - port %d; bytes=%d := count=%d : nofTxBytesFree=%d", __func__, port->port_number, nof_bytes_to_be_sent,count, priv->nofTxBytesFree); while (nof_bytes_to_be_sent > 0) { // check for empty urb in write pool spin_lock_irqsave(&priv->lock, flags); urb_index = find_first_zero_bit(&priv->write_urb_pool_lock, priv->urb_pool_size); dev_dbg(&port->dev,"%s - poolsize %d, urb_index %d\n",__func__, priv->urb_pool_size,urb_index); if (urb_index >= priv->urb_pool_size) { // no more urbs available spin_unlock_irqrestore(&priv->lock, flags); goto out_write_no_urbs; } dev_dbg(&port->dev,"%s - port %d;URB allocated=%d",__func__, port->port_number,urb_index); // reserve urb set_bit(urb_index, &priv->write_urb_pool_lock); urb = priv->write_urb_pool[urb_index]; spin_unlock_irqrestore(&priv->lock, flags); // copy data from userspace into urb transfer buffer bytes = (nof_bytes_to_be_sent > port->bulk_out_size) ? port->bulk_out_size : nof_bytes_to_be_sent; memcpy(urb->transfer_buffer, buf + sent, bytes); dev_dbg(&port->dev,"%s - port %d;bytes in urb=%d",__func__, port->port_number, bytes); usb_serial_debug_data( &port->dev, __func__, bytes, urb->transfer_buffer); urb->dev = serial->dev; urb->transfer_buffer_length = bytes; // sent urb to USB-RSA retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) { // return urb to pool spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->write_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, retval); sent = retval; // bail out goto out_write_submit_failed; } else { sent += bytes; count -= bytes; nof_bytes_to_be_sent -= bytes; dev_dbg(&port->dev,"%s - port %d;sent=%d;count=%d; nof_bytes_to_be_sent=%d;bytes=%d", __func__, port->port_number, sent,count, nof_bytes_to_be_sent, bytes); } } } out_write_no_urbs: out_write_submit_failed: dev_dbg(&port->dev,"%s() End - sent=%d\n",__func__,sent); return sent; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_ioctl // Purpose: copies data from user space, packs it into urbs, and sents // urbs downstream to USB-RSA // // ////////////////////////////////////////////////////////////////////// static int usbrsa_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; dev_dbg(&port->dev,"%s() cmd 0x%.4x", __func__, cmd); switch (cmd) { case TIOCGSERIAL: return get_serial_info(port, (struct serial_struct __user *) arg); break; case TIOCMIWAIT: dev_dbg(&port->dev,"%s(): TIOCMIWAIT", __func__); return wait_modem_info(port, arg); break; case TCGETS: dev_dbg(&port->dev,"%s(): TCGETS -- not implemented", __func__); break; case TCSETS: dev_dbg(&port->dev,"%s(): TCSETS -- not implemented", __func__); break; case TCFLSH: dev_dbg(&port->dev,"%s(): TCFLSH -- not implemented", __func__); break; default: dev_dbg(&port->dev,"%s(): 0x%04x not supported", __func__, cmd); break; } return -ENOIOCTLCMD; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_write_room // Purpose: Returns fill level of the tx queue. The tx queue consists // of 2 parts: A pool of URBs, and a buffer in the USB-RSA. // Mostly, the fill level of the pool will be returned. // Only if there is less memory available in the USB-RSA's // buffer than in the the pool, the fill level of the USB-RSA // will be returned to prevent clogging the tx queue. // // // ////////////////////////////////////////////////////////////////////// static int usbrsa_write_room(struct tty_struct *tty) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int room = 0; int i = 0; long t; unsigned long flags; int retval; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); // if no current fill level information is available, issue status update if (priv->read_running != USBRSA_READ_RUNNING) { // start reading from USB-RSA spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS,&priv->urb_lock))) { set_bit(LOCK_STATUS,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb,GFP_KERNEL); if (retval != 0) { return -ENODEV; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_STATUS, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // fetching of msr usb_kill_urb(priv->status_urb); dev_dbg(&port->dev,"%s - status urb timed out.", __func__); return -ETIMEDOUT; //goto send_reset_exit; } } else { spin_unlock_irqrestore(&priv->lock, flags); } } spin_lock_irqsave(&priv->lock, flags); for (i=0;i<priv->urb_pool_size;i++) { if (test_bit(i,&priv->write_urb_pool_lock) == 0) { room++; } } spin_unlock_irqrestore(&priv->lock, flags); //compute bytes available in write URB pool room *= port->bulk_out_size; dev_dbg(&port->dev,"%s(): Pool=%d;usbrsa.tx=%d", __func__, room,priv->nofTxBytesFree); // if usbrsa has fewer bytes available than URB pool return available bytes in USBRSA room = (room > priv->nofTxBytesFree) ? priv->nofTxBytesFree : room; dev_dbg(&port->dev,"%s(): %d", __func__, room); return room; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_chars_in_buffer // Purpose: Return the number of bytes still waiting to be sent // stored in the USBRSA as well as in the buffer of the // driver (URB pool). // The tty layer thereby calls the close function only // after all bytes are sent. // // // // todo: When should the bytes remaining in the buffer, and ////////////////////////////////////////////////////////////////////// static int usbrsa_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int chars = 0; int i = 0; unsigned long flags; long t; int retval; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); if (priv->read_running != USBRSA_READ_RUNNING) { // start reading from USB-RSA spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS,&priv->urb_lock))) { set_bit(LOCK_STATUS,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb,GFP_KERNEL); if (retval != 0) { chars = -ENODEV; goto chars_in_buffer_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_STATUS, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // fetching of msr usb_kill_urb(priv->status_urb); dev_dbg(&port->dev,"%s - status urb timed out.", __func__); chars = -ETIMEDOUT; goto chars_in_buffer_exit; } } else { spin_unlock_irqrestore(&priv->lock, flags); } } spin_lock_irqsave(&priv->lock, flags); //bytes in TX buffer of USBRSA chars = priv->nofTxMaxBytes - priv->nofTxBytesFree; // account for URBs in the pool and not yet transferred to the USB-RSA for (i=0;i<priv->urb_pool_size;i++) { if (test_bit(i,&priv->write_urb_pool_lock) != 0) { chars += priv->write_urb_pool[i]->transfer_buffer_length; } } spin_unlock_irqrestore(&priv->lock, flags); chars_in_buffer_exit: dev_dbg(&port->dev,"%s(): %d", __func__, chars); return chars; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_throttle // Purpose: // // // ///////////////////////////////////////////////////////////////////// static void usbrsa_throttle(struct tty_struct *tty) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); status = usbrsa_write(tty, port, &stop_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios.c_cflag & CRTSCTS) { priv->mcr &= ~USBRSA_ST16C550_MCR_RTS; status = send_mcr_register(port); if (status != 0) return; } } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_unthrottle // Purpose: // // // ///////////////////////////////////////////////////////////////////// static void usbrsa_unthrottle(struct tty_struct *tty) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); status = usbrsa_write(tty, port, &start_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios.c_cflag & CRTSCTS) { priv->mcr |= USBRSA_ST16C550_MCR_RTS; send_mcr_register(port); } } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_tiocmset // Purpose: // // // ///////////////////////////////////////////////////////////////////// static int usbrsa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; int retval; if (port == NULL) return -ENODEV; dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number); spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->mcr |= USBRSA_ST16C550_MCR_RTS; if (set & TIOCM_DTR) priv->mcr |= USBRSA_ST16C550_MCR_DTR; if (set & TIOCM_LOOP) { priv->mcr |= USBRSA_ST16C550_MCR_DIAG; priv->lloop = 1; } if (clear & TIOCM_RTS) priv->mcr &= ~USBRSA_ST16C550_MCR_RTS; if (clear & TIOCM_DTR) priv->mcr &= ~USBRSA_ST16C550_MCR_DTR; if (clear & TIOCM_LOOP) { priv->mcr &= ~USBRSA_ST16C550_MCR_DIAG; priv->lloop = 0; } // bring OP1 and OP2 to defined states priv->mcr &= ~USBRSA_ST16C550_MCR_OP1; priv->mcr &= ~USBRSA_ST16C550_MCR_OP2; spin_unlock_irqrestore(&priv->lock, flags); retval = send_mcr_register(port); dev_dbg(&port->dev,"%s: %d=send_mcr_register",__func__,retval); return(retval); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_tiocmget // Purpose: // // // ///////////////////////////////////////////////////////////////////// static int usbrsa_tiocmget(struct tty_struct *tty) { struct usb_serial_port* port = tty->driver_data; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int retval; if (port == NULL) return -ENODEV; dev_dbg(&port->dev,"%s() - port %d",__func__, port->port_number); retval = fetch_msr_register(port); dev_dbg(&port->dev,"%s: %d=fetch_msr_register",__func__,retval); if (retval == 0) { retval = ((priv->mcr & USBRSA_ST16C550_MCR_DTR) ? TIOCM_DTR : 0) | ((priv->mcr & USBRSA_ST16C550_MCR_RTS) ? TIOCM_RTS : 0) | ((priv->mcr & USBRSA_ST16C550_MCR_DIAG) ? TIOCM_LOOP : 0) | ((priv->msr & USBRSA_ST16C550_MSR_CTS) ? TIOCM_CTS : 0) | ((priv->msr & USBRSA_ST16C550_MSR_CD) ? TIOCM_CD : 0) | ((priv->msr & USBRSA_ST16C550_MSR_RI) ? TIOCM_RI : 0) | ((priv->msr & USBRSA_ST16C550_MSR_DSR) ? TIOCM_DSR : 0); } return(retval); } //////////////////////////////////////////////////////////////////////// // C O M P L E T I O N H A N D L E R S //////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Name: usbrsa_baudrate_lcr_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_baudrate_lcr_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number, priv->baudrate_lcr_urb->pipe); // unlock urb spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_BAUDRATE_LCR,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status); } wake_up(&priv->wait_flag); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_reset_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_reset_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number, priv->reset_urb->pipe); // unlock urb spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_RESET,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__,status); } wake_up(&priv->wait_flag); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_status_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_status_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; __u8* ep3in = urb->transfer_buffer; unsigned long flags; int retval; int read_urbs_needed = 0; int urb_index; unsigned int i; // dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number, // priv->status_urb->pipe); spin_lock_irqsave(&priv->lock, flags); // read payload data of urb, i.e. bytes received and bytes // available in tx queue of USB-RSA priv->nofTxBytesFree = ep3in[0] + (256 * ep3in[1]); priv->nofRxBytesReceived= ep3in[2] + (256 * ep3in[3]); // unlock urb clear_bit(LOCK_STATUS,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); // if coutinuous read enabled, either // -- issue next status request (USBRSA did not receive // anything) // -- issue a read urb (if rx queue is filled) if (priv->read_running == USBRSA_READ_RUNNING) { if(priv->nofRxBytesReceived != 0) { // USB-RSA received data // compute urbs needed read_urbs_needed = priv->nofRxBytesReceived/port->bulk_in_size; if (priv->nofRxBytesReceived%port->bulk_in_size) read_urbs_needed++; dev_dbg(&port->dev,"%s(): EP1IN: rx=%d, urbs_needed=%d,size_of_urb=%d", __func__, priv->nofRxBytesReceived, read_urbs_needed, port->bulk_in_size); // issue read urbs // todo: issue more than one read urb. Will this work ? if (read_urbs_needed > priv->urb_pool_size) read_urbs_needed = priv->urb_pool_size; for(i=0; i < read_urbs_needed;i++ ) { spin_lock_irqsave(&priv->lock, flags); urb_index = find_first_zero_bit(&priv->read_urb_pool_lock, priv->urb_pool_size); if (urb_index < priv->urb_pool_size) { set_bit(urb_index,&priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); // submit read dev_dbg(&port->dev,"%s(): submit read urb[%d]", __func__,urb_index ); retval = usb_submit_urb( priv->read_urb_pool[urb_index],GFP_KERNEL); if (retval) { // return urb to read pool spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index,&priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status); return; } } else { spin_unlock_irqrestore(&priv->lock, flags); i = read_urbs_needed; } } } spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_STATUS,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb,GFP_KERNEL); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, retval); spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_STATUS,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); } } else { // reading from device ceased -- do nothing dev_dbg(&port->dev,"%s(): reading stopped: tx_free=%d;rx_recv=%d", __func__, priv->nofTxBytesFree,priv->nofRxBytesReceived); } if (status) { dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status); } if (priv->read_running == USBRSA_READ_RUNNING) { usb_serial_port_softint(port); } else { wake_up(&priv->wait_flag); } return; } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_write_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_write_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; int urb_index; dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x", __func__, port->port_number, priv->status_urb->pipe); usb_serial_debug_data( &port->dev, __func__, urb->actual_length, urb->transfer_buffer); // find urb in write pool for (urb_index=0; urb_index < priv->urb_pool_size;urb_index++) { if (urb == priv->write_urb_pool[urb_index]) { // urb found; return urb to pool spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->write_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); break; } } if (urb != priv->write_urb_pool[urb_index]) { // urb not found -- this points to a bug dev_err(&port->dev, "%s(): urb not in pool", __func__); } dev_dbg(&port->dev,"%s(): Returned URB %d",__func__, urb_index); if (status) { dev_dbg(&port->dev,"%s(): nonzero urb status: 0x%d", __func__, status); } usb_serial_port_softint(port); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_read_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_read_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); struct tty_struct* tty; int status = urb->status; unsigned char* data = urb->transfer_buffer; int urb_index; unsigned long flags; dev_dbg(&port->dev,"%s() - port = %d, ep=0x%x", __func__, port->port_number, priv->status_urb->pipe); usb_serial_debug_data( &port->dev, __func__, urb->actual_length, data); // find urb in read pool for (urb_index=0; urb_index < priv->urb_pool_size;urb_index++) { if (urb == priv->read_urb_pool[urb_index]) { // urb found; break; } } if (urb != priv->read_urb_pool[urb_index]) { // urb not found -- this points to a bug dev_err(&port->dev, "%s(): urb not in pool", __func__); return; } dev_dbg(&port->dev,"%s() - port = %d: urb_index=%d", __func__, port->port_number,urb_index); tty = tty_port_tty_get(&port->port); if (tty != NULL && urb->actual_length > 0) { tty_insert_flip_string(tty->port, data, urb->actual_length); tty_flip_buffer_push(tty->port); } tty_kref_put(tty); // return urb to pool dev_dbg(&port->dev,"%s: return URB %d",__func__,urb_index); spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev,"%s: nonzero urb status: 0x%d", __func__, status); } usb_serial_port_softint(port); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_mcr_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_mcr_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x, status=%d", __func__, port->port_number, priv->status_urb->pipe,status); spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MCR,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev,"%s: nonzero urb status: 0x%d", __func__, status); } wake_up(&priv->wait_flag); } ///////////////////////////////////////////////////////////////////// // Name: usbrsa_msr_callback // Purpose: // // ////////////////////////////////////////////////////////////////////// static void usbrsa_msr_callback(struct urb *urb) { struct usb_serial_port* port = urb->context; struct usbrsa_port_private* priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; __u8 *msr; dev_dbg(&port->dev,"%s() - port = %d, ep =0x%x, status=%d", __func__, port->port_number, priv->status_urb->pipe,status); spin_lock_irqsave(&priv->lock, flags); msr = urb->transfer_buffer; priv->msr = msr[0]; clear_bit(LOCK_MSR,&priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev,"%s() - msr =%02x",__func__,priv->msr); if (status) { dev_dbg(&port->dev,"%s: nonzero urb status: 0x%d", __func__, status); } wake_up(&priv->wait_flag); } //////////////////////////////////////////////////////////////////////// // Help Functions //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Name: usbrsa_allocate_write_urbs // Purpose: Allocates and initializes pool of write urbs to EP1OUT // // ////////////////////////////////////////////////////////////////////// int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data) { int i; unsigned long flags; printk("%s() Mark 1",__func__); dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); printk("%s() Mark 2",__func__); for(i=0;i<priv_data->urb_pool_size;i++) { printk("%s; i=%d",__func__,i); 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_pool; } 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_pool; } usb_fill_bulk_urb(priv_data->write_urb_pool[i], priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev,EP1OUT), priv_data->write_urb_pool[i]->transfer_buffer, priv_data->parent_port->bulk_out_size, usbrsa_write_callback, priv_data->parent_port); printk("%s -- clear_bit",__func__); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( i,&priv_data->write_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock,flags); } printk("%s end",__func__); return 0; out_alloc_write_urb_pool: while (i > 0) { if (priv_data->write_urb_pool[i] != NULL) { if (priv_data->write_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->write_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->write_urb_pool[i]); } } printk("%s end error",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_read_urbs // Purpose: Allocates and initializes pool of read urbs to EP1IN // // ////////////////////////////////////////////////////////////////////// int allocate_read_urbs(struct usbrsa_port_private *priv_data) { int i; unsigned long flags; printk("%s start",__func__); dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); for(i=0;i<priv_data->urb_pool_size;i++) { 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,EP1OUT), priv_data->read_urb_pool[i]->transfer_buffer, priv_data->parent_port->bulk_in_size, usbrsa_read_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( i,&priv_data->read_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock,flags); } printk("%s end",__func__); return 0; out_alloc_read_urb_pool: while (i > 0) { if (priv_data->read_urb_pool[i] != NULL) { if (priv_data->read_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->read_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->read_urb_pool[i]); } } printk("%s end error",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_baudrate_lcr_urb // Purpose: Allocates and initializes urb to set baudrate and LCR // to EP2OUT or EP5OUT // // ////////////////////////////////////////////////////////////////////// static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); priv_data->baudrate_lcr_urb=usb_alloc_urb(0,GFP_KERNEL); if (priv_data->baudrate_lcr_urb == NULL) { goto out_alloc_baudrate_lcr; } priv_data->baudrate_lcr_urb->transfer_buffer=kmalloc(EP3OUTLEN,GFP_KERNEL); if (priv_data->baudrate_lcr_urb->transfer_buffer == NULL) { goto out_alloc_baudrate_lcr; } // sent to EP2OUT by default thereby disabling the rx handling of USB-RSA. // The USB-RSA does no longer process or forward the data it receives usb_fill_bulk_urb(priv_data->baudrate_lcr_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev, EP5OUT), priv_data->baudrate_lcr_urb->transfer_buffer, EP5OUTLEN, usbrsa_baudrate_lcr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( LOCK_BAUDRATE_LCR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); return 0; out_alloc_baudrate_lcr: spin_lock_irqsave(&priv_data->lock,flags); set_bit( LOCK_BAUDRATE_LCR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); dev_dbg(&(priv_data->parent_port->dev),"%s(): Could not allocate memory",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_reset_urb // Purpose: Allocates and initializes reset urb to EP4OUT // // ////////////////////////////////////////////////////////////////////// static int allocate_reset_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); priv_data->reset_urb = usb_alloc_urb(0,GFP_KERNEL); if (priv_data->reset_urb == NULL) { goto out_alloc_reset; } priv_data->reset_urb->transfer_buffer = NULL; usb_fill_bulk_urb(priv_data->reset_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev,EP4OUT), priv_data->reset_urb->transfer_buffer, EP4OUTLEN, usbrsa_reset_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( LOCK_RESET,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); return 0; out_alloc_reset: spin_lock_irqsave(&priv_data->lock,flags); set_bit( LOCK_RESET,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); dev_dbg(&(priv_data->parent_port->dev),"%s(): Could not allocate memory",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_status_urb // Purpose: Allocates and initializes status urb from EP3IN // // ////////////////////////////////////////////////////////////////////// static int allocate_status_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); 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(EP3INLEN,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_status_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( LOCK_STATUS,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); return 0; out_alloc_status: spin_lock_irqsave(&priv_data->lock,flags); set_bit( LOCK_STATUS,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); dev_dbg(&(priv_data->parent_port->dev),"%s(): Could not allocate memory",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_mcr_urb // Purpose: Allocates and initializes modem control register urb // to EP3OUT // ////////////////////////////////////////////////////////////////////// static int allocate_mcr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); priv_data->mcr_urb = usb_alloc_urb(0,GFP_KERNEL); if (priv_data->mcr_urb == NULL) { goto out_alloc_mcr; } priv_data->mcr_urb->transfer_buffer=kmalloc(EP3OUTLEN,GFP_KERNEL); if (priv_data->mcr_urb->transfer_buffer == NULL) { goto out_alloc_mcr; } usb_fill_bulk_urb(priv_data->mcr_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev,EP3OUT), priv_data->mcr_urb->transfer_buffer, EP3OUTLEN, usbrsa_mcr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( LOCK_MCR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); return 0; out_alloc_mcr: spin_lock_irqsave(&priv_data->lock,flags); set_bit( LOCK_MCR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); dev_dbg(&(priv_data->parent_port->dev),"%s(): Could not allocate memory",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: allocate_msr_urb // Purpose: Allocates and initializes modem status register urb // to EP3IN // ////////////////////////////////////////////////////////////////////// static int allocate_msr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); priv_data->msr_urb = usb_alloc_urb(0,GFP_KERNEL); if (priv_data->msr_urb == NULL) { goto out_alloc_msr; } priv_data->msr_urb->transfer_buffer=kmalloc(EP3OUTLEN,GFP_KERNEL); if (priv_data->msr_urb->transfer_buffer == NULL) { goto out_alloc_msr; } usb_fill_bulk_urb(priv_data->msr_urb, priv_data->parent_serial->dev, usb_rcvbulkpipe(priv_data->parent_serial->dev,EP2IN), priv_data->msr_urb->transfer_buffer, EP2INLEN, usbrsa_msr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock,flags); clear_bit( LOCK_MSR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); return 0; out_alloc_msr: spin_lock_irqsave(&priv_data->lock,flags); set_bit( LOCK_MSR,&priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock,flags); dev_dbg(&(priv_data->parent_port->dev),"%s(): Could not allocate memory",__func__); return ENOMEM; } ////////////////////////////////////////////////////////////////////// // Name: release_write_urbs // Purpose: Deallocate resource pool for EP1OUT // // ////////////////////////////////////////////////////////////////////// static void release_write_urbs(struct usbrsa_port_private *priv_data) { unsigned long flags; int i; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); for(i=0;i<priv_data->urb_pool_size;i++) { 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_urbs // Purpose: Deallocate resource pool for EP1IN // // ////////////////////////////////////////////////////////////////////// static void release_read_urbs(struct usbrsa_port_private *priv_data) { unsigned long flags; int i; dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); for(i=0;i<priv_data->urb_pool_size;i++) { 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_baudrate_lcr_urb // Purpose: Remove baudrate_lcr_urb // // ////////////////////////////////////////////////////////////////////// static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data) { dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); if (priv_data->baudrate_lcr_urb != NULL) { if (priv_data->baudrate_lcr_urb->transfer_buffer != NULL) { kfree(priv_data->baudrate_lcr_urb->transfer_buffer); } usb_free_urb(priv_data->baudrate_lcr_urb); priv_data->baudrate_lcr_urb = NULL; } } ////////////////////////////////////////////////////////////////////// // Name: release_reset_urb // Purpose: Remove release_reset_urb // // ////////////////////////////////////////////////////////////////////// static void release_reset_urb(struct usbrsa_port_private *priv_data) { dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); if (priv_data->reset_urb != NULL) { usb_free_urb(priv_data->reset_urb); priv_data->reset_urb = NULL; } } ////////////////////////////////////////////////////////////////////// // Name: release_status_urb // Purpose: Remove release_status_urb // // ////////////////////////////////////////////////////////////////////// static void release_status_urb(struct usbrsa_port_private *priv_data) { dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); if (priv_data->status_urb != NULL) { if (priv_data->status_urb->transfer_buffer != NULL) { kfree(priv_data->status_urb->transfer_buffer); } usb_free_urb(priv_data->status_urb); priv_data->status_urb = NULL; } } ////////////////////////////////////////////////////////////////////// // Name: release_mcr_urb // Purpose: Remove release_mcr_urb // // ////////////////////////////////////////////////////////////////////// static void release_mcr_urb(struct usbrsa_port_private *priv_data) { dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); if (priv_data->mcr_urb != NULL) { if (priv_data->mcr_urb->transfer_buffer != NULL) { kfree(priv_data->mcr_urb->transfer_buffer); } usb_free_urb(priv_data->mcr_urb); priv_data->mcr_urb = NULL; } } ////////////////////////////////////////////////////////////////////// // Name: release_msr_urb // Purpose: deallocate msr_urb // // ////////////////////////////////////////////////////////////////////// static void release_msr_urb(struct usbrsa_port_private *priv_data) { dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); if (priv_data->msr_urb != NULL) { if (priv_data->msr_urb->transfer_buffer != NULL) { kfree(priv_data->msr_urb->transfer_buffer); } usb_free_urb(priv_data->msr_urb); priv_data->msr_urb = NULL; } } ////////////////////////////////////////////////////////////////////// // Name: prepare_baudrate_lcr_urb // Purpose: Computes urb setting Line Control Regsister (LCR) and // divider register (DLL+DLM) to determine baud rate of // ST16c550. The urb is sent to either EP2OUT and EP5OUT. // An urb to EP2OUT sets the registers of the USB-RSA and // enables receive interrupts. An urb to EP5OUT only sets // the register. // // // Format of EP2OUT/EP5OUT // Byte 0: DLL of ST16c550 // Byte 1: DLM of ST16c550 // Byte 2: LCR of ST16c550 // ////////////////////////////////////////////////////////////////////// static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate, int endpoint, struct usb_serial_port *port) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; __u8 lcr = 0; __u16 divisor = 0; __u8* buffer_ptr = priv->baudrate_lcr_urb->transfer_buffer; dev_dbg(&port->dev,"%s() CFLAG=%u SPEED=%u ep=%d",__func__, cflag, baud_rate,endpoint ); // if word length is 5 bit, stop bit length is 1,5 bit times // else 2 bit times // restrict baud_rate to boundaries determined by // USB-RSA hardware if (baud_rate < 75 ) baud_rate = 75; if (baud_rate > 460800) baud_rate = 460800; divisor = USBRSA_ST16C550_CLOCK/(16 * baud_rate); priv->dll = divisor & 0xFF; priv->dlm = (divisor & 0xFF00) >> 8; switch (cflag & CSIZE) { case CS5: lcr = USBRSA_ST16C550_LCR_CS5; break; case CS6: lcr = USBRSA_ST16C550_LCR_CS6; break; case CS7: lcr = USBRSA_ST16C550_LCR_CS7; break; default: case CS8: lcr = USBRSA_ST16C550_LCR_CS8; break; } /* determine the parity */ if (cflag & PARENB) if (cflag & CMSPAR) if (cflag & PARODD) lcr |= USBRSA_ST16C550_LCR_MARK; else lcr |= USBRSA_ST16C550_LCR_SPACE; else if (cflag & PARODD) lcr |= USBRSA_ST16C550_LCR_ODD; else lcr |= USBRSA_ST16C550_LCR_EVEN; else lcr |= USBRSA_ST16C550_LCR_NONE; /* figure out the stop bits requested */ if (cflag & CSTOPB) lcr |= USBRSA_ST16C550_LCR_STOP2; else lcr |= USBRSA_ST16C550_LCR_STOP1; // FW of USB-RSA expects bit 7 (Baud Rate Counter Latch) to be 0 lcr &= 0x7F; priv->lcr = lcr; *buffer_ptr = priv->dll; buffer_ptr++; *buffer_ptr = priv->dlm; buffer_ptr++; *buffer_ptr = priv->lcr; dev_dbg(&port->dev,"%s() ST16C550.DLL=%d;ST16C550.DLM=%d;ST16C550.LCR=%d", __func__, priv->dll,priv->dlm,priv->lcr); spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_BAUDRATE_LCR,&priv->urb_lock))) { set_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock); priv->baudrate_lcr_urb->pipe = usb_sndbulkpipe(priv->parent_serial->dev,endpoint); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->baudrate_lcr_urb, GFP_ATOMIC); } else { // urb already in use spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev,"%s(): Cannot reserve baudrate_lcr_urb",__func__); // fix me: return appropriate return code retval = -1; // end fix me goto send_baudrate_lcr_exit; } if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev,"%s(): Cannot submit urb: %d",__func__, retval); goto send_baudrate_lcr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // timeout. Dequeue urb usb_kill_urb(priv->baudrate_lcr_urb); dev_dbg(&port->dev,"%s - sending baudrate_lcr_urb timed out.", __func__); retval = -ETIMEDOUT; goto send_baudrate_lcr_exit; } send_baudrate_lcr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev,"%s() leaving",__func__); return retval; } ////////////////////////////////////////////////////////////////////// // Name: send_mcr_register // Purpose: Sends MCR value in private data structure of device // to USBRSA // // Format of EP3OUT // USB Message Length: 1 Byte // Bit0: DTR // Bit1: RTS // Bit2: OP1 // Bit3: OP2 // Bit4: Diagnostics mode // ////////////////////////////////////////////////////////////////////// static int send_mcr_register(struct usb_serial_port *port) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev,"%s: 0x%02x", __func__, priv->mcr); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_MCR, &priv->urb_lock); memcpy(priv->mcr_urb->transfer_buffer,&priv->mcr,1); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->mcr_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev,"%s(): Cannot submit urb: %d",__func__, retval); goto send_mcr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_MCR, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // fetching of msr usb_kill_urb(priv->mcr_urb); dev_dbg(&port->dev,"%s - sending mcr timed out.", __func__); retval = -ETIMEDOUT; goto send_mcr_exit; } send_mcr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); return retval; } ////////////////////////////////////////////////////////////////////// // Name: fetch_msr_register // Purpose: Get MSR value from USBRSA and stores it in private data // structure // // Format of EP2IN // USB Message Length: 1 Byte // Bit0: Delta CTS (1 indicates a change on the line) // Bit1: Delta DTS (1 indicates a change on the line) // Bit2: Delta RI (1 indicates a change on the line) // Bit3: Delta CD (1 indicates a change on the line) // Bit4: CTS // Bit5: DTS // Bit6: RI // Bit7: CD // ////////////////////////////////////////////////////////////////////// static int fetch_msr_register(struct usb_serial_port *port) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev,"%s: 0x%02x", __func__, priv->msr); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_MSR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->msr_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev,"%s(): Cannot submit urb: %d",__func__, retval); goto send_msr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_MSR, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // fetching of msr usb_kill_urb(priv->msr_urb); dev_dbg(&port->dev,"%s - fetching msr timed out.", __func__); retval = -ETIMEDOUT; goto send_msr_exit; } send_msr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MSR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev,"%s: 0x%02x", __func__, priv->msr); return retval; } ////////////////////////////////////////////////////////////////////// // Name: send_reset // Purpose: sent reset urb to USBRSA and wait for completion // // ////////////////////////////////////////////////////////////////////// static int send_reset(struct usb_serial_port *port) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev,"%s: ", __func__); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_RESET, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->reset_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev,"%s(): Cannot submit urb: %d",__func__, retval); goto send_reset_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_RESET, &priv->urb_lock)==0), COMMAND_TIMEOUT); if (!t) { // fetching of msr usb_kill_urb(priv->reset_urb); dev_dbg(&port->dev,"%s - reset timed out.", __func__); retval = -ETIMEDOUT; goto send_reset_exit; } send_reset_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_RESET, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); return retval; } ////////////////////////////////////////////////////////////////////// // Name: wait_modem_info // Purpose: waits until a line reflected in the MSR (modem status // register) changes. Lines that can be tested are: // - CTS // - DSR // - RI // - CD // // ////////////////////////////////////////////////////////////////////// static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) { struct usbrsa_port_private* priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prev, status; unsigned int changed; int retval; spin_lock_irqsave(&priv->lock, flags); retval = fetch_msr_register(port); if (retval != 0) { goto bailout_wait_modem_info; } spin_lock_irqsave(&priv->lock, flags); prev = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); while (1) { retval = fetch_msr_register(port); if (retval != 0) { goto bailout_wait_modem_info; } spin_lock_irqsave(&priv->lock, flags); status = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave(&priv->lock, flags); changed = prev ^ status; prev = status; spin_unlock_irqrestore(&priv->lock, flags); if (((arg & TIOCM_RNG) && (changed & USBRSA_ST16C550_MSR_RI)) || ((arg & TIOCM_DSR) && (changed & USBRSA_ST16C550_MSR_DSR)) || ((arg & TIOCM_CD) && (changed & USBRSA_ST16C550_MSR_CD)) || ((arg & TIOCM_CTS) && (changed & USBRSA_ST16C550_MSR_CTS))) return 0; } bailout_wait_modem_info: /* NOTREACHED */ return retval; } ////////////////////////////////////////////////////////////////////// // Name: get_serial_info // Purpose: fills a struct containing information about the serial // port. // // ////////////////////////////////////////////////////////////////////// static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); struct serial_struct tmp; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = port->minor; tmp.port = port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = priv->urb_pool_size * port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; tmp.closing_wait = 30*HZ; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; } static struct usb_serial_driver * const serial_drivers[] = { &usbrsa_preenum_device,&usbrsa_enumerated_device, NULL }; module_usb_serial_driver(serial_drivers, id_table_combined); //request_module("ezusb"); //request_module("usbserial"); MODULE_FIRMWARE("usbrsa.fw"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(debug, int , S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debug"); // usbrsa.h /* * Driver for IO-Data's USB RSA serial dongle * * Copyright (C) 2012 * Tilman Glotzner <tilmanglotz...@hotmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * */ #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_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 */ 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 */ struct mutex mutex; } __attribute__ ((packed)); ; #endif -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html