diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/net/usb/hso.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/net/usb/hso.c | 3380 |
1 files changed, 0 insertions, 3380 deletions
diff --git a/ANDROID_3.4.5/drivers/net/usb/hso.c b/ANDROID_3.4.5/drivers/net/usb/hso.c deleted file mode 100644 index 2d2a6882..00000000 --- a/ANDROID_3.4.5/drivers/net/usb/hso.c +++ /dev/null @@ -1,3380 +0,0 @@ -/****************************************************************************** - * - * Driver for Option High Speed Mobile Devices. - * - * Copyright (C) 2008 Option International - * Filip Aben <f.aben@option.com> - * Denis Joseph Barrow <d.barow@option.com> - * Jan Dumon <j.dumon@option.com> - * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) - * <ajb@spheresystems.co.uk> - * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de> - * Copyright (C) 2008 Novell, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA - * - * - *****************************************************************************/ - -/****************************************************************************** - * - * Description of the device: - * - * Interface 0: Contains the IP network interface on the bulk end points. - * The multiplexed serial ports are using the interrupt and - * control endpoints. - * Interrupt contains a bitmap telling which multiplexed - * serialport needs servicing. - * - * Interface 1: Diagnostics port, uses bulk only, do not submit urbs until the - * port is opened, as this have a huge impact on the network port - * throughput. - * - * Interface 2: Standard modem interface - circuit switched interface, this - * can be used to make a standard ppp connection however it - * should not be used in conjunction with the IP network interface - * enabled for USB performance reasons i.e. if using this set - * ideally disable_net=1. - * - *****************************************************************************/ - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/module.h> -#include <linux/ethtool.h> -#include <linux/usb.h> -#include <linux/timer.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> -#include <linux/kmod.h> -#include <linux/rfkill.h> -#include <linux/ip.h> -#include <linux/uaccess.h> -#include <linux/usb/cdc.h> -#include <net/arp.h> -#include <asm/byteorder.h> -#include <linux/serial_core.h> -#include <linux/serial.h> - - -#define MOD_AUTHOR "Option Wireless" -#define MOD_DESCRIPTION "USB High Speed Option driver" -#define MOD_LICENSE "GPL" - -#define HSO_MAX_NET_DEVICES 10 -#define HSO__MAX_MTU 2048 -#define DEFAULT_MTU 1500 -#define DEFAULT_MRU 1500 - -#define CTRL_URB_RX_SIZE 1024 -#define CTRL_URB_TX_SIZE 64 - -#define BULK_URB_RX_SIZE 4096 -#define BULK_URB_TX_SIZE 8192 - -#define MUX_BULK_RX_BUF_SIZE HSO__MAX_MTU -#define MUX_BULK_TX_BUF_SIZE HSO__MAX_MTU -#define MUX_BULK_RX_BUF_COUNT 4 -#define USB_TYPE_OPTION_VENDOR 0x20 - -/* These definitions are used with the struct hso_net flags element */ -/* - use *_bit operations on it. (bit indices not values.) */ -#define HSO_NET_RUNNING 0 - -#define HSO_NET_TX_TIMEOUT (HZ*10) - -#define HSO_SERIAL_MAGIC 0x48534f31 - -/* Number of ttys to handle */ -#define HSO_SERIAL_TTY_MINORS 256 - -#define MAX_RX_URBS 2 - -static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty) -{ - if (tty) - return tty->driver_data; - return NULL; -} - -/*****************************************************************************/ -/* Debugging functions */ -/*****************************************************************************/ -#define D__(lvl_, fmt, arg...) \ - do { \ - printk(lvl_ "[%d:%s]: " fmt "\n", \ - __LINE__, __func__, ## arg); \ - } while (0) - -#define D_(lvl, args...) \ - do { \ - if (lvl & debug) \ - D__(KERN_INFO, args); \ - } while (0) - -#define D1(args...) D_(0x01, ##args) -#define D2(args...) D_(0x02, ##args) -#define D3(args...) D_(0x04, ##args) -#define D4(args...) D_(0x08, ##args) -#define D5(args...) D_(0x10, ##args) - -/*****************************************************************************/ -/* Enumerators */ -/*****************************************************************************/ -enum pkt_parse_state { - WAIT_IP, - WAIT_DATA, - WAIT_SYNC -}; - -/*****************************************************************************/ -/* Structs */ -/*****************************************************************************/ - -struct hso_shared_int { - struct usb_endpoint_descriptor *intr_endp; - void *shared_intr_buf; - struct urb *shared_intr_urb; - struct usb_device *usb; - int use_count; - int ref_count; - struct mutex shared_int_lock; -}; - -struct hso_net { - struct hso_device *parent; - struct net_device *net; - struct rfkill *rfkill; - - struct usb_endpoint_descriptor *in_endp; - struct usb_endpoint_descriptor *out_endp; - - struct urb *mux_bulk_rx_urb_pool[MUX_BULK_RX_BUF_COUNT]; - struct urb *mux_bulk_tx_urb; - void *mux_bulk_rx_buf_pool[MUX_BULK_RX_BUF_COUNT]; - void *mux_bulk_tx_buf; - - struct sk_buff *skb_rx_buf; - struct sk_buff *skb_tx_buf; - - enum pkt_parse_state rx_parse_state; - spinlock_t net_lock; - - unsigned short rx_buf_size; - unsigned short rx_buf_missing; - struct iphdr rx_ip_hdr; - - unsigned long flags; -}; - -enum rx_ctrl_state{ - RX_IDLE, - RX_SENT, - RX_PENDING -}; - -#define BM_REQUEST_TYPE (0xa1) -#define B_NOTIFICATION (0x20) -#define W_VALUE (0x0) -#define W_INDEX (0x2) -#define W_LENGTH (0x2) - -#define B_OVERRUN (0x1<<6) -#define B_PARITY (0x1<<5) -#define B_FRAMING (0x1<<4) -#define B_RING_SIGNAL (0x1<<3) -#define B_BREAK (0x1<<2) -#define B_TX_CARRIER (0x1<<1) -#define B_RX_CARRIER (0x1<<0) - -struct hso_serial_state_notification { - u8 bmRequestType; - u8 bNotification; - u16 wValue; - u16 wIndex; - u16 wLength; - u16 UART_state_bitmap; -} __packed; - -struct hso_tiocmget { - struct mutex mutex; - wait_queue_head_t waitq; - int intr_completed; - struct usb_endpoint_descriptor *endp; - struct urb *urb; - struct hso_serial_state_notification serial_state_notification; - u16 prev_UART_state_bitmap; - struct uart_icount icount; -}; - - -struct hso_serial { - struct hso_device *parent; - int magic; - u8 minor; - - struct hso_shared_int *shared_int; - - /* rx/tx urb could be either a bulk urb or a control urb depending - on which serial port it is used on. */ - struct urb *rx_urb[MAX_RX_URBS]; - u8 num_rx_urbs; - u8 *rx_data[MAX_RX_URBS]; - u16 rx_data_length; /* should contain allocated length */ - - struct urb *tx_urb; - u8 *tx_data; - u8 *tx_buffer; - u16 tx_data_length; /* should contain allocated length */ - u16 tx_data_count; - u16 tx_buffer_count; - struct usb_ctrlrequest ctrl_req_tx; - struct usb_ctrlrequest ctrl_req_rx; - - struct usb_endpoint_descriptor *in_endp; - struct usb_endpoint_descriptor *out_endp; - - enum rx_ctrl_state rx_state; - u8 rts_state; - u8 dtr_state; - unsigned tx_urb_used:1; - - /* from usb_serial_port */ - struct tty_struct *tty; - int open_count; - spinlock_t serial_lock; - - int (*write_data) (struct hso_serial *serial); - struct hso_tiocmget *tiocmget; - /* Hacks required to get flow control - * working on the serial receive buffers - * so as not to drop characters on the floor. - */ - int curr_rx_urb_idx; - u16 curr_rx_urb_offset; - u8 rx_urb_filled[MAX_RX_URBS]; - struct tasklet_struct unthrottle_tasklet; - struct work_struct retry_unthrottle_workqueue; -}; - -struct hso_device { - union { - struct hso_serial *dev_serial; - struct hso_net *dev_net; - } port_data; - - u32 port_spec; - - u8 is_active; - u8 usb_gone; - struct work_struct async_get_intf; - struct work_struct async_put_intf; - struct work_struct reset_device; - - struct usb_device *usb; - struct usb_interface *interface; - - struct device *dev; - struct kref ref; - struct mutex mutex; -}; - -/* Type of interface */ -#define HSO_INTF_MASK 0xFF00 -#define HSO_INTF_MUX 0x0100 -#define HSO_INTF_BULK 0x0200 - -/* Type of port */ -#define HSO_PORT_MASK 0xFF -#define HSO_PORT_NO_PORT 0x0 -#define HSO_PORT_CONTROL 0x1 -#define HSO_PORT_APP 0x2 -#define HSO_PORT_GPS 0x3 -#define HSO_PORT_PCSC 0x4 -#define HSO_PORT_APP2 0x5 -#define HSO_PORT_GPS_CONTROL 0x6 -#define HSO_PORT_MSD 0x7 -#define HSO_PORT_VOICE 0x8 -#define HSO_PORT_DIAG2 0x9 -#define HSO_PORT_DIAG 0x10 -#define HSO_PORT_MODEM 0x11 -#define HSO_PORT_NETWORK 0x12 - -/* Additional device info */ -#define HSO_INFO_MASK 0xFF000000 -#define HSO_INFO_CRC_BUG 0x01000000 - -/*****************************************************************************/ -/* Prototypes */ -/*****************************************************************************/ -/* Serial driver functions */ -static int hso_serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void ctrl_callback(struct urb *urb); -static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial); -static void hso_kick_transmit(struct hso_serial *serial); -/* Helper functions */ -static int hso_mux_submit_intr_urb(struct hso_shared_int *mux_int, - struct usb_device *usb, gfp_t gfp); -static void handle_usb_error(int status, const char *function, - struct hso_device *hso_dev); -static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, - int type, int dir); -static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports); -static void hso_free_interface(struct usb_interface *intf); -static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags); -static int hso_stop_serial_device(struct hso_device *hso_dev); -static int hso_start_net_device(struct hso_device *hso_dev); -static void hso_free_shared_int(struct hso_shared_int *shared_int); -static int hso_stop_net_device(struct hso_device *hso_dev); -static void hso_serial_ref_free(struct kref *ref); -static void hso_std_serial_read_bulk_callback(struct urb *urb); -static int hso_mux_serial_read(struct hso_serial *serial); -static void async_get_intf(struct work_struct *data); -static void async_put_intf(struct work_struct *data); -static int hso_put_activity(struct hso_device *hso_dev); -static int hso_get_activity(struct hso_device *hso_dev); -static void tiocmget_intr_callback(struct urb *urb); -static void reset_device(struct work_struct *data); -/*****************************************************************************/ -/* Helping functions */ -/*****************************************************************************/ - -/* #define DEBUG */ - -static inline struct hso_net *dev2net(struct hso_device *hso_dev) -{ - return hso_dev->port_data.dev_net; -} - -static inline struct hso_serial *dev2ser(struct hso_device *hso_dev) -{ - return hso_dev->port_data.dev_serial; -} - -/* Debugging functions */ -#ifdef DEBUG -static void dbg_dump(int line_count, const char *func_name, unsigned char *buf, - unsigned int len) -{ - static char name[255]; - - sprintf(name, "hso[%d:%s]", line_count, func_name); - print_hex_dump_bytes(name, DUMP_PREFIX_NONE, buf, len); -} - -#define DUMP(buf_, len_) \ - dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_) - -#define DUMP1(buf_, len_) \ - do { \ - if (0x01 & debug) \ - DUMP(buf_, len_); \ - } while (0) -#else -#define DUMP(buf_, len_) -#define DUMP1(buf_, len_) -#endif - -/* module parameters */ -static int debug; -static int tty_major; -static int disable_net; - -/* driver info */ -static const char driver_name[] = "hso"; -static const char tty_filename[] = "ttyHS"; -static const char *version = __FILE__ ": " MOD_AUTHOR; -/* the usb driver itself (registered in hso_init) */ -static struct usb_driver hso_driver; -/* serial structures */ -static struct tty_driver *tty_drv; -static struct hso_device *serial_table[HSO_SERIAL_TTY_MINORS]; -static struct hso_device *network_table[HSO_MAX_NET_DEVICES]; -static spinlock_t serial_table_lock; - -static const s32 default_port_spec[] = { - HSO_INTF_MUX | HSO_PORT_NETWORK, - HSO_INTF_BULK | HSO_PORT_DIAG, - HSO_INTF_BULK | HSO_PORT_MODEM, - 0 -}; - -static const s32 icon321_port_spec[] = { - HSO_INTF_MUX | HSO_PORT_NETWORK, - HSO_INTF_BULK | HSO_PORT_DIAG2, - HSO_INTF_BULK | HSO_PORT_MODEM, - HSO_INTF_BULK | HSO_PORT_DIAG, - 0 -}; - -#define default_port_device(vendor, product) \ - USB_DEVICE(vendor, product), \ - .driver_info = (kernel_ulong_t)default_port_spec - -#define icon321_port_device(vendor, product) \ - USB_DEVICE(vendor, product), \ - .driver_info = (kernel_ulong_t)icon321_port_spec - -/* list of devices we support */ -static const struct usb_device_id hso_ids[] = { - {default_port_device(0x0af0, 0x6711)}, - {default_port_device(0x0af0, 0x6731)}, - {default_port_device(0x0af0, 0x6751)}, - {default_port_device(0x0af0, 0x6771)}, - {default_port_device(0x0af0, 0x6791)}, - {default_port_device(0x0af0, 0x6811)}, - {default_port_device(0x0af0, 0x6911)}, - {default_port_device(0x0af0, 0x6951)}, - {default_port_device(0x0af0, 0x6971)}, - {default_port_device(0x0af0, 0x7011)}, - {default_port_device(0x0af0, 0x7031)}, - {default_port_device(0x0af0, 0x7051)}, - {default_port_device(0x0af0, 0x7071)}, - {default_port_device(0x0af0, 0x7111)}, - {default_port_device(0x0af0, 0x7211)}, - {default_port_device(0x0af0, 0x7251)}, - {default_port_device(0x0af0, 0x7271)}, - {default_port_device(0x0af0, 0x7311)}, - {default_port_device(0x0af0, 0xc031)}, /* Icon-Edge */ - {icon321_port_device(0x0af0, 0xd013)}, /* Module HSxPA */ - {icon321_port_device(0x0af0, 0xd031)}, /* Icon-321 */ - {icon321_port_device(0x0af0, 0xd033)}, /* Icon-322 */ - {USB_DEVICE(0x0af0, 0x7301)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7361)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7381)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ - {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ - {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ - {USB_DEVICE(0x0af0, 0x7701)}, - {USB_DEVICE(0x0af0, 0x7706)}, - {USB_DEVICE(0x0af0, 0x7801)}, - {USB_DEVICE(0x0af0, 0x7901)}, - {USB_DEVICE(0x0af0, 0x7A01)}, - {USB_DEVICE(0x0af0, 0x7A05)}, - {USB_DEVICE(0x0af0, 0x8200)}, - {USB_DEVICE(0x0af0, 0x8201)}, - {USB_DEVICE(0x0af0, 0x8300)}, - {USB_DEVICE(0x0af0, 0x8302)}, - {USB_DEVICE(0x0af0, 0x8304)}, - {USB_DEVICE(0x0af0, 0x8400)}, - {USB_DEVICE(0x0af0, 0x8600)}, - {USB_DEVICE(0x0af0, 0x8800)}, - {USB_DEVICE(0x0af0, 0x8900)}, - {USB_DEVICE(0x0af0, 0x9000)}, - {USB_DEVICE(0x0af0, 0xd035)}, - {USB_DEVICE(0x0af0, 0xd055)}, - {USB_DEVICE(0x0af0, 0xd155)}, - {USB_DEVICE(0x0af0, 0xd255)}, - {USB_DEVICE(0x0af0, 0xd057)}, - {USB_DEVICE(0x0af0, 0xd157)}, - {USB_DEVICE(0x0af0, 0xd257)}, - {USB_DEVICE(0x0af0, 0xd357)}, - {USB_DEVICE(0x0af0, 0xd058)}, - {USB_DEVICE(0x0af0, 0xc100)}, - {} -}; -MODULE_DEVICE_TABLE(usb, hso_ids); - -/* Sysfs attribute */ -static ssize_t hso_sysfs_show_porttype(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct hso_device *hso_dev = dev_get_drvdata(dev); - char *port_name; - - if (!hso_dev) - return 0; - - switch (hso_dev->port_spec & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - port_name = "Control"; - break; - case HSO_PORT_APP: - port_name = "Application"; - break; - case HSO_PORT_APP2: - port_name = "Application2"; - break; - case HSO_PORT_GPS: - port_name = "GPS"; - break; - case HSO_PORT_GPS_CONTROL: - port_name = "GPS Control"; - break; - case HSO_PORT_PCSC: - port_name = "PCSC"; - break; - case HSO_PORT_DIAG: - port_name = "Diagnostic"; - break; - case HSO_PORT_DIAG2: - port_name = "Diagnostic2"; - break; - case HSO_PORT_MODEM: - port_name = "Modem"; - break; - case HSO_PORT_NETWORK: - port_name = "Network"; - break; - default: - port_name = "Unknown"; - break; - } - - return sprintf(buf, "%s\n", port_name); -} -static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL); - -static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb) -{ - int idx; - - for (idx = 0; idx < serial->num_rx_urbs; idx++) - if (serial->rx_urb[idx] == urb) - return idx; - dev_err(serial->parent->dev, "hso_urb_to_index failed\n"); - return -1; -} - -/* converts mux value to a port spec value */ -static u32 hso_mux_to_port(int mux) -{ - u32 result; - - switch (mux) { - case 0x1: - result = HSO_PORT_CONTROL; - break; - case 0x2: - result = HSO_PORT_APP; - break; - case 0x4: - result = HSO_PORT_PCSC; - break; - case 0x8: - result = HSO_PORT_GPS; - break; - case 0x10: - result = HSO_PORT_APP2; - break; - default: - result = HSO_PORT_NO_PORT; - } - return result; -} - -/* converts port spec value to a mux value */ -static u32 hso_port_to_mux(int port) -{ - u32 result; - - switch (port & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - result = 0x0; - break; - case HSO_PORT_APP: - result = 0x1; - break; - case HSO_PORT_PCSC: - result = 0x2; - break; - case HSO_PORT_GPS: - result = 0x3; - break; - case HSO_PORT_APP2: - result = 0x4; - break; - default: - result = 0x0; - } - return result; -} - -static struct hso_serial *get_serial_by_shared_int_and_type( - struct hso_shared_int *shared_int, - int mux) -{ - int i, port; - - port = hso_mux_to_port(mux); - - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && - (dev2ser(serial_table[i])->shared_int == shared_int) && - ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { - return dev2ser(serial_table[i]); - } - } - - return NULL; -} - -static struct hso_serial *get_serial_by_index(unsigned index) -{ - struct hso_serial *serial = NULL; - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - if (serial_table[index]) - serial = dev2ser(serial_table[index]); - spin_unlock_irqrestore(&serial_table_lock, flags); - - return serial; -} - -static int get_free_serial_index(void) -{ - int index; - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) { - if (serial_table[index] == NULL) { - spin_unlock_irqrestore(&serial_table_lock, flags); - return index; - } - } - spin_unlock_irqrestore(&serial_table_lock, flags); - - printk(KERN_ERR "%s: no free serial devices in table\n", __func__); - return -1; -} - -static void set_serial_by_index(unsigned index, struct hso_serial *serial) -{ - unsigned long flags; - - spin_lock_irqsave(&serial_table_lock, flags); - if (serial) - serial_table[index] = serial->parent; - else - serial_table[index] = NULL; - spin_unlock_irqrestore(&serial_table_lock, flags); -} - -static void handle_usb_error(int status, const char *function, - struct hso_device *hso_dev) -{ - char *explanation; - - switch (status) { - case -ENODEV: - explanation = "no device"; - break; - case -ENOENT: - explanation = "endpoint not enabled"; - break; - case -EPIPE: - explanation = "endpoint stalled"; - break; - case -ENOSPC: - explanation = "not enough bandwidth"; - break; - case -ESHUTDOWN: - explanation = "device disabled"; - break; - case -EHOSTUNREACH: - explanation = "device suspended"; - break; - case -EINVAL: - case -EAGAIN: - case -EFBIG: - case -EMSGSIZE: - explanation = "internal error"; - break; - case -EILSEQ: - case -EPROTO: - case -ETIME: - case -ETIMEDOUT: - explanation = "protocol error"; - if (hso_dev) - schedule_work(&hso_dev->reset_device); - break; - default: - explanation = "unknown status"; - break; - } - - /* log a meaningful explanation of an USB status */ - D1("%s: received USB status - %s (%d)", function, explanation, status); -} - -/* Network interface functions */ - -/* called when net interface is brought up by ifconfig */ -static int hso_net_open(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - unsigned long flags = 0; - - if (!odev) { - dev_err(&net->dev, "No net device !\n"); - return -ENODEV; - } - - odev->skb_tx_buf = NULL; - - /* setup environment */ - spin_lock_irqsave(&odev->net_lock, flags); - odev->rx_parse_state = WAIT_IP; - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - spin_unlock_irqrestore(&odev->net_lock, flags); - - /* We are up and running. */ - set_bit(HSO_NET_RUNNING, &odev->flags); - hso_start_net_device(odev->parent); - - /* Tell the kernel we are ready to start receiving from it */ - netif_start_queue(net); - - return 0; -} - -/* called when interface is brought down by ifconfig */ -static int hso_net_close(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - - /* we don't need the queue anymore */ - netif_stop_queue(net); - /* no longer running */ - clear_bit(HSO_NET_RUNNING, &odev->flags); - - hso_stop_net_device(odev->parent); - - /* done */ - return 0; -} - -/* USB tells is xmit done, we should start the netqueue again */ -static void write_bulk_callback(struct urb *urb) -{ - struct hso_net *odev = urb->context; - int status = urb->status; - - /* Sanity check */ - if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { - dev_err(&urb->dev->dev, "%s: device not running\n", __func__); - return; - } - - /* Do we still have a valid kernel network device? */ - if (!netif_device_present(odev->net)) { - dev_err(&urb->dev->dev, "%s: net device not present\n", - __func__); - return; - } - - /* log status, but don't act on it, we don't need to resubmit anything - * anyhow */ - if (status) - handle_usb_error(status, __func__, odev->parent); - - hso_put_activity(odev->parent); - - /* Tell the network interface we are ready for another frame */ - netif_wake_queue(odev->net); -} - -/* called by kernel when we need to transmit a packet */ -static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb, - struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - int result; - - /* Tell the kernel, "No more frames 'til we are done with this one." */ - netif_stop_queue(net); - if (hso_get_activity(odev->parent) == -EAGAIN) { - odev->skb_tx_buf = skb; - return NETDEV_TX_OK; - } - - /* log if asked */ - DUMP1(skb->data, skb->len); - /* Copy it from kernel memory to OUR memory */ - memcpy(odev->mux_bulk_tx_buf, skb->data, skb->len); - D1("len: %d/%d", skb->len, MUX_BULK_TX_BUF_SIZE); - - /* Fill in the URB for shipping it out. */ - usb_fill_bulk_urb(odev->mux_bulk_tx_urb, - odev->parent->usb, - usb_sndbulkpipe(odev->parent->usb, - odev->out_endp-> - bEndpointAddress & 0x7F), - odev->mux_bulk_tx_buf, skb->len, write_bulk_callback, - odev); - - /* Deal with the Zero Length packet problem, I hope */ - odev->mux_bulk_tx_urb->transfer_flags |= URB_ZERO_PACKET; - - /* Send the URB on its merry way. */ - result = usb_submit_urb(odev->mux_bulk_tx_urb, GFP_ATOMIC); - if (result) { - dev_warn(&odev->parent->interface->dev, - "failed mux_bulk_tx_urb %d\n", result); - net->stats.tx_errors++; - netif_start_queue(net); - } else { - net->stats.tx_packets++; - net->stats.tx_bytes += skb->len; - } - dev_kfree_skb(skb); - /* we're done */ - return NETDEV_TX_OK; -} - -static const struct ethtool_ops ops = { - .get_link = ethtool_op_get_link -}; - -/* called when a packet did not ack after watchdogtimeout */ -static void hso_net_tx_timeout(struct net_device *net) -{ - struct hso_net *odev = netdev_priv(net); - - if (!odev) - return; - - /* Tell syslog we are hosed. */ - dev_warn(&net->dev, "Tx timed out.\n"); - - /* Tear the waiting frame off the list */ - if (odev->mux_bulk_tx_urb && - (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) - usb_unlink_urb(odev->mux_bulk_tx_urb); - - /* Update statistics */ - net->stats.tx_errors++; -} - -/* make a real packet from the received USB buffer */ -static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, - unsigned int count, unsigned char is_eop) -{ - unsigned short temp_bytes; - unsigned short buffer_offset = 0; - unsigned short frame_len; - unsigned char *tmp_rx_buf; - - /* log if needed */ - D1("Rx %d bytes", count); - DUMP(ip_pkt, min(128, (int)count)); - - while (count) { - switch (odev->rx_parse_state) { - case WAIT_IP: - /* waiting for IP header. */ - /* wanted bytes - size of ip header */ - temp_bytes = - (count < - odev->rx_buf_missing) ? count : odev-> - rx_buf_missing; - - memcpy(((unsigned char *)(&odev->rx_ip_hdr)) + - odev->rx_buf_size, ip_pkt + buffer_offset, - temp_bytes); - - odev->rx_buf_size += temp_bytes; - buffer_offset += temp_bytes; - odev->rx_buf_missing -= temp_bytes; - count -= temp_bytes; - - if (!odev->rx_buf_missing) { - /* header is complete allocate an sk_buffer and - * continue to WAIT_DATA */ - frame_len = ntohs(odev->rx_ip_hdr.tot_len); - - if ((frame_len > DEFAULT_MRU) || - (frame_len < sizeof(struct iphdr))) { - dev_err(&odev->net->dev, - "Invalid frame (%d) length\n", - frame_len); - odev->rx_parse_state = WAIT_SYNC; - continue; - } - /* Allocate an sk_buff */ - odev->skb_rx_buf = netdev_alloc_skb(odev->net, - frame_len); - if (!odev->skb_rx_buf) { - /* We got no receive buffer. */ - D1("could not allocate memory"); - odev->rx_parse_state = WAIT_SYNC; - return; - } - - /* Copy what we got so far. make room for iphdr - * after tail. */ - tmp_rx_buf = - skb_put(odev->skb_rx_buf, - sizeof(struct iphdr)); - memcpy(tmp_rx_buf, (char *)&(odev->rx_ip_hdr), - sizeof(struct iphdr)); - - /* ETH_HLEN */ - odev->rx_buf_size = sizeof(struct iphdr); - - /* Filip actually use .tot_len */ - odev->rx_buf_missing = - frame_len - sizeof(struct iphdr); - odev->rx_parse_state = WAIT_DATA; - } - break; - - case WAIT_DATA: - temp_bytes = (count < odev->rx_buf_missing) - ? count : odev->rx_buf_missing; - - /* Copy the rest of the bytes that are left in the - * buffer into the waiting sk_buf. */ - /* Make room for temp_bytes after tail. */ - tmp_rx_buf = skb_put(odev->skb_rx_buf, temp_bytes); - memcpy(tmp_rx_buf, ip_pkt + buffer_offset, temp_bytes); - - odev->rx_buf_missing -= temp_bytes; - count -= temp_bytes; - buffer_offset += temp_bytes; - odev->rx_buf_size += temp_bytes; - if (!odev->rx_buf_missing) { - /* Packet is complete. Inject into stack. */ - /* We have IP packet here */ - odev->skb_rx_buf->protocol = cpu_to_be16(ETH_P_IP); - skb_reset_mac_header(odev->skb_rx_buf); - - /* Ship it off to the kernel */ - netif_rx(odev->skb_rx_buf); - /* No longer our buffer. */ - odev->skb_rx_buf = NULL; - - /* update out statistics */ - odev->net->stats.rx_packets++; - - odev->net->stats.rx_bytes += odev->rx_buf_size; - - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - odev->rx_parse_state = WAIT_IP; - } - break; - - case WAIT_SYNC: - D1(" W_S"); - count = 0; - break; - default: - D1(" "); - count--; - break; - } - } - - /* Recovery mechanism for WAIT_SYNC state. */ - if (is_eop) { - if (odev->rx_parse_state == WAIT_SYNC) { - odev->rx_parse_state = WAIT_IP; - odev->rx_buf_size = 0; - odev->rx_buf_missing = sizeof(struct iphdr); - } - } -} - -static void fix_crc_bug(struct urb *urb, __le16 max_packet_size) -{ - static const u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; - u32 rest = urb->actual_length % le16_to_cpu(max_packet_size); - - if (((rest == 5) || (rest == 6)) && - !memcmp(((u8 *)urb->transfer_buffer) + urb->actual_length - 4, - crc_check, 4)) { - urb->actual_length -= 4; - } -} - -/* Moving data from usb to kernel (in interrupt state) */ -static void read_bulk_callback(struct urb *urb) -{ - struct hso_net *odev = urb->context; - struct net_device *net; - int result; - int status = urb->status; - - /* is al ok? (Filip: Who's Al ?) */ - if (status) { - handle_usb_error(status, __func__, odev->parent); - return; - } - - /* Sanity check */ - if (!odev || !test_bit(HSO_NET_RUNNING, &odev->flags)) { - D1("BULK IN callback but driver is not active!"); - return; - } - usb_mark_last_busy(urb->dev); - - net = odev->net; - - if (!netif_device_present(net)) { - /* Somebody killed our network interface... */ - return; - } - - if (odev->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, odev->in_endp->wMaxPacketSize); - - /* do we even have a packet? */ - if (urb->actual_length) { - /* Handle the IP stream, add header and push it onto network - * stack if the packet is complete. */ - spin_lock(&odev->net_lock); - packetizeRx(odev, urb->transfer_buffer, urb->actual_length, - (urb->transfer_buffer_length > - urb->actual_length) ? 1 : 0); - spin_unlock(&odev->net_lock); - } - - /* We are done with this URB, resubmit it. Prep the USB to wait for - * another frame. Reuse same as received. */ - usb_fill_bulk_urb(urb, - odev->parent->usb, - usb_rcvbulkpipe(odev->parent->usb, - odev->in_endp-> - bEndpointAddress & 0x7F), - urb->transfer_buffer, MUX_BULK_RX_BUF_SIZE, - read_bulk_callback, odev); - - /* Give this to the USB subsystem so it can tell us when more data - * arrives. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_warn(&odev->parent->interface->dev, - "%s failed submit mux_bulk_rx_urb %d\n", __func__, - result); -} - -/* Serial driver functions */ - -static void hso_init_termios(struct ktermios *termios) -{ - /* - * The default requirements for this device are: - */ - termios->c_iflag &= - ~(IGNBRK /* disable ignore break */ - | BRKINT /* disable break causes interrupt */ - | PARMRK /* disable mark parity errors */ - | ISTRIP /* disable clear high bit of input characters */ - | INLCR /* disable translate NL to CR */ - | IGNCR /* disable ignore CR */ - | ICRNL /* disable translate CR to NL */ - | IXON); /* disable enable XON/XOFF flow control */ - - /* disable postprocess output characters */ - termios->c_oflag &= ~OPOST; - - termios->c_lflag &= - ~(ECHO /* disable echo input characters */ - | ECHONL /* disable echo new line */ - | ICANON /* disable erase, kill, werase, and rprnt - special characters */ - | ISIG /* disable interrupt, quit, and suspend special - characters */ - | IEXTEN); /* disable non-POSIX special characters */ - - termios->c_cflag &= - ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD /* clear current baud rate */ - | CBAUDEX); /* clear current buad rate */ - - termios->c_cflag |= CS8; /* character size 8 bits */ - - /* baud rate 115200 */ - tty_termios_encode_baud_rate(termios, 115200, 115200); -} - -static void _hso_serial_set_termios(struct tty_struct *tty, - struct ktermios *old) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - struct ktermios *termios; - - if (!serial) { - printk(KERN_ERR "%s: no tty structures", __func__); - return; - } - - D4("port %d", serial->minor); - - /* - * Fix up unsupported bits - */ - termios = tty->termios; - termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */ - - termios->c_cflag &= - ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD /* clear current baud rate */ - | CBAUDEX); /* clear current buad rate */ - - termios->c_cflag |= CS8; /* character size 8 bits */ - - /* baud rate 115200 */ - tty_encode_baud_rate(tty, 115200, 115200); -} - -static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) -{ - int result; - /* We are done with this URB, resubmit it. Prep the USB to wait for - * another frame */ - usb_fill_bulk_urb(urb, serial->parent->usb, - usb_rcvbulkpipe(serial->parent->usb, - serial->in_endp-> - bEndpointAddress & 0x7F), - urb->transfer_buffer, serial->rx_data_length, - hso_std_serial_read_bulk_callback, serial); - /* Give this to the USB subsystem so it can tell us when more data - * arrives. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&urb->dev->dev, "%s failed submit serial rx_urb %d\n", - __func__, result); - } -} - - - - -static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial) -{ - int count; - struct urb *curr_urb; - - while (serial->rx_urb_filled[serial->curr_rx_urb_idx]) { - curr_urb = serial->rx_urb[serial->curr_rx_urb_idx]; - count = put_rxbuf_data(curr_urb, serial); - if (count == -1) - return; - if (count == 0) { - serial->curr_rx_urb_idx++; - if (serial->curr_rx_urb_idx >= serial->num_rx_urbs) - serial->curr_rx_urb_idx = 0; - hso_resubmit_rx_bulk_urb(serial, curr_urb); - } - } -} - -static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial) -{ - int count = 0; - struct urb *urb; - - urb = serial->rx_urb[0]; - if (serial->open_count > 0) { - count = put_rxbuf_data(urb, serial); - if (count == -1) - return; - } - /* Re issue a read as long as we receive data. */ - - if (count == 0 && ((urb->actual_length != 0) || - (serial->rx_state == RX_PENDING))) { - serial->rx_state = RX_SENT; - hso_mux_serial_read(serial); - } else - serial->rx_state = RX_IDLE; -} - - -/* read callback for Diag and CS port */ -static void hso_std_serial_read_bulk_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - int status = urb->status; - - /* sanity check */ - if (!serial) { - D1("serial == NULL"); - return; - } else if (status) { - handle_usb_error(status, __func__, serial->parent); - return; - } - - D4("\n--- Got serial_read_bulk callback %02x ---", status); - D1("Actual length = %d\n", urb->actual_length); - DUMP1(urb->transfer_buffer, urb->actual_length); - - /* Anyone listening? */ - if (serial->open_count == 0) - return; - - if (status == 0) { - if (serial->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); - /* Valid data, handle RX data */ - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock(&serial->serial_lock); - } else if (status == -ENOENT || status == -ECONNRESET) { - /* Unlinked - check for throttled port. */ - D2("Port %d, successfully unlinked urb", serial->minor); - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - hso_resubmit_rx_bulk_urb(serial, urb); - spin_unlock(&serial->serial_lock); - } else { - D2("Port %d, status = %d for read urb", serial->minor, status); - return; - } -} - -/* - * This needs to be a tasklet otherwise we will - * end up recursively calling this function. - */ -static void hso_unthrottle_tasklet(struct hso_serial *serial) -{ - unsigned long flags; - - spin_lock_irqsave(&serial->serial_lock, flags); - if ((serial->parent->port_spec & HSO_INTF_MUX)) - put_rxbuf_data_and_resubmit_ctrl_urb(serial); - else - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock_irqrestore(&serial->serial_lock, flags); -} - -static void hso_unthrottle(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - - tasklet_hi_schedule(&serial->unthrottle_tasklet); -} - -static void hso_unthrottle_workfunc(struct work_struct *work) -{ - struct hso_serial *serial = - container_of(work, struct hso_serial, - retry_unthrottle_workqueue); - hso_unthrottle_tasklet(serial); -} - -/* open the requested serial port */ -static int hso_serial_open(struct tty_struct *tty, struct file *filp) -{ - struct hso_serial *serial = get_serial_by_index(tty->index); - int result; - - /* sanity check */ - if (serial == NULL || serial->magic != HSO_SERIAL_MAGIC) { - WARN_ON(1); - tty->driver_data = NULL; - D1("Failed to open port"); - return -ENODEV; - } - - mutex_lock(&serial->parent->mutex); - result = usb_autopm_get_interface(serial->parent->interface); - if (result < 0) - goto err_out; - - D1("Opening %d", serial->minor); - kref_get(&serial->parent->ref); - - /* setup */ - spin_lock_irq(&serial->serial_lock); - tty->driver_data = serial; - tty_kref_put(serial->tty); - serial->tty = tty_kref_get(tty); - spin_unlock_irq(&serial->serial_lock); - - /* check for port already opened, if not set the termios */ - serial->open_count++; - if (serial->open_count == 1) { - serial->rx_state = RX_IDLE; - /* Force default termio settings */ - _hso_serial_set_termios(tty, NULL); - tasklet_init(&serial->unthrottle_tasklet, - (void (*)(unsigned long))hso_unthrottle_tasklet, - (unsigned long)serial); - INIT_WORK(&serial->retry_unthrottle_workqueue, - hso_unthrottle_workfunc); - result = hso_start_serial_device(serial->parent, GFP_KERNEL); - if (result) { - hso_stop_serial_device(serial->parent); - serial->open_count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); - } - } else { - D1("Port was already open"); - } - - usb_autopm_put_interface(serial->parent->interface); - - /* done */ - if (result) - hso_serial_tiocmset(tty, TIOCM_RTS | TIOCM_DTR, 0); -err_out: - mutex_unlock(&serial->parent->mutex); - return result; -} - -/* close the requested serial port */ -static void hso_serial_close(struct tty_struct *tty, struct file *filp) -{ - struct hso_serial *serial = tty->driver_data; - u8 usb_gone; - - D1("Closing serial port"); - - /* Open failed, no close cleanup required */ - if (serial == NULL) - return; - - mutex_lock(&serial->parent->mutex); - usb_gone = serial->parent->usb_gone; - - if (!usb_gone) - usb_autopm_get_interface(serial->parent->interface); - - /* reset the rts and dtr */ - /* do the actual close */ - serial->open_count--; - - if (serial->open_count <= 0) { - serial->open_count = 0; - spin_lock_irq(&serial->serial_lock); - if (serial->tty == tty) { - serial->tty->driver_data = NULL; - serial->tty = NULL; - tty_kref_put(tty); - } - spin_unlock_irq(&serial->serial_lock); - if (!usb_gone) - hso_stop_serial_device(serial->parent); - tasklet_kill(&serial->unthrottle_tasklet); - cancel_work_sync(&serial->retry_unthrottle_workqueue); - } - - if (!usb_gone) - usb_autopm_put_interface(serial->parent->interface); - - mutex_unlock(&serial->parent->mutex); - - kref_put(&serial->parent->ref, hso_serial_ref_free); -} - -/* close the requested serial port */ -static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int space, tx_bytes; - unsigned long flags; - - /* sanity check */ - if (serial == NULL) { - printk(KERN_ERR "%s: serial is NULL\n", __func__); - return -ENODEV; - } - - spin_lock_irqsave(&serial->serial_lock, flags); - - space = serial->tx_data_length - serial->tx_buffer_count; - tx_bytes = (count < space) ? count : space; - - if (!tx_bytes) - goto out; - - memcpy(serial->tx_buffer + serial->tx_buffer_count, buf, tx_bytes); - serial->tx_buffer_count += tx_bytes; - -out: - spin_unlock_irqrestore(&serial->serial_lock, flags); - - hso_kick_transmit(serial); - /* done */ - return tx_bytes; -} - -/* how much room is there for writing */ -static int hso_serial_write_room(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int room; - unsigned long flags; - - spin_lock_irqsave(&serial->serial_lock, flags); - room = serial->tx_data_length - serial->tx_buffer_count; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - /* return free room */ - return room; -} - -/* setup the term */ -static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - unsigned long flags; - - if (old) - D5("Termios called with: cflags new[%d] - old[%d]", - tty->termios->c_cflag, old->c_cflag); - - /* the actual setup */ - spin_lock_irqsave(&serial->serial_lock, flags); - if (serial->open_count) - _hso_serial_set_termios(tty, old); - else - tty->termios = old; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - /* done */ -} - -/* how many characters in the buffer */ -static int hso_serial_chars_in_buffer(struct tty_struct *tty) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int chars; - unsigned long flags; - - /* sanity check */ - if (serial == NULL) - return 0; - - spin_lock_irqsave(&serial->serial_lock, flags); - chars = serial->tx_buffer_count; - spin_unlock_irqrestore(&serial->serial_lock, flags); - - return chars; -} -static int tiocmget_submit_urb(struct hso_serial *serial, - struct hso_tiocmget *tiocmget, - struct usb_device *usb) -{ - int result; - - if (serial->parent->usb_gone) - return -ENODEV; - usb_fill_int_urb(tiocmget->urb, usb, - usb_rcvintpipe(usb, - tiocmget->endp-> - bEndpointAddress & 0x7F), - &tiocmget->serial_state_notification, - sizeof(struct hso_serial_state_notification), - tiocmget_intr_callback, serial, - tiocmget->endp->bInterval); - result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC); - if (result) { - dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__, - result); - } - return result; - -} - -static void tiocmget_intr_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - struct hso_tiocmget *tiocmget; - int status = urb->status; - u16 UART_state_bitmap, prev_UART_state_bitmap; - struct uart_icount *icount; - struct hso_serial_state_notification *serial_state_notification; - struct usb_device *usb; - - /* Sanity checks */ - if (!serial) - return; - if (status) { - handle_usb_error(status, __func__, serial->parent); - return; - } - tiocmget = serial->tiocmget; - if (!tiocmget) - return; - usb = serial->parent->usb; - serial_state_notification = &tiocmget->serial_state_notification; - if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || - serial_state_notification->bNotification != B_NOTIFICATION || - le16_to_cpu(serial_state_notification->wValue) != W_VALUE || - le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || - le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { - dev_warn(&usb->dev, - "hso received invalid serial state notification\n"); - DUMP(serial_state_notification, - sizeof(struct hso_serial_state_notification)); - } else { - - UART_state_bitmap = le16_to_cpu(serial_state_notification-> - UART_state_bitmap); - prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap; - icount = &tiocmget->icount; - spin_lock(&serial->serial_lock); - if ((UART_state_bitmap & B_OVERRUN) != - (prev_UART_state_bitmap & B_OVERRUN)) - icount->parity++; - if ((UART_state_bitmap & B_PARITY) != - (prev_UART_state_bitmap & B_PARITY)) - icount->parity++; - if ((UART_state_bitmap & B_FRAMING) != - (prev_UART_state_bitmap & B_FRAMING)) - icount->frame++; - if ((UART_state_bitmap & B_RING_SIGNAL) && - !(prev_UART_state_bitmap & B_RING_SIGNAL)) - icount->rng++; - if ((UART_state_bitmap & B_BREAK) != - (prev_UART_state_bitmap & B_BREAK)) - icount->brk++; - if ((UART_state_bitmap & B_TX_CARRIER) != - (prev_UART_state_bitmap & B_TX_CARRIER)) - icount->dsr++; - if ((UART_state_bitmap & B_RX_CARRIER) != - (prev_UART_state_bitmap & B_RX_CARRIER)) - icount->dcd++; - tiocmget->prev_UART_state_bitmap = UART_state_bitmap; - spin_unlock(&serial->serial_lock); - tiocmget->intr_completed = 1; - wake_up_interruptible(&tiocmget->waitq); - } - memset(serial_state_notification, 0, - sizeof(struct hso_serial_state_notification)); - tiocmget_submit_urb(serial, - tiocmget, - serial->parent->usb); -} - -/* - * next few functions largely stolen from drivers/serial/serial_core.c - */ -/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ -static int -hso_wait_modem_status(struct hso_serial *serial, unsigned long arg) -{ - DECLARE_WAITQUEUE(wait, current); - struct uart_icount cprev, cnow; - struct hso_tiocmget *tiocmget; - int ret; - - tiocmget = serial->tiocmget; - if (!tiocmget) - return -ENOENT; - /* - * note the counters on entry - */ - spin_lock_irq(&serial->serial_lock); - memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - add_wait_queue(&tiocmget->waitq, &wait); - for (;;) { - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - set_current_state(TASK_INTERRUPTIBLE); - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) { - ret = 0; - break; - } - schedule(); - /* see if a signal did it */ - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - cprev = cnow; - } - current->state = TASK_RUNNING; - remove_wait_queue(&tiocmget->waitq, &wait); - - return ret; -} - -/* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ -static int hso_get_count(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct uart_icount cnow; - struct hso_serial *serial = get_serial_by_tty(tty); - struct hso_tiocmget *tiocmget = serial->tiocmget; - - memset(icount, 0, sizeof(struct serial_icounter_struct)); - - if (!tiocmget) - return -ENOENT; - spin_lock_irq(&serial->serial_lock); - memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount)); - spin_unlock_irq(&serial->serial_lock); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - - -static int hso_serial_tiocmget(struct tty_struct *tty) -{ - int retval; - struct hso_serial *serial = get_serial_by_tty(tty); - struct hso_tiocmget *tiocmget; - u16 UART_state_bitmap; - - /* sanity check */ - if (!serial) { - D1("no tty structures"); - return -EINVAL; - } - spin_lock_irq(&serial->serial_lock); - retval = ((serial->rts_state) ? TIOCM_RTS : 0) | - ((serial->dtr_state) ? TIOCM_DTR : 0); - tiocmget = serial->tiocmget; - if (tiocmget) { - - UART_state_bitmap = le16_to_cpu( - tiocmget->prev_UART_state_bitmap); - if (UART_state_bitmap & B_RING_SIGNAL) - retval |= TIOCM_RNG; - if (UART_state_bitmap & B_RX_CARRIER) - retval |= TIOCM_CD; - if (UART_state_bitmap & B_TX_CARRIER) - retval |= TIOCM_DSR; - } - spin_unlock_irq(&serial->serial_lock); - return retval; -} - -static int hso_serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - int val = 0; - unsigned long flags; - int if_num; - struct hso_serial *serial = get_serial_by_tty(tty); - - /* sanity check */ - if (!serial) { - D1("no tty structures"); - return -EINVAL; - } - - if ((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM) - return -EINVAL; - - if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; - - spin_lock_irqsave(&serial->serial_lock, flags); - if (set & TIOCM_RTS) - serial->rts_state = 1; - if (set & TIOCM_DTR) - serial->dtr_state = 1; - - if (clear & TIOCM_RTS) - serial->rts_state = 0; - if (clear & TIOCM_DTR) - serial->dtr_state = 0; - - if (serial->dtr_state) - val |= 0x01; - if (serial->rts_state) - val |= 0x02; - - spin_unlock_irqrestore(&serial->serial_lock, flags); - - return usb_control_msg(serial->parent->usb, - usb_rcvctrlpipe(serial->parent->usb, 0), 0x22, - 0x21, val, if_num, NULL, 0, - USB_CTRL_SET_TIMEOUT); -} - -static int hso_serial_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct hso_serial *serial = get_serial_by_tty(tty); - int ret = 0; - D4("IOCTL cmd: %d, arg: %ld", cmd, arg); - - if (!serial) - return -ENODEV; - switch (cmd) { - case TIOCMIWAIT: - ret = hso_wait_modem_status(serial, arg); - break; - default: - ret = -ENOIOCTLCMD; - break; - } - return ret; -} - - -/* starts a transmit */ -static void hso_kick_transmit(struct hso_serial *serial) -{ - u8 *temp; - unsigned long flags; - int res; - - spin_lock_irqsave(&serial->serial_lock, flags); - if (!serial->tx_buffer_count) - goto out; - - if (serial->tx_urb_used) - goto out; - - /* Wakeup USB interface if necessary */ - if (hso_get_activity(serial->parent) == -EAGAIN) - goto out; - - /* Switch pointers around to avoid memcpy */ - temp = serial->tx_buffer; - serial->tx_buffer = serial->tx_data; - serial->tx_data = temp; - serial->tx_data_count = serial->tx_buffer_count; - serial->tx_buffer_count = 0; - - /* If temp is set, it means we switched buffers */ - if (temp && serial->write_data) { - res = serial->write_data(serial); - if (res >= 0) - serial->tx_urb_used = 1; - } -out: - spin_unlock_irqrestore(&serial->serial_lock, flags); -} - -/* make a request (for reading and writing data to muxed serial port) */ -static int mux_device_request(struct hso_serial *serial, u8 type, u16 port, - struct urb *ctrl_urb, - struct usb_ctrlrequest *ctrl_req, - u8 *ctrl_urb_data, u32 size) -{ - int result; - int pipe; - - /* Sanity check */ - if (!serial || !ctrl_urb || !ctrl_req) { - printk(KERN_ERR "%s: Wrong arguments\n", __func__); - return -EINVAL; - } - - /* initialize */ - ctrl_req->wValue = 0; - ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port)); - ctrl_req->wLength = cpu_to_le16(size); - - if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) { - /* Reading command */ - ctrl_req->bRequestType = USB_DIR_IN | - USB_TYPE_OPTION_VENDOR | - USB_RECIP_INTERFACE; - ctrl_req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; - pipe = usb_rcvctrlpipe(serial->parent->usb, 0); - } else { - /* Writing command */ - ctrl_req->bRequestType = USB_DIR_OUT | - USB_TYPE_OPTION_VENDOR | - USB_RECIP_INTERFACE; - ctrl_req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; - pipe = usb_sndctrlpipe(serial->parent->usb, 0); - } - /* syslog */ - D2("%s command (%02x) len: %d, port: %d", - type == USB_CDC_GET_ENCAPSULATED_RESPONSE ? "Read" : "Write", - ctrl_req->bRequestType, ctrl_req->wLength, port); - - /* Load ctrl urb */ - ctrl_urb->transfer_flags = 0; - usb_fill_control_urb(ctrl_urb, - serial->parent->usb, - pipe, - (u8 *) ctrl_req, - ctrl_urb_data, size, ctrl_callback, serial); - /* Send it on merry way */ - result = usb_submit_urb(ctrl_urb, GFP_ATOMIC); - if (result) { - dev_err(&ctrl_urb->dev->dev, - "%s failed submit ctrl_urb %d type %d\n", __func__, - result, type); - return result; - } - - /* done */ - return size; -} - -/* called by intr_callback when read occurs */ -static int hso_mux_serial_read(struct hso_serial *serial) -{ - if (!serial) - return -EINVAL; - - /* clean data */ - memset(serial->rx_data[0], 0, CTRL_URB_RX_SIZE); - /* make the request */ - - if (serial->num_rx_urbs != 1) { - dev_err(&serial->parent->interface->dev, - "ERROR: mux'd reads with multiple buffers " - "not possible\n"); - return 0; - } - return mux_device_request(serial, - USB_CDC_GET_ENCAPSULATED_RESPONSE, - serial->parent->port_spec & HSO_PORT_MASK, - serial->rx_urb[0], - &serial->ctrl_req_rx, - serial->rx_data[0], serial->rx_data_length); -} - -/* used for muxed serial port callback (muxed serial read) */ -static void intr_callback(struct urb *urb) -{ - struct hso_shared_int *shared_int = urb->context; - struct hso_serial *serial; - unsigned char *port_req; - int status = urb->status; - int i; - - usb_mark_last_busy(urb->dev); - - /* sanity check */ - if (!shared_int) - return; - - /* status check */ - if (status) { - handle_usb_error(status, __func__, NULL); - return; - } - D4("\n--- Got intr callback 0x%02X ---", status); - - /* what request? */ - port_req = urb->transfer_buffer; - D4(" port_req = 0x%.2X\n", *port_req); - /* loop over all muxed ports to find the one sending this */ - for (i = 0; i < 8; i++) { - /* max 8 channels on MUX */ - if (*port_req & (1 << i)) { - serial = get_serial_by_shared_int_and_type(shared_int, - (1 << i)); - if (serial != NULL) { - D1("Pending read interrupt on port %d\n", i); - spin_lock(&serial->serial_lock); - if (serial->rx_state == RX_IDLE && - serial->open_count > 0) { - /* Setup and send a ctrl req read on - * port i */ - if (!serial->rx_urb_filled[0]) { - serial->rx_state = RX_SENT; - hso_mux_serial_read(serial); - } else - serial->rx_state = RX_PENDING; - } else { - D1("Already a read pending on " - "port %d or port not open\n", i); - } - spin_unlock(&serial->serial_lock); - } - } - } - /* Resubmit interrupt urb */ - hso_mux_submit_intr_urb(shared_int, urb->dev, GFP_ATOMIC); -} - -/* called for writing to muxed serial port */ -static int hso_mux_serial_write_data(struct hso_serial *serial) -{ - if (NULL == serial) - return -EINVAL; - - return mux_device_request(serial, - USB_CDC_SEND_ENCAPSULATED_COMMAND, - serial->parent->port_spec & HSO_PORT_MASK, - serial->tx_urb, - &serial->ctrl_req_tx, - serial->tx_data, serial->tx_data_count); -} - -/* write callback for Diag and CS port */ -static void hso_std_serial_write_bulk_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - int status = urb->status; - struct tty_struct *tty; - - /* sanity check */ - if (!serial) { - D1("serial == NULL"); - return; - } - - spin_lock(&serial->serial_lock); - serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); - spin_unlock(&serial->serial_lock); - if (status) { - handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); - return; - } - hso_put_activity(serial->parent); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } - hso_kick_transmit(serial); - - D1(" "); -} - -/* called for writing diag or CS serial port */ -static int hso_std_serial_write_data(struct hso_serial *serial) -{ - int count = serial->tx_data_count; - int result; - - usb_fill_bulk_urb(serial->tx_urb, - serial->parent->usb, - usb_sndbulkpipe(serial->parent->usb, - serial->out_endp-> - bEndpointAddress & 0x7F), - serial->tx_data, serial->tx_data_count, - hso_std_serial_write_bulk_callback, serial); - - result = usb_submit_urb(serial->tx_urb, GFP_ATOMIC); - if (result) { - dev_warn(&serial->parent->usb->dev, - "Failed to submit urb - res %d\n", result); - return result; - } - - return count; -} - -/* callback after read or write on muxed serial port */ -static void ctrl_callback(struct urb *urb) -{ - struct hso_serial *serial = urb->context; - struct usb_ctrlrequest *req; - int status = urb->status; - struct tty_struct *tty; - - /* sanity check */ - if (!serial) - return; - - spin_lock(&serial->serial_lock); - serial->tx_urb_used = 0; - tty = tty_kref_get(serial->tty); - spin_unlock(&serial->serial_lock); - if (status) { - handle_usb_error(status, __func__, serial->parent); - tty_kref_put(tty); - return; - } - - /* what request? */ - req = (struct usb_ctrlrequest *)(urb->setup_packet); - D4("\n--- Got muxed ctrl callback 0x%02X ---", status); - D4("Actual length of urb = %d\n", urb->actual_length); - DUMP1(urb->transfer_buffer, urb->actual_length); - - if (req->bRequestType == - (USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) { - /* response to a read command */ - serial->rx_urb_filled[0] = 1; - spin_lock(&serial->serial_lock); - put_rxbuf_data_and_resubmit_ctrl_urb(serial); - spin_unlock(&serial->serial_lock); - } else { - hso_put_activity(serial->parent); - if (tty) - tty_wakeup(tty); - /* response to a write command */ - hso_kick_transmit(serial); - } - tty_kref_put(tty); -} - -/* handle RX data for serial port */ -static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) -{ - struct tty_struct *tty; - int write_length_remaining = 0; - int curr_write_len; - - /* Sanity check */ - if (urb == NULL || serial == NULL) { - D1("serial = NULL"); - return -2; - } - - /* All callers to put_rxbuf_data hold serial_lock */ - tty = tty_kref_get(serial->tty); - - /* Push data to tty */ - if (tty) { - write_length_remaining = urb->actual_length - - serial->curr_rx_urb_offset; - D1("data to push to tty"); - while (write_length_remaining) { - if (test_bit(TTY_THROTTLED, &tty->flags)) { - tty_kref_put(tty); - return -1; - } - curr_write_len = tty_insert_flip_string - (tty, urb->transfer_buffer + - serial->curr_rx_urb_offset, - write_length_remaining); - serial->curr_rx_urb_offset += curr_write_len; - write_length_remaining -= curr_write_len; - tty_flip_buffer_push(tty); - } - } - if (write_length_remaining == 0) { - serial->curr_rx_urb_offset = 0; - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - } - tty_kref_put(tty); - return write_length_remaining; -} - - -/* Base driver functions */ - -static void hso_log_port(struct hso_device *hso_dev) -{ - char *port_type; - char port_dev[20]; - - switch (hso_dev->port_spec & HSO_PORT_MASK) { - case HSO_PORT_CONTROL: - port_type = "Control"; - break; - case HSO_PORT_APP: - port_type = "Application"; - break; - case HSO_PORT_GPS: - port_type = "GPS"; - break; - case HSO_PORT_GPS_CONTROL: - port_type = "GPS control"; - break; - case HSO_PORT_APP2: - port_type = "Application2"; - break; - case HSO_PORT_PCSC: - port_type = "PCSC"; - break; - case HSO_PORT_DIAG: - port_type = "Diagnostic"; - break; - case HSO_PORT_DIAG2: - port_type = "Diagnostic2"; - break; - case HSO_PORT_MODEM: - port_type = "Modem"; - break; - case HSO_PORT_NETWORK: - port_type = "Network"; - break; - default: - port_type = "Unknown"; - break; - } - if ((hso_dev->port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - sprintf(port_dev, "%s", dev2net(hso_dev)->net->name); - } else - sprintf(port_dev, "/dev/%s%d", tty_filename, - dev2ser(hso_dev)->minor); - - dev_dbg(&hso_dev->interface->dev, "HSO: Found %s port %s\n", - port_type, port_dev); -} - -static int hso_start_net_device(struct hso_device *hso_dev) -{ - int i, result = 0; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return -ENODEV; - - /* send URBs for all read buffers */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - - /* Prep a receive URB */ - usb_fill_bulk_urb(hso_net->mux_bulk_rx_urb_pool[i], - hso_dev->usb, - usb_rcvbulkpipe(hso_dev->usb, - hso_net->in_endp-> - bEndpointAddress & 0x7F), - hso_net->mux_bulk_rx_buf_pool[i], - MUX_BULK_RX_BUF_SIZE, read_bulk_callback, - hso_net); - - /* Put it out there so the device can send us stuff */ - result = usb_submit_urb(hso_net->mux_bulk_rx_urb_pool[i], - GFP_NOIO); - if (result) - dev_warn(&hso_dev->usb->dev, - "%s failed mux_bulk_rx_urb[%d] %d\n", __func__, - i, result); - } - - return result; -} - -static int hso_stop_net_device(struct hso_device *hso_dev) -{ - int i; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return -ENODEV; - - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - if (hso_net->mux_bulk_rx_urb_pool[i]) - usb_kill_urb(hso_net->mux_bulk_rx_urb_pool[i]); - - } - if (hso_net->mux_bulk_tx_urb) - usb_kill_urb(hso_net->mux_bulk_tx_urb); - - return 0; -} - -static int hso_start_serial_device(struct hso_device *hso_dev, gfp_t flags) -{ - int i, result = 0; - struct hso_serial *serial = dev2ser(hso_dev); - - if (!serial) - return -ENODEV; - - /* If it is not the MUX port fill in and submit a bulk urb (already - * allocated in hso_serial_start) */ - if (!(serial->parent->port_spec & HSO_INTF_MUX)) { - for (i = 0; i < serial->num_rx_urbs; i++) { - usb_fill_bulk_urb(serial->rx_urb[i], - serial->parent->usb, - usb_rcvbulkpipe(serial->parent->usb, - serial->in_endp-> - bEndpointAddress & - 0x7F), - serial->rx_data[i], - serial->rx_data_length, - hso_std_serial_read_bulk_callback, - serial); - result = usb_submit_urb(serial->rx_urb[i], flags); - if (result) { - dev_warn(&serial->parent->usb->dev, - "Failed to submit urb - res %d\n", - result); - break; - } - } - } else { - mutex_lock(&serial->shared_int->shared_int_lock); - if (!serial->shared_int->use_count) { - result = - hso_mux_submit_intr_urb(serial->shared_int, - hso_dev->usb, flags); - } - serial->shared_int->use_count++; - mutex_unlock(&serial->shared_int->shared_int_lock); - } - if (serial->tiocmget) - tiocmget_submit_urb(serial, - serial->tiocmget, - serial->parent->usb); - return result; -} - -static int hso_stop_serial_device(struct hso_device *hso_dev) -{ - int i; - struct hso_serial *serial = dev2ser(hso_dev); - struct hso_tiocmget *tiocmget; - - if (!serial) - return -ENODEV; - - for (i = 0; i < serial->num_rx_urbs; i++) { - if (serial->rx_urb[i]) { - usb_kill_urb(serial->rx_urb[i]); - serial->rx_urb_filled[i] = 0; - } - } - serial->curr_rx_urb_idx = 0; - serial->curr_rx_urb_offset = 0; - - if (serial->tx_urb) - usb_kill_urb(serial->tx_urb); - - if (serial->shared_int) { - mutex_lock(&serial->shared_int->shared_int_lock); - if (serial->shared_int->use_count && - (--serial->shared_int->use_count == 0)) { - struct urb *urb; - - urb = serial->shared_int->shared_intr_urb; - if (urb) - usb_kill_urb(urb); - } - mutex_unlock(&serial->shared_int->shared_int_lock); - } - tiocmget = serial->tiocmget; - if (tiocmget) { - wake_up_interruptible(&tiocmget->waitq); - usb_kill_urb(tiocmget->urb); - } - - return 0; -} - -static void hso_serial_common_free(struct hso_serial *serial) -{ - int i; - - if (serial->parent->dev) - device_remove_file(serial->parent->dev, &dev_attr_hsotype); - - tty_unregister_device(tty_drv, serial->minor); - - for (i = 0; i < serial->num_rx_urbs; i++) { - /* unlink and free RX URB */ - usb_free_urb(serial->rx_urb[i]); - /* free the RX buffer */ - kfree(serial->rx_data[i]); - } - - /* unlink and free TX URB */ - usb_free_urb(serial->tx_urb); - kfree(serial->tx_data); -} - -static int hso_serial_common_create(struct hso_serial *serial, int num_urbs, - int rx_size, int tx_size) -{ - struct device *dev; - int minor; - int i; - - minor = get_free_serial_index(); - if (minor < 0) - goto exit; - - /* register our minor number */ - serial->parent->dev = tty_register_device(tty_drv, minor, - &serial->parent->interface->dev); - dev = serial->parent->dev; - dev_set_drvdata(dev, serial->parent); - i = device_create_file(dev, &dev_attr_hsotype); - - /* fill in specific data for later use */ - serial->minor = minor; - serial->magic = HSO_SERIAL_MAGIC; - spin_lock_init(&serial->serial_lock); - serial->num_rx_urbs = num_urbs; - - /* RX, allocate urb and initialize */ - - /* prepare our RX buffer */ - serial->rx_data_length = rx_size; - for (i = 0; i < serial->num_rx_urbs; i++) { - serial->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!serial->rx_urb[i]) { - dev_err(dev, "Could not allocate urb?\n"); - goto exit; - } - serial->rx_urb[i]->transfer_buffer = NULL; - serial->rx_urb[i]->transfer_buffer_length = 0; - serial->rx_data[i] = kzalloc(serial->rx_data_length, - GFP_KERNEL); - if (!serial->rx_data[i]) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - } - - /* TX, allocate urb and initialize */ - serial->tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!serial->tx_urb) { - dev_err(dev, "Could not allocate urb?\n"); - goto exit; - } - serial->tx_urb->transfer_buffer = NULL; - serial->tx_urb->transfer_buffer_length = 0; - /* prepare our TX buffer */ - serial->tx_data_count = 0; - serial->tx_buffer_count = 0; - serial->tx_data_length = tx_size; - serial->tx_data = kzalloc(serial->tx_data_length, GFP_KERNEL); - if (!serial->tx_data) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - serial->tx_buffer = kzalloc(serial->tx_data_length, GFP_KERNEL); - if (!serial->tx_buffer) { - dev_err(dev, "%s - Out of memory\n", __func__); - goto exit; - } - - return 0; -exit: - hso_serial_common_free(serial); - return -1; -} - -/* Creates a general hso device */ -static struct hso_device *hso_create_device(struct usb_interface *intf, - int port_spec) -{ - struct hso_device *hso_dev; - - hso_dev = kzalloc(sizeof(*hso_dev), GFP_ATOMIC); - if (!hso_dev) - return NULL; - - hso_dev->port_spec = port_spec; - hso_dev->usb = interface_to_usbdev(intf); - hso_dev->interface = intf; - kref_init(&hso_dev->ref); - mutex_init(&hso_dev->mutex); - - INIT_WORK(&hso_dev->async_get_intf, async_get_intf); - INIT_WORK(&hso_dev->async_put_intf, async_put_intf); - INIT_WORK(&hso_dev->reset_device, reset_device); - - return hso_dev; -} - -/* Removes a network device in the network device table */ -static int remove_net_device(struct hso_device *hso_dev) -{ - int i; - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] == hso_dev) { - network_table[i] = NULL; - break; - } - } - if (i == HSO_MAX_NET_DEVICES) - return -1; - return 0; -} - -/* Frees our network device */ -static void hso_free_net_device(struct hso_device *hso_dev) -{ - int i; - struct hso_net *hso_net = dev2net(hso_dev); - - if (!hso_net) - return; - - remove_net_device(hso_net->parent); - - if (hso_net->net) - unregister_netdev(hso_net->net); - - /* start freeing */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); - kfree(hso_net->mux_bulk_rx_buf_pool[i]); - hso_net->mux_bulk_rx_buf_pool[i] = NULL; - } - usb_free_urb(hso_net->mux_bulk_tx_urb); - kfree(hso_net->mux_bulk_tx_buf); - hso_net->mux_bulk_tx_buf = NULL; - - if (hso_net->net) - free_netdev(hso_net->net); - - kfree(hso_dev); -} - -static const struct net_device_ops hso_netdev_ops = { - .ndo_open = hso_net_open, - .ndo_stop = hso_net_close, - .ndo_start_xmit = hso_net_start_xmit, - .ndo_tx_timeout = hso_net_tx_timeout, -}; - -/* initialize the network interface */ -static void hso_net_init(struct net_device *net) -{ - struct hso_net *hso_net = netdev_priv(net); - - D1("sizeof hso_net is %d", (int)sizeof(*hso_net)); - - /* fill in the other fields */ - net->netdev_ops = &hso_netdev_ops; - net->watchdog_timeo = HSO_NET_TX_TIMEOUT; - net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - net->type = ARPHRD_NONE; - net->mtu = DEFAULT_MTU - 14; - net->tx_queue_len = 10; - SET_ETHTOOL_OPS(net, &ops); - - /* and initialize the semaphore */ - spin_lock_init(&hso_net->net_lock); -} - -/* Adds a network device in the network device table */ -static int add_net_device(struct hso_device *hso_dev) -{ - int i; - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] == NULL) { - network_table[i] = hso_dev; - break; - } - } - if (i == HSO_MAX_NET_DEVICES) - return -1; - return 0; -} - -static int hso_rfkill_set_block(void *data, bool blocked) -{ - struct hso_device *hso_dev = data; - int enabled = !blocked; - int rv; - - mutex_lock(&hso_dev->mutex); - if (hso_dev->usb_gone) - rv = 0; - else - rv = usb_control_msg(hso_dev->usb, usb_rcvctrlpipe(hso_dev->usb, 0), - enabled ? 0x82 : 0x81, 0x40, 0, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - mutex_unlock(&hso_dev->mutex); - return rv; -} - -static const struct rfkill_ops hso_rfkill_ops = { - .set_block = hso_rfkill_set_block, -}; - -/* Creates and sets up everything for rfkill */ -static void hso_create_rfkill(struct hso_device *hso_dev, - struct usb_interface *interface) -{ - struct hso_net *hso_net = dev2net(hso_dev); - struct device *dev = &hso_net->net->dev; - char *rfkn; - - rfkn = kzalloc(20, GFP_KERNEL); - if (!rfkn) - dev_err(dev, "%s - Out of memory\n", __func__); - - snprintf(rfkn, 20, "hso-%d", - interface->altsetting->desc.bInterfaceNumber); - - hso_net->rfkill = rfkill_alloc(rfkn, - &interface_to_usbdev(interface)->dev, - RFKILL_TYPE_WWAN, - &hso_rfkill_ops, hso_dev); - if (!hso_net->rfkill) { - dev_err(dev, "%s - Out of memory\n", __func__); - kfree(rfkn); - return; - } - if (rfkill_register(hso_net->rfkill) < 0) { - rfkill_destroy(hso_net->rfkill); - kfree(rfkn); - hso_net->rfkill = NULL; - dev_err(dev, "%s - Failed to register rfkill\n", __func__); - return; - } -} - -static struct device_type hso_type = { - .name = "wwan", -}; - -/* Creates our network device */ -static struct hso_device *hso_create_net_device(struct usb_interface *interface, - int port_spec) -{ - int result, i; - struct net_device *net; - struct hso_net *hso_net; - struct hso_device *hso_dev; - - hso_dev = hso_create_device(interface, port_spec); - if (!hso_dev) - return NULL; - - /* allocate our network device, then we can put in our private data */ - /* call hso_net_init to do the basic initialization */ - net = alloc_netdev(sizeof(struct hso_net), "hso%d", hso_net_init); - if (!net) { - dev_err(&interface->dev, "Unable to create ethernet device\n"); - goto exit; - } - - hso_net = netdev_priv(net); - - hso_dev->port_data.dev_net = hso_net; - hso_net->net = net; - hso_net->parent = hso_dev; - - hso_net->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_IN); - if (!hso_net->in_endp) { - dev_err(&interface->dev, "Can't find BULK IN endpoint\n"); - goto exit; - } - hso_net->out_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_OUT); - if (!hso_net->out_endp) { - dev_err(&interface->dev, "Can't find BULK OUT endpoint\n"); - goto exit; - } - SET_NETDEV_DEV(net, &interface->dev); - SET_NETDEV_DEVTYPE(net, &hso_type); - - /* registering our net device */ - result = register_netdev(net); - if (result) { - dev_err(&interface->dev, "Failed to register device\n"); - goto exit; - } - - /* start allocating */ - for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { - hso_net->mux_bulk_rx_urb_pool[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!hso_net->mux_bulk_rx_urb_pool[i]) { - dev_err(&interface->dev, "Could not allocate rx urb\n"); - goto exit; - } - hso_net->mux_bulk_rx_buf_pool[i] = kzalloc(MUX_BULK_RX_BUF_SIZE, - GFP_KERNEL); - if (!hso_net->mux_bulk_rx_buf_pool[i]) { - dev_err(&interface->dev, "Could not allocate rx buf\n"); - goto exit; - } - } - hso_net->mux_bulk_tx_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!hso_net->mux_bulk_tx_urb) { - dev_err(&interface->dev, "Could not allocate tx urb\n"); - goto exit; - } - hso_net->mux_bulk_tx_buf = kzalloc(MUX_BULK_TX_BUF_SIZE, GFP_KERNEL); - if (!hso_net->mux_bulk_tx_buf) { - dev_err(&interface->dev, "Could not allocate tx buf\n"); - goto exit; - } - - add_net_device(hso_dev); - - hso_log_port(hso_dev); - - hso_create_rfkill(hso_dev, interface); - - return hso_dev; -exit: - hso_free_net_device(hso_dev); - return NULL; -} - -static void hso_free_tiomget(struct hso_serial *serial) -{ - struct hso_tiocmget *tiocmget; - if (!serial) - return; - tiocmget = serial->tiocmget; - if (tiocmget) { - usb_free_urb(tiocmget->urb); - tiocmget->urb = NULL; - serial->tiocmget = NULL; - kfree(tiocmget); - } -} - -/* Frees an AT channel ( goes for both mux and non-mux ) */ -static void hso_free_serial_device(struct hso_device *hso_dev) -{ - struct hso_serial *serial = dev2ser(hso_dev); - - if (!serial) - return; - set_serial_by_index(serial->minor, NULL); - - hso_serial_common_free(serial); - - if (serial->shared_int) { - mutex_lock(&serial->shared_int->shared_int_lock); - if (--serial->shared_int->ref_count == 0) - hso_free_shared_int(serial->shared_int); - else - mutex_unlock(&serial->shared_int->shared_int_lock); - } - hso_free_tiomget(serial); - kfree(serial); - kfree(hso_dev); -} - -/* Creates a bulk AT channel */ -static struct hso_device *hso_create_bulk_serial_device( - struct usb_interface *interface, int port) -{ - struct hso_device *hso_dev; - struct hso_serial *serial; - int num_urbs; - struct hso_tiocmget *tiocmget; - - hso_dev = hso_create_device(interface, port); - if (!hso_dev) - return NULL; - - serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) - goto exit; - - serial->parent = hso_dev; - hso_dev->port_data.dev_serial = serial; - - if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) { - num_urbs = 2; - serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget), - GFP_KERNEL); - /* it isn't going to break our heart if serial->tiocmget - * allocation fails don't bother checking this. - */ - if (serial->tiocmget) { - tiocmget = serial->tiocmget; - tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); - if (tiocmget->urb) { - mutex_init(&tiocmget->mutex); - init_waitqueue_head(&tiocmget->waitq); - tiocmget->endp = hso_get_ep( - interface, - USB_ENDPOINT_XFER_INT, - USB_DIR_IN); - } else - hso_free_tiomget(serial); - } - } - else - num_urbs = 1; - - if (hso_serial_common_create(serial, num_urbs, BULK_URB_RX_SIZE, - BULK_URB_TX_SIZE)) - goto exit; - - serial->in_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, - USB_DIR_IN); - if (!serial->in_endp) { - dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit2; - } - - if (! - (serial->out_endp = - hso_get_ep(interface, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT))) { - dev_err(&interface->dev, "Failed to find BULK IN ep\n"); - goto exit2; - } - - serial->write_data = hso_std_serial_write_data; - - /* and record this serial */ - set_serial_by_index(serial->minor, serial); - - /* setup the proc dirs and files if needed */ - hso_log_port(hso_dev); - - /* done, return it */ - return hso_dev; - -exit2: - hso_serial_common_free(serial); -exit: - hso_free_tiomget(serial); - kfree(serial); - kfree(hso_dev); - return NULL; -} - -/* Creates a multiplexed AT channel */ -static -struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface, - int port, - struct hso_shared_int *mux) -{ - struct hso_device *hso_dev; - struct hso_serial *serial; - int port_spec; - - port_spec = HSO_INTF_MUX; - port_spec &= ~HSO_PORT_MASK; - - port_spec |= hso_mux_to_port(port); - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NO_PORT) - return NULL; - - hso_dev = hso_create_device(interface, port_spec); - if (!hso_dev) - return NULL; - - serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) - goto exit; - - hso_dev->port_data.dev_serial = serial; - serial->parent = hso_dev; - - if (hso_serial_common_create - (serial, 1, CTRL_URB_RX_SIZE, CTRL_URB_TX_SIZE)) - goto exit; - - serial->tx_data_length--; - serial->write_data = hso_mux_serial_write_data; - - serial->shared_int = mux; - mutex_lock(&serial->shared_int->shared_int_lock); - serial->shared_int->ref_count++; - mutex_unlock(&serial->shared_int->shared_int_lock); - - /* and record this serial */ - set_serial_by_index(serial->minor, serial); - - /* setup the proc dirs and files if needed */ - hso_log_port(hso_dev); - - /* done, return it */ - return hso_dev; - -exit: - if (serial) { - tty_unregister_device(tty_drv, serial->minor); - kfree(serial); - } - if (hso_dev) - kfree(hso_dev); - return NULL; - -} - -static void hso_free_shared_int(struct hso_shared_int *mux) -{ - usb_free_urb(mux->shared_intr_urb); - kfree(mux->shared_intr_buf); - mutex_unlock(&mux->shared_int_lock); - kfree(mux); -} - -static -struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface) -{ - struct hso_shared_int *mux = kzalloc(sizeof(*mux), GFP_KERNEL); - - if (!mux) - return NULL; - - mux->intr_endp = hso_get_ep(interface, USB_ENDPOINT_XFER_INT, - USB_DIR_IN); - if (!mux->intr_endp) { - dev_err(&interface->dev, "Can't find INT IN endpoint\n"); - goto exit; - } - - mux->shared_intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!mux->shared_intr_urb) { - dev_err(&interface->dev, "Could not allocate intr urb?\n"); - goto exit; - } - mux->shared_intr_buf = - kzalloc(le16_to_cpu(mux->intr_endp->wMaxPacketSize), - GFP_KERNEL); - if (!mux->shared_intr_buf) { - dev_err(&interface->dev, "Could not allocate intr buf?\n"); - goto exit; - } - - mutex_init(&mux->shared_int_lock); - - return mux; - -exit: - kfree(mux->shared_intr_buf); - usb_free_urb(mux->shared_intr_urb); - kfree(mux); - return NULL; -} - -/* Gets the port spec for a certain interface */ -static int hso_get_config_data(struct usb_interface *interface) -{ - struct usb_device *usbdev = interface_to_usbdev(interface); - u8 config_data[17]; - u32 if_num = interface->altsetting->desc.bInterfaceNumber; - s32 result; - - if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), - 0x86, 0xC0, 0, 0, config_data, 17, - USB_CTRL_SET_TIMEOUT) != 0x11) { - return -EIO; - } - - switch (config_data[if_num]) { - case 0x0: - result = 0; - break; - case 0x1: - result = HSO_PORT_DIAG; - break; - case 0x2: - result = HSO_PORT_GPS; - break; - case 0x3: - result = HSO_PORT_GPS_CONTROL; - break; - case 0x4: - result = HSO_PORT_APP; - break; - case 0x5: - result = HSO_PORT_APP2; - break; - case 0x6: - result = HSO_PORT_CONTROL; - break; - case 0x7: - result = HSO_PORT_NETWORK; - break; - case 0x8: - result = HSO_PORT_MODEM; - break; - case 0x9: - result = HSO_PORT_MSD; - break; - case 0xa: - result = HSO_PORT_PCSC; - break; - case 0xb: - result = HSO_PORT_VOICE; - break; - default: - result = 0; - } - - if (result) - result |= HSO_INTF_BULK; - - if (config_data[16] & 0x1) - result |= HSO_INFO_CRC_BUG; - - return result; -} - -/* called once for each interface upon device insertion */ -static int hso_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int mux, i, if_num, port_spec; - unsigned char port_mask; - struct hso_device *hso_dev = NULL; - struct hso_shared_int *shared_int; - struct hso_device *tmp_dev = NULL; - - if_num = interface->altsetting->desc.bInterfaceNumber; - - /* Get the interface/port specification from either driver_info or from - * the device itself */ - if (id->driver_info) - port_spec = ((u32 *)(id->driver_info))[if_num]; - else - port_spec = hso_get_config_data(interface); - - if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { - dev_err(&interface->dev, "Not our interface\n"); - return -ENODEV; - } - /* Check if we need to switch to alt interfaces prior to port - * configuration */ - if (interface->num_altsetting > 1) - usb_set_interface(interface_to_usbdev(interface), if_num, 1); - interface->needs_remote_wakeup = 1; - - /* Allocate new hso device(s) */ - switch (port_spec & HSO_INTF_MASK) { - case HSO_INTF_MUX: - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - /* Create the network device */ - if (!disable_net) { - hso_dev = hso_create_net_device(interface, - port_spec); - if (!hso_dev) - goto exit; - tmp_dev = hso_dev; - } - } - - if (hso_get_mux_ports(interface, &port_mask)) - /* TODO: de-allocate everything */ - goto exit; - - shared_int = hso_create_shared_int(interface); - if (!shared_int) - goto exit; - - for (i = 1, mux = 0; i < 0x100; i = i << 1, mux++) { - if (port_mask & i) { - hso_dev = hso_create_mux_serial_device( - interface, i, shared_int); - if (!hso_dev) - goto exit; - } - } - - if (tmp_dev) - hso_dev = tmp_dev; - break; - - case HSO_INTF_BULK: - /* It's a regular bulk interface */ - if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { - if (!disable_net) - hso_dev = - hso_create_net_device(interface, port_spec); - } else { - hso_dev = - hso_create_bulk_serial_device(interface, port_spec); - } - if (!hso_dev) - goto exit; - break; - default: - goto exit; - } - - /* save our data pointer in this device */ - usb_set_intfdata(interface, hso_dev); - - /* done */ - return 0; -exit: - hso_free_interface(interface); - return -ENODEV; -} - -/* device removed, cleaning up */ -static void hso_disconnect(struct usb_interface *interface) -{ - hso_free_interface(interface); - - /* remove reference of our private data */ - usb_set_intfdata(interface, NULL); -} - -static void async_get_intf(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, async_get_intf); - usb_autopm_get_interface(hso_dev->interface); -} - -static void async_put_intf(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, async_put_intf); - usb_autopm_put_interface(hso_dev->interface); -} - -static int hso_get_activity(struct hso_device *hso_dev) -{ - if (hso_dev->usb->state == USB_STATE_SUSPENDED) { - if (!hso_dev->is_active) { - hso_dev->is_active = 1; - schedule_work(&hso_dev->async_get_intf); - } - } - - if (hso_dev->usb->state != USB_STATE_CONFIGURED) - return -EAGAIN; - - usb_mark_last_busy(hso_dev->usb); - - return 0; -} - -static int hso_put_activity(struct hso_device *hso_dev) -{ - if (hso_dev->usb->state != USB_STATE_SUSPENDED) { - if (hso_dev->is_active) { - hso_dev->is_active = 0; - schedule_work(&hso_dev->async_put_intf); - return -EAGAIN; - } - } - hso_dev->is_active = 0; - return 0; -} - -/* called by kernel when we need to suspend device */ -static int hso_suspend(struct usb_interface *iface, pm_message_t message) -{ - int i, result; - - /* Stop all serial ports */ - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && (serial_table[i]->interface == iface)) { - result = hso_stop_serial_device(serial_table[i]); - if (result) - goto out; - } - } - - /* Stop all network ports */ - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == iface)) { - result = hso_stop_net_device(network_table[i]); - if (result) - goto out; - } - } - -out: - return 0; -} - -/* called by kernel when we need to resume device */ -static int hso_resume(struct usb_interface *iface) -{ - int i, result = 0; - struct hso_net *hso_net; - - /* Start all serial ports */ - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && (serial_table[i]->interface == iface)) { - if (dev2ser(serial_table[i])->open_count) { - result = - hso_start_serial_device(serial_table[i], GFP_NOIO); - hso_kick_transmit(dev2ser(serial_table[i])); - if (result) - goto out; - } - } - } - - /* Start all network ports */ - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == iface)) { - hso_net = dev2net(network_table[i]); - if (hso_net->flags & IFF_UP) { - /* First transmit any lingering data, - then restart the device. */ - if (hso_net->skb_tx_buf) { - dev_dbg(&iface->dev, - "Transmitting" - " lingering data\n"); - hso_net_start_xmit(hso_net->skb_tx_buf, - hso_net->net); - hso_net->skb_tx_buf = NULL; - } - result = hso_start_net_device(network_table[i]); - if (result) - goto out; - } - } - } - -out: - return result; -} - -static void reset_device(struct work_struct *data) -{ - struct hso_device *hso_dev = - container_of(data, struct hso_device, reset_device); - struct usb_device *usb = hso_dev->usb; - int result; - - if (hso_dev->usb_gone) { - D1("No reset during disconnect\n"); - } else { - result = usb_lock_device_for_reset(usb, hso_dev->interface); - if (result < 0) - D1("unable to lock device for reset: %d\n", result); - else { - usb_reset_device(usb); - usb_unlock_device(usb); - } - } -} - -static void hso_serial_ref_free(struct kref *ref) -{ - struct hso_device *hso_dev = container_of(ref, struct hso_device, ref); - - hso_free_serial_device(hso_dev); -} - -static void hso_free_interface(struct usb_interface *interface) -{ - struct hso_serial *hso_dev; - struct tty_struct *tty; - int i; - - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] && - (serial_table[i]->interface == interface)) { - hso_dev = dev2ser(serial_table[i]); - spin_lock_irq(&hso_dev->serial_lock); - tty = tty_kref_get(hso_dev->tty); - spin_unlock_irq(&hso_dev->serial_lock); - if (tty) - tty_hangup(tty); - mutex_lock(&hso_dev->parent->mutex); - tty_kref_put(tty); - hso_dev->parent->usb_gone = 1; - mutex_unlock(&hso_dev->parent->mutex); - kref_put(&serial_table[i]->ref, hso_serial_ref_free); - } - } - - for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] && - (network_table[i]->interface == interface)) { - struct rfkill *rfk = dev2net(network_table[i])->rfkill; - /* hso_stop_net_device doesn't stop the net queue since - * traffic needs to start it again when suspended */ - netif_stop_queue(dev2net(network_table[i])->net); - hso_stop_net_device(network_table[i]); - cancel_work_sync(&network_table[i]->async_put_intf); - cancel_work_sync(&network_table[i]->async_get_intf); - if (rfk) { - rfkill_unregister(rfk); - rfkill_destroy(rfk); - } - hso_free_net_device(network_table[i]); - } - } -} - -/* Helper functions */ - -/* Get the endpoint ! */ -static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf, - int type, int dir) -{ - int i; - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_endpoint_descriptor *endp; - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - endp = &iface->endpoint[i].desc; - if (((endp->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == dir) && - (usb_endpoint_type(endp) == type)) - return endp; - } - - return NULL; -} - -/* Get the byte that describes which ports are enabled */ -static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports) -{ - int i; - struct usb_host_interface *iface = intf->cur_altsetting; - - if (iface->extralen == 3) { - *ports = iface->extra[2]; - return 0; - } - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - if (iface->endpoint[i].extralen == 3) { - *ports = iface->endpoint[i].extra[2]; - return 0; - } - } - - return -1; -} - -/* interrupt urb needs to be submitted, used for serial read of muxed port */ -static int hso_mux_submit_intr_urb(struct hso_shared_int *shared_int, - struct usb_device *usb, gfp_t gfp) -{ - int result; - - usb_fill_int_urb(shared_int->shared_intr_urb, usb, - usb_rcvintpipe(usb, - shared_int->intr_endp->bEndpointAddress & 0x7F), - shared_int->shared_intr_buf, - 1, - intr_callback, shared_int, - shared_int->intr_endp->bInterval); - - result = usb_submit_urb(shared_int->shared_intr_urb, gfp); - if (result) - dev_warn(&usb->dev, "%s failed mux_intr_urb %d\n", __func__, - result); - - return result; -} - -/* operations setup of the serial interface */ -static const struct tty_operations hso_serial_ops = { - .open = hso_serial_open, - .close = hso_serial_close, - .write = hso_serial_write, - .write_room = hso_serial_write_room, - .ioctl = hso_serial_ioctl, - .set_termios = hso_serial_set_termios, - .chars_in_buffer = hso_serial_chars_in_buffer, - .tiocmget = hso_serial_tiocmget, - .tiocmset = hso_serial_tiocmset, - .get_icount = hso_get_count, - .unthrottle = hso_unthrottle -}; - -static struct usb_driver hso_driver = { - .name = driver_name, - .probe = hso_probe, - .disconnect = hso_disconnect, - .id_table = hso_ids, - .suspend = hso_suspend, - .resume = hso_resume, - .reset_resume = hso_resume, - .supports_autosuspend = 1, -}; - -static int __init hso_init(void) -{ - int i; - int result; - - /* put it in the log */ - printk(KERN_INFO "hso: %s\n", version); - - /* Initialise the serial table semaphore and table */ - spin_lock_init(&serial_table_lock); - for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) - serial_table[i] = NULL; - - /* allocate our driver using the proper amount of supported minors */ - tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); - if (!tty_drv) - return -ENOMEM; - - /* fill in all needed values */ - tty_drv->magic = TTY_DRIVER_MAGIC; - tty_drv->driver_name = driver_name; - tty_drv->name = tty_filename; - - /* if major number is provided as parameter, use that one */ - if (tty_major) - tty_drv->major = tty_major; - - tty_drv->minor_start = 0; - tty_drv->type = TTY_DRIVER_TYPE_SERIAL; - tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_drv->init_termios = tty_std_termios; - hso_init_termios(&tty_drv->init_termios); - tty_set_operations(tty_drv, &hso_serial_ops); - - /* register the tty driver */ - result = tty_register_driver(tty_drv); - if (result) { - printk(KERN_ERR "%s - tty_register_driver failed(%d)\n", - __func__, result); - return result; - } - - /* register this module as an usb driver */ - result = usb_register(&hso_driver); - if (result) { - printk(KERN_ERR "Could not register hso driver? error: %d\n", - result); - /* cleanup serial interface */ - tty_unregister_driver(tty_drv); - return result; - } - - /* done */ - return 0; -} - -static void __exit hso_exit(void) -{ - printk(KERN_INFO "hso: unloaded\n"); - - tty_unregister_driver(tty_drv); - /* deregister the usb driver */ - usb_deregister(&hso_driver); -} - -/* Module definitions */ -module_init(hso_init); -module_exit(hso_exit); - -MODULE_AUTHOR(MOD_AUTHOR); -MODULE_DESCRIPTION(MOD_DESCRIPTION); -MODULE_LICENSE(MOD_LICENSE); - -/* change the debug level (eg: insmod hso.ko debug=0x04) */ -MODULE_PARM_DESC(debug, "Level of debug [0x01 | 0x02 | 0x04 | 0x08 | 0x10]"); -module_param(debug, int, S_IRUGO | S_IWUSR); - -/* set the major tty number (eg: insmod hso.ko tty_major=245) */ -MODULE_PARM_DESC(tty_major, "Set the major tty number"); -module_param(tty_major, int, S_IRUGO | S_IWUSR); - -/* disable network interface (eg: insmod hso.ko disable_net=1) */ -MODULE_PARM_DESC(disable_net, "Disable the network interface"); -module_param(disable_net, int, S_IRUGO | S_IWUSR); |