172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/****************************************************************************** 272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Driver for Option High Speed Mobile Devices. 472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Copyright (C) 2008 Option International 611cd29b028be88b13717401496fe4953fb96be03Denis Joseph Barrow * Filip Aben <f.aben@option.com> 711cd29b028be88b13717401496fe4953fb96be03Denis Joseph Barrow * Denis Joseph Barrow <d.barow@option.com> 83b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon * Jan Dumon <j.dumon@option.com> 972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) 1072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * <ajb@spheresystems.co.uk> 1172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> 1272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Copyright (C) 2008 Novell, Inc. 1372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 1472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * This program is free software; you can redistribute it and/or modify 1572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * it under the terms of the GNU General Public License version 2 as 1672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * published by the Free Software Foundation. 1772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 1872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * This program is distributed in the hope that it will be useful, 1972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * but WITHOUT ANY WARRANTY; without even the implied warranty of 2072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * GNU General Public License for more details. 2272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 2372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * You should have received a copy of the GNU General Public License 2472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * along with this program; if not, write to the Free Software 2572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 2672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * USA 2772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 2872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 2972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman *****************************************************************************/ 3072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 3172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/****************************************************************************** 3272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 3372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Description of the device: 3472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 3572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Interface 0: Contains the IP network interface on the bulk end points. 3672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * The multiplexed serial ports are using the interrupt and 3772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * control endpoints. 3872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Interrupt contains a bitmap telling which multiplexed 3972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * serialport needs servicing. 4072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 4172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the 4272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * port is opened, as this have a huge impact on the network port 4372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * throughput. 4472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 45542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * Interface 2: Standard modem interface - circuit switched interface, this 46542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * can be used to make a standard ppp connection however it 47542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * should not be used in conjunction with the IP network interface 48542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * enabled for USB performance reasons i.e. if using this set 49542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * ideally disable_net=1. 5072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * 5172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman *****************************************************************************/ 5272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 5372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/sched.h> 5472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/slab.h> 5572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/init.h> 5672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/delay.h> 5772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/netdevice.h> 5872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/module.h> 5972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/ethtool.h> 6072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/usb.h> 6172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/timer.h> 6272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/tty.h> 6372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/tty_driver.h> 6472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/tty_flip.h> 6572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/kmod.h> 6672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/rfkill.h> 6772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/ip.h> 6872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/uaccess.h> 6972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <linux/usb/cdc.h> 7072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <net/arp.h> 7172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#include <asm/byteorder.h> 72542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#include <linux/serial_core.h> 73542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#include <linux/serial.h> 7472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 7572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 7672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MOD_AUTHOR "Option Wireless" 7772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MOD_DESCRIPTION "USB High Speed Option driver" 7872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MOD_LICENSE "GPL" 7972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 8072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_MAX_NET_DEVICES 10 8172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO__MAX_MTU 2048 8272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DEFAULT_MTU 1500 8372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DEFAULT_MRU 1500 8472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 8572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define CTRL_URB_RX_SIZE 1024 8672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define CTRL_URB_TX_SIZE 64 8772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 8872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define BULK_URB_RX_SIZE 4096 8972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define BULK_URB_TX_SIZE 8192 9072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 9172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU 9272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU 9372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MUX_BULK_RX_BUF_COUNT 4 9472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define USB_TYPE_OPTION_VENDOR 0x20 9572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 9672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* These definitions are used with the struct hso_net flags element */ 9772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* - use *_bit operations on it. (bit indices not values.) */ 9872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_NET_RUNNING 0 9972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_NET_TX_TIMEOUT (HZ*10) 10172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_SERIAL_MAGIC 0x48534f31 10372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Number of ttys to handle */ 10572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_SERIAL_TTY_MINORS 256 10672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define MAX_RX_URBS 2 10872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 1090235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartmanstatic inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) 1100235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman{ 1110235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman if (tty) 1120235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman return tty->driver_data; 1130235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman return NULL; 1140235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman} 11572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 11672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 11772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Debugging functions */ 11872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 11972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D__(lvl_, fmt, arg...) \ 12072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman do { \ 12172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(lvl_ "[%d:%s]: " fmt "\n", \ 12272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman __LINE__, __func__, ## arg); \ 12372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } while (0) 12472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 12572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D_(lvl, args...) \ 12672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman do { \ 12772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (lvl & debug) \ 12872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D__(KERN_INFO, args); \ 12972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } while (0) 13072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 13172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D1(args...) D_(0x01, ##args) 13272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D2(args...) D_(0x02, ##args) 13372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D3(args...) D_(0x04, ##args) 13472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D4(args...) D_(0x08, ##args) 13572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define D5(args...) D_(0x10, ##args) 13672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 13772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 13872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Enumerators */ 13972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 14072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanenum pkt_parse_state { 14172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman WAIT_IP, 14272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman WAIT_DATA, 14372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman WAIT_SYNC 14472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 14572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 14672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 14772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Structs */ 14872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 14972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 15072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_shared_int { 15172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *intr_endp; 15272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman void *shared_intr_buf; 15372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *shared_intr_urb; 15472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_device *usb; 15572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int use_count; 15672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int ref_count; 15772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct mutex shared_int_lock; 15872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 15972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 16072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_net { 16172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *parent; 16272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct net_device *net; 16372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct rfkill *rfkill; 16472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 16572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *in_endp; 16672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *out_endp; 16772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 16872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT]; 16972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *mux_bulk_tx_urb; 17072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT]; 17172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman void *mux_bulk_tx_buf; 17272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 17372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct sk_buff *skb_rx_buf; 17472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct sk_buff *skb_tx_buf; 17572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 17672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman enum pkt_parse_state rx_parse_state; 17772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spinlock_t net_lock; 17872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 17972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned short rx_buf_size; 18072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned short rx_buf_missing; 18172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct iphdr rx_ip_hdr; 18272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 18372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 18472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 18572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 1868ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowenum rx_ctrl_state{ 1878ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow RX_IDLE, 1888ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow RX_SENT, 1898ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow RX_PENDING 1908ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow}; 1918ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 192542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define BM_REQUEST_TYPE (0xa1) 193542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_NOTIFICATION (0x20) 194542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define W_VALUE (0x0) 195542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define W_INDEX (0x2) 196542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define W_LENGTH (0x2) 197542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 198542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_OVERRUN (0x1<<6) 199542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_PARITY (0x1<<5) 200542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_FRAMING (0x1<<4) 201542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_RING_SIGNAL (0x1<<3) 202542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_BREAK (0x1<<2) 203542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_TX_CARRIER (0x1<<1) 204542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow#define B_RX_CARRIER (0x1<<0) 205542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 206542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstruct hso_serial_state_notification { 207542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u8 bmRequestType; 208542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u8 bNotification; 209542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 wValue; 210542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 wIndex; 211542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 wLength; 212542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 UART_state_bitmap; 213ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 214542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 215542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstruct hso_tiocmget { 216542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct mutex mutex; 217542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow wait_queue_head_t waitq; 218542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int intr_completed; 219542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct usb_endpoint_descriptor *endp; 220542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct urb *urb; 221542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_serial_state_notification serial_state_notification; 222542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 prev_UART_state_bitmap; 223542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct uart_icount icount; 224542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow}; 225542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 226542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 22772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_serial { 22872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *parent; 22972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int magic; 23072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 minor; 23172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 23272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *shared_int; 23372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 23472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* rx/tx urb could be either a bulk urb or a control urb depending 23572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman on which serial port it is used on. */ 23672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *rx_urb[MAX_RX_URBS]; 23772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 num_rx_urbs; 23872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 *rx_data[MAX_RX_URBS]; 23972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u16 rx_data_length; /* should contain allocated length */ 24072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 24172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *tx_urb; 24272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 *tx_data; 24372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 *tx_buffer; 24472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u16 tx_data_length; /* should contain allocated length */ 24572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u16 tx_data_count; 24672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u16 tx_buffer_count; 24772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_ctrlrequest ctrl_req_tx; 24872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_ctrlrequest ctrl_req_rx; 24972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 25072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *in_endp; 25172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *out_endp; 25272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow enum rx_ctrl_state rx_state; 25472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 rts_state; 25572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 dtr_state; 25672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned tx_urb_used:1; 25772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 25872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* from usb_serial_port */ 25972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct tty_struct *tty; 26072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int open_count; 26172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spinlock_t serial_lock; 26272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 26372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int (*write_data) (struct hso_serial *serial); 264542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 2658ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Hacks required to get flow control 2668ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * working on the serial receive buffers 2678ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * so as not to drop characters on the floor. 2688ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow */ 2698ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int curr_rx_urb_idx; 2708ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow u16 curr_rx_urb_offset; 2718ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow u8 rx_urb_filled[MAX_RX_URBS]; 2728ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct tasklet_struct unthrottle_tasklet; 2738ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct work_struct retry_unthrottle_workqueue; 27472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 27572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 27672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_device { 27772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman union { 27872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *dev_serial; 27972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *dev_net; 28072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } port_data; 28172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 28272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u32 port_spec; 28372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 28472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 is_active; 28572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 usb_gone; 28672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct work_struct async_get_intf; 28772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct work_struct async_put_intf; 28868a351c501ad22077a969df157cd13367cb43a40Jan Dumon struct work_struct reset_device; 28972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 29072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_device *usb; 29172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_interface *interface; 29272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 29372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct device *dev; 29472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct kref ref; 295ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller struct mutex mutex; 29672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 29772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 29872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Type of interface */ 29972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_INTF_MASK 0xFF00 30072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_INTF_MUX 0x0100 30172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_INTF_BULK 0x0200 30272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 30372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Type of port */ 30472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_MASK 0xFF 30572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_NO_PORT 0x0 30672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_CONTROL 0x1 30772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_APP 0x2 30872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_GPS 0x3 30972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_PCSC 0x4 31072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_APP2 0x5 31172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_GPS_CONTROL 0x6 31272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_MSD 0x7 31372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_VOICE 0x8 31472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_DIAG2 0x9 31572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_DIAG 0x10 31672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_MODEM 0x11 31772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_PORT_NETWORK 0x12 31872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 31972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Additional device info */ 32072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_INFO_MASK 0xFF000000 32172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define HSO_INFO_CRC_BUG 0x01000000 32272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 32372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 32472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Prototypes */ 32572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 32672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Serial driver functions */ 32720b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int hso_serial_tiocmset(struct tty_struct *tty, 32872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned int set, unsigned int clear); 32972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void ctrl_callback(struct urb *urb); 3308ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); 33172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_kick_transmit(struct hso_serial *serial); 33272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Helper functions */ 33372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, 33472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_device *usb, gfp_t gfp); 33568a351c501ad22077a969df157cd13367cb43a40Jan Dumonstatic void handle_usb_error(int status, const char *function, 33668a351c501ad22077a969df157cd13367cb43a40Jan Dumon struct hso_device *hso_dev); 33772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, 33872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int type, int dir); 33972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports); 34072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_interface(struct usb_interface *intf); 34172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags); 34272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_stop_serial_device(struct hso_device *hso_dev); 34372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_start_net_device(struct hso_device *hso_dev); 34472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_shared_int(struct hso_shared_int *shared_int); 34572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_stop_net_device(struct hso_device *hso_dev); 34672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_serial_ref_free(struct kref *ref); 3478ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void hso_std_serial_read_bulk_callback(struct urb *urb); 3488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic int hso_mux_serial_read(struct hso_serial *serial); 34972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void async_get_intf(struct work_struct *data); 35072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void async_put_intf(struct work_struct *data); 35172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_put_activity(struct hso_device *hso_dev); 35272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_get_activity(struct hso_device *hso_dev); 353542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstatic void tiocmget_intr_callback(struct urb *urb); 35468a351c501ad22077a969df157cd13367cb43a40Jan Dumonstatic void reset_device(struct work_struct *data); 35572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 35672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Helping functions */ 35772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/*****************************************************************************/ 35872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 35972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* #define DEBUG */ 36072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 3610235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartmanstatic inline struct hso_net *dev2net(struct hso_device *hso_dev) 3620235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman{ 3630235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman return hso_dev->port_data.dev_net; 3640235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman} 3650235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman 3660235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartmanstatic inline struct hso_serial *dev2ser(struct hso_device *hso_dev) 3670235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman{ 3680235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman return hso_dev->port_data.dev_serial; 3690235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman} 37072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 37172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Debugging functions */ 37272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#ifdef DEBUG 37372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void dbg_dump(int line_count, const char *func_name, unsigned char *buf, 37472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned int len) 37572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 3760235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman static char name[255]; 37772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 3780235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman sprintf(name, "hso[%d:%s]", line_count, func_name); 3790235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len); 38072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 38172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 38272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DUMP(buf_, len_) \ 3839ce673d5e919966efc1ef5adf20248e6ecc62724Antti Kaijanmäki dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_) 38472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 38572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DUMP1(buf_, len_) \ 38672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman do { \ 38772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (0x01 & debug) \ 38872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman DUMP(buf_, len_); \ 38972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } while (0) 39072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#else 39172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DUMP(buf_, len_) 39272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define DUMP1(buf_, len_) 39372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#endif 39472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 39572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* module parameters */ 39672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int debug; 39772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int tty_major; 39872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int disable_net; 39972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 40072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* driver info */ 40172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic const char driver_name[] = "hso"; 40272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic const char tty_filename[] = "ttyHS"; 403242647bcf8464860f173f3d4d4ab3490d3558518Filip Abenstatic const char *version = __FILE__ ": " MOD_AUTHOR; 40472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* the usb driver itself (registered in hso_init) */ 40572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct usb_driver hso_driver; 40672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* serial structures */ 40772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct tty_driver *tty_drv; 40872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; 40972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_device *network_table[HSO_MAX_NET_DEVICES]; 41072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic spinlock_t serial_table_lock; 41172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 41272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic const s32 default_port_spec[] = { 41372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_MUX | HSO_PORT_NETWORK, 41472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_BULK | HSO_PORT_DIAG, 41572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_BULK | HSO_PORT_MODEM, 41672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 0 41772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 41872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 41972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic const s32 icon321_port_spec[] = { 42072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_MUX | HSO_PORT_NETWORK, 42172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_BULK | HSO_PORT_DIAG2, 42272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_BULK | HSO_PORT_MODEM, 42372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman HSO_INTF_BULK | HSO_PORT_DIAG, 42472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 0 42572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 42672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 42772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define default_port_device(vendor, product) \ 42872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DEVICE(vendor, product), \ 42972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .driver_info = (kernel_ulong_t)default_port_spec 43072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 43172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman#define icon321_port_device(vendor, product) \ 43272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DEVICE(vendor, product), \ 43372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .driver_info = (kernel_ulong_t)icon321_port_spec 43472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 43572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* list of devices we support */ 43672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic const struct usb_device_id hso_ids[] = { 43772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6711)}, 43872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6731)}, 43972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6751)}, 44072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6771)}, 44172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6791)}, 44272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6811)}, 44372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6911)}, 44472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6951)}, 44572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x6971)}, 44672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7011)}, 44772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7031)}, 44872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7051)}, 44972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7071)}, 45072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7111)}, 45172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7211)}, 45272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7251)}, 45372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7271)}, 45472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0x7311)}, 45572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ 45672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ 45772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ 45895eacee870a521d2647f42c4f670cd65a145a6bdDenis Joseph Barrow {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */ 45972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ 46072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ 46167dd82462d553c35bef14de1bf8afcb1095e041dFilip Aben {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */ 46272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ 46372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ 46472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ 465bab04c3adbb55aeb5e8db60522f14ce0bb0d4179Denis Joseph Barrow {USB_DEVICE(0x0af0, 0x7701)}, 466ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x7706)}, 467bab04c3adbb55aeb5e8db60522f14ce0bb0d4179Denis Joseph Barrow {USB_DEVICE(0x0af0, 0x7801)}, 468bab04c3adbb55aeb5e8db60522f14ce0bb0d4179Denis Joseph Barrow {USB_DEVICE(0x0af0, 0x7901)}, 469ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x7A01)}, 470ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x7A05)}, 4719961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0x8200)}, 4729961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0x8201)}, 473ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x8300)}, 474ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x8302)}, 475ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x8304)}, 476ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0x8400)}, 477dd7496f217462a23a9a8a15b9925866eaad76e22Filip Aben {USB_DEVICE(0x0af0, 0x8600)}, 478dd7496f217462a23a9a8a15b9925866eaad76e22Filip Aben {USB_DEVICE(0x0af0, 0x8800)}, 479dd7496f217462a23a9a8a15b9925866eaad76e22Filip Aben {USB_DEVICE(0x0af0, 0x8900)}, 4805c7bf2f4d6304ab4741f38365ca0c0223147263dFilip Aben {USB_DEVICE(0x0af0, 0x9000)}, 4819961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd035)}, 48267dd82462d553c35bef14de1bf8afcb1095e041dFilip Aben {USB_DEVICE(0x0af0, 0xd055)}, 4839961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd155)}, 4849961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd255)}, 4859961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd057)}, 4869961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd157)}, 4879961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd257)}, 4889961d84270ce1d5f4c662382acf0b418a3ff6a0fJan Dumon {USB_DEVICE(0x0af0, 0xd357)}, 489ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0xd058)}, 490ec157937d9799cf30c9a19bd18be33721242c64fJan Dumon {USB_DEVICE(0x0af0, 0xc100)}, 49172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman {} 49272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 49372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_DEVICE_TABLE(usb, hso_ids); 49472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 49572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Sysfs attribute */ 49672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic ssize_t hso_sysfs_show_porttype(struct device *dev, 49772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct device_attribute *attr, 49872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char *buf) 49972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 5001aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman struct hso_device *hso_dev = dev_get_drvdata(dev); 50172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char *port_name; 50272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 50372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 50472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 50572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 50672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (hso_dev->port_spec & HSO_PORT_MASK) { 50772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_CONTROL: 50872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Control"; 50972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 51072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP: 51172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Application"; 51272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 51372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP2: 51472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Application2"; 51572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 51672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_GPS: 51772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "GPS"; 51872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 51972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_GPS_CONTROL: 52072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "GPS Control"; 52172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 52272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_PCSC: 52372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "PCSC"; 52472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 52572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_DIAG: 52672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Diagnostic"; 52772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 52872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_DIAG2: 52972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Diagnostic2"; 53072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 53172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_MODEM: 53272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Modem"; 53372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 53472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_NETWORK: 53572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Network"; 53672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 53772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 53872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_name = "Unknown"; 53972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 54072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 54172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 54272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return sprintf(buf, "%s\n", port_name); 54372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 54472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); 54572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 5468ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) 5478ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 5488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int idx; 5498ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 5508ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow for (idx = 0; idx < serial->num_rx_urbs; idx++) 5518ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (serial->rx_urb[idx] == urb) 5528ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return idx; 5538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); 5548ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return -1; 5558ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 5568ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 55772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* converts mux value to a port spec value */ 55872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic u32 hso_mux_to_port(int mux) 55972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 56072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u32 result; 56172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 56272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (mux) { 56372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x1: 56472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_CONTROL; 56572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 56672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x2: 56772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_APP; 56872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 56972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x4: 57072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_PCSC; 57172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 57272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x8: 57372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_GPS; 57472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 57572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x10: 57672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_APP2; 57772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 57872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 57972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_NO_PORT; 58072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 58172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 58272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 58372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 58472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* converts port spec value to a mux value */ 58572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic u32 hso_port_to_mux(int port) 58672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 58772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u32 result; 58872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 58972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (port & HSO_PORT_MASK) { 59072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_CONTROL: 59172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x0; 59272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 59372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP: 59472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x1; 59572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 59672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_PCSC: 59772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x2; 59872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 59972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_GPS: 60072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x3; 60172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 60272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP2: 60372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x4; 60472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 60572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 60672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0x0; 60772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 60872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 60972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 61072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 61172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_serial *get_serial_by_shared_int_and_type( 61272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *shared_int, 61372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int mux) 61472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 61572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i, port; 61672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 61772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port = hso_mux_to_port(mux); 61872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 61972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { 6208e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (serial_table[i] && 6218e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches (dev2ser(serial_table[i])->shared_int == shared_int) && 6228e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { 62372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return dev2ser(serial_table[i]); 62472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 62572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 62672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 62772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 62872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 62972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 63072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_serial *get_serial_by_index(unsigned index) 63172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 6320235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman struct hso_serial *serial = NULL; 63372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 63472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 63572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial_table_lock, flags); 6360235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman if (serial_table[index]) 6370235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman serial = dev2ser(serial_table[index]); 63872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial_table_lock, flags); 63972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 64072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return serial; 64172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 64272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 64372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int get_free_serial_index(void) 64472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 64572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int index; 64672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 64772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 64872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial_table_lock, flags); 64972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { 65072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial_table[index] == NULL) { 65172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial_table_lock, flags); 65272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return index; 65372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 65472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 65572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial_table_lock, flags); 65672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 65772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_ERR "%s: no free serial devices in table\n", __func__); 65872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -1; 65972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 66072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 66172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void set_serial_by_index(unsigned index, struct hso_serial *serial) 66272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 66372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 6640235f64175db41fa17a6ce5c9b58fd3550986eb4Greg Kroah-Hartman 66572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial_table_lock, flags); 66672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial) 66772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial_table[index] = serial->parent; 66872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 66972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial_table[index] = NULL; 67072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial_table_lock, flags); 67172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 67272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 67368a351c501ad22077a969df157cd13367cb43a40Jan Dumonstatic void handle_usb_error(int status, const char *function, 67468a351c501ad22077a969df157cd13367cb43a40Jan Dumon struct hso_device *hso_dev) 67572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 67672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char *explanation; 67772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 67872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (status) { 67972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -ENODEV: 68072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "no device"; 68172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 68272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -ENOENT: 68372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "endpoint not enabled"; 68472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 68572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EPIPE: 68672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "endpoint stalled"; 68772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 68872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -ENOSPC: 68972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "not enough bandwidth"; 69072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 69172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -ESHUTDOWN: 69272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "device disabled"; 69372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 69472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EHOSTUNREACH: 69572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "device suspended"; 69672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 69772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EINVAL: 69872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EAGAIN: 69972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EFBIG: 70072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case -EMSGSIZE: 70172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "internal error"; 70272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 70368a351c501ad22077a969df157cd13367cb43a40Jan Dumon case -EILSEQ: 70468a351c501ad22077a969df157cd13367cb43a40Jan Dumon case -EPROTO: 70568a351c501ad22077a969df157cd13367cb43a40Jan Dumon case -ETIME: 70668a351c501ad22077a969df157cd13367cb43a40Jan Dumon case -ETIMEDOUT: 70768a351c501ad22077a969df157cd13367cb43a40Jan Dumon explanation = "protocol error"; 70868a351c501ad22077a969df157cd13367cb43a40Jan Dumon if (hso_dev) 70968a351c501ad22077a969df157cd13367cb43a40Jan Dumon schedule_work(&hso_dev->reset_device); 71068a351c501ad22077a969df157cd13367cb43a40Jan Dumon break; 71172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 71272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman explanation = "unknown status"; 71372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 71472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 71568a351c501ad22077a969df157cd13367cb43a40Jan Dumon 71668a351c501ad22077a969df157cd13367cb43a40Jan Dumon /* log a meaningful explanation of an USB status */ 71772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("%s: received USB status - %s (%d)", function, explanation, status); 71872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 71972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 72072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Network interface functions */ 72172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 72272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called when net interface is brought up by ifconfig */ 72372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_net_open(struct net_device *net) 72472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 72572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = netdev_priv(net); 72672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags = 0; 72772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 72872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev) { 72972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&net->dev, "No net device !\n"); 73072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 73172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 73272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 73372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->skb_tx_buf = NULL; 73472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 73572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* setup environment */ 73672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&odev->net_lock, flags); 73772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_IP; 73872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size = 0; 73972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing = sizeof(struct iphdr); 74072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&odev->net_lock, flags); 74172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 74272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* We are up and running. */ 74372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman set_bit(HSO_NET_RUNNING, &odev->flags); 744889bd9b6dbcd426b8698c4a779dd7dbf247f57b8Oliver Neukum hso_start_net_device(odev->parent); 74572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 74672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Tell the kernel we are ready to start receiving from it */ 74772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_start_queue(net); 74872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 74972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 75072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 75172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 75272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called when interface is brought down by ifconfig */ 75372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_net_close(struct net_device *net) 75472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 75572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = netdev_priv(net); 75672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 75772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* we don't need the queue anymore */ 75872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_stop_queue(net); 75972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* no longer running */ 76072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman clear_bit(HSO_NET_RUNNING, &odev->flags); 76172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 76272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_stop_net_device(odev->parent); 76372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 76472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 76572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 76672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 76772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 76872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* USB tells is xmit done, we should start the netqueue again */ 76972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void write_bulk_callback(struct urb *urb) 77072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 77172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = urb->context; 77272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int status = urb->status; 77372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 77472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Sanity check */ 77572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { 77672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&urb->dev->dev, "%s: device not running\n", __func__); 77772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 77872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 77972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 78072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Do we still have a valid kernel network device? */ 78172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!netif_device_present(odev->net)) { 78272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&urb->dev->dev, "%s: net device not present\n", 78372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman __func__); 78472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 78572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 78672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 78772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* log status, but don't act on it, we don't need to resubmit anything 78872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * anyhow */ 78972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (status) 79068a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, odev->parent); 79172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 79272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_put_activity(odev->parent); 79372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 79472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Tell the network interface we are ready for another frame */ 79572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_wake_queue(odev->net); 79672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 79772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 79872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called by kernel when we need to transmit a packet */ 79925a79c41ce0ce88a4288adf278e9b0e00f228383Stephen Hemmingerstatic netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, 80025a79c41ce0ce88a4288adf278e9b0e00f228383Stephen Hemminger struct net_device *net) 80172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 80272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = netdev_priv(net); 80372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 80472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 80572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Tell the kernel, "No more frames 'til we are done with this one." */ 80672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_stop_queue(net); 80772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_get_activity(odev->parent) == -EAGAIN) { 80872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->skb_tx_buf = skb; 8096ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 81072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 81172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 81272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* log if asked */ 81372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman DUMP1(skb->data, skb->len); 81472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Copy it from kernel memory to OUR memory */ 81572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); 81672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); 81772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 81872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Fill in the URB for shipping it out. */ 81972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_bulk_urb(odev->mux_bulk_tx_urb, 82072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->parent->usb, 82172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_sndbulkpipe(odev->parent->usb, 82272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->out_endp-> 82372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman bEndpointAddress & 0x7F), 82472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, 82572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev); 82672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 82772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Deal with the Zero Length packet problem, I hope */ 82872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; 82972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 83072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Send the URB on its merry way. */ 83172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); 83272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 83372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&odev->parent->interface->dev, 8348a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon "failed mux_bulk_tx_urb %d\n", result); 83572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->stats.tx_errors++; 83672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_start_queue(net); 83772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 83872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->stats.tx_packets++; 83972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->stats.tx_bytes += skb->len; 84072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 84172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_kfree_skb(skb); 84272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* we're done */ 8435b2c4b972c0226406361f83b747eb5cdab51e68ePatrick McHardy return NETDEV_TX_OK; 84472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 84572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 8460fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops ops = { 84772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .get_link = ethtool_op_get_link 84872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 84972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 85072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called when a packet did not ack after watchdogtimeout */ 85172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_net_tx_timeout(struct net_device *net) 85272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 85372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = netdev_priv(net); 85472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 85572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev) 85672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 85772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 85872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Tell syslog we are hosed. */ 85972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&net->dev, "Tx timed out.\n"); 86072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 86172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Tear the waiting frame off the list */ 8628e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (odev->mux_bulk_tx_urb && 8638e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) 86472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_unlink_urb(odev->mux_bulk_tx_urb); 86572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 86672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Update statistics */ 86772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->stats.tx_errors++; 86872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 86972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 87072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* make a real packet from the received USB buffer */ 87172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, 87272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned int count, unsigned char is_eop) 87372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 87472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned short temp_bytes; 87572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned short buffer_offset = 0; 87672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned short frame_len; 87772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned char *tmp_rx_buf; 87872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 87972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* log if needed */ 88072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Rx %d bytes", count); 88172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman DUMP(ip_pkt, min(128, (int)count)); 88272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 88372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman while (count) { 88472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (odev->rx_parse_state) { 88572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case WAIT_IP: 88672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* waiting for IP header. */ 88772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* wanted bytes - size of ip header */ 88872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman temp_bytes = 88972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (count < 89072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing) ? count : odev-> 89172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman rx_buf_missing; 89272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 89372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + 89472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size, ip_pkt + buffer_offset, 89572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman temp_bytes); 89672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 89772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size += temp_bytes; 89872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman buffer_offset += temp_bytes; 89972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing -= temp_bytes; 90072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman count -= temp_bytes; 90172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 90272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev->rx_buf_missing) { 90372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* header is complete allocate an sk_buffer and 90472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * continue to WAIT_DATA */ 90572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman frame_len = ntohs(odev->rx_ip_hdr.tot_len); 90672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 90772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if ((frame_len > DEFAULT_MRU) || 90872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (frame_len < sizeof(struct iphdr))) { 90972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&odev->net->dev, 91072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "Invalid frame (%d) length\n", 91172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman frame_len); 91272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_SYNC; 91372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman continue; 91472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 91572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Allocate an sk_buff */ 916d65a68a8da5c9d1041ebc5e018e677d641910668Paulius Zaleckas odev->skb_rx_buf = netdev_alloc_skb(odev->net, 917d65a68a8da5c9d1041ebc5e018e677d641910668Paulius Zaleckas frame_len); 91872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev->skb_rx_buf) { 91972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* We got no receive buffer. */ 92072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("could not allocate memory"); 92172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_SYNC; 92272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 92372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 92472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 92572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Copy what we got so far. make room for iphdr 92672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * after tail. */ 92772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tmp_rx_buf = 92872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman skb_put(odev->skb_rx_buf, 92972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman sizeof(struct iphdr)); 93072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), 93172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman sizeof(struct iphdr)); 93272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 93372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* ETH_HLEN */ 93472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size = sizeof(struct iphdr); 93572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 93672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Filip actually use .tot_len */ 93772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing = 93872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman frame_len - sizeof(struct iphdr); 93972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_DATA; 94072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 94172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 94272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 94372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case WAIT_DATA: 94472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman temp_bytes = (count < odev->rx_buf_missing) 94572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ? count : odev->rx_buf_missing; 94672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 94772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Copy the rest of the bytes that are left in the 94872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * buffer into the waiting sk_buf. */ 94972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Make room for temp_bytes after tail. */ 95072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); 95172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); 95272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 95372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing -= temp_bytes; 95472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman count -= temp_bytes; 95572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman buffer_offset += temp_bytes; 95672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size += temp_bytes; 95772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev->rx_buf_missing) { 95872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Packet is complete. Inject into stack. */ 95972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* We have IP packet here */ 96009640e6365c679b5642b1c41b6d7078f51689ddfHarvey Harrison odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); 96172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman skb_reset_mac_header(odev->skb_rx_buf); 96272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 96372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Ship it off to the kernel */ 96472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_rx(odev->skb_rx_buf); 96572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* No longer our buffer. */ 96672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->skb_rx_buf = NULL; 96772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 96872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* update out statistics */ 96972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->net->stats.rx_packets++; 97072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 97172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->net->stats.rx_bytes += odev->rx_buf_size; 97272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 97372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size = 0; 97472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing = sizeof(struct iphdr); 97572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_IP; 97672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 97772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 97872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 97972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case WAIT_SYNC: 98072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1(" W_S"); 98172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman count = 0; 98272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 98372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 98472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1(" "); 98572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman count--; 98672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 98772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 98872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 98972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 99072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Recovery mechanism for WAIT_SYNC state. */ 99172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (is_eop) { 99272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (odev->rx_parse_state == WAIT_SYNC) { 99372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_parse_state = WAIT_IP; 99472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_size = 0; 99572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->rx_buf_missing = sizeof(struct iphdr); 99672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 99772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 99872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 99972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10005591c75dc345d93d353d2ab2962824648a73efe4Joe Perchesstatic void fix_crc_bug(struct urb *urb, __le16 max_packet_size) 10015591c75dc345d93d353d2ab2962824648a73efe4Joe Perches{ 10025591c75dc345d93d353d2ab2962824648a73efe4Joe Perches static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; 10035591c75dc345d93d353d2ab2962824648a73efe4Joe Perches u32 rest = urb->actual_length % le16_to_cpu(max_packet_size); 10045591c75dc345d93d353d2ab2962824648a73efe4Joe Perches 10055591c75dc345d93d353d2ab2962824648a73efe4Joe Perches if (((rest == 5) || (rest == 6)) && 10065591c75dc345d93d353d2ab2962824648a73efe4Joe Perches !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4, 10075591c75dc345d93d353d2ab2962824648a73efe4Joe Perches crc_check, 4)) { 10085591c75dc345d93d353d2ab2962824648a73efe4Joe Perches urb->actual_length -= 4; 10095591c75dc345d93d353d2ab2962824648a73efe4Joe Perches } 10105591c75dc345d93d353d2ab2962824648a73efe4Joe Perches} 10115591c75dc345d93d353d2ab2962824648a73efe4Joe Perches 101272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Moving data from usb to kernel (in interrupt state) */ 101372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void read_bulk_callback(struct urb *urb) 101472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 101572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *odev = urb->context; 101672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct net_device *net; 101772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 101872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int status = urb->status; 101972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 102072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* is al ok? (Filip: Who's Al ?) */ 102172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (status) { 102268a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, odev->parent); 102372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 102472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 102572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 102672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Sanity check */ 102772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { 102872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("BULK IN callback but driver is not active!"); 102972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 103072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 103172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_mark_last_busy(urb->dev); 103272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 103372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net = odev->net; 103472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 103572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!netif_device_present(net)) { 103672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Somebody killed our network interface... */ 103772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 103872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 103972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 10405591c75dc345d93d353d2ab2962824648a73efe4Joe Perches if (odev->parent->port_spec & HSO_INFO_CRC_BUG) 10415591c75dc345d93d353d2ab2962824648a73efe4Joe Perches fix_crc_bug(urb, odev->in_endp->wMaxPacketSize); 104272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 104372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* do we even have a packet? */ 104472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (urb->actual_length) { 104572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Handle the IP stream, add header and push it onto network 104672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * stack if the packet is complete. */ 104772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock(&odev->net_lock); 104872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman packetizeRx(odev, urb->transfer_buffer, urb->actual_length, 104972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (urb->transfer_buffer_length > 105072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman urb->actual_length) ? 1 : 0); 105172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock(&odev->net_lock); 105272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 105372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 105472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* We are done with this URB, resubmit it. Prep the USB to wait for 105572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * another frame. Reuse same as received. */ 105672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_bulk_urb(urb, 105772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->parent->usb, 105872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_rcvbulkpipe(odev->parent->usb, 105972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman odev->in_endp-> 106072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman bEndpointAddress & 0x7F), 106172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, 106272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman read_bulk_callback, odev); 106372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 106472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Give this to the USB subsystem so it can tell us when more data 106572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * arrives. */ 106672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(urb, GFP_ATOMIC); 106772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 106872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&odev->parent->interface->dev, 10698a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon "%s failed submit mux_bulk_rx_urb %d\n", __func__, 107072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result); 107172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 107272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 107372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Serial driver functions */ 107472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 1075ac9720c37e8795317e8be3adad63cb0d5522a640Alan Coxstatic void hso_init_termios(struct ktermios *termios) 107672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 107772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* 107872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * The default requirements for this device are: 107972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman */ 108072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman termios->c_iflag &= 108172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ~(IGNBRK /* disable ignore break */ 108272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | BRKINT /* disable break causes interrupt */ 108372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | PARMRK /* disable mark parity errors */ 108472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | ISTRIP /* disable clear high bit of input characters */ 108572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | INLCR /* disable translate NL to CR */ 108672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | IGNCR /* disable ignore CR */ 108772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | ICRNL /* disable translate CR to NL */ 108872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | IXON); /* disable enable XON/XOFF flow control */ 108972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 109072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* disable postprocess output characters */ 109172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman termios->c_oflag &= ~OPOST; 109272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 109372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman termios->c_lflag &= 109472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ~(ECHO /* disable echo input characters */ 109572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | ECHONL /* disable echo new line */ 109672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | ICANON /* disable erase, kill, werase, and rprnt 109772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman special characters */ 109872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | ISIG /* disable interrupt, quit, and suspend special 109972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman characters */ 110072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | IEXTEN); /* disable non-POSIX special characters */ 110172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 110272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman termios->c_cflag &= 110372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ~(CSIZE /* no size */ 110472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | PARENB /* disable parity bit */ 110572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | CBAUD /* clear current baud rate */ 110672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman | CBAUDEX); /* clear current buad rate */ 110772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 110872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman termios->c_cflag |= CS8; /* character size 8 bits */ 110972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 111072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* baud rate 115200 */ 1111ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox tty_termios_encode_baud_rate(termios, 115200, 115200); 1112ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox} 1113ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1114ac9720c37e8795317e8be3adad63cb0d5522a640Alan Coxstatic void _hso_serial_set_termios(struct tty_struct *tty, 1115ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox struct ktermios *old) 1116ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox{ 1117ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox struct hso_serial *serial = get_serial_by_tty(tty); 1118ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox struct ktermios *termios; 1119ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1120ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox if (!serial) { 1121ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox printk(KERN_ERR "%s: no tty structures", __func__); 1122ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox return; 1123ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox } 1124ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1125ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox D4("port %d", serial->minor); 112672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 112772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* 1128ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox * Fix up unsupported bits 112972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman */ 1130ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox termios = tty->termios; 1131ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ 1132ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1133ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox termios->c_cflag &= 1134ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox ~(CSIZE /* no size */ 1135ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox | PARENB /* disable parity bit */ 1136ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox | CBAUD /* clear current baud rate */ 1137ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox | CBAUDEX); /* clear current buad rate */ 1138ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1139ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox termios->c_cflag |= CS8; /* character size 8 bits */ 1140ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox 1141ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox /* baud rate 115200 */ 1142ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox tty_encode_baud_rate(tty, 115200, 115200); 114372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 114472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 11458ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) 11468ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 11478ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int result; 11488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* We are done with this URB, resubmit it. Prep the USB to wait for 11498ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * another frame */ 11508ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow usb_fill_bulk_urb(urb, serial->parent->usb, 11518ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow usb_rcvbulkpipe(serial->parent->usb, 11528ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->in_endp-> 11538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow bEndpointAddress & 0x7F), 11548ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow urb->transfer_buffer, serial->rx_data_length, 11558ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_std_serial_read_bulk_callback, serial); 11568ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Give this to the USB subsystem so it can tell us when more data 11578ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * arrives. */ 11588ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow result = usb_submit_urb(urb, GFP_ATOMIC); 11598ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (result) { 11608ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", 11618ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow __func__, result); 11628ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 11638ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 11648ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11658ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11668ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11678ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11688ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial) 11698ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 11708ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int count; 11718ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct urb *curr_urb; 11728ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11738ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { 11748ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; 11758ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow count = put_rxbuf_data(curr_urb, serial); 11768ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (count == -1) 11778ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 11788ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (count == 0) { 11798ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_idx++; 11808ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) 11818ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_idx = 0; 11828ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_resubmit_rx_bulk_urb(serial, curr_urb); 11838ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 11848ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 11858ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 11868ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11878ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) 11888ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 11898ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int count = 0; 11908ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct urb *urb; 11918ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 11928ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow urb = serial->rx_urb[0]; 11938ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (serial->open_count > 0) { 11948ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow count = put_rxbuf_data(urb, serial); 11958ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (count == -1) 11968ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 11978ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 11988ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Re issue a read as long as we receive data. */ 11998ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12008ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (count == 0 && ((urb->actual_length != 0) || 12018ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow (serial->rx_state == RX_PENDING))) { 12028ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_state = RX_SENT; 12038ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_mux_serial_read(serial); 12048ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } else 12058ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_state = RX_IDLE; 12068ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 12078ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12088ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12098ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow/* read callback for Diag and CS port */ 12108ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void hso_std_serial_read_bulk_callback(struct urb *urb) 12118ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 12128ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct hso_serial *serial = urb->context; 12138ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int status = urb->status; 12148ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12158ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* sanity check */ 12168ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (!serial) { 12178ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow D1("serial == NULL"); 12188ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 12198ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } else if (status) { 122068a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, serial->parent); 12218ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 12228ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 12238ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12248ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow D4("\n--- Got serial_read_bulk callback %02x ---", status); 12258ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow D1("Actual length = %d\n", urb->actual_length); 12268ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow DUMP1(urb->transfer_buffer, urb->actual_length); 12278ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12288ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Anyone listening? */ 12298ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (serial->open_count == 0) 12308ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 12318ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12328ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (status == 0) { 12335591c75dc345d93d353d2ab2962824648a73efe4Joe Perches if (serial->parent->port_spec & HSO_INFO_CRC_BUG) 12345591c75dc345d93d353d2ab2962824648a73efe4Joe Perches fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); 12358ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Valid data, handle RX data */ 12368ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_lock(&serial->serial_lock); 12378ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; 12388ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow put_rxbuf_data_and_resubmit_bulk_urb(serial); 12398ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_unlock(&serial->serial_lock); 12408ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } else if (status == -ENOENT || status == -ECONNRESET) { 12418ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow /* Unlinked - check for throttled port. */ 12428ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow D2("Port %d, successfully unlinked urb", serial->minor); 12438ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_lock(&serial->serial_lock); 12448ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; 12458ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_resubmit_rx_bulk_urb(serial, urb); 12468ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_unlock(&serial->serial_lock); 12478ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } else { 12488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow D2("Port %d, status = %d for read urb", serial->minor, status); 12498ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return; 12508ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 12518ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 12528ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow/* 12548ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * This needs to be a tasklet otherwise we will 12558ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow * end up recursively calling this function. 12568ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow */ 12570227abc9d011892fd13f360b56a7b276ebea8b07Hannes Ederstatic void hso_unthrottle_tasklet(struct hso_serial *serial) 12588ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 12598ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow unsigned long flags; 12608ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12618ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_lock_irqsave(&serial->serial_lock, flags); 12628ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if ((serial->parent->port_spec & HSO_INTF_MUX)) 12638ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow put_rxbuf_data_and_resubmit_ctrl_urb(serial); 12648ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow else 12658ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow put_rxbuf_data_and_resubmit_bulk_urb(serial); 12668ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_unlock_irqrestore(&serial->serial_lock, flags); 12678ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 12688ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12698ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic void hso_unthrottle(struct tty_struct *tty) 12708ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 12718ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct hso_serial *serial = get_serial_by_tty(tty); 12728ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12738ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow tasklet_hi_schedule(&serial->unthrottle_tasklet); 12748ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 12758ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 12760227abc9d011892fd13f360b56a7b276ebea8b07Hannes Ederstatic void hso_unthrottle_workfunc(struct work_struct *work) 12778ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow{ 12788ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow struct hso_serial *serial = 12798ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow container_of(work, struct hso_serial, 12808ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow retry_unthrottle_workqueue); 12818ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_unthrottle_tasklet(serial); 12828ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow} 12838ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 128472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* open the requested serial port */ 128572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_serial_open(struct tty_struct *tty, struct file *filp) 128672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 128772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_index(tty->index); 1288ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller int result; 128972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 129072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 129172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { 1292e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox WARN_ON(1); 129372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty->driver_data = NULL; 129472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Failed to open port"); 129572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 129672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 129772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 1298ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_lock(&serial->parent->mutex); 1299ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller result = usb_autopm_get_interface(serial->parent->interface); 1300ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller if (result < 0) 130172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto err_out; 130272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 130372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Opening %d", serial->minor); 130472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kref_get(&serial->parent->ref); 130572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 130672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* setup */ 1307e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_lock_irq(&serial->serial_lock); 130872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty->driver_data = serial; 1309fe41cbb164a0dc55f3914a0e4cabe8240410157cAlan Cox tty_kref_put(serial->tty); 1310e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox serial->tty = tty_kref_get(tty); 1311e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_unlock_irq(&serial->serial_lock); 131272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 13132f9889a20cd2854bc6305198255c617b0b4eb719David S. Miller /* check for port already opened, if not set the termios */ 13142f9889a20cd2854bc6305198255c617b0b4eb719David S. Miller serial->open_count++; 131572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->open_count == 1) { 13168ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_state = RX_IDLE; 131772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Force default termio settings */ 131872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman _hso_serial_set_termios(tty, NULL); 13198ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow tasklet_init(&serial->unthrottle_tasklet, 13208ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow (void (*)(unsigned long))hso_unthrottle_tasklet, 13218ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow (unsigned long)serial); 13228ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow INIT_WORK(&serial->retry_unthrottle_workqueue, 13238ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_unthrottle_workfunc); 1324ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller result = hso_start_serial_device(serial->parent, GFP_KERNEL); 1325ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller if (result) { 132672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_stop_serial_device(serial->parent); 132772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->open_count--; 1328ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller kref_put(&serial->parent->ref, hso_serial_ref_free); 132972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 133072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 133172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Port was already open"); 133272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 133372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 133472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_autopm_put_interface(serial->parent->interface); 133572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 133672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 1337ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller if (result) 133820b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Cox hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0); 133972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanerr_out: 1340ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_unlock(&serial->parent->mutex); 1341ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller return result; 134272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 134372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 134472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* close the requested serial port */ 134572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_serial_close(struct tty_struct *tty, struct file *filp) 134672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 134772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = tty->driver_data; 134872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 usb_gone; 134972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 135072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Closing serial port"); 135172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 1352e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox /* Open failed, no close cleanup required */ 1353e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox if (serial == NULL) 1354e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox return; 1355e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox 1356ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_lock(&serial->parent->mutex); 135772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_gone = serial->parent->usb_gone; 135872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 135972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!usb_gone) 136072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_autopm_get_interface(serial->parent->interface); 136172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 136272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* reset the rts and dtr */ 136372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* do the actual close */ 136472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->open_count--; 1365dcfcb256cc23c4436691b0fe677275306699d6a1Antti Kaijanmäki 136672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->open_count <= 0) { 136772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->open_count = 0; 1368e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_lock_irq(&serial->serial_lock); 1369e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox if (serial->tty == tty) { 137072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tty->driver_data = NULL; 137172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tty = NULL; 1372e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 137372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 1374e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_unlock_irq(&serial->serial_lock); 137572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!usb_gone) 137672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_stop_serial_device(serial->parent); 13778ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow tasklet_kill(&serial->unthrottle_tasklet); 13788ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow cancel_work_sync(&serial->retry_unthrottle_workqueue); 137972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 13808ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 138172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!usb_gone) 138272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_autopm_put_interface(serial->parent->interface); 1383ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller 1384ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_unlock(&serial->parent->mutex); 1385dcfcb256cc23c4436691b0fe677275306699d6a1Antti Kaijanmäki 1386dcfcb256cc23c4436691b0fe677275306699d6a1Antti Kaijanmäki kref_put(&serial->parent->ref, hso_serial_ref_free); 138772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 138872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 138972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* close the requested serial port */ 139072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, 139172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int count) 139272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 139372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 139472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int space, tx_bytes; 139572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 139672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 139772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 139872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial == NULL) { 139972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_ERR "%s: serial is NULL\n", __func__); 140072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 140172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 140272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 140372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 140472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 140572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman space = serial->tx_data_length - serial->tx_buffer_count; 140672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tx_bytes = (count < space) ? count : space; 140772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 140872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!tx_bytes) 140972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 141072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 141172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes); 141272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_buffer_count += tx_bytes; 141372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 141472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanout: 141572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 141672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 141772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_kick_transmit(serial); 141872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 141972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return tx_bytes; 142072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 142172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 142272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* how much room is there for writing */ 142372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_serial_write_room(struct tty_struct *tty) 142472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 142572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 142672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int room; 142772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 142872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 142972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 143072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman room = serial->tx_data_length - serial->tx_buffer_count; 143172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 143272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 143372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* return free room */ 143472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return room; 143572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 143672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 143772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* setup the term */ 143872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) 143972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 144072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 144172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 144272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 144372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (old) 144472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D5("Termios called with: cflags new[%d] - old[%d]", 144572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty->termios->c_cflag, old->c_cflag); 144672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 144772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* the actual setup */ 144872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 144972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->open_count) 145072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman _hso_serial_set_termios(tty, old); 145172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 145272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty->termios = old; 145372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 145472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 145572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 145672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 145772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 145872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* how many characters in the buffer */ 145972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_serial_chars_in_buffer(struct tty_struct *tty) 146072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 146172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 146272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int chars; 146372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 146472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 146572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 146672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial == NULL) 146772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 146872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 146972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 147072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman chars = serial->tx_buffer_count; 147172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 147272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 147372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return chars; 147472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 14750227abc9d011892fd13f360b56a7b276ebea8b07Hannes Ederstatic int tiocmget_submit_urb(struct hso_serial *serial, 14760227abc9d011892fd13f360b56a7b276ebea8b07Hannes Eder struct hso_tiocmget *tiocmget, 14770227abc9d011892fd13f360b56a7b276ebea8b07Hannes Eder struct usb_device *usb) 1478542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 1479542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int result; 1480542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1481542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (serial->parent->usb_gone) 1482542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return -ENODEV; 1483542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow usb_fill_int_urb(tiocmget->urb, usb, 1484542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow usb_rcvintpipe(usb, 1485542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->endp-> 1486542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow bEndpointAddress & 0x7F), 1487542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow &tiocmget->serial_state_notification, 1488542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow sizeof(struct hso_serial_state_notification), 1489542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget_intr_callback, serial, 1490542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->endp->bInterval); 1491542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); 1492542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (result) { 1493542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, 1494542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow result); 1495542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1496542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return result; 1497542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1498542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 1499542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1500542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstatic void tiocmget_intr_callback(struct urb *urb) 1501542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 1502542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_serial *serial = urb->context; 1503542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 1504542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int status = urb->status; 1505542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 UART_state_bitmap, prev_UART_state_bitmap; 1506542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct uart_icount *icount; 1507542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_serial_state_notification *serial_state_notification; 1508542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct usb_device *usb; 1509542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1510542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow /* Sanity checks */ 1511542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (!serial) 1512542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return; 1513542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (status) { 151468a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, serial->parent); 1515542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return; 1516542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1517542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget = serial->tiocmget; 1518542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (!tiocmget) 1519542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return; 1520542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow usb = serial->parent->usb; 1521542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial_state_notification = &tiocmget->serial_state_notification; 1522542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || 1523542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial_state_notification->bNotification != B_NOTIFICATION || 1524542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow le16_to_cpu(serial_state_notification->wValue) != W_VALUE || 1525542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || 1526542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { 1527542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow dev_warn(&usb->dev, 1528542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow "hso received invalid serial state notification\n"); 1529542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow DUMP(serial_state_notification, 15309ce673d5e919966efc1ef5adf20248e6ecc62724Antti Kaijanmäki sizeof(struct hso_serial_state_notification)); 1531542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } else { 1532542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1533542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow UART_state_bitmap = le16_to_cpu(serial_state_notification-> 1534542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow UART_state_bitmap); 1535542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; 1536542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount = &tiocmget->icount; 1537542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_lock(&serial->serial_lock); 1538542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_OVERRUN) != 1539542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_OVERRUN)) 1540542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->parity++; 1541542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_PARITY) != 1542542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_PARITY)) 1543542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->parity++; 1544542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_FRAMING) != 1545542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_FRAMING)) 1546542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->frame++; 1547542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_RING_SIGNAL) && 1548542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow !(prev_UART_state_bitmap & B_RING_SIGNAL)) 1549542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->rng++; 1550542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_BREAK) != 1551542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_BREAK)) 1552542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->brk++; 1553542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_TX_CARRIER) != 1554542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_TX_CARRIER)) 1555542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->dsr++; 1556542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if ((UART_state_bitmap & B_RX_CARRIER) != 1557542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow (prev_UART_state_bitmap & B_RX_CARRIER)) 1558542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow icount->dcd++; 1559542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->prev_UART_state_bitmap = UART_state_bitmap; 1560542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_unlock(&serial->serial_lock); 1561542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->intr_completed = 1; 1562542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow wake_up_interruptible(&tiocmget->waitq); 1563542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1564542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow memset(serial_state_notification, 0, 1565542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow sizeof(struct hso_serial_state_notification)); 1566542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget_submit_urb(serial, 1567542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget, 1568542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial->parent->usb); 1569542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 1570542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1571542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow/* 1572542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * next few functions largely stolen from drivers/serial/serial_core.c 1573542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow */ 1574542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change 1575542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * - mask passed in arg for lines of interest 1576542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) 1577542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * Caller should use TIOCGICOUNT to see which one it was 1578542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow */ 1579542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstatic int 1580542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowhso_wait_modem_status(struct hso_serial *serial, unsigned long arg) 1581542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 1582542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow DECLARE_WAITQUEUE(wait, current); 1583542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct uart_icount cprev, cnow; 1584542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 1585542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int ret; 1586542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1587542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget = serial->tiocmget; 1588542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (!tiocmget) 1589542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return -ENOENT; 1590542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow /* 1591542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * note the counters on entry 1592542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow */ 1593542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_lock_irq(&serial->serial_lock); 1594542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); 1595542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_unlock_irq(&serial->serial_lock); 1596542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow add_wait_queue(&tiocmget->waitq, &wait); 1597542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow for (;;) { 1598542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_lock_irq(&serial->serial_lock); 1599542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); 1600542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_unlock_irq(&serial->serial_lock); 1601542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow set_current_state(TASK_INTERRUPTIBLE); 1602542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || 1603542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || 1604542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { 1605542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ret = 0; 1606542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow break; 1607542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1608542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow schedule(); 1609542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow /* see if a signal did it */ 1610542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (signal_pending(current)) { 1611542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ret = -ERESTARTSYS; 1612542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow break; 1613542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1614542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow cprev = cnow; 1615542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1616542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow current->state = TASK_RUNNING; 1617542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow remove_wait_queue(&tiocmget->waitq, &wait); 1618542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1619542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return ret; 1620542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 1621542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1622542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow/* 1623542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) 1624542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * Return: write counters to the user passed counter struct 1625542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * NB: both 1->0 and 0->1 transitions are counted except for 1626542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * RI where only 0->1 is counted. 1627542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow */ 16280bca1b913affbd7e2fdaffee62a499659a466eb5Alan Coxstatic int hso_get_count(struct tty_struct *tty, 16290bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct serial_icounter_struct *icount) 1630542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 1631542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct uart_icount cnow; 16320bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox struct hso_serial *serial = get_serial_by_tty(tty); 1633542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget = serial->tiocmget; 1634542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 163522ad7499bc9297e47c8779bf5523694f28338499Dan Carpenter memset(icount, 0, sizeof(struct serial_icounter_struct)); 16367011e660938fc44ed86319c18a5954e95a82ab3eDan Rosenberg 1637542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (!tiocmget) 1638542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return -ENOENT; 1639542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_lock_irq(&serial->serial_lock); 1640542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); 1641542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_unlock_irq(&serial->serial_lock); 1642542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 16430bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->cts = cnow.cts; 16440bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->dsr = cnow.dsr; 16450bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->rng = cnow.rng; 16460bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->dcd = cnow.dcd; 16470bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->rx = cnow.rx; 16480bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->tx = cnow.tx; 16490bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->frame = cnow.frame; 16500bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->overrun = cnow.overrun; 16510bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->parity = cnow.parity; 16520bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->brk = cnow.brk; 16530bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox icount->buf_overrun = cnow.buf_overrun; 1654542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 16550bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox return 0; 1656542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 1657542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 165872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 165960b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int hso_serial_tiocmget(struct tty_struct *tty) 166072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 1661542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int retval; 166272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 1663542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 1664542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow u16 UART_state_bitmap; 166572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 166672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 166772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) { 166872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("no tty structures"); 166972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EINVAL; 167072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 1671542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_lock_irq(&serial->serial_lock); 1672542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow retval = ((serial->rts_state) ? TIOCM_RTS : 0) | 167372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ((serial->dtr_state) ? TIOCM_DTR : 0); 1674542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget = serial->tiocmget; 1675542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (tiocmget) { 1676542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1677542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow UART_state_bitmap = le16_to_cpu( 1678542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->prev_UART_state_bitmap); 1679542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (UART_state_bitmap & B_RING_SIGNAL) 1680542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow retval |= TIOCM_RNG; 1681542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (UART_state_bitmap & B_RX_CARRIER) 1682542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow retval |= TIOCM_CD; 1683542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (UART_state_bitmap & B_TX_CARRIER) 1684542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow retval |= TIOCM_DSR; 1685542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1686542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow spin_unlock_irq(&serial->serial_lock); 1687542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return retval; 168872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 168972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 169020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int hso_serial_tiocmset(struct tty_struct *tty, 169172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned int set, unsigned int clear) 169272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 169372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int val = 0; 169472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 169572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int if_num; 169672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = get_serial_by_tty(tty); 169772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 169872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 169972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) { 170072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("no tty structures"); 170172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EINVAL; 170272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 17030e0367e980b55629917f3dd5f5f0ccbf3d0dab62Jan Dumon 17040e0367e980b55629917f3dd5f5f0ccbf3d0dab62Jan Dumon if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM) 17050e0367e980b55629917f3dd5f5f0ccbf3d0dab62Jan Dumon return -EINVAL; 17060e0367e980b55629917f3dd5f5f0ccbf3d0dab62Jan Dumon 170772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; 170872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 170972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 171072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (set & TIOCM_RTS) 171172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rts_state = 1; 171272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (set & TIOCM_DTR) 171372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->dtr_state = 1; 171472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 171572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (clear & TIOCM_RTS) 171672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rts_state = 0; 171772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (clear & TIOCM_DTR) 171872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->dtr_state = 0; 171972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 172072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->dtr_state) 172172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman val |= 0x01; 172272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->rts_state) 172372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman val |= 0x02; 172472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 172572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 172672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 172772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return usb_control_msg(serial->parent->usb, 172872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_rcvctrlpipe(serial->parent->usb, 0), 0x22, 172972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 0x21, val, if_num, NULL, 0, 173072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_CTRL_SET_TIMEOUT); 173172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 173272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 17336caa76b7786891b42b66a0e61e2c2fff2c884620Alan Coxstatic int hso_serial_ioctl(struct tty_struct *tty, 1734542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow unsigned int cmd, unsigned long arg) 1735542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 1736542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_serial *serial = get_serial_by_tty(tty); 1737542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow int ret = 0; 1738542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow D4("IOCTL cmd: %d, arg: %ld", cmd, arg); 1739542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1740542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (!serial) 1741542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return -ENODEV; 1742542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow switch (cmd) { 1743542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow case TIOCMIWAIT: 1744542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ret = hso_wait_modem_status(serial, arg); 1745542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow break; 1746542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow default: 1747542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow ret = -ENOIOCTLCMD; 1748542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow break; 1749542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 1750542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow return ret; 1751542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 1752542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 1753542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 175472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* starts a transmit */ 175572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_kick_transmit(struct hso_serial *serial) 175672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 175772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 *temp; 175872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned long flags; 175972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int res; 176072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 176172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_irqsave(&serial->serial_lock, flags); 176272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->tx_buffer_count) 176372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 176472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 176572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->tx_urb_used) 176672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 176772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 176872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Wakeup USB interface if necessary */ 176972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_get_activity(serial->parent) == -EAGAIN) 177072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 177172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 177272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Switch pointers around to avoid memcpy */ 177372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman temp = serial->tx_buffer; 177472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_buffer = serial->tx_data; 177572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data = temp; 177672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data_count = serial->tx_buffer_count; 177772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_buffer_count = 0; 177872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 177972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* If temp is set, it means we switched buffers */ 178072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (temp && serial->write_data) { 178172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman res = serial->write_data(serial); 178272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (res >= 0) 178372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb_used = 1; 178472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 178572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanout: 178672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock_irqrestore(&serial->serial_lock, flags); 178772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 178872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 178972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* make a request (for reading and writing data to muxed serial port) */ 179072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int mux_device_request(struct hso_serial *serial, u8 type, u16 port, 179172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *ctrl_urb, 179272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_ctrlrequest *ctrl_req, 179372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 *ctrl_urb_data, u32 size) 179472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 179572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 179672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int pipe; 179772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 179872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Sanity check */ 179972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial || !ctrl_urb || !ctrl_req) { 180072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_ERR "%s: Wrong arguments\n", __func__); 180172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EINVAL; 180272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 180372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 180472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* initialize */ 180572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->wValue = 0; 1806b74f62c1e736ea01c660355526dd54132d241ca9Denis Joseph Barrow ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port)); 1807b74f62c1e736ea01c660355526dd54132d241ca9Denis Joseph Barrow ctrl_req->wLength = cpu_to_le16(size); 180872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 180972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) { 181072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Reading command */ 181172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->bRequestType = USB_DIR_IN | 181272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_TYPE_OPTION_VENDOR | 181372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_RECIP_INTERFACE; 181472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; 181572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman pipe = usb_rcvctrlpipe(serial->parent->usb, 0); 181672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 181772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Writing command */ 181872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->bRequestType = USB_DIR_OUT | 181972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_TYPE_OPTION_VENDOR | 182072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_RECIP_INTERFACE; 182172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; 182272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman pipe = usb_sndctrlpipe(serial->parent->usb, 0); 182372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 182472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* syslog */ 182572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D2("%s command (%02x) len: %d, port: %d", 182672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write", 182772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_req->bRequestType, ctrl_req->wLength, port); 182872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 182972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Load ctrl urb */ 183072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_urb->transfer_flags = 0; 183172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_control_urb(ctrl_urb, 183272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->usb, 183372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman pipe, 183472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (u8 *) ctrl_req, 183572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman ctrl_urb_data, size, ctrl_callback, serial); 183672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Send it on merry way */ 183772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(ctrl_urb, GFP_ATOMIC); 183872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 183972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&ctrl_urb->dev->dev, 18408a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon "%s failed submit ctrl_urb %d type %d\n", __func__, 184172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result, type); 184272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 184372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 184472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 184572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 184672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return size; 184772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 184872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 184972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called by intr_callback when read occurs */ 185072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_mux_serial_read(struct hso_serial *serial) 185172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 185272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 185372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EINVAL; 185472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 185572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* clean data */ 185672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE); 185772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* make the request */ 185872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 185972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->num_rx_urbs != 1) { 186072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&serial->parent->interface->dev, 186172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "ERROR: mux'd reads with multiple buffers " 186272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "not possible\n"); 186372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 186472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 186572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return mux_device_request(serial, 186672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_CDC_GET_ENCAPSULATED_RESPONSE, 186772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->port_spec & HSO_PORT_MASK, 186872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_urb[0], 186972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman &serial->ctrl_req_rx, 187072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_data[0], serial->rx_data_length); 187172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 187272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 187372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* used for muxed serial port callback (muxed serial read) */ 187472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void intr_callback(struct urb *urb) 187572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 187672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *shared_int = urb->context; 187772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial; 187872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned char *port_req; 187972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int status = urb->status; 188072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 188172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 188272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_mark_last_busy(urb->dev); 188372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 188472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 188572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!shared_int) 188672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 188772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 188872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* status check */ 188972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (status) { 189068a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, NULL); 189172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 189272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 189372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D4("\n--- Got intr callback 0x%02X ---", status); 189472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 189572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* what request? */ 189672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_req = urb->transfer_buffer; 189772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D4(" port_req = 0x%.2X\n", *port_req); 189872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* loop over all muxed ports to find the one sending this */ 189972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < 8; i++) { 190072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* max 8 channels on MUX */ 190172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (*port_req & (1 << i)) { 190272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial = get_serial_by_shared_int_and_type(shared_int, 190372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (1 << i)); 190472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial != NULL) { 190572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("Pending read interrupt on port %d\n", i); 19068ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_lock(&serial->serial_lock); 1907f4763e96c08ea0790750603999e5b3158c3b50d4Jan Dumon if (serial->rx_state == RX_IDLE && 1908f4763e96c08ea0790750603999e5b3158c3b50d4Jan Dumon serial->open_count > 0) { 190972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Setup and send a ctrl req read on 191072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * port i */ 1911f4763e96c08ea0790750603999e5b3158c3b50d4Jan Dumon if (!serial->rx_urb_filled[0]) { 19128ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_state = RX_SENT; 19138ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow hso_mux_serial_read(serial); 19148ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } else 19158ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_state = RX_PENDING; 191672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 1917f4763e96c08ea0790750603999e5b3158c3b50d4Jan Dumon D1("Already a read pending on " 1918f4763e96c08ea0790750603999e5b3158c3b50d4Jan Dumon "port %d or port not open\n", i); 191972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 19208ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_unlock(&serial->serial_lock); 192172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 192272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 192372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 192472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Resubmit interrupt urb */ 192572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC); 192672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 192772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 192872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called for writing to muxed serial port */ 192972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_mux_serial_write_data(struct hso_serial *serial) 193072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 193172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (NULL == serial) 193272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EINVAL; 193372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 193472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return mux_device_request(serial, 193572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_CDC_SEND_ENCAPSULATED_COMMAND, 193672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->port_spec & HSO_PORT_MASK, 193772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb, 193872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman &serial->ctrl_req_tx, 193972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data, serial->tx_data_count); 194072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 194172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 194272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* write callback for Diag and CS port */ 194372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_std_serial_write_bulk_callback(struct urb *urb) 194472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 194572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = urb->context; 194672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int status = urb->status; 1947e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox struct tty_struct *tty; 194872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 194972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 195072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) { 195172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("serial == NULL"); 195272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 195372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 195472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 195572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock(&serial->serial_lock); 195672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb_used = 0; 1957e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty = tty_kref_get(serial->tty); 195872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock(&serial->serial_lock); 195972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (status) { 196068a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, serial->parent); 1961e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 196272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 196372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 196472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_put_activity(serial->parent); 1965e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox if (tty) { 1966e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_wakeup(tty); 1967e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 1968e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox } 196972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_kick_transmit(serial); 197072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 197172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1(" "); 197272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 197372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 197472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called for writing diag or CS serial port */ 197572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_std_serial_write_data(struct hso_serial *serial) 197672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 197772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int count = serial->tx_data_count; 197872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 197972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 198072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_bulk_urb(serial->tx_urb, 198172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->usb, 198272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_sndbulkpipe(serial->parent->usb, 198372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->out_endp-> 198472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman bEndpointAddress & 0x7F), 198572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data, serial->tx_data_count, 198672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_std_serial_write_bulk_callback, serial); 198772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 198872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC); 198972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 199072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&serial->parent->usb->dev, 199172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "Failed to submit urb - res %d\n", result); 199272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 199372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 199472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 199572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return count; 199672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 199772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 199872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* callback after read or write on muxed serial port */ 199972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void ctrl_callback(struct urb *urb) 200072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 200172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = urb->context; 200272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_ctrlrequest *req; 200372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int status = urb->status; 2004e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox struct tty_struct *tty; 200572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 200672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* sanity check */ 200772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 200872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 200972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 201072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock(&serial->serial_lock); 201172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb_used = 0; 2012e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty = tty_kref_get(serial->tty); 201372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_unlock(&serial->serial_lock); 201472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (status) { 201568a351c501ad22077a969df157cd13367cb43a40Jan Dumon handle_usb_error(status, __func__, serial->parent); 2016e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 201772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 201872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 201972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 202072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* what request? */ 202172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman req = (struct usb_ctrlrequest *)(urb->setup_packet); 202272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D4("\n--- Got muxed ctrl callback 0x%02X ---", status); 202372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D4("Actual length of urb = %d\n", urb->actual_length); 202472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman DUMP1(urb->transfer_buffer, urb->actual_length); 202572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 202672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (req->bRequestType == 202772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { 202872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* response to a read command */ 20298ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_urb_filled[0] = 1; 20308ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_lock(&serial->serial_lock); 20318ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow put_rxbuf_data_and_resubmit_ctrl_urb(serial); 20328ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow spin_unlock(&serial->serial_lock); 203372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 203472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_put_activity(serial->parent); 2035e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox if (tty) 2036e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_wakeup(tty); 203772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* response to a write command */ 203872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_kick_transmit(serial); 203972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2040e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 204172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 204272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 204372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* handle RX data for serial port */ 20448ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrowstatic int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) 204572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 2046e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox struct tty_struct *tty; 20478ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int write_length_remaining = 0; 20488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow int curr_write_len; 2049e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox 205072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Sanity check */ 205172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (urb == NULL || serial == NULL) { 205272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("serial = NULL"); 20538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return -2; 205472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 205572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2056d45eb81c3e345fabaf27ef3ab437b85c0bf9fafaDenis Joseph Barrow /* All callers to put_rxbuf_data hold serial_lock */ 2057e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty = tty_kref_get(serial->tty); 2058e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox 205972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Push data to tty */ 20608ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (tty) { 20618ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow write_length_remaining = urb->actual_length - 20628ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_offset; 206372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("data to push to tty"); 20648ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow while (write_length_remaining) { 20655839b414f9f9d2d6a471988763b61dbf85eb2dbaDenis Joseph Barrow if (test_bit(TTY_THROTTLED, &tty->flags)) { 20665839b414f9f9d2d6a471988763b61dbf85eb2dbaDenis Joseph Barrow tty_kref_put(tty); 20678ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return -1; 20685839b414f9f9d2d6a471988763b61dbf85eb2dbaDenis Joseph Barrow } 20698ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow curr_write_len = tty_insert_flip_string 20708ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow (tty, urb->transfer_buffer + 20718ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_offset, 20728ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow write_length_remaining); 20738ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_offset += curr_write_len; 20748ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow write_length_remaining -= curr_write_len; 20758ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow tty_flip_buffer_push(tty); 207672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 207772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 20788ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (write_length_remaining == 0) { 20798ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_offset = 0; 20808ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; 208172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2082e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 20838ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow return write_length_remaining; 208472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 208572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 20868ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow 208772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Base driver functions */ 208872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 208972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_log_port(struct hso_device *hso_dev) 209072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 209172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char *port_type; 209272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char port_dev[20]; 209372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 209472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (hso_dev->port_spec & HSO_PORT_MASK) { 209572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_CONTROL: 209672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Control"; 209772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 209872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP: 209972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Application"; 210072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 210172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_GPS: 210272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "GPS"; 210372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 210472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_GPS_CONTROL: 210572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "GPS control"; 210672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 210772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_APP2: 210872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Application2"; 210972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 211072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_PCSC: 211172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "PCSC"; 211272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 211372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_DIAG: 211472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Diagnostic"; 211572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 211672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_DIAG2: 211772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Diagnostic2"; 211872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 211972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_MODEM: 212072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Modem"; 212172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 212272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_PORT_NETWORK: 212372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Network"; 212472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 212572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 212672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type = "Unknown"; 212772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 212872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 212972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { 213072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman sprintf(port_dev, "%s", dev2net(hso_dev)->net->name); 213172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else 213272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman sprintf(port_dev, "/dev/%s%d", tty_filename, 213372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev2ser(hso_dev)->minor); 213472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 213572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n", 213672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_type, port_dev); 213772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 213872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 213972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_start_net_device(struct hso_device *hso_dev) 214072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 214172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i, result = 0; 214272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net = dev2net(hso_dev); 214372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 214472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net) 214572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 214672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 214772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* send URBs for all read buffers */ 214872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { 214972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 215072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Prep a receive URB */ 215172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i], 215272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->usb, 215372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_rcvbulkpipe(hso_dev->usb, 215472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->in_endp-> 215572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman bEndpointAddress & 0x7F), 215672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->mux_bulk_rx_buf_pool[i], 215772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman MUX_BULK_RX_BUF_SIZE, read_bulk_callback, 215872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net); 215972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 216072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Put it out there so the device can send us stuff */ 216172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i], 216272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman GFP_NOIO); 216372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 216472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&hso_dev->usb->dev, 216572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "%s failed mux_bulk_rx_urb[%d] %d\n", __func__, 216672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman i, result); 216772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 216872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 216972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 217072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 217172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 217272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_stop_net_device(struct hso_device *hso_dev) 217372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 217472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 217572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net = dev2net(hso_dev); 217672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 217772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net) 217872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 217972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 218072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { 218172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_net->mux_bulk_rx_urb_pool[i]) 218272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]); 218372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 218472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 218572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_net->mux_bulk_tx_urb) 218672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_kill_urb(hso_net->mux_bulk_tx_urb); 218772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 218872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 218972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 219072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 219172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) 219272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 219372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i, result = 0; 219472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = dev2ser(hso_dev); 219572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 219672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 219772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 219872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 219972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* If it is not the MUX port fill in and submit a bulk urb (already 220072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * allocated in hso_serial_start) */ 220172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!(serial->parent->port_spec & HSO_INTF_MUX)) { 220272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < serial->num_rx_urbs; i++) { 220372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_bulk_urb(serial->rx_urb[i], 220472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->usb, 220572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_rcvbulkpipe(serial->parent->usb, 220672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->in_endp-> 220772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman bEndpointAddress & 220872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 0x7F), 220972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_data[i], 221072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_data_length, 221172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_std_serial_read_bulk_callback, 221272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial); 221372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(serial->rx_urb[i], flags); 221472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 221572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_warn(&serial->parent->usb->dev, 221672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman "Failed to submit urb - res %d\n", 221772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result); 221872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 221972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 222072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 222172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } else { 222272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_lock(&serial->shared_int->shared_int_lock); 222372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->shared_int->use_count) { 222472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 222572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_mux_submit_intr_urb(serial->shared_int, 222672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->usb, flags); 222772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 222872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->shared_int->use_count++; 222972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_unlock(&serial->shared_int->shared_int_lock); 223072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2231542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (serial->tiocmget) 2232542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget_submit_urb(serial, 2233542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial->tiocmget, 2234542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial->parent->usb); 223572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 223672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 223772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 223872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_stop_serial_device(struct hso_device *hso_dev) 223972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 224072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 224172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = dev2ser(hso_dev); 2242542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 224372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 224472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 224572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 224672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 224772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < serial->num_rx_urbs; i++) { 22488ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow if (serial->rx_urb[i]) { 224972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_kill_urb(serial->rx_urb[i]); 22508ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->rx_urb_filled[i] = 0; 22518ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow } 225272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 22538ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_idx = 0; 22548ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow serial->curr_rx_urb_offset = 0; 225572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 225672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->tx_urb) 225772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_kill_urb(serial->tx_urb); 225872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 225972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->shared_int) { 226072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_lock(&serial->shared_int->shared_int_lock); 226172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->shared_int->use_count && 226272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (--serial->shared_int->use_count == 0)) { 226372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct urb *urb; 226472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 226572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman urb = serial->shared_int->shared_intr_urb; 226672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (urb) 226772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_kill_urb(urb); 226872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 226972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_unlock(&serial->shared_int->shared_int_lock); 227072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2271542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget = serial->tiocmget; 2272542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (tiocmget) { 2273542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow wake_up_interruptible(&tiocmget->waitq); 2274542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow usb_kill_urb(tiocmget->urb); 2275542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 227672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 227772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 227872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 227972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 228072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_serial_common_free(struct hso_serial *serial) 228172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 228272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 228372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 228472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->parent->dev) 228572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman device_remove_file(serial->parent->dev, &dev_attr_hsotype); 228672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 228772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_unregister_device(tty_drv, serial->minor); 228872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 228972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < serial->num_rx_urbs; i++) { 229072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* unlink and free RX URB */ 229172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(serial->rx_urb[i]); 229272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* free the RX buffer */ 229372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(serial->rx_data[i]); 229472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 229572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 229672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* unlink and free TX URB */ 229772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(serial->tx_urb); 229872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(serial->tx_data); 229972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 230072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 230172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_serial_common_create(struct hso_serial *serial, int num_urbs, 230272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int rx_size, int tx_size) 230372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 230472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct device *dev; 230572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int minor; 230672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 230772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 230872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman minor = get_free_serial_index(); 230972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (minor < 0) 231072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 231172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 231272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* register our minor number */ 231372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent->dev = tty_register_device(tty_drv, minor, 231472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman &serial->parent->interface->dev); 231572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev = serial->parent->dev; 23161aec5bdfed91b50aedbcad43393bcb05033c7ef3Greg Kroah-Hartman dev_set_drvdata(dev, serial->parent); 231772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman i = device_create_file(dev, &dev_attr_hsotype); 231872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 231972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* fill in specific data for later use */ 232072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->minor = minor; 232172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->magic = HSO_SERIAL_MAGIC; 232272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_init(&serial->serial_lock); 232372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->num_rx_urbs = num_urbs; 232472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 232572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* RX, allocate urb and initialize */ 232672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 232772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* prepare our RX buffer */ 232872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_data_length = rx_size; 232972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < serial->num_rx_urbs; i++) { 233072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 233172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->rx_urb[i]) { 233272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(dev, "Could not allocate urb?\n"); 233372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 233472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 233572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_urb[i]->transfer_buffer = NULL; 233672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_urb[i]->transfer_buffer_length = 0; 233772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->rx_data[i] = kzalloc(serial->rx_data_length, 233872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman GFP_KERNEL); 233972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->rx_data[i]) { 234072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(dev, "%s - Out of memory\n", __func__); 234172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 234272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 234372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 234472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 234572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* TX, allocate urb and initialize */ 234672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL); 234772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->tx_urb) { 234872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(dev, "Could not allocate urb?\n"); 234972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 235072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 235172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb->transfer_buffer = NULL; 235272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_urb->transfer_buffer_length = 0; 235372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* prepare our TX buffer */ 235472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data_count = 0; 235572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_buffer_count = 0; 235672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data_length = tx_size; 235772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL); 235872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->tx_data) { 23598a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon dev_err(dev, "%s - Out of memory\n", __func__); 236072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 236172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 236272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL); 236372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->tx_buffer) { 23648a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon dev_err(dev, "%s - Out of memory\n", __func__); 236572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 236672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 236772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 236872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 236972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 237072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_serial_common_free(serial); 237172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -1; 237272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 237372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 237472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Creates a general hso device */ 237572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_device *hso_create_device(struct usb_interface *intf, 237672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int port_spec) 237772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 237872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev; 237972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 238072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC); 238172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 238272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 238372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 238472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->port_spec = port_spec; 238572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->usb = interface_to_usbdev(intf); 238672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->interface = intf; 238772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kref_init(&hso_dev->ref); 2388ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_init(&hso_dev->mutex); 2389ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller 239072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman INIT_WORK(&hso_dev->async_get_intf, async_get_intf); 239172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman INIT_WORK(&hso_dev->async_put_intf, async_put_intf); 239268a351c501ad22077a969df157cd13367cb43a40Jan Dumon INIT_WORK(&hso_dev->reset_device, reset_device); 239372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 239472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return hso_dev; 239572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 239672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 239772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Removes a network device in the network device table */ 239872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int remove_net_device(struct hso_device *hso_dev) 239972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 240072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 240172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 240272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { 240372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (network_table[i] == hso_dev) { 240472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman network_table[i] = NULL; 240572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 240672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 240772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 240872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (i == HSO_MAX_NET_DEVICES) 240972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -1; 241072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 241172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 241272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 241372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Frees our network device */ 241472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_net_device(struct hso_device *hso_dev) 241572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 241672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 241772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net = dev2net(hso_dev); 241872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 241972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net) 242072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 242172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 24223b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon remove_net_device(hso_net->parent); 24233b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon 24245e2cd0825a43824827b233d95bc47c0c970e5befGreg Kroah-Hartman if (hso_net->net) 24253b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon unregister_netdev(hso_net->net); 24263b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon 242772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* start freeing */ 242872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { 242972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); 243072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(hso_net->mux_bulk_rx_buf_pool[i]); 24313b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon hso_net->mux_bulk_rx_buf_pool[i] = NULL; 243272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 243372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(hso_net->mux_bulk_tx_urb); 243472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(hso_net->mux_bulk_tx_buf); 24353b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon hso_net->mux_bulk_tx_buf = NULL; 2436ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller 24375e2cd0825a43824827b233d95bc47c0c970e5befGreg Kroah-Hartman if (hso_net->net) 24385e2cd0825a43824827b233d95bc47c0c970e5befGreg Kroah-Hartman free_netdev(hso_net->net); 24395e2cd0825a43824827b233d95bc47c0c970e5befGreg Kroah-Hartman 2440e44578ea7c4f87462e05e0d0a2dd43b6beecd5f6Paulius Zaleckas kfree(hso_dev); 244172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 244272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2443c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemmingerstatic const struct net_device_ops hso_netdev_ops = { 2444c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger .ndo_open = hso_net_open, 2445c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger .ndo_stop = hso_net_close, 2446c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger .ndo_start_xmit = hso_net_start_xmit, 2447c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger .ndo_tx_timeout = hso_net_tx_timeout, 2448c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger}; 2449c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger 245072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* initialize the network interface */ 245172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_net_init(struct net_device *net) 245272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 245372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net = netdev_priv(net); 245472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 245572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman D1("sizeof hso_net is %d", (int)sizeof(*hso_net)); 245672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 245772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* fill in the other fields */ 2458c266cb4ef2ef1f1e3f46d81022939feebe8fa54dStephen Hemminger net->netdev_ops = &hso_netdev_ops; 245972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->watchdog_timeo = HSO_NET_TX_TIMEOUT; 246072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; 246172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->type = ARPHRD_NONE; 246272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->mtu = DEFAULT_MTU - 14; 246372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net->tx_queue_len = 10; 246472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman SET_ETHTOOL_OPS(net, &ops); 246572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 246672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* and initialize the semaphore */ 246772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_init(&hso_net->net_lock); 246872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 246972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 247072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Adds a network device in the network device table */ 247172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int add_net_device(struct hso_device *hso_dev) 247272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 247372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 247472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 247572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { 247672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (network_table[i] == NULL) { 247772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman network_table[i] = hso_dev; 247872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 247972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 248072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 248172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (i == HSO_MAX_NET_DEVICES) 248272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -1; 248372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 248472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 248572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 248619d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Bergstatic int hso_rfkill_set_block(void *data, bool blocked) 248772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 248872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev = data; 248919d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg int enabled = !blocked; 249072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int rv; 249172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2492ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_lock(&hso_dev->mutex); 249372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev->usb_gone) 249472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman rv = 0; 249572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 249672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), 249772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, 249872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_CTRL_SET_TIMEOUT); 2499ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_unlock(&hso_dev->mutex); 250072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return rv; 250172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 250272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 250319d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Bergstatic const struct rfkill_ops hso_rfkill_ops = { 250419d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg .set_block = hso_rfkill_set_block, 250519d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg}; 250619d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg 250772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Creates and sets up everything for rfkill */ 250872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_create_rfkill(struct hso_device *hso_dev, 250972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_interface *interface) 251072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 251172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net = dev2net(hso_dev); 2512939a9516416ad8ccec27aa05bd19236c550c0c03Jonathan McDowell struct device *dev = &hso_net->net->dev; 251372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman char *rfkn; 251472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 251572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman rfkn = kzalloc(20, GFP_KERNEL); 251619d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg if (!rfkn) 2517939a9516416ad8ccec27aa05bd19236c550c0c03Jonathan McDowell dev_err(dev, "%s - Out of memory\n", __func__); 251819d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg 251972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman snprintf(rfkn, 20, "hso-%d", 252072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman interface->altsetting->desc.bInterfaceNumber); 252119d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg 252219d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg hso_net->rfkill = rfkill_alloc(rfkn, 252319d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg &interface_to_usbdev(interface)->dev, 252419d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg RFKILL_TYPE_WWAN, 252519d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg &hso_rfkill_ops, hso_dev); 252619d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg if (!hso_net->rfkill) { 252719d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg dev_err(dev, "%s - Out of memory\n", __func__); 252819d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg kfree(rfkn); 252919d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg return; 253019d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg } 253172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (rfkill_register(hso_net->rfkill) < 0) { 253219d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg rfkill_destroy(hso_net->rfkill); 253372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(rfkn); 2534939a9516416ad8ccec27aa05bd19236c550c0c03Jonathan McDowell hso_net->rfkill = NULL; 2535939a9516416ad8ccec27aa05bd19236c550c0c03Jonathan McDowell dev_err(dev, "%s - Failed to register rfkill\n", __func__); 253672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 253772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 253872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 253972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2540384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmannstatic struct device_type hso_type = { 2541384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann .name = "wwan", 2542384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann}; 2543384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann 254472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Creates our network device */ 25450de8ca597d7b449e9e7ce7af138944acf06c8f05Jan Dumonstatic struct hso_device *hso_create_net_device(struct usb_interface *interface, 25460de8ca597d7b449e9e7ce7af138944acf06c8f05Jan Dumon int port_spec) 254772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 254872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result, i; 254972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct net_device *net; 255072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net; 255172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev; 255272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 25530de8ca597d7b449e9e7ce7af138944acf06c8f05Jan Dumon hso_dev = hso_create_device(interface, port_spec); 255472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 255572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 255672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 255772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* allocate our network device, then we can put in our private data */ 255872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* call hso_net_init to do the basic initialization */ 255972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); 256072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!net) { 256172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Unable to create ethernet device\n"); 256272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 256372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 256472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 256572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net = netdev_priv(net); 256672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 256772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->port_data.dev_net = hso_net; 256872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->net = net; 256972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->parent = hso_dev; 257072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 257172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, 257272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DIR_IN); 257372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->in_endp) { 257472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Can't find BULK IN endpoint\n"); 257572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 257672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 257772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, 257872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DIR_OUT); 257972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->out_endp) { 258072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Can't find BULK OUT endpoint\n"); 258172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 258272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 258372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman SET_NETDEV_DEV(net, &interface->dev); 2584384912ed194e43c03ad1cdaa09b0b1e488c34d46Marcel Holtmann SET_NETDEV_DEVTYPE(net, &hso_type); 258572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 258672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* registering our net device */ 258772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = register_netdev(net); 258872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 258972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Failed to register device\n"); 259072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 259172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 259272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 259372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* start allocating */ 259472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { 259572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL); 259672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->mux_bulk_rx_urb_pool[i]) { 259772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Could not allocate rx urb\n"); 259872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 259972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 260072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE, 260172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman GFP_KERNEL); 260272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->mux_bulk_rx_buf_pool[i]) { 260372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Could not allocate rx buf\n"); 260472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 260572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 260672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 260772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL); 260872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->mux_bulk_tx_urb) { 260972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Could not allocate tx urb\n"); 261072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 261172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 261272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL); 261372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_net->mux_bulk_tx_buf) { 261472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Could not allocate tx buf\n"); 261572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 261672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 261772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 261872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman add_net_device(hso_dev); 261972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 262072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_log_port(hso_dev); 262172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 262272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_create_rfkill(hso_dev, interface); 262372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 262472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return hso_dev; 262572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 262672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_net_device(hso_dev); 262772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 262872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 262972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 2630542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrowstatic void hso_free_tiomget(struct hso_serial *serial) 2631542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow{ 26325b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl struct hso_tiocmget *tiocmget; 26335b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl if (!serial) 26345b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl return; 26355b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl tiocmget = serial->tiocmget; 2636542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (tiocmget) { 26375b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl usb_free_urb(tiocmget->urb); 26385b89db0e84bef81f6aa324f8f22a9258ff873de3Jesper Juhl tiocmget->urb = NULL; 2639542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial->tiocmget = NULL; 26403b7d2b319db0ba1f6208ca58b297fb419301f85aJan Dumon kfree(tiocmget); 2641542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 2642542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow} 2643542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow 264472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Frees an AT channel ( goes for both mux and non-mux ) */ 264572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_serial_device(struct hso_device *hso_dev) 264672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 264772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial = dev2ser(hso_dev); 264872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 264972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 265072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return; 265172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman set_serial_by_index(serial->minor, NULL); 265272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 265372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_serial_common_free(serial); 265472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 265572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial->shared_int) { 265672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_lock(&serial->shared_int->shared_int_lock); 265772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (--serial->shared_int->ref_count == 0) 265872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_shared_int(serial->shared_int); 265972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 266072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_unlock(&serial->shared_int->shared_int_lock); 266172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2662542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow hso_free_tiomget(serial); 266372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(serial); 2664e44578ea7c4f87462e05e0d0a2dd43b6beecd5f6Paulius Zaleckas kfree(hso_dev); 266572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 266672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 266772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Creates a bulk AT channel */ 266872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct hso_device *hso_create_bulk_serial_device( 266972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_interface *interface, int port) 267072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 267172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev; 267272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial; 267372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int num_urbs; 2674542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow struct hso_tiocmget *tiocmget; 267572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 267672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = hso_create_device(interface, port); 267772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 267872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 267972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 268072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial = kzalloc(sizeof(*serial), GFP_KERNEL); 268172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 268272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 268372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 268472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent = hso_dev; 268572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->port_data.dev_serial = serial; 268672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 268758eb17f155704062d76729d1fb7e23d3559ca86aDenis Joseph Barrow if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { 268872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman num_urbs = 2; 2689542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), 2690542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow GFP_KERNEL); 2691542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow /* it isn't going to break our heart if serial->tiocmget 2692542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow * allocation fails don't bother checking this. 2693542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow */ 2694542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (serial->tiocmget) { 2695542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget = serial->tiocmget; 2696542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); 2697542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow if (tiocmget->urb) { 2698542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow mutex_init(&tiocmget->mutex); 2699542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow init_waitqueue_head(&tiocmget->waitq); 2700542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow tiocmget->endp = hso_get_ep( 2701542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow interface, 2702542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow USB_ENDPOINT_XFER_INT, 2703542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow USB_DIR_IN); 2704542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } else 2705542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow hso_free_tiomget(serial); 2706542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 2707542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow } 270872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 270972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman num_urbs = 1; 271072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 271172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE, 271272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman BULK_URB_TX_SIZE)) 271372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 271472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 271572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, 271672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DIR_IN); 271772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial->in_endp) { 271872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Failed to find BULK IN ep\n"); 2719e57b641dfafc10ce23d26cf271fd2638589fdb3fAdrian Bunk goto exit2; 272072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 272172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 272272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (! 272372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (serial->out_endp = 272472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { 272572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Failed to find BULK IN ep\n"); 2726e57b641dfafc10ce23d26cf271fd2638589fdb3fAdrian Bunk goto exit2; 272772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 272872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 272972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->write_data = hso_std_serial_write_data; 273072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 273172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* and record this serial */ 273272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman set_serial_by_index(serial->minor, serial); 273372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 273472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* setup the proc dirs and files if needed */ 273572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_log_port(hso_dev); 273672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 273772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done, return it */ 273872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return hso_dev; 2739e57b641dfafc10ce23d26cf271fd2638589fdb3fAdrian Bunk 2740e57b641dfafc10ce23d26cf271fd2638589fdb3fAdrian Bunkexit2: 2741e57b641dfafc10ce23d26cf271fd2638589fdb3fAdrian Bunk hso_serial_common_free(serial); 274272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 2743542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow hso_free_tiomget(serial); 274472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(serial); 2745e44578ea7c4f87462e05e0d0a2dd43b6beecd5f6Paulius Zaleckas kfree(hso_dev); 274672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 274772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 274872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 274972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Creates a multiplexed AT channel */ 275072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic 275172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_device *hso_create_mux_serial_device(struct usb_interface *interface, 275272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int port, 275372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *mux) 275472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 275572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev; 275672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *serial; 275772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int port_spec; 275872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 275972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_spec = HSO_INTF_MUX; 276072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_spec &= ~HSO_PORT_MASK; 276172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 276272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_spec |= hso_mux_to_port(port); 276372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT) 276472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 276572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 276672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = hso_create_device(interface, port_spec); 276772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 276872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 276972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 277072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial = kzalloc(sizeof(*serial), GFP_KERNEL); 277172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!serial) 277272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 277372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 277472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->port_data.dev_serial = serial; 277572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->parent = hso_dev; 277672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 277772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_serial_common_create 277872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE)) 277972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 278072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 278172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->tx_data_length--; 278272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->write_data = hso_mux_serial_write_data; 278372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 278472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->shared_int = mux; 278572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_lock(&serial->shared_int->shared_int_lock); 278672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial->shared_int->ref_count++; 278772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_unlock(&serial->shared_int->shared_int_lock); 278872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 278972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* and record this serial */ 279072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman set_serial_by_index(serial->minor, serial); 279172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 279272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* setup the proc dirs and files if needed */ 279372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_log_port(hso_dev); 279472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 279572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done, return it */ 279672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return hso_dev; 279772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 279872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 279972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial) { 280072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_unregister_device(tty_drv, serial->minor); 280172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(serial); 280272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 280372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev) 2804e44578ea7c4f87462e05e0d0a2dd43b6beecd5f6Paulius Zaleckas kfree(hso_dev); 280572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 280672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 280772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 280872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 280972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_shared_int(struct hso_shared_int *mux) 281072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 281172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(mux->shared_intr_urb); 281272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(mux->shared_intr_buf); 281372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_unlock(&mux->shared_int_lock); 281472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(mux); 281572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 281672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 281772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic 281872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstruct hso_shared_int *hso_create_shared_int(struct usb_interface *interface) 281972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 282072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL); 282172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 282272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!mux) 282372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 282472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 282572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, 282672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_DIR_IN); 282772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!mux->intr_endp) { 282872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Can't find INT IN endpoint\n"); 282972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 283072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 283172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 283272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL); 283372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!mux->shared_intr_urb) { 28348a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon dev_err(&interface->dev, "Could not allocate intr urb?\n"); 283572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 283672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 2837d9ced80d1084758772d350ac66b1ad0eeefc7f95Jan Dumon mux->shared_intr_buf = 2838d9ced80d1084758772d350ac66b1ad0eeefc7f95Jan Dumon kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize), 2839d9ced80d1084758772d350ac66b1ad0eeefc7f95Jan Dumon GFP_KERNEL); 284072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!mux->shared_intr_buf) { 28418a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon dev_err(&interface->dev, "Could not allocate intr buf?\n"); 284272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 284372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 284472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 284572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman mutex_init(&mux->shared_int_lock); 284672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 284772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return mux; 284872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 284972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 285072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(mux->shared_intr_buf); 285172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_free_urb(mux->shared_intr_urb); 285272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman kfree(mux); 285372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 285472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 285572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 285672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Gets the port spec for a certain interface */ 285772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_get_config_data(struct usb_interface *interface) 285872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 285972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_device *usbdev = interface_to_usbdev(interface); 286072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u8 config_data[17]; 286172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman u32 if_num = interface->altsetting->desc.bInterfaceNumber; 286272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman s32 result; 286372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 286472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 286572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 0x86, 0xC0, 0, 0, config_data, 17, 286672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman USB_CTRL_SET_TIMEOUT) != 0x11) { 286772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EIO; 286872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 286972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 287072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (config_data[if_num]) { 287172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x0: 287272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0; 287372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 287472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x1: 287572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_DIAG; 287672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 287772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x2: 287872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_GPS; 287972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 288072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x3: 288172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_GPS_CONTROL; 288272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 288372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x4: 288472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_APP; 288572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 288672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x5: 288772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_APP2; 288872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 288972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x6: 289072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_CONTROL; 289172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 289272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x7: 289372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_NETWORK; 289472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 289572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x8: 289672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_MODEM; 289772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 289872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0x9: 289972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_MSD; 290072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 290172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0xa: 290272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_PCSC; 290372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 290472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case 0xb: 290572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = HSO_PORT_VOICE; 290672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 290772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 290872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 0; 290972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 291072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 291172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 291272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result |= HSO_INTF_BULK; 291372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 291472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (config_data[16] & 0x1) 291572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result |= HSO_INFO_CRC_BUG; 291672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 291772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 291872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 291972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 292072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called once for each interface upon device insertion */ 292172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_probe(struct usb_interface *interface, 292272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman const struct usb_device_id *id) 292372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 292472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int mux, i, if_num, port_spec; 292572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman unsigned char port_mask; 292672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev = NULL; 292772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_shared_int *shared_int; 292872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *tmp_dev = NULL; 292972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 293072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if_num = interface->altsetting->desc.bInterfaceNumber; 293172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 293272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Get the interface/port specification from either driver_info or from 293372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * the device itself */ 293472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (id->driver_info) 293572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_spec = ((u32 *)(id->driver_info))[if_num]; 293672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman else 293772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman port_spec = hso_get_config_data(interface); 293872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 293972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { 294072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman dev_err(&interface->dev, "Not our interface\n"); 294172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 294272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 294372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Check if we need to switch to alt interfaces prior to port 294472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * configuration */ 294572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (interface->num_altsetting > 1) 294672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_set_interface(interface_to_usbdev(interface), if_num, 1); 294772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman interface->needs_remote_wakeup = 1; 294872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 294972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Allocate new hso device(s) */ 295072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman switch (port_spec & HSO_INTF_MASK) { 295172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_INTF_MUX: 295272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { 295372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Create the network device */ 295472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!disable_net) { 29550de8ca597d7b449e9e7ce7af138944acf06c8f05Jan Dumon hso_dev = hso_create_net_device(interface, 29560de8ca597d7b449e9e7ce7af138944acf06c8f05Jan Dumon port_spec); 295772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 295872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 295972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tmp_dev = hso_dev; 296072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 296172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 296272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 296372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_get_mux_ports(interface, &port_mask)) 296472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* TODO: de-allocate everything */ 296572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 296672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 296772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman shared_int = hso_create_shared_int(interface); 296872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!shared_int) 296972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 297072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 297172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) { 297272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (port_mask & i) { 297372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = hso_create_mux_serial_device( 297472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman interface, i, shared_int); 297572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 297672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 297772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 297872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 297972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 298072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (tmp_dev) 298172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = tmp_dev; 298272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 298372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 298472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman case HSO_INTF_BULK: 298572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* It's a regular bulk interface */ 29868e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { 29878e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben if (!disable_net) 29888e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben hso_dev = 29898e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben hso_create_net_device(interface, port_spec); 29908e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben } else { 299172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = 299272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_create_bulk_serial_device(interface, port_spec); 29938e65c0ece6f2aa732f9b755331869c67aeb1c7f6Filip Aben } 299472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev) 299572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 299672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman break; 299772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman default: 299872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto exit; 299972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 300072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 300172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* save our data pointer in this device */ 300272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_set_intfdata(interface, hso_dev); 300372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 300472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 300572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 300672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanexit: 300772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_interface(interface); 300872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENODEV; 300972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 301072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 301172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* device removed, cleaning up */ 301272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_disconnect(struct usb_interface *interface) 301372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 301472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_interface(interface); 301572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 301672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* remove reference of our private data */ 301772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_set_intfdata(interface, NULL); 301872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 301972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 302072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void async_get_intf(struct work_struct *data) 302172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 302272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev = 302372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman container_of(data, struct hso_device, async_get_intf); 302472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_autopm_get_interface(hso_dev->interface); 302572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 302672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 302772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void async_put_intf(struct work_struct *data) 302872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 302972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev = 303072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman container_of(data, struct hso_device, async_put_intf); 303172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_autopm_put_interface(hso_dev->interface); 303272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 303372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 303472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_get_activity(struct hso_device *hso_dev) 303572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 303672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev->usb->state == USB_STATE_SUSPENDED) { 303772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!hso_dev->is_active) { 303872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->is_active = 1; 303972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman schedule_work(&hso_dev->async_get_intf); 304072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 304172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 304272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 304372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev->usb->state != USB_STATE_CONFIGURED) 304472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EAGAIN; 304572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 304672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_mark_last_busy(hso_dev->usb); 304772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 304872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 304972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 305072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 305172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_put_activity(struct hso_device *hso_dev) 305272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 305372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev->usb->state != USB_STATE_SUSPENDED) { 305472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (hso_dev->is_active) { 305572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->is_active = 0; 305672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman schedule_work(&hso_dev->async_put_intf); 305772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -EAGAIN; 305872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 305972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 306072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->is_active = 0; 306172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 306272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 306372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 306472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called by kernel when we need to suspend device */ 306572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_suspend(struct usb_interface *iface, pm_message_t message) 306672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 306772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i, result; 306872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 306972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Stop all serial ports */ 307072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { 307172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial_table[i] && (serial_table[i]->interface == iface)) { 307272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = hso_stop_serial_device(serial_table[i]); 307372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 307472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 307572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 307672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 307772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 307872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Stop all network ports */ 307972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { 308072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (network_table[i] && 308172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (network_table[i]->interface == iface)) { 308272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = hso_stop_net_device(network_table[i]); 308372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 308472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 308572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 308672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 308772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 308872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanout: 308972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 309072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 309172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 309272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* called by kernel when we need to resume device */ 309372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_resume(struct usb_interface *iface) 309472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 309572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i, result = 0; 309672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_net *hso_net; 309772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 309872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Start all serial ports */ 309972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { 310072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (serial_table[i] && (serial_table[i]->interface == iface)) { 310172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (dev2ser(serial_table[i])->open_count) { 310272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = 310372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_start_serial_device(serial_table[i], GFP_NOIO); 310472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_kick_transmit(dev2ser(serial_table[i])); 310572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 310672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman goto out; 310772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 310872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 310972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 311072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 311172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Start all network ports */ 311272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { 311372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (network_table[i] && 311472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman (network_table[i]->interface == iface)) { 311572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_net = dev2net(network_table[i]); 311689930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow if (hso_net->flags & IFF_UP) { 311789930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow /* First transmit any lingering data, 311889930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow then restart the device. */ 311989930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow if (hso_net->skb_tx_buf) { 312089930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow dev_dbg(&iface->dev, 312189930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow "Transmitting" 312289930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow " lingering data\n"); 312389930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow hso_net_start_xmit(hso_net->skb_tx_buf, 312489930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow hso_net->net); 312589930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow hso_net->skb_tx_buf = NULL; 312689930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow } 312789930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow result = hso_start_net_device(network_table[i]); 312889930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow if (result) 312989930b7b5e3e9bfe9c6ec5e19920451c8f5d9088Denis Joseph Barrow goto out; 313072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 313172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 313272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 313372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 313472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanout: 313572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 313672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 313772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 313868a351c501ad22077a969df157cd13367cb43a40Jan Dumonstatic void reset_device(struct work_struct *data) 313968a351c501ad22077a969df157cd13367cb43a40Jan Dumon{ 314068a351c501ad22077a969df157cd13367cb43a40Jan Dumon struct hso_device *hso_dev = 314168a351c501ad22077a969df157cd13367cb43a40Jan Dumon container_of(data, struct hso_device, reset_device); 314268a351c501ad22077a969df157cd13367cb43a40Jan Dumon struct usb_device *usb = hso_dev->usb; 314368a351c501ad22077a969df157cd13367cb43a40Jan Dumon int result; 314468a351c501ad22077a969df157cd13367cb43a40Jan Dumon 314568a351c501ad22077a969df157cd13367cb43a40Jan Dumon if (hso_dev->usb_gone) { 314668a351c501ad22077a969df157cd13367cb43a40Jan Dumon D1("No reset during disconnect\n"); 314768a351c501ad22077a969df157cd13367cb43a40Jan Dumon } else { 314868a351c501ad22077a969df157cd13367cb43a40Jan Dumon result = usb_lock_device_for_reset(usb, hso_dev->interface); 314968a351c501ad22077a969df157cd13367cb43a40Jan Dumon if (result < 0) 315068a351c501ad22077a969df157cd13367cb43a40Jan Dumon D1("unable to lock device for reset: %d\n", result); 315168a351c501ad22077a969df157cd13367cb43a40Jan Dumon else { 315268a351c501ad22077a969df157cd13367cb43a40Jan Dumon usb_reset_device(usb); 315368a351c501ad22077a969df157cd13367cb43a40Jan Dumon usb_unlock_device(usb); 315468a351c501ad22077a969df157cd13367cb43a40Jan Dumon } 315568a351c501ad22077a969df157cd13367cb43a40Jan Dumon } 315668a351c501ad22077a969df157cd13367cb43a40Jan Dumon} 315768a351c501ad22077a969df157cd13367cb43a40Jan Dumon 315872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_serial_ref_free(struct kref *ref) 315972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 316072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); 316172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 316272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_serial_device(hso_dev); 316372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 316472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 316572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void hso_free_interface(struct usb_interface *interface) 316672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 316772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct hso_serial *hso_dev; 3168e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox struct tty_struct *tty; 316972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 317072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 317172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { 31728e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (serial_table[i] && 31738e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches (serial_table[i]->interface == interface)) { 317472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev = dev2ser(serial_table[i]); 3175e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_lock_irq(&hso_dev->serial_lock); 3176e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty = tty_kref_get(hso_dev->tty); 3177e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox spin_unlock_irq(&hso_dev->serial_lock); 3178e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox if (tty) 3179e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_hangup(tty); 3180ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_lock(&hso_dev->parent->mutex); 3181e136e3036bf27569dbfeae245cc09c7167cdc749Alan Cox tty_kref_put(tty); 318272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_dev->parent->usb_gone = 1; 3183ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller mutex_unlock(&hso_dev->parent->mutex); 3184ab153d84d9609b4e6f53632a6f14b882e866cb47David S. Miller kref_put(&serial_table[i]->ref, hso_serial_ref_free); 318572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 318672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 318772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 318872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { 31898e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if (network_table[i] && 31908e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches (network_table[i]->interface == interface)) { 319172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct rfkill *rfk = dev2net(network_table[i])->rfkill; 319272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* hso_stop_net_device doesn't stop the net queue since 319372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman * traffic needs to start it again when suspended */ 319472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman netif_stop_queue(dev2net(network_table[i])->net); 319572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_stop_net_device(network_table[i]); 319672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman cancel_work_sync(&network_table[i]->async_put_intf); 319772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman cancel_work_sync(&network_table[i]->async_get_intf); 319819d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg if (rfk) { 319972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman rfkill_unregister(rfk); 320019d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg rfkill_destroy(rfk); 320119d337dff95cbf76edd3ad95c0cee2732c3e1ec5Johannes Berg } 320272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman hso_free_net_device(network_table[i]); 320372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 320472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 320572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 320672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 320772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Helper functions */ 320872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 320972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Get the endpoint ! */ 321072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, 321172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int type, int dir) 321272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 321372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 321472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_host_interface *iface = intf->cur_altsetting; 321572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_endpoint_descriptor *endp; 321672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 321772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < iface->desc.bNumEndpoints; i++) { 321872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman endp = &iface->endpoint[i].desc; 321972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) && 3220f201a8a4511a4c9953189924df3c880207194b41Julia Lawall (usb_endpoint_type(endp) == type)) 322172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return endp; 322272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 322372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 322472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return NULL; 322572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 322672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 322772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Get the byte that describes which ports are enabled */ 322872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports) 322972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 323072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 323172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_host_interface *iface = intf->cur_altsetting; 323272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 323372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (iface->extralen == 3) { 323472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman *ports = iface->extra[2]; 323572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 323672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 323772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 323872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < iface->desc.bNumEndpoints; i++) { 323972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (iface->endpoint[i].extralen == 3) { 324072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman *ports = iface->endpoint[i].extra[2]; 324172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 324272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 324372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 324472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 324572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -1; 324672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 324772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 324872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* interrupt urb needs to be submitted, used for serial read of muxed port */ 324972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int, 325072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman struct usb_device *usb, gfp_t gfp) 325172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 325272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 325372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 325472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_fill_int_urb(shared_int->shared_intr_urb, usb, 325572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_rcvintpipe(usb, 325672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman shared_int->intr_endp->bEndpointAddress & 0x7F), 325772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman shared_int->shared_intr_buf, 3258d9ced80d1084758772d350ac66b1ad0eeefc7f95Jan Dumon 1, 325972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman intr_callback, shared_int, 326072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman shared_int->intr_endp->bInterval); 326172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 326272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_submit_urb(shared_int->shared_intr_urb, gfp); 326372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) 32648a5c9c4932ad1fbe9daa501e89a7357a2804e3faJan Dumon dev_warn(&usb->dev, "%s failed mux_intr_urb %d\n", __func__, 326572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result); 326672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 326772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 326872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 326972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 327072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* operations setup of the serial interface */ 32716c59f56978c3dffd447176d218bc5852842c9ce9Greg Kroah-Hartmanstatic const struct tty_operations hso_serial_ops = { 327272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .open = hso_serial_open, 327372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .close = hso_serial_close, 327472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .write = hso_serial_write, 327572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .write_room = hso_serial_write_room, 3276542f54823614915780c3459b0e6062f06c0c0f99Denis Joseph Barrow .ioctl = hso_serial_ioctl, 327772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .set_termios = hso_serial_set_termios, 327872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .chars_in_buffer = hso_serial_chars_in_buffer, 327972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .tiocmget = hso_serial_tiocmget, 328072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .tiocmset = hso_serial_tiocmset, 32810bca1b913affbd7e2fdaffee62a499659a466eb5Alan Cox .get_icount = hso_get_count, 32828ef5ba63b94b04b182ac4a6009dbbf1406beb3c5Denis Joseph Barrow .unthrottle = hso_unthrottle 328372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 328472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 328572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic struct usb_driver hso_driver = { 328672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .name = driver_name, 328772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .probe = hso_probe, 328872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .disconnect = hso_disconnect, 328972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .id_table = hso_ids, 329072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .suspend = hso_suspend, 329172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .resume = hso_resume, 32929c8f92aed16dbd1924910f3305f5992a4f29fe2aDenis Joseph Barrow .reset_resume = hso_resume, 329372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman .supports_autosuspend = 1, 329472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman}; 329572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 329672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic int __init hso_init(void) 329772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 329872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int i; 329972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman int result; 330072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 330172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* put it in the log */ 330272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_INFO "hso: %s\n", version); 330372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 330472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* Initialise the serial table semaphore and table */ 330572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman spin_lock_init(&serial_table_lock); 330672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) 330772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman serial_table[i] = NULL; 330872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 330972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* allocate our driver using the proper amount of supported minors */ 331072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); 331172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (!tty_drv) 331272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return -ENOMEM; 331372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 331472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* fill in all needed values */ 331572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->magic = TTY_DRIVER_MAGIC; 331672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->owner = THIS_MODULE; 331772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->driver_name = driver_name; 331872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->name = tty_filename; 331972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 332072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* if major number is provided as parameter, use that one */ 332172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (tty_major) 332272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->major = tty_major; 332372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 332472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->minor_start = 0; 332572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->num = HSO_SERIAL_TTY_MINORS; 332672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->type = TTY_DRIVER_TYPE_SERIAL; 332772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->subtype = SERIAL_TYPE_NORMAL; 332872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 332972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_drv->init_termios = tty_std_termios; 3330ac9720c37e8795317e8be3adad63cb0d5522a640Alan Cox hso_init_termios(&tty_drv->init_termios); 333172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_set_operations(tty_drv, &hso_serial_ops); 333272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 333372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* register the tty driver */ 333472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = tty_register_driver(tty_drv); 333572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 333672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", 333772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman __func__, result); 333872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 333972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 334072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 334172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* register this module as an usb driver */ 334272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result = usb_register(&hso_driver); 334372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman if (result) { 334472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_ERR "Could not register hso driver? error: %d\n", 334572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman result); 334672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* cleanup serial interface */ 334772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_unregister_driver(tty_drv); 334872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return result; 334972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman } 335072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 335172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* done */ 335272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman return 0; 335372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 335472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 335572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanstatic void __exit hso_exit(void) 335672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman{ 335772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman printk(KERN_INFO "hso: unloaded\n"); 335872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 335972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman tty_unregister_driver(tty_drv); 336072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman /* deregister the usb driver */ 336172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman usb_deregister(&hso_driver); 336272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman} 336372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 336472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* Module definitions */ 336572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanmodule_init(hso_init); 336672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanmodule_exit(hso_exit); 336772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 336872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_AUTHOR(MOD_AUTHOR); 336972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_DESCRIPTION(MOD_DESCRIPTION); 337072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_LICENSE(MOD_LICENSE); 337172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 337272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* change the debug level (eg: insmod hso.ko debug=0x04) */ 337372dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]"); 337472dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanmodule_param(debug, int, S_IRUGO | S_IWUSR); 337572dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 337672dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* set the major tty number (eg: insmod hso.ko tty_major=245) */ 337772dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_PARM_DESC(tty_major, "Set the major tty number"); 337872dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanmodule_param(tty_major, int, S_IRUGO | S_IWUSR); 337972dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman 338072dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartman/* disable network interface (eg: insmod hso.ko disable_net=1) */ 338172dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-HartmanMODULE_PARM_DESC(disable_net, "Disable the network interface"); 338272dc1c096c7051a48ab1dbb12f71976656b55eb5Greg Kroah-Hartmanmodule_param(disable_net, int, S_IRUGO | S_IWUSR); 3383