linux/drivers/net/usb/hso.c

// SPDX-License-Identifier: GPL-2.0-only
/******************************************************************************
 *
 * Driver for Option High Speed Mobile Devices.
 *
 *  Copyright (C) 2008 Option International
 *                     Filip Aben <[email protected]>
 *                     Denis Joseph Barrow <[email protected]>
 *                     Jan Dumon <[email protected]>
 *  Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd)
 *  			<[email protected]>
 *  Copyright (C) 2008 Greg Kroah-Hartman <[email protected]>
 *  Copyright (C) 2008 Novell, Inc.
 *
 *****************************************************************************/

/******************************************************************************
 *
 * 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.
 *
 *****************************************************************************/

#define pr_fmt(fmt)

#include <linux/sched/signal.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/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
#define MOD_DESCRIPTION

#define HSO_MAX_NET_DEVICES
#define HSO__MAX_MTU
#define DEFAULT_MTU
#define DEFAULT_MRU

#define CTRL_URB_RX_SIZE
#define CTRL_URB_TX_SIZE

#define BULK_URB_RX_SIZE
#define BULK_URB_TX_SIZE

#define MUX_BULK_RX_BUF_SIZE
#define MUX_BULK_TX_BUF_SIZE
#define MUX_BULK_RX_BUF_COUNT
#define USB_TYPE_OPTION_VENDOR

/* These definitions are used with the struct hso_net flags element */
/* - use *_bit operations on it. (bit indices not values.) */
#define HSO_NET_RUNNING

#define HSO_NET_TX_TIMEOUT

#define HSO_SERIAL_MAGIC

/* Number of ttys to handle */
#define HSO_SERIAL_TTY_MINORS

#define MAX_RX_URBS

/*****************************************************************************/
/* Debugging functions                                                       */
/*****************************************************************************/
#define hso_dbg(lvl, fmt, ...)

/*****************************************************************************/
/* Enumerators                                                               */
/*****************************************************************************/
enum pkt_parse_state {};

/*****************************************************************************/
/* Structs                                                                   */
/*****************************************************************************/

struct hso_shared_int {};

struct hso_net {};

enum rx_ctrl_state{};

#define BM_REQUEST_TYPE
#define B_NOTIFICATION
#define W_VALUE
#define W_LENGTH

#define B_OVERRUN
#define B_PARITY
#define B_FRAMING
#define B_RING_SIGNAL
#define B_BREAK
#define B_TX_CARRIER
#define B_RX_CARRIER

struct hso_serial_state_notification {} __packed;

struct hso_tiocmget {};


struct hso_serial {};

struct hso_device {};

/* Type of interface */
#define HSO_INTF_MASK
#define HSO_INTF_MUX
#define HSO_INTF_BULK

/* Type of port */
#define HSO_PORT_MASK
#define HSO_PORT_NO_PORT
#define HSO_PORT_CONTROL
#define HSO_PORT_APP
#define HSO_PORT_GPS
#define HSO_PORT_PCSC
#define HSO_PORT_APP2
#define HSO_PORT_GPS_CONTROL
#define HSO_PORT_MSD
#define HSO_PORT_VOICE
#define HSO_PORT_DIAG2
#define HSO_PORT_DIAG
#define HSO_PORT_MODEM
#define HSO_PORT_NETWORK

/* Additional device info */
#define HSO_INFO_MASK
#define HSO_INFO_CRC_BUG

/*****************************************************************************/
/* 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);
/*****************************************************************************/
/* Helping functions                                                         */
/*****************************************************************************/

/* #define DEBUG */

static inline struct hso_net *dev2net(struct hso_device *hso_dev)
{}

static inline struct hso_serial *dev2ser(struct hso_device *hso_dev)
{}

/* 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

#define DUMP1
#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[] =;
static const char tty_filename[] =;
/* 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 DEFINE_SPINLOCK(serial_table_lock);

static const s32 default_port_spec[] =;

static const s32 icon321_port_spec[] =;

#define default_port_device(vendor, product)

#define icon321_port_device(vendor, product)

/* list of devices we support */
static const struct usb_device_id hso_ids[] =;
MODULE_DEVICE_TABLE(usb, hso_ids);

/* Sysfs attribute */
static ssize_t hsotype_show(struct device *dev,
			    struct device_attribute *attr, char *buf)
{}
static DEVICE_ATTR_RO(hsotype);

static struct attribute *hso_serial_dev_attrs[] =;

ATTRIBUTE_GROUPS();

static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb)
{}

/* converts mux value to a port spec value */
static u32 hso_mux_to_port(int mux)
{}

/* converts port spec value to a mux value */
static u32 hso_port_to_mux(int port)
{}

static struct hso_serial *get_serial_by_shared_int_and_type(
					struct hso_shared_int *shared_int,
					int mux)
{}

static struct hso_serial *get_serial_by_index(unsigned index)
{}

static int obtain_minor(struct hso_serial *serial)
{}

static void release_minor(struct hso_serial *serial)
{}

static void handle_usb_error(int status, const char *function,
			     struct hso_device *hso_dev)
{}

/* Network interface functions */

/* called when net interface is brought up by ifconfig */
static int hso_net_open(struct net_device *net)
{}

/* called when interface is brought down by ifconfig */
static int hso_net_close(struct net_device *net)
{}

/* USB tells is xmit done, we should start the netqueue again */
static void write_bulk_callback(struct urb *urb)
{}

/* 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)
{}

static const struct ethtool_ops ops =;

/* called when a packet did not ack after watchdogtimeout */
static void hso_net_tx_timeout(struct net_device *net, unsigned int txqueue)
{}

/* 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)
{}

static void fix_crc_bug(struct urb *urb, __le16 max_packet_size)
{}

/* Moving data from usb to kernel (in interrupt state) */
static void read_bulk_callback(struct urb *urb)
{}

/* Serial driver functions */

static void hso_init_termios(struct ktermios *termios)
{}

static void _hso_serial_set_termios(struct tty_struct *tty)
{}

static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb)
{}




static void put_rxbuf_data_and_resubmit_bulk_urb(struct hso_serial *serial)
{}

static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
{}


/* read callback for Diag and CS port */
static void hso_std_serial_read_bulk_callback(struct urb *urb)
{}

/*
 * This needs to be a tasklet otherwise we will
 * end up recursively calling this function.
 */
static void hso_unthrottle_tasklet(struct tasklet_struct *t)
{}

static	void hso_unthrottle(struct tty_struct *tty)
{}

/* open the requested serial port */
static int hso_serial_open(struct tty_struct *tty, struct file *filp)
{}

/* close the requested serial port */
static void hso_serial_close(struct tty_struct *tty, struct file *filp)
{}

/* close the requested serial port */
static ssize_t hso_serial_write(struct tty_struct *tty, const u8 *buf,
				size_t count)
{}

/* how much room is there for writing */
static unsigned int hso_serial_write_room(struct tty_struct *tty)
{}

static void hso_serial_cleanup(struct tty_struct *tty)
{}

/* setup the term */
static void hso_serial_set_termios(struct tty_struct *tty,
				   const struct ktermios *old)
{}

/* how many characters in the buffer */
static unsigned int hso_serial_chars_in_buffer(struct tty_struct *tty)
{}
static int tiocmget_submit_urb(struct hso_serial *serial,
			       struct hso_tiocmget *tiocmget,
			       struct usb_device *usb)
{}

static void tiocmget_intr_callback(struct urb *urb)
{}

/*
 * 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)
{}

/*
 * 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)
{}


static int hso_serial_tiocmget(struct tty_struct *tty)
{}

static int hso_serial_tiocmset(struct tty_struct *tty,
			       unsigned int set, unsigned int clear)
{}

static int hso_serial_ioctl(struct tty_struct *tty,
			    unsigned int cmd, unsigned long arg)
{}


/* starts a transmit */
static void hso_kick_transmit(struct hso_serial *serial)
{}

/* 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)
{}

/* called by intr_callback when read occurs */
static int hso_mux_serial_read(struct hso_serial *serial)
{}

/* used for muxed serial port callback (muxed serial read) */
static void intr_callback(struct urb *urb)
{}

/* called for writing to muxed serial port */
static int hso_mux_serial_write_data(struct hso_serial *serial)
{}

/* write callback for Diag and CS port */
static void hso_std_serial_write_bulk_callback(struct urb *urb)
{}

/* called for writing diag or CS serial port */
static int hso_std_serial_write_data(struct hso_serial *serial)
{}

/* callback after read or write on muxed serial port */
static void ctrl_callback(struct urb *urb)
{}

/* handle RX data for serial port */
static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
{}


/* Base driver functions */

static void hso_log_port(struct hso_device *hso_dev)
{}

static int hso_start_net_device(struct hso_device *hso_dev)
{}

static int hso_stop_net_device(struct hso_device *hso_dev)
{}

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 void hso_serial_tty_unregister(struct hso_serial *serial)
{}

static void hso_serial_common_free(struct hso_serial *serial)
{}

static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
				    int rx_size, int tx_size)
{}

/* Creates a general hso device */
static struct hso_device *hso_create_device(struct usb_interface *intf,
					    int port_spec)
{}

/* Removes a network device in the network device table */
static int remove_net_device(struct hso_device *hso_dev)
{}

/* Frees our network device */
static void hso_free_net_device(struct hso_device *hso_dev)
{}

static const struct net_device_ops hso_netdev_ops =;

/* initialize the network interface */
static void hso_net_init(struct net_device *net)
{}

/* Adds a network device in the network device table */
static int add_net_device(struct hso_device *hso_dev)
{}

static int hso_rfkill_set_block(void *data, bool blocked)
{}

static const struct rfkill_ops hso_rfkill_ops =;

/* Creates and sets up everything for rfkill */
static void hso_create_rfkill(struct hso_device *hso_dev,
			     struct usb_interface *interface)
{}

static const struct device_type hso_type =;

/* Creates our network device */
static struct hso_device *hso_create_net_device(struct usb_interface *interface,
						int port_spec)
{}

static void hso_free_tiomget(struct hso_serial *serial)
{}

/* Frees an AT channel ( goes for both mux and non-mux ) */
static void hso_free_serial_device(struct hso_device *hso_dev)
{}

/* Creates a bulk AT channel */
static struct hso_device *hso_create_bulk_serial_device(
			struct usb_interface *interface, int port)
{}

/* 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)
{}

static void hso_free_shared_int(struct hso_shared_int *mux)
{}

static
struct hso_shared_int *hso_create_shared_int(struct usb_interface *interface)
{}

/* Gets the port spec for a certain interface */
static int hso_get_config_data(struct usb_interface *interface)
{}

/* called once for each interface upon device insertion */
static int hso_probe(struct usb_interface *interface,
		     const struct usb_device_id *id)
{}

/* device removed, cleaning up */
static void hso_disconnect(struct usb_interface *interface)
{}

static void async_get_intf(struct work_struct *data)
{}

static void async_put_intf(struct work_struct *data)
{}

static int hso_get_activity(struct hso_device *hso_dev)
{}

static int hso_put_activity(struct hso_device *hso_dev)
{}

/* called by kernel when we need to suspend device */
static int hso_suspend(struct usb_interface *iface, pm_message_t message)
{}

/* called by kernel when we need to resume device */
static int hso_resume(struct usb_interface *iface)
{}

static void hso_serial_ref_free(struct kref *ref)
{}

static void hso_free_interface(struct usb_interface *interface)
{}

/* Helper functions */

/* Get the endpoint ! */
static struct usb_endpoint_descriptor *hso_get_ep(struct usb_interface *intf,
						  int type, int dir)
{}

/* Get the byte that describes which ports are enabled */
static int hso_get_mux_ports(struct usb_interface *intf, unsigned char *ports)
{}

/* 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)
{}

/* operations setup of the serial interface */
static const struct tty_operations hso_serial_ops =;

static struct usb_driver hso_driver =;

static int __init hso_init(void)
{}

static void __exit hso_exit(void)
{}

/* Module definitions */
module_init();
module_exit(hso_exit);

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

/* change the debug level (eg: insmod hso.ko debug=0x04) */
MODULE_PARM_DESC();
module_param(debug, int, 0644);

/* set the major tty number (eg: insmod hso.ko tty_major=245) */
MODULE_PARM_DESC();
module_param(tty_major, int, 0644);

/* disable network interface (eg: insmod hso.ko disable_net=1) */
MODULE_PARM_DESC();
module_param(disable_net, int, 0644);