Hi Greg Kind of Driver: Driver for a dongle usb-> serial Manufacturer: Io-Data Device: USB-RSA (based on EZUSB-CHip) Goal: Port the driver that was working on kernel version 3.17 to current kernel version Problem Description: - The driver initializes properly, and downloads the firmware. - When issuing echo "0123456789" > /dev/ttyUSB0, the data is sent downstream to the device. echo then blocks for 30 seconds. usbrsa_close is then called. With it, also echo terminates (return code = 0) - When issuing stty -F /dev/ttyUSB0 300, the command is apparently executed. stty however blocks (as it seems indefinitely). usbrsa_close is only called once I cancel stty with CTRL-C Remark: From what I can see, the driver does not block within the driver code but somewhere else. For log and source code, please look below (As you suggested, I scanned the source with checkpatch.pl. I have removed all errors). gkh> Why not post the updated gkh> code so that everyone can see it and possibly help out with it? No issue with that -- just wanted to save everybody from utterly long postings. ===== command: echo "0123456789" > /dev/ttyUSB0 SYSLOG: [105791.355511] tty ttyUSB0: usbrsa_init_termios() [105791.355528] usbrsa_open; priv=ffff880307620e00 [105791.355533] usbrsa ttyUSB0: usbrsa_open - port 0 [105791.355536] usbrsa ttyUSB0: usbrsa_set_termios - port 0 [105791.355539] usbrsa ttyUSB0: usbrsa_set_termios - baudrate = 300 [105791.355543] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207 SPEED=300 ep=2 [105791.355547] usbrsa ttyUSB0: send_baudrate_lcr_register() ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3 [105791.355615] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0, ep=0xc0010f00 [105791.355656] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving [105791.355669] usbrsa ttyUSB0: usbrsa_open - port 0: leaving [105791.355712] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint [105791.355724] usbrsa_write; private struct =ffff880307620e00 [105791.355729] usbrsa ttyUSB0: usbrsa_write - port 0; bytes=11 := count=11 : nofTxBytesFree=4063 [105791.355734] usbrsa ttyUSB0: usbrsa_write - poolsize 10, urb_index 0 [105791.355739] usbrsa ttyUSB0: usbrsa_write - port 0;URB allocated=0 [105791.355744] usbrsa ttyUSB0: usbrsa_write - port 0;bytes in urb=11 [105791.355748] usbrsa ttyUSB0: usbrsa_write - length = 11, data = 30 31 32 33 34 35 36 37 38 39 0a [105791.355753] usbrsa ttyUSB0: usbrsa_write - port 0;sent=11;count=0; nof_bytes_to_be_sent=0;bytes=11 [105791.355756] usbrsa ttyUSB0: usbrsa_write() End - sent=11 [105791.355801] usbrsa ttyUSB0: usbrsa_write_callback() - port = 0, ep =0xc0018f80 [105791.355809] usbrsa ttyUSB0: usbrsa_write_callback - length = 11, data = 30 31 32 33 34 35 36 37 38 39 0a [105791.355817] usbrsa ttyUSB0: usbrsa_write_callback(): Returned URB 0 [105791.355958] usbrsa_status_callback: nofTxBytesFree=4052,nofRxBytesReceived=0 ... (here the blocking of "echo" starts) [105793.353318] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint [105795.353432] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint ... (repeats every 2 seconds for around 30 seconds) usbrsa_status_callback(): usb_serial_port_softint [105821.354309] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint [105821.766319] usbrsa_close - start [105821.766328] usbrsa ttyUSB0: usbrsa_close - port 0 start [105821.766334] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207 SPEED=300 ep=5 [105821.766338] usbrsa ttyUSB0: send_baudrate_lcr_register() ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3 [105821.766380] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0, ep=0xc0028f00 [105821.766392] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving [105821.766395] usbrsa ttyUSB0: usbrsa_close - #retries=3 [105821.766397] usbrsa_close - end [105821.766399] usbrsa ttyUSB0: usbrsa_close - end [105821.766416] usbrsa ttyUSB0: usbrsa_status_callback(): wake_up ... (echo terminates)..... command: stty -F /dev/ttyUSB0 300 SYSLOG: [106202.139819] usbrsa_open; priv=ffff880307620e00 [106202.139824] usbrsa ttyUSB0: usbrsa_open - port 0 [106202.139827] usbrsa ttyUSB0: usbrsa_set_termios - port 0 [106202.139830] usbrsa ttyUSB0: usbrsa_set_termios - baudrate = 300 [106202.139834] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207 SPEED=300 ep=2 [106202.139838] usbrsa ttyUSB0: send_baudrate_lcr_register() ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3 [106202.139924] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0, ep=0xc0010f00 [106202.139949] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving [106202.139958] usbrsa ttyUSB0: usbrsa_open - port 0: leaving [106202.139978] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5401 [106202.139982] usbrsa ttyUSB0: usbrsa_ioctl(): TCGETS -- not implemented [106202.139986] usbrsa ttyUSB0: usbrsa_ioctl() leaving [106202.139996] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint [106202.140016] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5401 [106202.140021] usbrsa ttyUSB0: usbrsa_ioctl(): TCGETS -- not implemented [106202.140025] usbrsa ttyUSB0: usbrsa_ioctl() leaving [106202.140030] usbrsa ttyUSB0: usbrsa_ioctl() cmd 0x5403 [106202.140035] usbrsa ttyUSB0: usbrsa_ioctl(): 0x5403 not supported [106202.140038] usbrsa ttyUSB0: usbrsa_ioctl() leaving [106204.139545] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint .... (stty waits blocked on the command line) .... [106206.139617] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint ... (repeats every 2 seconds until CTRL-C is sent to the stty command) [106428.147311] usbrsa ttyUSB0: usbrsa_status_callback(): usb_serial_port_softint [106428.665722] usbrsa_close - start [106428.665733] usbrsa ttyUSB0: usbrsa_close - port 0 start [106428.665740] usbrsa ttyUSB0: send_baudrate_lcr_register() CFLAG=1207 SPEED=300 ep=5 [106428.665744] usbrsa ttyUSB0: send_baudrate_lcr_register() ST16C550.DLL=74;ST16C550.DLM=6;ST16C550.LCR=3 [106428.665782] usbrsa ttyUSB0: usbrsa_baudrate_lcr_callback() - port = 0, ep=0xc0028f00 [106428.665794] usbrsa ttyUSB0: send_baudrate_lcr_register() leaving [106428.665797] usbrsa ttyUSB0: usbrsa_close - #retries=3 [106428.665799] usbrsa_close - end [106428.665801] usbrsa ttyUSB0: usbrsa_close - end [106428.665824] usbrsa ttyUSB0: usbrsa_status_callback(): wake_up ... (stty returns to command line. return code = 130) SOURCE CODE: /* * Driver for IO-Data's USB RSA serial dongle * Copyright (C) 2012 * Tilman Glotzner(tilmanglotzner@xxxxxxxxx) * * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * * USB-RSA by IO-DATA * USB to serial converter * ======================= * * Remark: The device uses an AN2131Q (Eazy USB) and a ST16C550(UART) * * End Points: * ============ * * End Point: EP1OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 64 bytes * Desc: Data to be transmitted * Format: 64 bytes of data * * * End Point: EP2OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 3 bytes * Desc: Set baud rate counter and Line Control Register * of the ST16C550. Receiver Interrupts are turned * ON, i.e. Modem status IR, RX line status IR, * and RX holding register IR * Format: * Byte0: Low Byte of counter (DLL) * Byte1: High Byte of counter (DLM) * Byte2: Line Control Register (LCR) * - Bit 0: Word Length 0 * - Bit 1: Word Length 1 * - Bit 2: Stop Bits * - Bit 3: Parity Enable * - Bit 4: Parity Even * - Bit 5: Set Parity * - Bit 6: Set Break * - Bit 7: Counter Register Enable * (needs to be set to '0') * * * End Point: EP3OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 1 bytes * Desc: Set modem control register of the ST16C550 * Format: * Byte0: Modem Control Register * - Bit0: DTR * - Bit1: RTS * - Bit2: OP1 * - Bit3: OP2 * - Bit4: Diagnostics mode * * * End Point: EP4OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 0 bytes * Desc: Reset EP1OUT and EP1IN (Tx/Rx pipes) * Format: n.a. * * * End Point: EP5OUT * Direction: Host to Device * Type: Bulk Transfer * Size: 3 bytes * Desc: Set baud rate counter and Line Control Register * of the ST16C550. Receiver Interrupts are turned * OFF, i.e. Modem status IR, RX line status IR, * and RX holding register IR * Format: * Byte0: Low Byte of counter (DLL) * Byte1: High Byte of counter (DLM) * Byte2: Line Control Register (LCR) * - Bit 0: Word Length 0 * - Bit 1: Word Length 1 * - Bit 2: Stop Bits * - Bit 3: Parity Enable * - Bit 4: Parity Even * - Bit 5: Set Parity * - Bit 6: Set Break * - Bit 7: Counter Register Enable * (needs to be set to '0') * * * End Point: EP1IN * Direction: Device to Host * Type: Bulk Transfer * Size: 64 bytes * Desc: Data received by USB-RSA * Format: 64 bytes of data * * * End Point: EP2IN * Direction: Device to Host * Type: Bulk Transfer * Size: 1 byte * Desc: Read Modem Status Register of ST16C550 * Format: * Byte0: Modem Status Register * - Bit0: Delta CTS * - Bit1: Delta DSR * - Bit2: Delta RI * - Bit3: Delta CD * - Bit4: CTS * - Bit5: DSR * - Bit6: RI * - Bit7: CD * * * End Point: EP3IN * Direction: Device to Host * Type: Bulk Transfer * Size: 4 bytes * Desc: Read RX/TX Pipe Status * Format: * Byte0: Byte available in TX Buffer of USB-RSA (Low Byte) * Byte1: Byte available in TX Buffer of USB-RSA (High Byte) * Byte2: Byte received and stored in RX Buffer * of USB-RSA (Low Byte) * Byte3: Byte received and stored in RX Buffer * of USB-RSA (High Byte) * * * todo: * use of status urb information (status urb returns tx_bytes_available * on usbrsa) (done) * debug: write blocks if more than 9 URBs (done) * debug rx pipe (first urb read is always empty) * CTS, and DSR: do these need to be enabled OP1/OP2 ? (no) * xon/xoff correctly implemented ? * write function to issue lcr und divisor urb (EPOUT2 and EPOUT5) * + waits for completion (done) * reflect lcr, dll, dlm in usbrsa_port_private (done) * send break * buffering effect: when writing to USB-RSA not all characters are * transferred at once (done) * Are parent_serial,parent_port in usbrsa_port_private * really necessary? * Load kernel modules on which this driver depends. * */ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/module.h> #include <linux/spinlock.h> #include <linux/mutex.h> #include <linux/uaccess.h> #include <asm/termbits.h> #include <linux/usb.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/usb/serial.h> #include <linux/usb/ezusb.h> #include <linux/firmware.h> #include <linux/ihex.h> #include <linux/usb/ezusb.h> #include "usbrsa.h" #define CONFIG_USB_SERIAL_DEBUG 1 #ifdef CONFIG_USB_SERIAL_DEBUG int debug = 1; #else int debug = 0; #endif /* * Version Information */ #define DRIVER_VERSION "v0.1" #define DRIVER_AUTHOR "Tilman Glotzner <tilman.gloetzner@xxxxxxxxx>" #define DRIVER_DESC "Driver for IODATA's USBRSA serial dongle" #define IODATA_VENDOR_ID 0x4bb #define IODATA_USBRSA_PREENUM_ID 0xa01 #define IODATA_USBRSA_ID 0xa02 #define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ /* * Taken whiteheat driver as role model: * ID tables for usb-rsa are unusual, because we want to different * things for different versions of the device. Eventually, this * will be doable from a single table. But, for now, we define two * separate ID tables, and then a third table that combines them * just for the purpose of exporting the autoloading information. */ static const struct usb_device_id id_table_std[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) }, { } /* Terminating entry */ }; static const struct usb_device_id id_table_prerenumeration[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) }, { } /* Terminating entry */ }; static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_USBRSA_PREENUM_ID) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); /*********************************************************************** * Preenumeration device ************************************************************************/ /*********************************************************************** * Function Prototypes ***********************************************************************/ static int usbrsa_firmware_download(struct usb_serial *serial, const struct usb_device_id *id); static int usbrsa_firmware_attach(struct usb_serial *serial); /*********************************************************************** * Driver object declaration ***********************************************************************/ static struct usb_serial_driver usbrsa_preenum_device = { .driver = { .owner = THIS_MODULE, .name = "usbrsanofirm", }, .description = "IO-DATA - USB-RSA - (prerenumeration)", .id_table = id_table_prerenumeration, .num_ports = 1, .probe = usbrsa_firmware_download, .attach = usbrsa_firmware_attach, }; /*********************************************************************** * Functions ************************************************************************/ /*********************************************************************** * Name: usbrsa_firmware_download * Purpose: Downloads firmware to AN2134Q * ***********************************************************************/ static int usbrsa_firmware_download(struct usb_serial *serial, const struct usb_device_id *id) { int response; dev_dbg(&serial->dev->dev, "%s", __func__); response = ezusb_fx1_ihex_firmware_download(serial->dev, "usbrsa.fw"); if (response >= 0) { dev_dbg(&serial->dev->dev, "%s(): Firmware downloaded.", __func__); /* The USB-RSA does not reenumerate without * toggeling the reset bit */ udelay(1000); response = ezusb_fx1_set_reset(serial->dev, 1); udelay(10000); if (response >= 0) { response = ezusb_fx1_set_reset(serial->dev, 0); if (response >= 0) { dev_dbg(&serial->dev->dev, "%s(): Device with new firmware reset.", __func__); return 0; } } dev_err(&serial->dev->dev, "%s(): Status register of EZUSB not accessible.", __func__); } dev_err(&serial->dev->dev, "%s(): Firmware download or subsequent reset failed", __func__); return -ENOENT; } /*********************************************************************** * Name: usbrsa_firmware_attach * Purpose: Prevents the driver from attaching, so that can attach * to the reenumerated device * ***********************************************************************/ static int usbrsa_firmware_attach(struct usb_serial *serial) { /* We want this device to fail to have the driver * assigned to the reenumerated device */ return 1; } /***********************************************************************/ /*********************************************************************** * REENUMERATED DEVICE ***********************************************************************/ /*********************************************************************** * Function Prototypes ***********************************************************************/ static int usbrsa_attach(struct usb_serial *serial); static void usbrsa_release(struct usb_serial *serial); static int usbrsa_probe(struct usb_serial_port *port); static int usbrsa_remove(struct usb_serial_port *port); static int usbrsa_open(struct tty_struct *tty, struct usb_serial_port *port); static void usbrsa_close(struct usb_serial_port *port); static void usbrsa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void usbrsa_init_termios(struct tty_struct *tty); static int usbrsa_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int usbrsa_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static int usbrsa_write_room(struct tty_struct *tty); static int usbrsa_chars_in_buffer(struct tty_struct *tty); static void usbrsa_unthrottle(struct tty_struct *tty); static void usbrsa_throttle(struct tty_struct *tty); static int usbrsa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static int usbrsa_tiocmget(struct tty_struct *tty); /*********************************************************************** * Completion Handler Prototypes ***********************************************************************/ static void usbrsa_baudrate_lcr_callback(struct urb *urb); static void usbrsa_reset_callback(struct urb *urb); static void usbrsa_status_callback(struct urb *urb); static void usbrsa_write_callback(struct urb *urb); static void usbrsa_read_callback(struct urb *urb); static void usbrsa_mcr_callback(struct urb *urb); static void usbrsa_msr_callback(struct urb *urb); /*********************************************************************** * Driver object declaration ***********************************************************************/ static struct usb_serial_driver usbrsa_enumerated_device = { .driver = { .owner = THIS_MODULE, .name = "usbrsa", }, .description = "IO-DATA - USB-RSA", .id_table = id_table_std, .num_ports = 1, .attach = usbrsa_attach, .release = usbrsa_release, .port_probe = usbrsa_probe, .port_remove = usbrsa_remove, .open = usbrsa_open, .close = usbrsa_close, .write = usbrsa_write, .write_bulk_callback = usbrsa_write_callback, .read_bulk_callback = usbrsa_read_callback, .set_termios = usbrsa_set_termios, .tiocmset = usbrsa_tiocmset, .tiocmget = usbrsa_tiocmget, .init_termios = usbrsa_init_termios, .ioctl = usbrsa_ioctl, .write_room = usbrsa_write_room, .chars_in_buffer = usbrsa_chars_in_buffer, .throttle = usbrsa_throttle, .unthrottle = usbrsa_unthrottle }; /*********************************************************************** * Function Prototypes of help functions ***********************************************************************/ static int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data); static int allocate_read_urbs(struct usbrsa_port_private *priv_data); static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data); static int allocate_reset_urb(struct usbrsa_port_private *priv_data); static int allocate_status_urb(struct usbrsa_port_private *priv_data); static int allocate_mcr_urb(struct usbrsa_port_private *priv_data); static int allocate_msr_urb(struct usbrsa_port_private *priv_data); static void release_write_urbs(struct usbrsa_port_private *priv_data); static void release_read_urbs(struct usbrsa_port_private *priv_data); static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data); static void release_reset_urb(struct usbrsa_port_private *priv_data); static void release_status_urb(struct usbrsa_port_private *priv_data); static void release_mcr_urb(struct usbrsa_port_private *priv_data); static void release_msr_urb(struct usbrsa_port_private *priv_data); static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate, int endpoint, struct usb_serial_port *port); static int send_mcr_register(struct usb_serial_port *port); static int fetch_msr_register(struct usb_serial_port *port); static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo); static int send_reset(struct usb_serial_port *port); static int wait_modem_info(struct usb_serial_port *port, unsigned int arg); /*********************************************************************** * Functions ***********************************************************************/ /*********************************************************************** * Name: usbrsa_attach * Purpose: * * ***********************************************************************/ static int usbrsa_attach(struct usb_serial *serial) { int ret = 0; printk(KERN_DEBUG "%s start", __func__); dev_dbg(&serial->dev->dev, "%s", __func__); return ret; } /*********************************************************************** * Name: usbrsa_release * Purpose: * * ***********************************************************************/ static void usbrsa_release(struct usb_serial *serial) { printk("%s: start: numberOfPorts=%d", __func__, serial->num_ports); dev_dbg(&serial->dev->dev, "%s()", __func__); } /*********************************************************************** * Name: usbrsa_probe * Purpose: Creates private data structures of driver * * * ***********************************************************************/ static int usbrsa_probe(struct usb_serial_port *port) { int ret = 0; struct usbrsa_port_private *priv = NULL; printk("%s", __func__); /* struct usbrsa_private *info; * * info = kzalloc(sizeof(*info), GFP_KERNEL); * if (!info) * return -ENOMEM; * * usb_set_serial_port_data(port, info); */ dev_dbg(&port->dev, "%s", __func__); if (!port) { dev_err(&port->dev, "%s(): Invalid handler", __func__); return -ENODEV; } /* allocate struct for driver's private data */ priv = kmalloc(sizeof(struct usbrsa_port_private), GFP_KERNEL); if (priv == NULL) { dev_err(&port->dev, "%s: Out of memory for port structures\n", __func__); goto out_no_private; } priv->parent_serial = port->serial; priv->parent_port = port; priv->read_running = USBRSA_READ_STOP; priv->urb_pool_size = NUM_URBS; priv->nofTxMaxBytes = USBRSA_TX_MAX_BYTES; mutex_init(&priv->mutex); priv->debugTimeStamp = jiffies; spin_lock_init(&priv->lock); init_waitqueue_head(&priv->wait_flag); printk("%s: private struct at %p\n", __func__, priv); usb_set_serial_port_data(port, priv); printk("%s: private struct at %p\n", __func__, usb_get_serial_port_data(port)); /* allocate urbs */ printk("%s about to enter 'usbrsa_allocate_write_urbs'\n", __func__); ret = usbrsa_allocate_write_urbs(priv); if (ret != 0) goto out_no_alloc_write; printk("%s allocate_read_urbs", __func__); ret = allocate_read_urbs(priv); if (ret != 0) goto out_no_alloc_read; printk("%s allocate_baudrate_lcr_urb\n", __func__); ret = allocate_baudrate_lcr_urb(priv); if (ret != 0) goto out_no_alloc_baudrate_lcr; printk("%s allocate_reset_urb\n", __func__); ret = allocate_reset_urb(priv); if (ret != 0) goto out_no_alloc_reset; printk("%s allocate_status_urb\n", __func__); ret = allocate_status_urb(priv); if (ret != 0) goto out_no_alloc_status; printk("%s allocate_mcr_urb\n", __func__); ret = allocate_mcr_urb(priv); if (ret != 0) goto out_no_alloc_mcr; printk("%s allocate_msr_urb\n", __func__); ret = allocate_msr_urb(priv); if (ret != 0) goto out_no_alloc_msr; printk("%s send_reset", __func__); /* sent reset */ ret = send_reset(port); if (ret != 0) { dev_err(&port->dev, "%s(): Failed to issue reset command. " " Error=%d\n", __func__, ret); ret = ENODEV; goto out_no_device; } printk("%s reset successful sent (ret=%d)", __func__, ret); printk("%s end", __func__); return 0; out_no_device: release_msr_urb(priv); out_no_alloc_msr: release_mcr_urb(priv); out_no_alloc_mcr: release_status_urb(priv); out_no_alloc_status: release_reset_urb(priv); out_no_alloc_reset: release_baudrate_lcr_urb(priv); out_no_alloc_baudrate_lcr: release_read_urbs(priv); out_no_alloc_read: release_write_urbs(priv); out_no_alloc_write: kfree(priv); out_no_private: printk("%s end error", __func__); return ret; } /*********************************************************************** * Name: usbrsa_remove * Purpose: Cleans up private data structures of driver * * * ***********************************************************************/ static int usbrsa_remove(struct usb_serial_port *port) { struct usbrsa_port_private *priv; struct usb_serial_port *serport; printk("%s", __func__); dev_dbg(&port->dev, "%s()", __func__); printk("%s: Mark1\n", __func__); serport = port; priv = usb_get_serial_port_data(serport); printk("%s: Mark2\n", __func__); printk("%s: private struct at %p\n", __func__, priv); release_msr_urb(priv); printk("%s: Mark2b ", __func__); release_mcr_urb(priv); printk("%s: Mark2c ", __func__); release_status_urb(priv); printk("%s: Mark2d ", __func__); release_reset_urb(priv); printk("%s: Mark2a ", __func__); release_baudrate_lcr_urb(priv); release_read_urbs(priv); printk("%s: Mark3", __func__); release_write_urbs(priv); printk("%s: Mark4", __func__); kfree(priv); printk("%s: Mark5", __func__); return 0; } /*********************************************************************** * Name: usbrsa_open * Purpose: Open USB device. Sets termios, tty, and starts to sent * status queries to EP3IN. * * ***********************************************************************/ static int usbrsa_open(struct tty_struct *tty, struct usb_serial_port *port) { struct ktermios tmp_termios; int retval = 0; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; printk("%s; priv=%p\n", __func__, priv); dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number); /* flush buffer of USB-RSA by sending reset */ /*retval = send_reset(port); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed with error %d\n", __func__, retval); return -ENODEV; } */ if (tty) { /* usbrsa_set_termios will sent to endpoint 2 of the USB-RSA thereby * turning on the RX interrupt */ usbrsa_set_termios(tty, port, &tmp_termios); } /* start reading from USB-RSA */ spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) { set_bit(LOCK_STATUS, &priv->urb_lock); /* enable continuous reading */ priv->read_running = USBRSA_READ_RUNNING; spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb, GFP_KERNEL); } else { spin_unlock_irqrestore(&priv->lock, flags); } dev_dbg(&port->dev, "%s - port %d: leaving", __func__, port->port_number); return 0; } /*********************************************************************** * Name: usbrsa_close * Purpose: closes USB-RSA device * * ***********************************************************************/ static void usbrsa_close(struct usb_serial_port *port) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int retries = 3; unsigned long flags; int retval; printk("%s - start", __func__); dev_dbg(&port->dev, "%s - port %d start", __func__, port->port_number); /* turn off RX interrupt of USB-RSA by sending to EP5) */ while (retries > 0) { /* turn off RX interrupt of USB-RSA by sending to EP5.*/ retval = send_baudrate_lcr_register(priv->c_flag, priv->baudrate, EP5OUT, port); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, retval); } else { dev_dbg(&port->dev, "%s - #retries=%d", __func__, retries); break; } retries--; } /* disable continuous reading */ spin_lock_irqsave(&priv->lock, flags); priv->read_running = USBRSA_READ_STOP; spin_unlock_irqrestore(&priv->lock, flags); printk("%s - end", __func__); dev_dbg(&port->dev, "%s - end ", __func__); } /*********************************************************************** * Name: usbrsa_init_termios * Purpose: Initialize termios of tty * * ***********************************************************************/ static void usbrsa_init_termios(struct tty_struct *tty) { dev_dbg(tty->dev, "%s()", __func__); /* tty->termios = tty_std_termios; tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty->termios.c_ispeed = 9600; tty->termios.c_ospeed = 9600; */ } /*********************************************************************** * Name: usbrsa_set_termios * Purpose: Initialize USB-RSA with terminal settings * * ***********************************************************************/ static void usbrsa_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned int cflag; speed_t baud_rate; int retval; int retries = 3; dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number); if (!tty) { dev_err(&port->dev, "%s(): no tty structures", __func__); return; } if (I_IXOFF(tty) || I_IXON(tty)) { priv->xon = START_CHAR(tty); priv->xoff = STOP_CHAR(tty); dev_dbg(&port->dev, "%s - XON = %2x, XOFF = %2x", __func__, priv->xon, priv->xoff); } cflag = tty->termios.c_cflag; priv->c_flag = cflag; /* get the baud rate wanted */ baud_rate = tty_get_baud_rate(tty); priv->baudrate = baud_rate; dev_dbg(&port->dev, "%s - baudrate = %u", __func__, baud_rate); /* if baud rate is B0, drop DTR */ if ((baud_rate & CBAUD) == B0) { priv->mcr &= ~(USBRSA_ST16C550_MCR_DTR); retval = send_mcr_register(port); if (retval != 0) return; } while (retries > 0) { retval = send_baudrate_lcr_register(cflag, baud_rate, EP2OUT, port); if (retval != 0) { dev_err(&port->dev, "%s(): send_baudrate_lcr_register() failed" " with error %d\n", __func__, retval); retries--; } else { /* bail out */ retries = 0; } } } /*********************************************************************** * Name: usbrsa_write * Purpose: copies data from user space, packs it into urbs, and sents * urbs downstream to USB-RSA * * ***********************************************************************/ static int usbrsa_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; int retval; int nof_bytes_to_be_sent; int bytes; int urb_index; int sent = 0; struct urb *urb; dev_dbg(&port->dev, "%s - port %d START", __func__, port->port_number); printk("%s; private struct =%p\n", __func__, priv); while (count > 0) { /* transfer only as many bytes as USB-RSA can take */ nof_bytes_to_be_sent = (count > priv->nofTxBytesFree) ? priv->nofTxBytesFree : count; dev_dbg(&port->dev, "%s - port %d; bytes=%d := count=%d : nofTxBytesFree=%d", __func__, port->port_number, nof_bytes_to_be_sent, count, priv->nofTxBytesFree); while (nof_bytes_to_be_sent > 0) { /* check for empty urb in write pool */ spin_lock_irqsave(&priv->lock, flags); urb_index = find_first_zero_bit(&priv->write_urb_pool_lock, priv->urb_pool_size); dev_dbg(&port->dev, "%s - poolsize %d, urb_index %d\n", __func__, priv->urb_pool_size, urb_index); if (urb_index >= priv->urb_pool_size) { /* no more urbs available */ spin_unlock_irqrestore(&priv->lock, flags); goto out_write_no_urbs; } dev_dbg(&port->dev, "%s - port %d;URB allocated=%d", __func__, port->port_number, urb_index); /* reserve urb */ set_bit(urb_index, &priv->write_urb_pool_lock); urb = priv->write_urb_pool[urb_index]; spin_unlock_irqrestore(&priv->lock, flags); /* copy data from userspace into urb transfer buffer */ bytes = (nof_bytes_to_be_sent > port->bulk_out_size) ? port->bulk_out_size : nof_bytes_to_be_sent; memcpy(urb->transfer_buffer, buf + sent, bytes); dev_dbg(&port->dev, "%s - port %d;bytes in urb=%d", __func__, port->port_number, bytes); usb_serial_debug_data(&port->dev, __func__, bytes, urb->transfer_buffer); urb->dev = serial->dev; urb->transfer_buffer_length = bytes; /* sent urb to USB-RSA */ retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) { /* return urb to pool */ spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->write_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, retval); sent = retval; /* bail out */ goto out_write_submit_failed; } else { sent += bytes; count -= bytes; nof_bytes_to_be_sent -= bytes; dev_dbg(&port->dev, "%s - port %d;sent=%d;count=%d; nof_bytes_to_be_sent=%d;bytes=%d", __func__, port->port_number, sent, count, nof_bytes_to_be_sent, bytes); } } } out_write_no_urbs: out_write_submit_failed: dev_dbg(&port->dev, "%s() End - sent=%d\n", __func__, sent); usb_serial_port_softint(port); return sent; } /*********************************************************************** * Name: usbrsa_ioctl * Purpose: copies data from user space, packs it into urbs, and sents * urbs downstream to USB-RSA * * ***********************************************************************/ static int usbrsa_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; dev_dbg(&port->dev, "%s() cmd 0x%.4x", __func__, cmd); switch (cmd) { case TIOCGSERIAL: return get_serial_info(port, (struct serial_struct __user *) arg); break; case TIOCMIWAIT: dev_dbg(&port->dev, "%s(): TIOCMIWAIT", __func__); return wait_modem_info(port, arg); break; case TCGETS: dev_dbg(&port->dev, "%s(): TCGETS -- not implemented", __func__); break; case TCSETS: dev_dbg(&port->dev, "%s(): TCSETS -- not implemented", __func__); break; case TCFLSH: dev_dbg(&port->dev, "%s(): TCFLSH -- not implemented", __func__); break; default: dev_dbg(&port->dev, "%s(): 0x%04x not supported", __func__, cmd); break; } dev_dbg(&port->dev, "%s() leaving", __func__); return -ENOIOCTLCMD; } /*********************************************************************** * Name: usbrsa_write_room * Purpose: Returns fill level of the tx queue. The tx queue consists * of 2 parts: A pool of URBs, and a buffer in the USB-RSA. * Mostly, the fill level of the pool will be returned. * Only if there is less memory available in the USB-RSA's * buffer than in the the pool, the fill level of the USB-RSA * will be returned to prevent clogging the tx queue. * * * ***********************************************************************/ static int usbrsa_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int room = 0; int i = 0; long t; unsigned long flags; int retval; /*dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number);*/ /* if no current fill level information is available, issue status update */ if (priv->read_running != USBRSA_READ_RUNNING) { /* start reading from USB-RSA */ spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) { set_bit(LOCK_STATUS, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb, GFP_KERNEL); if (retval != 0) { return -ENODEV; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_STATUS, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* fetching of msr */ usb_kill_urb(priv->status_urb); dev_dbg(&port->dev, "%s - status urb timed out.", __func__); return -ETIMEDOUT; /*goto send_reset_exit; */ } } else { spin_unlock_irqrestore(&priv->lock, flags); } } spin_lock_irqsave(&priv->lock, flags); for (i = 0; i < priv->urb_pool_size; i++) { if (test_bit(i, &priv->write_urb_pool_lock) == 0) { room++; } } spin_unlock_irqrestore(&priv->lock, flags); /*compute bytes available in write URB pool */ room *= port->bulk_out_size; dev_dbg(&port->dev, "%s(): Pool=%d;usbrsa.tx=%d", __func__, room, priv->nofTxBytesFree); /* if usbrsa has fewer bytes available than URB pool return available bytes in USBRSA */ room = (room > priv->nofTxBytesFree) ? priv->nofTxBytesFree : room; /*dev_dbg(&port->dev, "%s(): %d", __func__, room); */ return room; } /*********************************************************************** * Name: usbrsa_chars_in_buffer * Purpose: Return the number of bytes still waiting to be sent * stored in the USBRSA as well as in the buffer of the * driver (URB pool). * The tty layer thereby calls the close function only * after all bytes are sent. * * * * ***********************************************************************/ static int usbrsa_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int chars = 0; int i = 0; unsigned long flags; long t; int retval; /*dev_dbg(&port->dev,"%s - port %d", __func__,port->port_number);*/ if (priv->read_running != USBRSA_READ_RUNNING) { /* start reading from USB-RSA */ spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_STATUS, &priv->urb_lock))) { set_bit(LOCK_STATUS, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb, GFP_KERNEL); if (retval != 0) { chars = -ENODEV; goto chars_in_buffer_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_STATUS, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* fetching of msr */ usb_kill_urb(priv->status_urb); dev_dbg(&port->dev, "%s - status urb timed out.", __func__); chars = -ETIMEDOUT; goto chars_in_buffer_exit; } } else { spin_unlock_irqrestore(&priv->lock, flags); } } spin_lock_irqsave(&priv->lock, flags); /*bytes in TX buffer of USBRSA */ chars = priv->nofTxMaxBytes - priv->nofTxBytesFree; /* account for URBs in the pool and not yet transferred to the USB-RSA */ for (i = 0; i < priv->urb_pool_size; i++) { if (test_bit(i, &priv->write_urb_pool_lock) != 0) { chars += priv->write_urb_pool[i]->transfer_buffer_length; } } spin_unlock_irqrestore(&priv->lock, flags); chars_in_buffer_exit: /*dev_dbg(&port->dev,"%s(): %d", __func__, chars);*/ return chars; } /*********************************************************************** * Name: usbrsa_throttle * Purpose: * * * ***********************************************************************/ static void usbrsa_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status; dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number); /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); status = usbrsa_write(tty, port, &stop_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios.c_cflag & CRTSCTS) { priv->mcr &= ~USBRSA_ST16C550_MCR_RTS; status = send_mcr_register(port); if (status != 0) return; } } /*********************************************************************** * Name: usbrsa_unthrottle * Purpose: * * * ***********************************************************************/ static void usbrsa_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status; dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number); /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); status = usbrsa_write(tty, port, &start_char, 1); if (status <= 0) return; } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios.c_cflag & CRTSCTS) { priv->mcr |= USBRSA_ST16C550_MCR_RTS; send_mcr_register(port); } } /*********************************************************************** * Name: usbrsa_tiocmset * Purpose: * * * ***********************************************************************/ static int usbrsa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; int retval; if (port == NULL) return -ENODEV; dev_dbg(&port->dev, "%s - port %d", __func__, port->port_number); spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->mcr |= USBRSA_ST16C550_MCR_RTS; if (set & TIOCM_DTR) priv->mcr |= USBRSA_ST16C550_MCR_DTR; if (set & TIOCM_LOOP) { priv->mcr |= USBRSA_ST16C550_MCR_DIAG; priv->lloop = 1; } if (clear & TIOCM_RTS) priv->mcr &= ~USBRSA_ST16C550_MCR_RTS; if (clear & TIOCM_DTR) priv->mcr &= ~USBRSA_ST16C550_MCR_DTR; if (clear & TIOCM_LOOP) { priv->mcr &= ~USBRSA_ST16C550_MCR_DIAG; priv->lloop = 0; } /* bring OP1 and OP2 to defined states */ priv->mcr &= ~USBRSA_ST16C550_MCR_OP1; priv->mcr &= ~USBRSA_ST16C550_MCR_OP2; spin_unlock_irqrestore(&priv->lock, flags); retval = send_mcr_register(port); dev_dbg(&port->dev, "%s: %d=send_mcr_register", __func__, retval); return retval; } /*********************************************************************** * Name: usbrsa_tiocmget * Purpose: * * * ***********************************************************************/ static int usbrsa_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int retval; if (port == NULL) return -ENODEV; dev_dbg(&port->dev, "%s() - port %d", __func__, port->port_number); retval = fetch_msr_register(port); dev_dbg(&port->dev, "%s: %d=fetch_msr_register", __func__, retval); if (retval == 0) { retval = ((priv->mcr & USBRSA_ST16C550_MCR_DTR) ? TIOCM_DTR : 0) | ((priv->mcr & USBRSA_ST16C550_MCR_RTS) ? TIOCM_RTS : 0) | ((priv->mcr & USBRSA_ST16C550_MCR_DIAG) ? TIOCM_LOOP : 0) | ((priv->msr & USBRSA_ST16C550_MSR_CTS) ? TIOCM_CTS : 0) | ((priv->msr & USBRSA_ST16C550_MSR_CD) ? TIOCM_CD : 0) | ((priv->msr & USBRSA_ST16C550_MSR_RI) ? TIOCM_RI : 0) | ((priv->msr & USBRSA_ST16C550_MSR_DSR) ? TIOCM_DSR : 0); } return retval; } /*********************************************************************** * C O M P L E T I O N H A N D L E R S ***********************************************************************/ /*********************************************************************** * Name: usbrsa_baudrate_lcr_callback * Purpose: * * ***********************************************************************/ static void usbrsa_baudrate_lcr_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev, "%s() - port = %d, ep=0x%x", __func__, port->port_number, priv->baudrate_lcr_urb->pipe); /* unlock urb */ spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, status); } wake_up(&priv->wait_flag); } /*********************************************************************** * Name: usbrsa_reset_callback * Purpose: * * ***********************************************************************/ static void usbrsa_reset_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__, port->port_number, priv->reset_urb->pipe); /* unlock urb */ spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_RESET, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, status); } wake_up(&priv->wait_flag); } /*********************************************************************** * Name: usbrsa_status_callback * Purpose: * * ***********************************************************************/ static void usbrsa_status_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; __u8 *ep3in = urb->transfer_buffer; unsigned long flags; int retval; int read_urbs_needed = 0; int urb_index; unsigned int i; /* dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__, port->port_number, * priv->status_urb->pipe); */ spin_lock_irqsave(&priv->lock, flags); /* read payload data of urb, i.e. bytes received and bytes * available in tx queue of USB-RSA */ priv->nofTxBytesFree = ep3in[0] + (256 * ep3in[1]); priv->nofRxBytesReceived = ep3in[2] + (256 * ep3in[3]); /* unlock urb */ clear_bit(LOCK_STATUS, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if ((priv->debugNofTxBytesFree != priv->nofTxBytesFree) || (priv->debugRxBytesReceived != priv->nofRxBytesReceived)) { printk("%s: nofTxBytesFree=%d,nofRxBytesReceived=%d\n", __func__, priv->nofTxBytesFree, priv->nofRxBytesReceived); } priv->debugNofTxBytesFree = priv->nofTxBytesFree; priv->debugRxBytesReceived = priv->nofRxBytesReceived; /* if coutinuous read enabled, either * -- issue next status request (USBRSA did not receive * anything) * -- issue a read urb (if rx queue is filled) */ if (priv->read_running == USBRSA_READ_RUNNING) { if (priv->nofRxBytesReceived != 0) { /* USB-RSA received data */ /* compute urbs needed */ read_urbs_needed = priv->nofRxBytesReceived/port->bulk_in_size; if (priv->nofRxBytesReceived%port->bulk_in_size) read_urbs_needed++; dev_dbg(&port->dev, "%s(): EP1IN: rx=%d, urbs_needed=%d,size_of_urb=%d", __func__, priv->nofRxBytesReceived, read_urbs_needed, port->bulk_in_size); /* issue read urbs */ if (read_urbs_needed > priv->urb_pool_size) read_urbs_needed = priv->urb_pool_size; for (i = 0; i < read_urbs_needed; i++) { spin_lock_irqsave(&priv->lock, flags); urb_index = find_first_zero_bit(&priv->read_urb_pool_lock, priv->urb_pool_size); if (urb_index < priv->urb_pool_size) { set_bit(urb_index, &priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); /* submit read */ dev_dbg(&port->dev, "%s(): submit read urb[%d]", __func__, urb_index); retval = usb_submit_urb(priv->read_urb_pool[urb_index], GFP_KERNEL); if (retval) { /* return urb to read pool */ spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, status); return; } } else { spin_unlock_irqrestore(&priv->lock, flags); i = read_urbs_needed; } } } spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_STATUS, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->status_urb, GFP_KERNEL); if (retval != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __func__, retval); spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_STATUS, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); } } else { /* reading from device ceased -- do nothing *dev_dbg(&port->dev,"%s(): reading stopped: tx_free=%d;rx_recv=%d", * __func__, priv->nofTxBytesFree,priv->nofRxBytesReceived); */ } if (status) { dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, status); } if (priv->read_running == USBRSA_READ_RUNNING) { if ((jiffies - priv->debugTimeStamp)/HZ > 1 ) { dev_dbg(&port->dev,"%s(): usb_serial_port_softint", __func__); priv->debugTimeStamp = jiffies; } usb_serial_port_softint(port); } else { dev_dbg(&port->dev, "%s(): wake_up", __func__); wake_up(&priv->wait_flag); } return; } /*********************************************************************** * Name: usbrsa_write_callback * Purpose: * * ***********************************************************************/ static void usbrsa_write_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; int urb_index; dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x", __func__, port->port_number, priv->status_urb->pipe); usb_serial_debug_data(&port->dev, __func__, urb->actual_length, urb->transfer_buffer); /* find urb in write pool */ for (urb_index = 0; urb_index < priv->urb_pool_size; urb_index++) { if (urb == priv->write_urb_pool[urb_index]) { /* urb found; return urb to pool */ spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->write_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); break; } } if (urb != priv->write_urb_pool[urb_index]) { /* urb not found -- this points to a bug */ dev_err(&port->dev, "%s(): urb not in pool", __func__); } dev_dbg(&port->dev, "%s(): Returned URB %d", __func__, urb_index); if (status) { dev_dbg(&port->dev, "%s(): nonzero urb status: 0x%x", __func__, status); } usb_serial_port_softint(port); } /*********************************************************************** * Name: usbrsa_read_callback * Purpose: * * ***********************************************************************/ static void usbrsa_read_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; int status = urb->status; unsigned char *data = urb->transfer_buffer; int urb_index; unsigned long flags; dev_dbg(&port->dev, "%s() - port = %d, ep=0x%x", __func__, port->port_number, priv->status_urb->pipe); usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); /* find urb in read pool */ for (urb_index = 0; urb_index < priv->urb_pool_size; urb_index++) { if (urb == priv->read_urb_pool[urb_index]) { /* urb found; */ break; } } if (urb != priv->read_urb_pool[urb_index]) { /* urb not found -- this points to a bug */ dev_err(&port->dev, "%s(): urb not in pool", __func__); return; } dev_dbg(&port->dev, "%s() - port = %d: urb_index=%d", __func__, port->port_number, urb_index); tty = tty_port_tty_get(&port->port); if (tty != NULL && urb->actual_length > 0) { tty_insert_flip_string(tty->port, data, urb->actual_length); tty_flip_buffer_push(tty->port); } tty_kref_put(tty); /* return urb to pool */ dev_dbg(&port->dev, "%s: return URB %d", __func__, urb_index); spin_lock_irqsave(&priv->lock, flags); clear_bit(urb_index, &priv->read_urb_pool_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, status); } usb_serial_port_softint(port); } /*********************************************************************** * Name: usbrsa_mcr_callbacks * Purpose: * * ***********************************************************************/ static void usbrsa_mcr_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x, status=%d", __func__, port->port_number, priv->mcr_urb->pipe, status); spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); if (status) { dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, status); } wake_up(&priv->wait_flag); } /*********************************************************************** * Name: usbrsa_msr_callbackS * Purpose: * * ***********************************************************************/ static void usbrsa_msr_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct usbrsa_port_private *priv = usb_get_serial_port_data(port); int status = urb->status; unsigned long flags; __u8 *msr; dev_dbg(&port->dev, "%s() - port = %d, ep =0x%x, status=%d", __func__, port->port_number, priv->msr_urb->pipe, status); spin_lock_irqsave(&priv->lock, flags); msr = urb->transfer_buffer; priv->msr = msr[0]; clear_bit(LOCK_MSR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev, "%s() - msr =%02x", __func__, priv->msr); if (status) { dev_dbg(&port->dev, "%s: nonzero urb status: 0x%x", __func__, status); } wake_up(&priv->wait_flag); } /*********************************************************************** * Help Functions ***********************************************************************/ /*********************************************************************** * Name: usbrsa_allocate_write_urbs * Purpose: Allocates and initializes pool of write urbs to EP1OUT * * ***********************************************************************/ int usbrsa_allocate_write_urbs(struct usbrsa_port_private *priv_data) { int i; unsigned long flags; struct urb *urb; void *buf = NULL; printk("%s() Mark 1\n", __func__); /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); */ printk("%s() Mark 2\n", __func__); for (i = 0; i < priv_data->urb_pool_size; i++) { printk("%s; i=%d\n", __func__, i); urb = usb_alloc_urb(0, GFP_KERNEL); printk("%s; urb=%p\n", __func__, urb); printk("%s: pre priv_data->write_urb_pool[%d]=%p\n", __func__, i, priv_data->write_urb_pool[i]); priv_data->write_urb_pool[i] = urb; printk("%s: post priv_data->write_urb_pool[%d]=%p\n", __func__, i, priv_data->write_urb_pool[i]); if (priv_data->write_urb_pool[i] == NULL) { goto out_alloc_write_urb_pool; } printk("%s: pre priv_data->write_urb_pool[%d]->transfer_buffer=%p\n", __func__, i, priv_data->write_urb_pool[i]->transfer_buffer); buf = kmalloc(priv_data->parent_port->bulk_out_size, GFP_KERNEL); printk("%s: post buf=%p\n", __func__, buf); priv_data->write_urb_pool[i]->transfer_buffer = buf; printk("%s: post priv_data->write_urb_pool[%d]->transfer_buffer=%p\n", __func__, i, priv_data->write_urb_pool[i]->transfer_buffer); if (priv_data->write_urb_pool[i]->transfer_buffer == NULL) { goto out_alloc_write_urb_pool; } printk("%s; Mark3\n", __func__); usb_fill_bulk_urb(priv_data->write_urb_pool[i], priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev, EP1OUT), priv_data->write_urb_pool[i]->transfer_buffer, priv_data->parent_port->bulk_out_size, usbrsa_write_callback, priv_data->parent_port); printk("%s; Mark4\n", __func__); printk("%s -- clear_bit\n", __func__); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(i, &priv_data->write_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock, flags); printk("%s -- clear_bit end\n", __func__); } printk("%s end", __func__); return 0; out_alloc_write_urb_pool: while (i > 0) { if (priv_data->write_urb_pool[i] != NULL) { if (priv_data->write_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->write_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->write_urb_pool[i]); } i--; } printk("%s end error", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_read_urbs * Purpose: Allocates and initializes pool of read urbs to EP1IN * * ***********************************************************************/ int allocate_read_urbs(struct usbrsa_port_private *priv_data) { int i; unsigned long flags; struct urb *urb; void *buf = NULL; printk("%s start", __func__); /* dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ for (i = 0; i < priv_data->urb_pool_size; i++) { urb = usb_alloc_urb(0, GFP_KERNEL); priv_data->read_urb_pool[i] = urb; if (priv_data->read_urb_pool[i] == NULL) { goto out_alloc_read_urb_pool; } buf = kmalloc(priv_data->parent_port->bulk_in_size, GFP_KERNEL); priv_data->read_urb_pool[i]->transfer_buffer = buf; if (priv_data->read_urb_pool[i]->transfer_buffer == NULL) { goto out_alloc_read_urb_pool; } usb_fill_bulk_urb(priv_data->read_urb_pool[i], priv_data->parent_serial->dev, usb_rcvbulkpipe(priv_data->parent_serial->dev, EP1OUT), priv_data->read_urb_pool[i]->transfer_buffer, priv_data->parent_port->bulk_in_size, usbrsa_read_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(i, &priv_data->read_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock, flags); } printk("%s end", __func__); return 0; out_alloc_read_urb_pool: while (i > 0) { if (priv_data->read_urb_pool[i] != NULL) { if (priv_data->read_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->read_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->read_urb_pool[i]); } i--; } printk("%s end error", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_baudrate_lcr_urb * Purpose: Allocates and initializes urb to set baudrate and LCR * to EP2OUT or EP5OUT * * ***********************************************************************/ static int allocate_baudrate_lcr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; /* dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__); */ printk("%s: Start priv_data=%p\n", __func__, priv_data); priv_data->baudrate_lcr_urb = usb_alloc_urb(0, GFP_KERNEL); if (priv_data->baudrate_lcr_urb == NULL) { goto out_alloc_baudrate_lcr; } printk("%s: urb successfully allocated @ %p\n", __func__, priv_data->baudrate_lcr_urb); priv_data->baudrate_lcr_urb->transfer_buffer = kmalloc(EP3OUTLEN, GFP_KERNEL); if (priv_data->baudrate_lcr_urb->transfer_buffer == NULL) { goto out_alloc_baudrate_lcr; } printk("%s: transfer buffer successfully allocated @ %p\n", __func__, priv_data->baudrate_lcr_urb->transfer_buffer); /* sent to EP2OUT by default thereby disabling the rx handling of USB-RSA. * The USB-RSA does no longer process or forward the data it receives */ usb_fill_bulk_urb(priv_data->baudrate_lcr_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev, EP5OUT), priv_data->baudrate_lcr_urb->transfer_buffer, EP5OUTLEN, usbrsa_baudrate_lcr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(LOCK_BAUDRATE_LCR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); return 0; out_alloc_baudrate_lcr: spin_lock_irqsave(&priv_data->lock, flags); set_bit(LOCK_BAUDRATE_LCR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate memory\n", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_reset_urb * Purpose: Allocates and initializes reset urb to EP4OUT * * ***********************************************************************/ static int allocate_reset_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s() start\n", __func__); priv_data->reset_urb = usb_alloc_urb(0, GFP_KERNEL); printk("%s() reset_urb=%p\n", __func__, priv_data->reset_urb); if (priv_data->reset_urb == NULL) { goto out_alloc_reset; } priv_data->reset_urb->transfer_buffer = NULL; printk("%s() reset_urb->transfer_buffer=%p\n", __func__, priv_data->reset_urb); usb_fill_bulk_urb(priv_data->reset_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev, EP4OUT), priv_data->reset_urb->transfer_buffer, EP4OUTLEN, usbrsa_reset_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(LOCK_RESET, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); return 0; out_alloc_reset: spin_lock_irqsave(&priv_data->lock, flags); set_bit(LOCK_RESET, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate memory", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_status_urb * Purpose: Allocates and initializes status urb from EP3IN * * ***********************************************************************/ static int allocate_status_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s() -- start\n", __func__); priv_data->status_urb = usb_alloc_urb(0, GFP_KERNEL); if (priv_data->status_urb == NULL) { goto out_alloc_status; } printk("%s() priv_data->status_urb =%p\n", __func__, priv_data->status_urb); priv_data->status_urb->transfer_buffer = kmalloc(EP3INLEN, GFP_KERNEL); if (priv_data->status_urb->transfer_buffer == NULL) { goto out_alloc_status; } printk("%s() priv_data->status_urb->transfer_buffer =%p\n", __func__, priv_data->status_urb->transfer_buffer); usb_fill_bulk_urb(priv_data->status_urb, priv_data->parent_serial->dev, usb_rcvbulkpipe(priv_data->parent_serial->dev, EP3IN), priv_data->status_urb->transfer_buffer, EP3INLEN, usbrsa_status_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(LOCK_STATUS, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); return 0; out_alloc_status: spin_lock_irqsave(&priv_data->lock, flags); set_bit(LOCK_STATUS, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate memory", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_mcr_urb * Purpose: Allocates and initializes modem control register urb * to EP3OUT * ***********************************************************************/ static int allocate_mcr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; printk("%s() -- start\n", __func__); /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ priv_data->mcr_urb = usb_alloc_urb(0, GFP_KERNEL); printk("%s() priv_data->mcr_urb = %p\n", __func__, priv_data->mcr_urb); if (priv_data->mcr_urb == NULL) { goto out_alloc_mcr; } priv_data->mcr_urb->transfer_buffer = kmalloc(EP3OUTLEN, GFP_KERNEL); if (priv_data->mcr_urb->transfer_buffer == NULL) { goto out_alloc_mcr; } printk("%s() priv_data->mcr_urb->transfer_buffer = %p\n", __func__, priv_data->mcr_urb->transfer_buffer); usb_fill_bulk_urb(priv_data->mcr_urb, priv_data->parent_serial->dev, usb_sndbulkpipe(priv_data->parent_serial->dev, EP3OUT), priv_data->mcr_urb->transfer_buffer, EP3OUTLEN, usbrsa_mcr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(LOCK_MCR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); return 0; out_alloc_mcr: spin_lock_irqsave(&priv_data->lock, flags); set_bit(LOCK_MCR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate memory", __func__); return -ENOMEM; } /*********************************************************************** * Name: allocate_msr_urb * Purpose: Allocates and initializes modem status register urb * to EP3IN * ***********************************************************************/ static int allocate_msr_urb(struct usbrsa_port_private *priv_data) { unsigned long flags; /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s() -- start \n", __func__); priv_data->msr_urb = usb_alloc_urb(0, GFP_KERNEL); if (priv_data->msr_urb == NULL) { goto out_alloc_msr; } printk("%s() priv_data->msr_urb=%p \n", __func__, priv_data->msr_urb); priv_data->msr_urb->transfer_buffer = kmalloc(EP3OUTLEN, GFP_KERNEL); if (priv_data->msr_urb->transfer_buffer == NULL) { goto out_alloc_msr; } printk("%s() priv_data->msr_urb->transfer_buffer=%p \n", __func__, priv_data->msr_urb->transfer_buffer); usb_fill_bulk_urb(priv_data->msr_urb, priv_data->parent_serial->dev, usb_rcvbulkpipe(priv_data->parent_serial->dev, EP2IN), priv_data->msr_urb->transfer_buffer, EP2INLEN, usbrsa_msr_callback, priv_data->parent_port); spin_lock_irqsave(&priv_data->lock, flags); clear_bit(LOCK_MSR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); return 0; out_alloc_msr: spin_lock_irqsave(&priv_data->lock, flags); set_bit(LOCK_MSR, &priv_data->urb_lock); spin_unlock_irqrestore(&priv_data->lock, flags); dev_dbg(&(priv_data->parent_port->dev), "%s(): Could not allocate memory", __func__); return -ENOMEM; } /*********************************************************************** * Name: release_write_urbs * Purpose: Deallocate resource pool for EP1OUT * * ***********************************************************************/ static void release_write_urbs(struct usbrsa_port_private *priv_data) { unsigned long flags; int i; /*dev_dbg(&(priv_data->parent_port->dev),"%s(): pool_size=%d",__func__,priv_data->urb_pool_size);*/ printk("%s(): pool_size=%d\n", __func__, priv_data->urb_pool_size); for (i = 0; i < priv_data->urb_pool_size; i++) { printk("%s: post priv_data->write_urb_pool[%d]=%p\n", __func__, i, priv_data->write_urb_pool[i]); if (priv_data->write_urb_pool[i] != NULL) { printk("%s: post priv_data->write_urb_pool[%d]->transfer_buffer=%p\n", __func__, i, priv_data->write_urb_pool[i]->transfer_buffer); if (priv_data->write_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->write_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->write_urb_pool[i]); } spin_lock_irqsave(&priv_data->lock, flags); set_bit(i, &priv_data->write_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock, flags); } } /*********************************************************************** * Name: release_read_urbs * Purpose: Deallocate resource pool for EP1IN * * ***********************************************************************/ static void release_read_urbs(struct usbrsa_port_private *priv_data) { unsigned long flags; int i; /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s()\n", __func__); for (i = 0; i < priv_data->urb_pool_size; i++) { if (priv_data->read_urb_pool[i] != NULL) { if (priv_data->read_urb_pool[i]->transfer_buffer != NULL) { kfree(priv_data->read_urb_pool[i]->transfer_buffer); } usb_free_urb(priv_data->read_urb_pool[i]); } spin_lock_irqsave(&priv_data->lock, flags); set_bit(i, &priv_data->read_urb_pool_lock); spin_unlock_irqrestore(&priv_data->lock, flags); } } /*********************************************************************** * Name: release_baudrate_lcr_urb * Purpose: Remove baudrate_lcr_urb * * ***********************************************************************/ static void release_baudrate_lcr_urb(struct usbrsa_port_private *priv_data) { /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s: Start", __func__); if (priv_data->baudrate_lcr_urb != NULL) { if (priv_data->baudrate_lcr_urb->transfer_buffer != NULL) { kfree(priv_data->baudrate_lcr_urb->transfer_buffer); } usb_free_urb(priv_data->baudrate_lcr_urb); priv_data->baudrate_lcr_urb = NULL; } } /*********************************************************************** * Name: release_reset_urb * Purpose: Remove release_reset_urb * * ***********************************************************************/ static void release_reset_urb(struct usbrsa_port_private *priv_data) { /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s()\n", __func__); if (priv_data->reset_urb != NULL) { usb_free_urb(priv_data->reset_urb); priv_data->reset_urb = NULL; } } /*********************************************************************** * Name: release_status_urb * Purpose: Remove release_status_urb * * ***********************************************************************/ static void release_status_urb(struct usbrsa_port_private *priv_data) { /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s()\n", __func__); if (priv_data->status_urb != NULL) { if (priv_data->status_urb->transfer_buffer != NULL) { kfree(priv_data->status_urb->transfer_buffer); } usb_free_urb(priv_data->status_urb); priv_data->status_urb = NULL; } } /*********************************************************************** * Name: release_mcr_urb * Purpose: Remove release_mcr_urb * * ***********************************************************************/ static void release_mcr_urb(struct usbrsa_port_private *priv_data) { /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s()\n", __func__); if (priv_data->mcr_urb != NULL) { if (priv_data->mcr_urb->transfer_buffer != NULL) { kfree(priv_data->mcr_urb->transfer_buffer); } usb_free_urb(priv_data->mcr_urb); priv_data->mcr_urb = NULL; } } /*********************************************************************** * Name: release_msr_urb * Purpose: deallocate msr_urb * * ***********************************************************************/ static void release_msr_urb(struct usbrsa_port_private *priv_data) { /*dev_dbg(&(priv_data->parent_port->dev),"%s()",__func__);*/ printk("%s()\n", __func__); if (priv_data->msr_urb != NULL) { if (priv_data->msr_urb->transfer_buffer != NULL) { kfree(priv_data->msr_urb->transfer_buffer); } usb_free_urb(priv_data->msr_urb); priv_data->msr_urb = NULL; } } /*********************************************************************** * Name: prepare_baudrate_lcr_urb * Purpose: Computes urb setting Line Control Regsister (LCR) and * divider register (DLL+DLM) to determine baud rate of * ST16c550. The urb is sent to either EP2OUT and EP5OUT. * An urb to EP2OUT sets the registers of the USB-RSA and * enables receive interrupts. An urb to EP5OUT only sets * the register. * * * Format of EP2OUT/EP5OUT * Byte 0: DLL of ST16c550 * Byte 1: DLM of ST16c550 * Byte 2: LCR of ST16c550 * ***********************************************************************/ static int send_baudrate_lcr_register(unsigned int cflag, speed_t baud_rate, int endpoint, struct usb_serial_port *port) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; __u8 lcr = 0; __u16 divisor = 0; __u8 *buffer_ptr = priv->baudrate_lcr_urb->transfer_buffer; dev_dbg(&port->dev, "%s() CFLAG=%u SPEED=%u ep=%d", __func__, cflag, baud_rate, endpoint); /* if word length is 5 bit, stop bit length is 1,5 bit times * else 2 bit times */ /* restrict baud_rate to boundaries determined by * USB-RSA hardware */ if (baud_rate < 75) baud_rate = 75; if (baud_rate > 460800) baud_rate = 460800; divisor = USBRSA_ST16C550_CLOCK / (16 * baud_rate); priv->dll = divisor & 0xFF; priv->dlm = (divisor & 0xFF00) >> 8; switch (cflag & CSIZE) { case CS5: lcr = USBRSA_ST16C550_LCR_CS5; break; case CS6: lcr = USBRSA_ST16C550_LCR_CS6; break; case CS7: lcr = USBRSA_ST16C550_LCR_CS7; break; default: case CS8: lcr = USBRSA_ST16C550_LCR_CS8; break; } /* determine the parity */ if (cflag & PARENB) if (cflag & CMSPAR) if (cflag & PARODD) lcr |= USBRSA_ST16C550_LCR_MARK; else lcr |= USBRSA_ST16C550_LCR_SPACE; else if (cflag & PARODD) lcr |= USBRSA_ST16C550_LCR_ODD; else lcr |= USBRSA_ST16C550_LCR_EVEN; else lcr |= USBRSA_ST16C550_LCR_NONE; /* figure out the stop bits requested */ if (cflag & CSTOPB) lcr |= USBRSA_ST16C550_LCR_STOP2; else lcr |= USBRSA_ST16C550_LCR_STOP1; /* FW of USB-RSA expects bit 7 (Baud Rate Counter Latch) to be 0 */ lcr &= 0x7F; priv->lcr = lcr; *buffer_ptr = priv->dll; buffer_ptr++; *buffer_ptr = priv->dlm; buffer_ptr++; *buffer_ptr = priv->lcr; dev_dbg(&port->dev, "%s() ST16C550.DLL=%d;ST16C550.DLM=%d;ST16C550.LCR=%d", __func__, priv->dll, priv->dlm, priv->lcr); spin_lock_irqsave(&priv->lock, flags); if (!(test_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock))) { set_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock); priv->baudrate_lcr_urb->pipe = usb_sndbulkpipe(priv->parent_serial->dev, endpoint); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->baudrate_lcr_urb, GFP_ATOMIC); } else { /* urb already in use */ spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev, "%s(): Cannot reserve baudrate_lcr_urb", __func__); /* fix me: return appropriate return code */ retval = -1; /* end fix me */ goto send_baudrate_lcr_exit; } if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, retval); goto send_baudrate_lcr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* timeout. Dequeue urb */ usb_kill_urb(priv->baudrate_lcr_urb); dev_dbg(&port->dev, "%s - sending baudrate_lcr_urb timed out.", __func__); retval = -ETIMEDOUT; goto send_baudrate_lcr_exit; } send_baudrate_lcr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_BAUDRATE_LCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev, "%s() leaving", __func__); return retval; } /*********************************************************************** * Name: send_mcr_register * Purpose: Sends MCR value in private data structure of device * to USBRSA * * Format of EP3OUT * USB Message Length: 1 Byte * Bit0: DTR * Bit1: RTS * Bit2: OP1 * Bit3: OP2 * Bit4: Diagnostics mode * ***********************************************************************/ static int send_mcr_register(struct usb_serial_port *port) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->mcr); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_MCR, &priv->urb_lock); memcpy(priv->mcr_urb->transfer_buffer, &priv->mcr, 1); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->mcr_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, retval); goto send_mcr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_MCR, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* fetching of msr */ usb_kill_urb(priv->mcr_urb); dev_dbg(&port->dev, "%s - sending mcr timed out.", __func__); retval = -ETIMEDOUT; goto send_mcr_exit; } send_mcr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MCR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); return retval; } /*********************************************************************** * Name: fetch_msr_register * Purpose: Get MSR value from USBRSA and stores it in private data * structure * * Format of EP2IN * USB Message Length: 1 Byte * Bit0: Delta CTS (1 indicates a change on the line) * Bit1: Delta DTS (1 indicates a change on the line) * Bit2: Delta RI (1 indicates a change on the line) * Bit3: Delta CD (1 indicates a change on the line) * Bit4: CTS * Bit5: DTS * Bit6: RI * Bit7: CD * ***********************************************************************/ static int fetch_msr_register(struct usb_serial_port *port) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->msr); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_MSR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->msr_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, retval); goto send_msr_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_MSR, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* fetching of msr */ usb_kill_urb(priv->msr_urb); dev_dbg(&port->dev, "%s - fetching msr timed out.", __func__); retval = -ETIMEDOUT; goto send_msr_exit; } send_msr_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_MSR, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); dev_dbg(&port->dev, "%s: 0x%02x", __func__, priv->msr); return retval; } /*********************************************************************** * Name: send_reset * Purpose: sent reset urb to USBRSA and wait for completion * * ***********************************************************************/ static int send_reset(struct usb_serial_port *port) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; long t; int retval; dev_dbg(&port->dev, "%s: ", __func__); spin_lock_irqsave(&priv->lock, flags); set_bit(LOCK_RESET, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); retval = usb_submit_urb(priv->reset_urb, GFP_ATOMIC); if (retval) { /* something bad happened, let's free up the urb */ dev_dbg(&port->dev, "%s(): Cannot submit urb: %d", __func__, retval); goto send_reset_exit; } /* wait for the command to complete * (waits, until timeout or condition==true) */ t = wait_event_timeout(priv->wait_flag, (test_bit(LOCK_RESET, &priv->urb_lock) == 0), COMMAND_TIMEOUT); if (!t) { /* fetching of msr */ usb_kill_urb(priv->reset_urb); dev_dbg(&port->dev, "%s - reset timed out.", __func__); retval = -ETIMEDOUT; goto send_reset_exit; } send_reset_exit: spin_lock_irqsave(&priv->lock, flags); clear_bit(LOCK_RESET, &priv->urb_lock); spin_unlock_irqrestore(&priv->lock, flags); return retval; } /*********************************************************************** * Name: wait_modem_info * Purpose: waits until a line reflected in the MSR (modem status * register) changes. Lines that can be tested are: * - CTS * - DSR * - RI * - CD * * ***********************************************************************/ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prev, status; unsigned int changed; int retval; spin_lock_irqsave(&priv->lock, flags); retval = fetch_msr_register(port); if (retval != 0) { goto bailout_wait_modem_info; } spin_lock_irqsave(&priv->lock, flags); prev = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); while (1) { retval = fetch_msr_register(port); if (retval != 0) { goto bailout_wait_modem_info; } spin_lock_irqsave(&priv->lock, flags); status = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave(&priv->lock, flags); changed = prev ^ status; prev = status; spin_unlock_irqrestore(&priv->lock, flags); if (((arg & TIOCM_RNG) && (changed & USBRSA_ST16C550_MSR_RI)) || ((arg & TIOCM_DSR) && (changed & USBRSA_ST16C550_MSR_DSR)) || ((arg & TIOCM_CD) && (changed & USBRSA_ST16C550_MSR_CD)) || ((arg & TIOCM_CTS) && (changed & USBRSA_ST16C550_MSR_CTS))) return 0; } bailout_wait_modem_info: /* NOTREACHED */ return retval; } /*********************************************************************** * Name: get_serial_info * Purpose: fills a struct containing information about the serial * port. * * ***********************************************************************/ static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) { struct usbrsa_port_private *priv = usb_get_serial_port_data(port); struct serial_struct tmp; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = port->minor; tmp.port = port->port_number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = priv->urb_pool_size * port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; tmp.closing_wait = 30*HZ; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; } static struct usb_serial_driver * const serial_drivers[] = { &usbrsa_preenum_device, &usbrsa_enumerated_device, NULL }; module_usb_serial_driver(serial_drivers, id_table_combined); /* * request_module("ezusb"); * request_module("usbserial"); */ MODULE_FIRMWARE("usbrsa.fw"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debug"); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html