162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci  Keyspan USB to Serial Converter driver
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci  (C) Copyright (C) 2000-2001	Hugh Blemings <hugh@blemings.org>
662306a36Sopenharmony_ci  (C) Copyright (C) 2002	Greg Kroah-Hartman <greg@kroah.com>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci  See http://blemings.org/hugh/keyspan.html for more information.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci  Code in this driver inspired by and in a number of places taken
1162306a36Sopenharmony_ci  from Brian Warner's original Keyspan-PDA driver.
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci  This driver has been put together with the support of Innosys, Inc.
1462306a36Sopenharmony_ci  and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
1562306a36Sopenharmony_ci  Thanks Guys :)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
1862306a36Sopenharmony_ci  of much nicer and/or completely new code and (perhaps most uniquely)
1962306a36Sopenharmony_ci  having the patience to sit down and explain why and where he'd changed
2062306a36Sopenharmony_ci  stuff.
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci  Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
2362306a36Sopenharmony_ci  staff in their work on open source projects.
2462306a36Sopenharmony_ci*/
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/kernel.h>
2862306a36Sopenharmony_ci#include <linux/jiffies.h>
2962306a36Sopenharmony_ci#include <linux/errno.h>
3062306a36Sopenharmony_ci#include <linux/slab.h>
3162306a36Sopenharmony_ci#include <linux/tty.h>
3262306a36Sopenharmony_ci#include <linux/tty_driver.h>
3362306a36Sopenharmony_ci#include <linux/tty_flip.h>
3462306a36Sopenharmony_ci#include <linux/module.h>
3562306a36Sopenharmony_ci#include <linux/spinlock.h>
3662306a36Sopenharmony_ci#include <linux/uaccess.h>
3762306a36Sopenharmony_ci#include <linux/usb.h>
3862306a36Sopenharmony_ci#include <linux/usb/serial.h>
3962306a36Sopenharmony_ci#include <linux/usb/ezusb.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
4262306a36Sopenharmony_ci#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic void keyspan_send_setup(struct usb_serial_port *port, int reset_port);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int keyspan_usa19_calc_baud(struct usb_serial_port *port,
4762306a36Sopenharmony_ci				   u32 baud_rate, u32 baudclk,
4862306a36Sopenharmony_ci				   u8 *rate_hi, u8 *rate_low,
4962306a36Sopenharmony_ci				   u8 *prescaler, int portnum);
5062306a36Sopenharmony_cistatic int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
5162306a36Sopenharmony_ci				    u32 baud_rate, u32 baudclk,
5262306a36Sopenharmony_ci				    u8 *rate_hi, u8 *rate_low,
5362306a36Sopenharmony_ci				    u8 *prescaler, int portnum);
5462306a36Sopenharmony_cistatic int keyspan_usa28_calc_baud(struct usb_serial_port *port,
5562306a36Sopenharmony_ci				   u32 baud_rate, u32 baudclk,
5662306a36Sopenharmony_ci				   u8 *rate_hi, u8 *rate_low,
5762306a36Sopenharmony_ci				   u8 *prescaler, int portnum);
5862306a36Sopenharmony_cistatic int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
5962306a36Sopenharmony_ci				     u32 baud_rate, u32 baudclk,
6062306a36Sopenharmony_ci				     u8 *rate_hi, u8 *rate_low,
6162306a36Sopenharmony_ci				     u8 *prescaler, int portnum);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int keyspan_usa28_send_setup(struct usb_serial *serial,
6462306a36Sopenharmony_ci				    struct usb_serial_port *port,
6562306a36Sopenharmony_ci				    int reset_port);
6662306a36Sopenharmony_cistatic int keyspan_usa26_send_setup(struct usb_serial *serial,
6762306a36Sopenharmony_ci				    struct usb_serial_port *port,
6862306a36Sopenharmony_ci				    int reset_port);
6962306a36Sopenharmony_cistatic int keyspan_usa49_send_setup(struct usb_serial *serial,
7062306a36Sopenharmony_ci				    struct usb_serial_port *port,
7162306a36Sopenharmony_ci				    int reset_port);
7262306a36Sopenharmony_cistatic int keyspan_usa90_send_setup(struct usb_serial *serial,
7362306a36Sopenharmony_ci				    struct usb_serial_port *port,
7462306a36Sopenharmony_ci				    int reset_port);
7562306a36Sopenharmony_cistatic int keyspan_usa67_send_setup(struct usb_serial *serial,
7662306a36Sopenharmony_ci				    struct usb_serial_port *port,
7762306a36Sopenharmony_ci				    int reset_port);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Values used for baud rate calculation - device specific */
8062306a36Sopenharmony_ci#define KEYSPAN_INVALID_BAUD_RATE		(-1)
8162306a36Sopenharmony_ci#define KEYSPAN_BAUD_RATE_OK			(0)
8262306a36Sopenharmony_ci#define KEYSPAN_USA18X_BAUDCLK			(12000000L)	/* a guess */
8362306a36Sopenharmony_ci#define KEYSPAN_USA19_BAUDCLK			(12000000L)
8462306a36Sopenharmony_ci#define KEYSPAN_USA19W_BAUDCLK			(24000000L)
8562306a36Sopenharmony_ci#define KEYSPAN_USA19HS_BAUDCLK			(14769231L)
8662306a36Sopenharmony_ci#define KEYSPAN_USA28_BAUDCLK			(1843200L)
8762306a36Sopenharmony_ci#define KEYSPAN_USA28X_BAUDCLK			(12000000L)
8862306a36Sopenharmony_ci#define KEYSPAN_USA49W_BAUDCLK			(48000000L)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* Some constants used to characterise each device.  */
9162306a36Sopenharmony_ci#define KEYSPAN_MAX_NUM_PORTS			(4)
9262306a36Sopenharmony_ci#define KEYSPAN_MAX_FLIPS			(2)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * Device info for the Keyspan serial converter, used by the overall
9662306a36Sopenharmony_ci * usb-serial probe function.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_ci#define KEYSPAN_VENDOR_ID			(0x06cd)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Product IDs for the products supported, pre-renumeration */
10162306a36Sopenharmony_ci#define keyspan_usa18x_pre_product_id		0x0105
10262306a36Sopenharmony_ci#define keyspan_usa19_pre_product_id		0x0103
10362306a36Sopenharmony_ci#define keyspan_usa19qi_pre_product_id		0x010b
10462306a36Sopenharmony_ci#define keyspan_mpr_pre_product_id		0x011b
10562306a36Sopenharmony_ci#define keyspan_usa19qw_pre_product_id		0x0118
10662306a36Sopenharmony_ci#define keyspan_usa19w_pre_product_id		0x0106
10762306a36Sopenharmony_ci#define keyspan_usa28_pre_product_id		0x0101
10862306a36Sopenharmony_ci#define keyspan_usa28x_pre_product_id		0x0102
10962306a36Sopenharmony_ci#define keyspan_usa28xa_pre_product_id		0x0114
11062306a36Sopenharmony_ci#define keyspan_usa28xb_pre_product_id		0x0113
11162306a36Sopenharmony_ci#define keyspan_usa49w_pre_product_id		0x0109
11262306a36Sopenharmony_ci#define keyspan_usa49wlc_pre_product_id		0x011a
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * Product IDs post-renumeration.  Note that the 28x and 28xb have the same
11662306a36Sopenharmony_ci * id's post-renumeration but behave identically so it's not an issue. As
11762306a36Sopenharmony_ci * such, the 28xb is not listed in any of the device tables.
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_ci#define keyspan_usa18x_product_id		0x0112
12062306a36Sopenharmony_ci#define keyspan_usa19_product_id		0x0107
12162306a36Sopenharmony_ci#define keyspan_usa19qi_product_id		0x010c
12262306a36Sopenharmony_ci#define keyspan_usa19hs_product_id		0x0121
12362306a36Sopenharmony_ci#define keyspan_mpr_product_id			0x011c
12462306a36Sopenharmony_ci#define keyspan_usa19qw_product_id		0x0119
12562306a36Sopenharmony_ci#define keyspan_usa19w_product_id		0x0108
12662306a36Sopenharmony_ci#define keyspan_usa28_product_id		0x010f
12762306a36Sopenharmony_ci#define keyspan_usa28x_product_id		0x0110
12862306a36Sopenharmony_ci#define keyspan_usa28xa_product_id		0x0115
12962306a36Sopenharmony_ci#define keyspan_usa28xb_product_id		0x0110
13062306a36Sopenharmony_ci#define keyspan_usa28xg_product_id		0x0135
13162306a36Sopenharmony_ci#define keyspan_usa49w_product_id		0x010a
13262306a36Sopenharmony_ci#define keyspan_usa49wlc_product_id		0x012a
13362306a36Sopenharmony_ci#define keyspan_usa49wg_product_id		0x0131
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistruct keyspan_device_details {
13662306a36Sopenharmony_ci	/* product ID value */
13762306a36Sopenharmony_ci	int	product_id;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	enum	{msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		/* Number of physical ports */
14262306a36Sopenharmony_ci	int	num_ports;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		/* 1 if endpoint flipping used on input, 0 if not */
14562306a36Sopenharmony_ci	int	indat_endp_flip;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		/* 1 if endpoint flipping used on output, 0 if not */
14862306a36Sopenharmony_ci	int	outdat_endp_flip;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci		/*
15162306a36Sopenharmony_ci		 * Table mapping input data endpoint IDs to physical port
15262306a36Sopenharmony_ci		 * number and flip if used
15362306a36Sopenharmony_ci		 */
15462306a36Sopenharmony_ci	int	indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci		/* Same for output endpoints */
15762306a36Sopenharmony_ci	int	outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		/* Input acknowledge endpoints */
16062306a36Sopenharmony_ci	int	inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		/* Output control endpoints */
16362306a36Sopenharmony_ci	int	outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		/* Endpoint used for input status */
16662306a36Sopenharmony_ci	int	instat_endpoint;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		/* Endpoint used for input data 49WG only */
16962306a36Sopenharmony_ci	int	indat_endpoint;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		/* Endpoint used for global control functions */
17262306a36Sopenharmony_ci	int	glocont_endpoint;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	int	(*calculate_baud_rate)(struct usb_serial_port *port,
17562306a36Sopenharmony_ci				       u32 baud_rate, u32 baudclk,
17662306a36Sopenharmony_ci				       u8 *rate_hi, u8 *rate_low, u8 *prescaler,
17762306a36Sopenharmony_ci				       int portnum);
17862306a36Sopenharmony_ci	u32	baudclk;
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/*
18262306a36Sopenharmony_ci * Now for each device type we setup the device detail structure with the
18362306a36Sopenharmony_ci * appropriate information (provided in Keyspan's documentation)
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic const struct keyspan_device_details usa18x_device_details = {
18762306a36Sopenharmony_ci	.product_id		= keyspan_usa18x_product_id,
18862306a36Sopenharmony_ci	.msg_format		= msg_usa26,
18962306a36Sopenharmony_ci	.num_ports		= 1,
19062306a36Sopenharmony_ci	.indat_endp_flip	= 0,
19162306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
19262306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
19362306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
19462306a36Sopenharmony_ci	.inack_endpoints	= {0x85},
19562306a36Sopenharmony_ci	.outcont_endpoints	= {0x05},
19662306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
19762306a36Sopenharmony_ci	.indat_endpoint		= -1,
19862306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
19962306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
20062306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA18X_BAUDCLK,
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic const struct keyspan_device_details usa19_device_details = {
20462306a36Sopenharmony_ci	.product_id		= keyspan_usa19_product_id,
20562306a36Sopenharmony_ci	.msg_format		= msg_usa28,
20662306a36Sopenharmony_ci	.num_ports		= 1,
20762306a36Sopenharmony_ci	.indat_endp_flip	= 1,
20862306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
20962306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
21062306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
21162306a36Sopenharmony_ci	.inack_endpoints	= {0x83},
21262306a36Sopenharmony_ci	.outcont_endpoints	= {0x03},
21362306a36Sopenharmony_ci	.instat_endpoint	= 0x84,
21462306a36Sopenharmony_ci	.indat_endpoint		= -1,
21562306a36Sopenharmony_ci	.glocont_endpoint	= -1,
21662306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19_calc_baud,
21762306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic const struct keyspan_device_details usa19qi_device_details = {
22162306a36Sopenharmony_ci	.product_id		= keyspan_usa19qi_product_id,
22262306a36Sopenharmony_ci	.msg_format		= msg_usa28,
22362306a36Sopenharmony_ci	.num_ports		= 1,
22462306a36Sopenharmony_ci	.indat_endp_flip	= 1,
22562306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
22662306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
22762306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
22862306a36Sopenharmony_ci	.inack_endpoints	= {0x83},
22962306a36Sopenharmony_ci	.outcont_endpoints	= {0x03},
23062306a36Sopenharmony_ci	.instat_endpoint	= 0x84,
23162306a36Sopenharmony_ci	.indat_endpoint		= -1,
23262306a36Sopenharmony_ci	.glocont_endpoint	= -1,
23362306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
23462306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const struct keyspan_device_details mpr_device_details = {
23862306a36Sopenharmony_ci	.product_id		= keyspan_mpr_product_id,
23962306a36Sopenharmony_ci	.msg_format		= msg_usa28,
24062306a36Sopenharmony_ci	.num_ports		= 1,
24162306a36Sopenharmony_ci	.indat_endp_flip	= 1,
24262306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
24362306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
24462306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
24562306a36Sopenharmony_ci	.inack_endpoints	= {0x83},
24662306a36Sopenharmony_ci	.outcont_endpoints	= {0x03},
24762306a36Sopenharmony_ci	.instat_endpoint	= 0x84,
24862306a36Sopenharmony_ci	.indat_endpoint		= -1,
24962306a36Sopenharmony_ci	.glocont_endpoint	= -1,
25062306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
25162306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic const struct keyspan_device_details usa19qw_device_details = {
25562306a36Sopenharmony_ci	.product_id		= keyspan_usa19qw_product_id,
25662306a36Sopenharmony_ci	.msg_format		= msg_usa26,
25762306a36Sopenharmony_ci	.num_ports		= 1,
25862306a36Sopenharmony_ci	.indat_endp_flip	= 0,
25962306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
26062306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
26162306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
26262306a36Sopenharmony_ci	.inack_endpoints	= {0x85},
26362306a36Sopenharmony_ci	.outcont_endpoints	= {0x05},
26462306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
26562306a36Sopenharmony_ci	.indat_endpoint		= -1,
26662306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
26762306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
26862306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic const struct keyspan_device_details usa19w_device_details = {
27262306a36Sopenharmony_ci	.product_id		= keyspan_usa19w_product_id,
27362306a36Sopenharmony_ci	.msg_format		= msg_usa26,
27462306a36Sopenharmony_ci	.num_ports		= 1,
27562306a36Sopenharmony_ci	.indat_endp_flip	= 0,
27662306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
27762306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
27862306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
27962306a36Sopenharmony_ci	.inack_endpoints	= {0x85},
28062306a36Sopenharmony_ci	.outcont_endpoints	= {0x05},
28162306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
28262306a36Sopenharmony_ci	.indat_endpoint		= -1,
28362306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
28462306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
28562306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic const struct keyspan_device_details usa19hs_device_details = {
28962306a36Sopenharmony_ci	.product_id		= keyspan_usa19hs_product_id,
29062306a36Sopenharmony_ci	.msg_format		= msg_usa90,
29162306a36Sopenharmony_ci	.num_ports		= 1,
29262306a36Sopenharmony_ci	.indat_endp_flip	= 0,
29362306a36Sopenharmony_ci	.outdat_endp_flip	= 0,
29462306a36Sopenharmony_ci	.indat_endpoints	= {0x81},
29562306a36Sopenharmony_ci	.outdat_endpoints	= {0x01},
29662306a36Sopenharmony_ci	.inack_endpoints	= {-1},
29762306a36Sopenharmony_ci	.outcont_endpoints	= {0x02},
29862306a36Sopenharmony_ci	.instat_endpoint	= 0x82,
29962306a36Sopenharmony_ci	.indat_endpoint		= -1,
30062306a36Sopenharmony_ci	.glocont_endpoint	= -1,
30162306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19hs_calc_baud,
30262306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19HS_BAUDCLK,
30362306a36Sopenharmony_ci};
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic const struct keyspan_device_details usa28_device_details = {
30662306a36Sopenharmony_ci	.product_id		= keyspan_usa28_product_id,
30762306a36Sopenharmony_ci	.msg_format		= msg_usa28,
30862306a36Sopenharmony_ci	.num_ports		= 2,
30962306a36Sopenharmony_ci	.indat_endp_flip	= 1,
31062306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
31162306a36Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
31262306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
31362306a36Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
31462306a36Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
31562306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
31662306a36Sopenharmony_ci	.indat_endpoint		= -1,
31762306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
31862306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
31962306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA28_BAUDCLK,
32062306a36Sopenharmony_ci};
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic const struct keyspan_device_details usa28x_device_details = {
32362306a36Sopenharmony_ci	.product_id		= keyspan_usa28x_product_id,
32462306a36Sopenharmony_ci	.msg_format		= msg_usa26,
32562306a36Sopenharmony_ci	.num_ports		= 2,
32662306a36Sopenharmony_ci	.indat_endp_flip	= 0,
32762306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
32862306a36Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
32962306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
33062306a36Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
33162306a36Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
33262306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
33362306a36Sopenharmony_ci	.indat_endpoint		= -1,
33462306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
33562306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
33662306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic const struct keyspan_device_details usa28xa_device_details = {
34062306a36Sopenharmony_ci	.product_id		= keyspan_usa28xa_product_id,
34162306a36Sopenharmony_ci	.msg_format		= msg_usa26,
34262306a36Sopenharmony_ci	.num_ports		= 2,
34362306a36Sopenharmony_ci	.indat_endp_flip	= 0,
34462306a36Sopenharmony_ci	.outdat_endp_flip	= 1,
34562306a36Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
34662306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
34762306a36Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
34862306a36Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
34962306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
35062306a36Sopenharmony_ci	.indat_endpoint		= -1,
35162306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
35262306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
35362306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic const struct keyspan_device_details usa28xg_device_details = {
35762306a36Sopenharmony_ci	.product_id		= keyspan_usa28xg_product_id,
35862306a36Sopenharmony_ci	.msg_format		= msg_usa67,
35962306a36Sopenharmony_ci	.num_ports		= 2,
36062306a36Sopenharmony_ci	.indat_endp_flip	= 0,
36162306a36Sopenharmony_ci	.outdat_endp_flip	= 0,
36262306a36Sopenharmony_ci	.indat_endpoints	= {0x84, 0x88},
36362306a36Sopenharmony_ci	.outdat_endpoints	= {0x02, 0x06},
36462306a36Sopenharmony_ci	.inack_endpoints	= {-1, -1},
36562306a36Sopenharmony_ci	.outcont_endpoints	= {-1, -1},
36662306a36Sopenharmony_ci	.instat_endpoint	= 0x81,
36762306a36Sopenharmony_ci	.indat_endpoint		= -1,
36862306a36Sopenharmony_ci	.glocont_endpoint	= 0x01,
36962306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
37062306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci/*
37362306a36Sopenharmony_ci * We don't need a separate entry for the usa28xb as it appears as a 28x
37462306a36Sopenharmony_ci * anyway.
37562306a36Sopenharmony_ci */
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic const struct keyspan_device_details usa49w_device_details = {
37862306a36Sopenharmony_ci	.product_id		= keyspan_usa49w_product_id,
37962306a36Sopenharmony_ci	.msg_format		= msg_usa49,
38062306a36Sopenharmony_ci	.num_ports		= 4,
38162306a36Sopenharmony_ci	.indat_endp_flip	= 0,
38262306a36Sopenharmony_ci	.outdat_endp_flip	= 0,
38362306a36Sopenharmony_ci	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
38462306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
38562306a36Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
38662306a36Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
38762306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
38862306a36Sopenharmony_ci	.indat_endpoint		= -1,
38962306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
39062306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
39162306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA49W_BAUDCLK,
39262306a36Sopenharmony_ci};
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic const struct keyspan_device_details usa49wlc_device_details = {
39562306a36Sopenharmony_ci	.product_id		= keyspan_usa49wlc_product_id,
39662306a36Sopenharmony_ci	.msg_format		= msg_usa49,
39762306a36Sopenharmony_ci	.num_ports		= 4,
39862306a36Sopenharmony_ci	.indat_endp_flip	= 0,
39962306a36Sopenharmony_ci	.outdat_endp_flip	= 0,
40062306a36Sopenharmony_ci	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
40162306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
40262306a36Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
40362306a36Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
40462306a36Sopenharmony_ci	.instat_endpoint	= 0x87,
40562306a36Sopenharmony_ci	.indat_endpoint		= -1,
40662306a36Sopenharmony_ci	.glocont_endpoint	= 0x07,
40762306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
40862306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
40962306a36Sopenharmony_ci};
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cistatic const struct keyspan_device_details usa49wg_device_details = {
41262306a36Sopenharmony_ci	.product_id		= keyspan_usa49wg_product_id,
41362306a36Sopenharmony_ci	.msg_format		= msg_usa49,
41462306a36Sopenharmony_ci	.num_ports		= 4,
41562306a36Sopenharmony_ci	.indat_endp_flip	= 0,
41662306a36Sopenharmony_ci	.outdat_endp_flip	= 0,
41762306a36Sopenharmony_ci	.indat_endpoints	= {-1, -1, -1, -1},	/* single 'global' data in EP */
41862306a36Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x04, 0x06},
41962306a36Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
42062306a36Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
42162306a36Sopenharmony_ci	.instat_endpoint	= 0x81,
42262306a36Sopenharmony_ci	.indat_endpoint		= 0x88,
42362306a36Sopenharmony_ci	.glocont_endpoint	= 0x00,			/* uses control EP */
42462306a36Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
42562306a36Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
42662306a36Sopenharmony_ci};
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic const struct keyspan_device_details *keyspan_devices[] = {
42962306a36Sopenharmony_ci	&usa18x_device_details,
43062306a36Sopenharmony_ci	&usa19_device_details,
43162306a36Sopenharmony_ci	&usa19qi_device_details,
43262306a36Sopenharmony_ci	&mpr_device_details,
43362306a36Sopenharmony_ci	&usa19qw_device_details,
43462306a36Sopenharmony_ci	&usa19w_device_details,
43562306a36Sopenharmony_ci	&usa19hs_device_details,
43662306a36Sopenharmony_ci	&usa28_device_details,
43762306a36Sopenharmony_ci	&usa28x_device_details,
43862306a36Sopenharmony_ci	&usa28xa_device_details,
43962306a36Sopenharmony_ci	&usa28xg_device_details,
44062306a36Sopenharmony_ci	/* 28xb not required as it renumerates as a 28x */
44162306a36Sopenharmony_ci	&usa49w_device_details,
44262306a36Sopenharmony_ci	&usa49wlc_device_details,
44362306a36Sopenharmony_ci	&usa49wg_device_details,
44462306a36Sopenharmony_ci	NULL,
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic const struct usb_device_id keyspan_ids_combined[] = {
44862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
44962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
45062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
45162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
45262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
45362306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
45462306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
45562306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
45662306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
45762306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
45862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
45962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
46062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
46162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
46262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
46362306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
46462306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
46562306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
46662306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
46762306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
46862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
46962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
47062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
47162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
47262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
47362306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
47462306a36Sopenharmony_ci	{ } /* Terminating entry */
47562306a36Sopenharmony_ci};
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci/* usb_device_id table for the pre-firmware download keyspan devices */
48062306a36Sopenharmony_cistatic const struct usb_device_id keyspan_pre_ids[] = {
48162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
48262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
48362306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
48462306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
48562306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
48662306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
48762306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
48862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
48962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
49062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
49162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
49262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
49362306a36Sopenharmony_ci	{ } /* Terminating entry */
49462306a36Sopenharmony_ci};
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic const struct usb_device_id keyspan_1port_ids[] = {
49762306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
49862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
49962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
50062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
50162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
50262306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
50362306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
50462306a36Sopenharmony_ci	{ } /* Terminating entry */
50562306a36Sopenharmony_ci};
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic const struct usb_device_id keyspan_2port_ids[] = {
50862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
50962306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
51062306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
51162306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
51262306a36Sopenharmony_ci	{ } /* Terminating entry */
51362306a36Sopenharmony_ci};
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic const struct usb_device_id keyspan_4port_ids[] = {
51662306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
51762306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
51862306a36Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
51962306a36Sopenharmony_ci	{ } /* Terminating entry */
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci#define INSTAT_BUFLEN	32
52362306a36Sopenharmony_ci#define GLOCONT_BUFLEN	64
52462306a36Sopenharmony_ci#define INDAT49W_BUFLEN	512
52562306a36Sopenharmony_ci#define IN_BUFLEN	64
52662306a36Sopenharmony_ci#define OUT_BUFLEN	64
52762306a36Sopenharmony_ci#define INACK_BUFLEN	1
52862306a36Sopenharmony_ci#define OUTCONT_BUFLEN	64
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* Per device and per port private data */
53162306a36Sopenharmony_cistruct keyspan_serial_private {
53262306a36Sopenharmony_ci	const struct keyspan_device_details	*device_details;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	struct urb	*instat_urb;
53562306a36Sopenharmony_ci	char		*instat_buf;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* added to support 49wg, where data from all 4 ports comes in
53862306a36Sopenharmony_ci	   on 1 EP and high-speed supported */
53962306a36Sopenharmony_ci	struct urb	*indat_urb;
54062306a36Sopenharmony_ci	char		*indat_buf;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* XXX this one probably will need a lock */
54362306a36Sopenharmony_ci	struct urb	*glocont_urb;
54462306a36Sopenharmony_ci	char		*glocont_buf;
54562306a36Sopenharmony_ci	char		*ctrl_buf;	/* for EP0 control message */
54662306a36Sopenharmony_ci};
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistruct keyspan_port_private {
54962306a36Sopenharmony_ci	/* Keep track of which input & output endpoints to use */
55062306a36Sopenharmony_ci	int		in_flip;
55162306a36Sopenharmony_ci	int		out_flip;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Keep duplicate of device details in each port
55462306a36Sopenharmony_ci	   structure as well - simplifies some of the
55562306a36Sopenharmony_ci	   callback functions etc. */
55662306a36Sopenharmony_ci	const struct keyspan_device_details	*device_details;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* Input endpoints and buffer for this port */
55962306a36Sopenharmony_ci	struct urb	*in_urbs[2];
56062306a36Sopenharmony_ci	char		*in_buffer[2];
56162306a36Sopenharmony_ci	/* Output endpoints and buffer for this port */
56262306a36Sopenharmony_ci	struct urb	*out_urbs[2];
56362306a36Sopenharmony_ci	char		*out_buffer[2];
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Input ack endpoint */
56662306a36Sopenharmony_ci	struct urb	*inack_urb;
56762306a36Sopenharmony_ci	char		*inack_buffer;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* Output control endpoint */
57062306a36Sopenharmony_ci	struct urb	*outcont_urb;
57162306a36Sopenharmony_ci	char		*outcont_buffer;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* Settings for the port */
57462306a36Sopenharmony_ci	int		baud;
57562306a36Sopenharmony_ci	int		old_baud;
57662306a36Sopenharmony_ci	unsigned int	cflag;
57762306a36Sopenharmony_ci	unsigned int	old_cflag;
57862306a36Sopenharmony_ci	enum		{flow_none, flow_cts, flow_xon} flow_control;
57962306a36Sopenharmony_ci	int		rts_state;	/* Handshaking pins (outputs) */
58062306a36Sopenharmony_ci	int		dtr_state;
58162306a36Sopenharmony_ci	int		cts_state;	/* Handshaking pins (inputs) */
58262306a36Sopenharmony_ci	int		dsr_state;
58362306a36Sopenharmony_ci	int		dcd_state;
58462306a36Sopenharmony_ci	int		ri_state;
58562306a36Sopenharmony_ci	int		break_on;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	unsigned long	tx_start_time[2];
58862306a36Sopenharmony_ci	int		resend_cont;	/* need to resend control packet */
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/* Include Keyspan message headers.  All current Keyspan Adapters
59262306a36Sopenharmony_ci   make use of one of five message formats which are referred
59362306a36Sopenharmony_ci   to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
59462306a36Sopenharmony_ci   within this driver. */
59562306a36Sopenharmony_ci#include "keyspan_usa26msg.h"
59662306a36Sopenharmony_ci#include "keyspan_usa28msg.h"
59762306a36Sopenharmony_ci#include "keyspan_usa49msg.h"
59862306a36Sopenharmony_ci#include "keyspan_usa90msg.h"
59962306a36Sopenharmony_ci#include "keyspan_usa67msg.h"
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_cistatic int keyspan_break_ctl(struct tty_struct *tty, int break_state)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
60562306a36Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (break_state == -1)
61062306a36Sopenharmony_ci		p_priv->break_on = 1;
61162306a36Sopenharmony_ci	else
61262306a36Sopenharmony_ci		p_priv->break_on = 0;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* FIXME: return errors */
61562306a36Sopenharmony_ci	keyspan_send_setup(port, 0);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void keyspan_set_termios(struct tty_struct *tty,
62262306a36Sopenharmony_ci				struct usb_serial_port *port,
62362306a36Sopenharmony_ci				const struct ktermios *old_termios)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	int				baud_rate, device_port;
62662306a36Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
62762306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
62862306a36Sopenharmony_ci	unsigned int 			cflag;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
63162306a36Sopenharmony_ci	d_details = p_priv->device_details;
63262306a36Sopenharmony_ci	cflag = tty->termios.c_cflag;
63362306a36Sopenharmony_ci	device_port = port->port_number;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* Baud rate calculation takes baud rate as an integer
63662306a36Sopenharmony_ci	   so other rates can be generated if desired. */
63762306a36Sopenharmony_ci	baud_rate = tty_get_baud_rate(tty);
63862306a36Sopenharmony_ci	/* If no match or invalid, don't change */
63962306a36Sopenharmony_ci	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
64062306a36Sopenharmony_ci				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
64162306a36Sopenharmony_ci		/* FIXME - more to do here to ensure rate changes cleanly */
64262306a36Sopenharmony_ci		/* FIXME - calculate exact rate from divisor ? */
64362306a36Sopenharmony_ci		p_priv->baud = baud_rate;
64462306a36Sopenharmony_ci	} else
64562306a36Sopenharmony_ci		baud_rate = tty_termios_baud_rate(old_termios);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	tty_encode_baud_rate(tty, baud_rate, baud_rate);
64862306a36Sopenharmony_ci	/* set CTS/RTS handshake etc. */
64962306a36Sopenharmony_ci	p_priv->cflag = cflag;
65062306a36Sopenharmony_ci	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Mark/Space not supported */
65362306a36Sopenharmony_ci	tty->termios.c_cflag &= ~CMSPAR;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	keyspan_send_setup(port, 0);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic int keyspan_tiocmget(struct tty_struct *tty)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
66162306a36Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
66262306a36Sopenharmony_ci	unsigned int			value;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
66562306a36Sopenharmony_ci		((p_priv->dtr_state) ? TIOCM_DTR : 0) |
66662306a36Sopenharmony_ci		((p_priv->cts_state) ? TIOCM_CTS : 0) |
66762306a36Sopenharmony_ci		((p_priv->dsr_state) ? TIOCM_DSR : 0) |
66862306a36Sopenharmony_ci		((p_priv->dcd_state) ? TIOCM_CAR : 0) |
66962306a36Sopenharmony_ci		((p_priv->ri_state) ? TIOCM_RNG : 0);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return value;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int keyspan_tiocmset(struct tty_struct *tty,
67562306a36Sopenharmony_ci			    unsigned int set, unsigned int clear)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
67862306a36Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (set & TIOCM_RTS)
68162306a36Sopenharmony_ci		p_priv->rts_state = 1;
68262306a36Sopenharmony_ci	if (set & TIOCM_DTR)
68362306a36Sopenharmony_ci		p_priv->dtr_state = 1;
68462306a36Sopenharmony_ci	if (clear & TIOCM_RTS)
68562306a36Sopenharmony_ci		p_priv->rts_state = 0;
68662306a36Sopenharmony_ci	if (clear & TIOCM_DTR)
68762306a36Sopenharmony_ci		p_priv->dtr_state = 0;
68862306a36Sopenharmony_ci	keyspan_send_setup(port, 0);
68962306a36Sopenharmony_ci	return 0;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci/* Write function is similar for the four protocols used
69362306a36Sopenharmony_ci   with only a minor change for usa90 (usa19hs) required */
69462306a36Sopenharmony_cistatic int keyspan_write(struct tty_struct *tty,
69562306a36Sopenharmony_ci	struct usb_serial_port *port, const unsigned char *buf, int count)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
69862306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
69962306a36Sopenharmony_ci	int				flip;
70062306a36Sopenharmony_ci	int 				left, todo;
70162306a36Sopenharmony_ci	struct urb			*this_urb;
70262306a36Sopenharmony_ci	int 				err, maxDataLen, dataOffset;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
70562306a36Sopenharmony_ci	d_details = p_priv->device_details;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (d_details->msg_format == msg_usa90) {
70862306a36Sopenharmony_ci		maxDataLen = 64;
70962306a36Sopenharmony_ci		dataOffset = 0;
71062306a36Sopenharmony_ci	} else {
71162306a36Sopenharmony_ci		maxDataLen = 63;
71262306a36Sopenharmony_ci		dataOffset = 1;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
71662306a36Sopenharmony_ci		p_priv->out_flip);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	for (left = count; left > 0; left -= todo) {
71962306a36Sopenharmony_ci		todo = left;
72062306a36Sopenharmony_ci		if (todo > maxDataLen)
72162306a36Sopenharmony_ci			todo = maxDataLen;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		flip = p_priv->out_flip;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		/* Check we have a valid urb/endpoint before we use it... */
72662306a36Sopenharmony_ci		this_urb = p_priv->out_urbs[flip];
72762306a36Sopenharmony_ci		if (this_urb == NULL) {
72862306a36Sopenharmony_ci			/* no bulk out, so return 0 bytes written */
72962306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
73062306a36Sopenharmony_ci			return count;
73162306a36Sopenharmony_ci		}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
73462306a36Sopenharmony_ci			__func__, usb_pipeendpoint(this_urb->pipe), flip);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		if (this_urb->status == -EINPROGRESS) {
73762306a36Sopenharmony_ci			if (time_before(jiffies,
73862306a36Sopenharmony_ci					p_priv->tx_start_time[flip] + 10 * HZ))
73962306a36Sopenharmony_ci				break;
74062306a36Sopenharmony_ci			usb_unlink_urb(this_urb);
74162306a36Sopenharmony_ci			break;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		/* First byte in buffer is "last flag" (except for usa19hx)
74562306a36Sopenharmony_ci		   - unused so for now so set to zero */
74662306a36Sopenharmony_ci		((char *)this_urb->transfer_buffer)[0] = 0;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
74962306a36Sopenharmony_ci		buf += todo;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		/* send the data out the bulk port */
75262306a36Sopenharmony_ci		this_urb->transfer_buffer_length = todo + dataOffset;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		err = usb_submit_urb(this_urb, GFP_ATOMIC);
75562306a36Sopenharmony_ci		if (err != 0)
75662306a36Sopenharmony_ci			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
75762306a36Sopenharmony_ci		p_priv->tx_start_time[flip] = jiffies;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		/* Flip for next time if usa26 or usa28 interface
76062306a36Sopenharmony_ci		   (not used on usa49) */
76162306a36Sopenharmony_ci		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	return count - left;
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_cistatic void	usa26_indat_callback(struct urb *urb)
76862306a36Sopenharmony_ci{
76962306a36Sopenharmony_ci	int			i, err;
77062306a36Sopenharmony_ci	int			endpoint;
77162306a36Sopenharmony_ci	struct usb_serial_port	*port;
77262306a36Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
77362306a36Sopenharmony_ci	int status = urb->status;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (status) {
77862306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
77962306a36Sopenharmony_ci			__func__, status, endpoint);
78062306a36Sopenharmony_ci		return;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	port =  urb->context;
78462306a36Sopenharmony_ci	if (urb->actual_length) {
78562306a36Sopenharmony_ci		/* 0x80 bit is error flag */
78662306a36Sopenharmony_ci		if ((data[0] & 0x80) == 0) {
78762306a36Sopenharmony_ci			/* no errors on individual bytes, only
78862306a36Sopenharmony_ci			   possible overrun err */
78962306a36Sopenharmony_ci			if (data[0] & RXERROR_OVERRUN) {
79062306a36Sopenharmony_ci				tty_insert_flip_char(&port->port, 0,
79162306a36Sopenharmony_ci								TTY_OVERRUN);
79262306a36Sopenharmony_ci			}
79362306a36Sopenharmony_ci			for (i = 1; i < urb->actual_length ; ++i)
79462306a36Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i],
79562306a36Sopenharmony_ci								TTY_NORMAL);
79662306a36Sopenharmony_ci		} else {
79762306a36Sopenharmony_ci			/* some bytes had errors, every byte has status */
79862306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
79962306a36Sopenharmony_ci			for (i = 0; i + 1 < urb->actual_length; i += 2) {
80062306a36Sopenharmony_ci				int stat = data[i];
80162306a36Sopenharmony_ci				int flag = TTY_NORMAL;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
80462306a36Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
80562306a36Sopenharmony_ci								TTY_OVERRUN);
80662306a36Sopenharmony_ci				}
80762306a36Sopenharmony_ci				/* XXX should handle break (0x10) */
80862306a36Sopenharmony_ci				if (stat & RXERROR_PARITY)
80962306a36Sopenharmony_ci					flag = TTY_PARITY;
81062306a36Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
81162306a36Sopenharmony_ci					flag = TTY_FRAME;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
81462306a36Sopenharmony_ci						flag);
81562306a36Sopenharmony_ci			}
81662306a36Sopenharmony_ci		}
81762306a36Sopenharmony_ci		tty_flip_buffer_push(&port->port);
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
82162306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
82262306a36Sopenharmony_ci	if (err != 0)
82362306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/* Outdat handling is common for all devices */
82762306a36Sopenharmony_cistatic void	usa2x_outdat_callback(struct urb *urb)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	struct usb_serial_port *port;
83062306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	port =  urb->context;
83362306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
83462306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	usb_serial_port_softint(port);
83762306a36Sopenharmony_ci}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic void	usa26_inack_callback(struct urb *urb)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic void	usa26_outcont_callback(struct urb *urb)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct usb_serial_port *port;
84662306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	port =  urb->context;
84962306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	if (p_priv->resend_cont) {
85262306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
85362306a36Sopenharmony_ci		keyspan_usa26_send_setup(port->serial, port,
85462306a36Sopenharmony_ci						p_priv->resend_cont - 1);
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void	usa26_instat_callback(struct urb *urb)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
86162306a36Sopenharmony_ci	struct keyspan_usa26_portStatusMessage	*msg;
86262306a36Sopenharmony_ci	struct usb_serial			*serial;
86362306a36Sopenharmony_ci	struct usb_serial_port			*port;
86462306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
86562306a36Sopenharmony_ci	int old_dcd_state, err;
86662306a36Sopenharmony_ci	int status = urb->status;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	serial =  urb->context;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (status) {
87162306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
87262306a36Sopenharmony_ci				__func__, status);
87362306a36Sopenharmony_ci		return;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci	if (urb->actual_length != 9) {
87662306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
87762306a36Sopenharmony_ci		goto exit;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	msg = (struct keyspan_usa26_portStatusMessage *)data;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	/* Check port number from message and retrieve private data */
88362306a36Sopenharmony_ci	if (msg->port >= serial->num_ports) {
88462306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
88562306a36Sopenharmony_ci		goto exit;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci	port = serial->port[msg->port];
88862306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
88962306a36Sopenharmony_ci	if (!p_priv)
89062306a36Sopenharmony_ci		goto resubmit;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* Update handshaking pin state information */
89362306a36Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
89462306a36Sopenharmony_ci	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
89562306a36Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
89662306a36Sopenharmony_ci	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
89762306a36Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state)
90062306a36Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
90162306a36Sopenharmony_ciresubmit:
90262306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
90362306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
90462306a36Sopenharmony_ci	if (err != 0)
90562306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
90662306a36Sopenharmony_ciexit: ;
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic void	usa26_glocont_callback(struct urb *urb)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic void usa28_indat_callback(struct urb *urb)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	int                     err;
91762306a36Sopenharmony_ci	struct usb_serial_port  *port;
91862306a36Sopenharmony_ci	unsigned char           *data;
91962306a36Sopenharmony_ci	struct keyspan_port_private             *p_priv;
92062306a36Sopenharmony_ci	int status = urb->status;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	port =  urb->context;
92362306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
92462306a36Sopenharmony_ci	data = urb->transfer_buffer;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (urb != p_priv->in_urbs[p_priv->in_flip])
92762306a36Sopenharmony_ci		return;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	do {
93062306a36Sopenharmony_ci		if (status) {
93162306a36Sopenharmony_ci			dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
93262306a36Sopenharmony_ci				__func__, status, usb_pipeendpoint(urb->pipe));
93362306a36Sopenharmony_ci			return;
93462306a36Sopenharmony_ci		}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		port =  urb->context;
93762306a36Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
93862306a36Sopenharmony_ci		data = urb->transfer_buffer;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		if (urb->actual_length) {
94162306a36Sopenharmony_ci			tty_insert_flip_string(&port->port, data,
94262306a36Sopenharmony_ci					urb->actual_length);
94362306a36Sopenharmony_ci			tty_flip_buffer_push(&port->port);
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		/* Resubmit urb so we continue receiving */
94762306a36Sopenharmony_ci		err = usb_submit_urb(urb, GFP_ATOMIC);
94862306a36Sopenharmony_ci		if (err != 0)
94962306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
95062306a36Sopenharmony_ci							__func__, err);
95162306a36Sopenharmony_ci		p_priv->in_flip ^= 1;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		urb = p_priv->in_urbs[p_priv->in_flip];
95462306a36Sopenharmony_ci	} while (urb->status != -EINPROGRESS);
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_cistatic void	usa28_inack_callback(struct urb *urb)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic void	usa28_outcont_callback(struct urb *urb)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	struct usb_serial_port *port;
96462306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	port =  urb->context;
96762306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (p_priv->resend_cont) {
97062306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
97162306a36Sopenharmony_ci		keyspan_usa28_send_setup(port->serial, port,
97262306a36Sopenharmony_ci						p_priv->resend_cont - 1);
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_cistatic void	usa28_instat_callback(struct urb *urb)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	int					err;
97962306a36Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
98062306a36Sopenharmony_ci	struct keyspan_usa28_portStatusMessage	*msg;
98162306a36Sopenharmony_ci	struct usb_serial			*serial;
98262306a36Sopenharmony_ci	struct usb_serial_port			*port;
98362306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
98462306a36Sopenharmony_ci	int old_dcd_state;
98562306a36Sopenharmony_ci	int status = urb->status;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	serial =  urb->context;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (status) {
99062306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
99162306a36Sopenharmony_ci				__func__, status);
99262306a36Sopenharmony_ci		return;
99362306a36Sopenharmony_ci	}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
99662306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
99762306a36Sopenharmony_ci		goto exit;
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	msg = (struct keyspan_usa28_portStatusMessage *)data;
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* Check port number from message and retrieve private data */
100362306a36Sopenharmony_ci	if (msg->port >= serial->num_ports) {
100462306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
100562306a36Sopenharmony_ci		goto exit;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci	port = serial->port[msg->port];
100862306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
100962306a36Sopenharmony_ci	if (!p_priv)
101062306a36Sopenharmony_ci		goto resubmit;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/* Update handshaking pin state information */
101362306a36Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
101462306a36Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
101562306a36Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
101662306a36Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
101762306a36Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
102062306a36Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
102162306a36Sopenharmony_ciresubmit:
102262306a36Sopenharmony_ci		/* Resubmit urb so we continue receiving */
102362306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
102462306a36Sopenharmony_ci	if (err != 0)
102562306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
102662306a36Sopenharmony_ciexit: ;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic void	usa28_glocont_callback(struct urb *urb)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic void	usa49_glocont_callback(struct urb *urb)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct usb_serial *serial;
103762306a36Sopenharmony_ci	struct usb_serial_port *port;
103862306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
103962306a36Sopenharmony_ci	int i;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	serial =  urb->context;
104262306a36Sopenharmony_ci	for (i = 0; i < serial->num_ports; ++i) {
104362306a36Sopenharmony_ci		port = serial->port[i];
104462306a36Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
104562306a36Sopenharmony_ci		if (!p_priv)
104662306a36Sopenharmony_ci			continue;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		if (p_priv->resend_cont) {
104962306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
105062306a36Sopenharmony_ci			keyspan_usa49_send_setup(serial, port,
105162306a36Sopenharmony_ci						p_priv->resend_cont - 1);
105262306a36Sopenharmony_ci			break;
105362306a36Sopenharmony_ci		}
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	/* This is actually called glostat in the Keyspan
105862306a36Sopenharmony_ci	   doco */
105962306a36Sopenharmony_cistatic void	usa49_instat_callback(struct urb *urb)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	int					err;
106262306a36Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
106362306a36Sopenharmony_ci	struct keyspan_usa49_portStatusMessage	*msg;
106462306a36Sopenharmony_ci	struct usb_serial			*serial;
106562306a36Sopenharmony_ci	struct usb_serial_port			*port;
106662306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
106762306a36Sopenharmony_ci	int old_dcd_state;
106862306a36Sopenharmony_ci	int status = urb->status;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	serial =  urb->context;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	if (status) {
107362306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
107462306a36Sopenharmony_ci				__func__, status);
107562306a36Sopenharmony_ci		return;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	if (urb->actual_length !=
107962306a36Sopenharmony_ci			sizeof(struct keyspan_usa49_portStatusMessage)) {
108062306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
108162306a36Sopenharmony_ci		goto exit;
108262306a36Sopenharmony_ci	}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	msg = (struct keyspan_usa49_portStatusMessage *)data;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* Check port number from message and retrieve private data */
108762306a36Sopenharmony_ci	if (msg->portNumber >= serial->num_ports) {
108862306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
108962306a36Sopenharmony_ci			__func__, msg->portNumber);
109062306a36Sopenharmony_ci		goto exit;
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci	port = serial->port[msg->portNumber];
109362306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
109462306a36Sopenharmony_ci	if (!p_priv)
109562306a36Sopenharmony_ci		goto resubmit;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	/* Update handshaking pin state information */
109862306a36Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
109962306a36Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
110062306a36Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
110162306a36Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
110262306a36Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
110562306a36Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
110662306a36Sopenharmony_ciresubmit:
110762306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
110862306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
110962306a36Sopenharmony_ci	if (err != 0)
111062306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
111162306a36Sopenharmony_ciexit:	;
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic void	usa49_inack_callback(struct urb *urb)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic void	usa49_indat_callback(struct urb *urb)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	int			i, err;
112162306a36Sopenharmony_ci	int			endpoint;
112262306a36Sopenharmony_ci	struct usb_serial_port	*port;
112362306a36Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
112462306a36Sopenharmony_ci	int status = urb->status;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (status) {
112962306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
113062306a36Sopenharmony_ci			__func__, status, endpoint);
113162306a36Sopenharmony_ci		return;
113262306a36Sopenharmony_ci	}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	port =  urb->context;
113562306a36Sopenharmony_ci	if (urb->actual_length) {
113662306a36Sopenharmony_ci		/* 0x80 bit is error flag */
113762306a36Sopenharmony_ci		if ((data[0] & 0x80) == 0) {
113862306a36Sopenharmony_ci			/* no error on any byte */
113962306a36Sopenharmony_ci			tty_insert_flip_string(&port->port, data + 1,
114062306a36Sopenharmony_ci						urb->actual_length - 1);
114162306a36Sopenharmony_ci		} else {
114262306a36Sopenharmony_ci			/* some bytes had errors, every byte has status */
114362306a36Sopenharmony_ci			for (i = 0; i + 1 < urb->actual_length; i += 2) {
114462306a36Sopenharmony_ci				int stat = data[i];
114562306a36Sopenharmony_ci				int flag = TTY_NORMAL;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
114862306a36Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
114962306a36Sopenharmony_ci								TTY_OVERRUN);
115062306a36Sopenharmony_ci				}
115162306a36Sopenharmony_ci				/* XXX should handle break (0x10) */
115262306a36Sopenharmony_ci				if (stat & RXERROR_PARITY)
115362306a36Sopenharmony_ci					flag = TTY_PARITY;
115462306a36Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
115562306a36Sopenharmony_ci					flag = TTY_FRAME;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
115862306a36Sopenharmony_ci						flag);
115962306a36Sopenharmony_ci			}
116062306a36Sopenharmony_ci		}
116162306a36Sopenharmony_ci		tty_flip_buffer_push(&port->port);
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
116562306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
116662306a36Sopenharmony_ci	if (err != 0)
116762306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
116862306a36Sopenharmony_ci}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_cistatic void usa49wg_indat_callback(struct urb *urb)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	int			i, len, x, err;
117362306a36Sopenharmony_ci	struct usb_serial	*serial;
117462306a36Sopenharmony_ci	struct usb_serial_port	*port;
117562306a36Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
117662306a36Sopenharmony_ci	int status = urb->status;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	serial = urb->context;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	if (status) {
118162306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
118262306a36Sopenharmony_ci				__func__, status);
118362306a36Sopenharmony_ci		return;
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* inbound data is in the form P#, len, status, data */
118762306a36Sopenharmony_ci	i = 0;
118862306a36Sopenharmony_ci	len = 0;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	while (i < urb->actual_length) {
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		/* Check port number from message */
119362306a36Sopenharmony_ci		if (data[i] >= serial->num_ports) {
119462306a36Sopenharmony_ci			dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
119562306a36Sopenharmony_ci				__func__, data[i]);
119662306a36Sopenharmony_ci			return;
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci		port = serial->port[data[i++]];
119962306a36Sopenharmony_ci		len = data[i++];
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci		/* 0x80 bit is error flag */
120262306a36Sopenharmony_ci		if ((data[i] & 0x80) == 0) {
120362306a36Sopenharmony_ci			/* no error on any byte */
120462306a36Sopenharmony_ci			i++;
120562306a36Sopenharmony_ci			for (x = 1; x < len && i < urb->actual_length; ++x)
120662306a36Sopenharmony_ci				tty_insert_flip_char(&port->port,
120762306a36Sopenharmony_ci						data[i++], 0);
120862306a36Sopenharmony_ci		} else {
120962306a36Sopenharmony_ci			/*
121062306a36Sopenharmony_ci			 * some bytes had errors, every byte has status
121162306a36Sopenharmony_ci			 */
121262306a36Sopenharmony_ci			for (x = 0; x + 1 < len &&
121362306a36Sopenharmony_ci				    i + 1 < urb->actual_length; x += 2) {
121462306a36Sopenharmony_ci				int stat = data[i];
121562306a36Sopenharmony_ci				int flag = TTY_NORMAL;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
121862306a36Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
121962306a36Sopenharmony_ci								TTY_OVERRUN);
122062306a36Sopenharmony_ci				}
122162306a36Sopenharmony_ci				/* XXX should handle break (0x10) */
122262306a36Sopenharmony_ci				if (stat & RXERROR_PARITY)
122362306a36Sopenharmony_ci					flag = TTY_PARITY;
122462306a36Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
122562306a36Sopenharmony_ci					flag = TTY_FRAME;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
122862306a36Sopenharmony_ci						     flag);
122962306a36Sopenharmony_ci				i += 2;
123062306a36Sopenharmony_ci			}
123162306a36Sopenharmony_ci		}
123262306a36Sopenharmony_ci		tty_flip_buffer_push(&port->port);
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
123662306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
123762306a36Sopenharmony_ci	if (err != 0)
123862306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci/* not used, usa-49 doesn't have per-port control endpoints */
124262306a36Sopenharmony_cistatic void usa49_outcont_callback(struct urb *urb)
124362306a36Sopenharmony_ci{
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic void usa90_indat_callback(struct urb *urb)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	int			i, err;
124962306a36Sopenharmony_ci	int			endpoint;
125062306a36Sopenharmony_ci	struct usb_serial_port	*port;
125162306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
125262306a36Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
125362306a36Sopenharmony_ci	int status = urb->status;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	if (status) {
125862306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
125962306a36Sopenharmony_ci			__func__, status, endpoint);
126062306a36Sopenharmony_ci		return;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	port =  urb->context;
126462306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (urb->actual_length) {
126762306a36Sopenharmony_ci		/* if current mode is DMA, looks like usa28 format
126862306a36Sopenharmony_ci		   otherwise looks like usa26 data format */
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (p_priv->baud > 57600)
127162306a36Sopenharmony_ci			tty_insert_flip_string(&port->port, data,
127262306a36Sopenharmony_ci					urb->actual_length);
127362306a36Sopenharmony_ci		else {
127462306a36Sopenharmony_ci			/* 0x80 bit is error flag */
127562306a36Sopenharmony_ci			if ((data[0] & 0x80) == 0) {
127662306a36Sopenharmony_ci				/* no errors on individual bytes, only
127762306a36Sopenharmony_ci				   possible overrun err*/
127862306a36Sopenharmony_ci				if (data[0] & RXERROR_OVERRUN) {
127962306a36Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
128062306a36Sopenharmony_ci								TTY_OVERRUN);
128162306a36Sopenharmony_ci				}
128262306a36Sopenharmony_ci				for (i = 1; i < urb->actual_length ; ++i)
128362306a36Sopenharmony_ci					tty_insert_flip_char(&port->port,
128462306a36Sopenharmony_ci							data[i], TTY_NORMAL);
128562306a36Sopenharmony_ci			}  else {
128662306a36Sopenharmony_ci			/* some bytes had errors, every byte has status */
128762306a36Sopenharmony_ci				dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
128862306a36Sopenharmony_ci				for (i = 0; i + 1 < urb->actual_length; i += 2) {
128962306a36Sopenharmony_ci					int stat = data[i];
129062306a36Sopenharmony_ci					int flag = TTY_NORMAL;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci					if (stat & RXERROR_OVERRUN) {
129362306a36Sopenharmony_ci						tty_insert_flip_char(
129462306a36Sopenharmony_ci								&port->port, 0,
129562306a36Sopenharmony_ci								TTY_OVERRUN);
129662306a36Sopenharmony_ci					}
129762306a36Sopenharmony_ci					/* XXX should handle break (0x10) */
129862306a36Sopenharmony_ci					if (stat & RXERROR_PARITY)
129962306a36Sopenharmony_ci						flag = TTY_PARITY;
130062306a36Sopenharmony_ci					else if (stat & RXERROR_FRAMING)
130162306a36Sopenharmony_ci						flag = TTY_FRAME;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci					tty_insert_flip_char(&port->port,
130462306a36Sopenharmony_ci							data[i+1], flag);
130562306a36Sopenharmony_ci				}
130662306a36Sopenharmony_ci			}
130762306a36Sopenharmony_ci		}
130862306a36Sopenharmony_ci		tty_flip_buffer_push(&port->port);
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
131262306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
131362306a36Sopenharmony_ci	if (err != 0)
131462306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic void	usa90_instat_callback(struct urb *urb)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
132162306a36Sopenharmony_ci	struct keyspan_usa90_portStatusMessage	*msg;
132262306a36Sopenharmony_ci	struct usb_serial			*serial;
132362306a36Sopenharmony_ci	struct usb_serial_port			*port;
132462306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
132562306a36Sopenharmony_ci	int old_dcd_state, err;
132662306a36Sopenharmony_ci	int status = urb->status;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	serial =  urb->context;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	if (status) {
133162306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
133262306a36Sopenharmony_ci				__func__, status);
133362306a36Sopenharmony_ci		return;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci	if (urb->actual_length < 14) {
133662306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
133762306a36Sopenharmony_ci		goto exit;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	msg = (struct keyspan_usa90_portStatusMessage *)data;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* Now do something useful with the data */
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	port = serial->port[0];
134562306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
134662306a36Sopenharmony_ci	if (!p_priv)
134762306a36Sopenharmony_ci		goto resubmit;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	/* Update handshaking pin state information */
135062306a36Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
135162306a36Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
135262306a36Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
135362306a36Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
135462306a36Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
135762306a36Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
135862306a36Sopenharmony_ciresubmit:
135962306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
136062306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
136162306a36Sopenharmony_ci	if (err != 0)
136262306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
136362306a36Sopenharmony_ciexit:
136462306a36Sopenharmony_ci	;
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic void	usa90_outcont_callback(struct urb *urb)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct usb_serial_port *port;
137062306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	port =  urb->context;
137362306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (p_priv->resend_cont) {
137662306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
137762306a36Sopenharmony_ci		keyspan_usa90_send_setup(port->serial, port,
137862306a36Sopenharmony_ci						p_priv->resend_cont - 1);
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci/* Status messages from the 28xg */
138362306a36Sopenharmony_cistatic void	usa67_instat_callback(struct urb *urb)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	int					err;
138662306a36Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
138762306a36Sopenharmony_ci	struct keyspan_usa67_portStatusMessage	*msg;
138862306a36Sopenharmony_ci	struct usb_serial			*serial;
138962306a36Sopenharmony_ci	struct usb_serial_port			*port;
139062306a36Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
139162306a36Sopenharmony_ci	int old_dcd_state;
139262306a36Sopenharmony_ci	int status = urb->status;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	serial = urb->context;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (status) {
139762306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
139862306a36Sopenharmony_ci				__func__, status);
139962306a36Sopenharmony_ci		return;
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	if (urb->actual_length !=
140362306a36Sopenharmony_ci			sizeof(struct keyspan_usa67_portStatusMessage)) {
140462306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
140562306a36Sopenharmony_ci		return;
140662306a36Sopenharmony_ci	}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* Now do something useful with the data */
141062306a36Sopenharmony_ci	msg = (struct keyspan_usa67_portStatusMessage *)data;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	/* Check port number from message and retrieve private data */
141362306a36Sopenharmony_ci	if (msg->port >= serial->num_ports) {
141462306a36Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
141562306a36Sopenharmony_ci		return;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	port = serial->port[msg->port];
141962306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
142062306a36Sopenharmony_ci	if (!p_priv)
142162306a36Sopenharmony_ci		goto resubmit;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* Update handshaking pin state information */
142462306a36Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
142562306a36Sopenharmony_ci	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
142662306a36Sopenharmony_ci	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
142962306a36Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
143062306a36Sopenharmony_ciresubmit:
143162306a36Sopenharmony_ci	/* Resubmit urb so we continue receiving */
143262306a36Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
143362306a36Sopenharmony_ci	if (err != 0)
143462306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic void usa67_glocont_callback(struct urb *urb)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct usb_serial *serial;
144062306a36Sopenharmony_ci	struct usb_serial_port *port;
144162306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
144262306a36Sopenharmony_ci	int i;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	serial = urb->context;
144562306a36Sopenharmony_ci	for (i = 0; i < serial->num_ports; ++i) {
144662306a36Sopenharmony_ci		port = serial->port[i];
144762306a36Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
144862306a36Sopenharmony_ci		if (!p_priv)
144962306a36Sopenharmony_ci			continue;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci		if (p_priv->resend_cont) {
145262306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
145362306a36Sopenharmony_ci			keyspan_usa67_send_setup(serial, port,
145462306a36Sopenharmony_ci						p_priv->resend_cont - 1);
145562306a36Sopenharmony_ci			break;
145662306a36Sopenharmony_ci		}
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_cistatic unsigned int keyspan_write_room(struct tty_struct *tty)
146162306a36Sopenharmony_ci{
146262306a36Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
146362306a36Sopenharmony_ci	struct keyspan_port_private	*p_priv;
146462306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
146562306a36Sopenharmony_ci	int				flip;
146662306a36Sopenharmony_ci	unsigned int			data_len;
146762306a36Sopenharmony_ci	struct urb			*this_urb;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
147062306a36Sopenharmony_ci	d_details = p_priv->device_details;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	/* FIXME: locking */
147362306a36Sopenharmony_ci	if (d_details->msg_format == msg_usa90)
147462306a36Sopenharmony_ci		data_len = 64;
147562306a36Sopenharmony_ci	else
147662306a36Sopenharmony_ci		data_len = 63;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	flip = p_priv->out_flip;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	/* Check both endpoints to see if any are available. */
148162306a36Sopenharmony_ci	this_urb = p_priv->out_urbs[flip];
148262306a36Sopenharmony_ci	if (this_urb != NULL) {
148362306a36Sopenharmony_ci		if (this_urb->status != -EINPROGRESS)
148462306a36Sopenharmony_ci			return data_len;
148562306a36Sopenharmony_ci		flip = (flip + 1) & d_details->outdat_endp_flip;
148662306a36Sopenharmony_ci		this_urb = p_priv->out_urbs[flip];
148762306a36Sopenharmony_ci		if (this_urb != NULL) {
148862306a36Sopenharmony_ci			if (this_urb->status != -EINPROGRESS)
148962306a36Sopenharmony_ci				return data_len;
149062306a36Sopenharmony_ci		}
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci	return 0;
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
149962306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
150062306a36Sopenharmony_ci	int				i, err;
150162306a36Sopenharmony_ci	int				baud_rate, device_port;
150262306a36Sopenharmony_ci	struct urb			*urb;
150362306a36Sopenharmony_ci	unsigned int			cflag = 0;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
150662306a36Sopenharmony_ci	d_details = p_priv->device_details;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/* Set some sane defaults */
150962306a36Sopenharmony_ci	p_priv->rts_state = 1;
151062306a36Sopenharmony_ci	p_priv->dtr_state = 1;
151162306a36Sopenharmony_ci	p_priv->baud = 9600;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* force baud and lcr to be set on open */
151462306a36Sopenharmony_ci	p_priv->old_baud = 0;
151562306a36Sopenharmony_ci	p_priv->old_cflag = 0;
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	p_priv->out_flip = 0;
151862306a36Sopenharmony_ci	p_priv->in_flip = 0;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	/* Reset low level data toggle and start reading from endpoints */
152162306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
152262306a36Sopenharmony_ci		urb = p_priv->in_urbs[i];
152362306a36Sopenharmony_ci		if (urb == NULL)
152462306a36Sopenharmony_ci			continue;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci		/* make sure endpoint data toggle is synchronized
152762306a36Sopenharmony_ci		   with the device */
152862306a36Sopenharmony_ci		usb_clear_halt(urb->dev, urb->pipe);
152962306a36Sopenharmony_ci		err = usb_submit_urb(urb, GFP_KERNEL);
153062306a36Sopenharmony_ci		if (err != 0)
153162306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	/* Reset low level data toggle on out endpoints */
153562306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
153662306a36Sopenharmony_ci		urb = p_priv->out_urbs[i];
153762306a36Sopenharmony_ci		if (urb == NULL)
153862306a36Sopenharmony_ci			continue;
153962306a36Sopenharmony_ci		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
154062306a36Sopenharmony_ci						usb_pipeout(urb->pipe), 0); */
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	/* get the terminal config for the setup message now so we don't
154462306a36Sopenharmony_ci	 * need to send 2 of them */
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	device_port = port->port_number;
154762306a36Sopenharmony_ci	if (tty) {
154862306a36Sopenharmony_ci		cflag = tty->termios.c_cflag;
154962306a36Sopenharmony_ci		/* Baud rate calculation takes baud rate as an integer
155062306a36Sopenharmony_ci		   so other rates can be generated if desired. */
155162306a36Sopenharmony_ci		baud_rate = tty_get_baud_rate(tty);
155262306a36Sopenharmony_ci		/* If no match or invalid, leave as default */
155362306a36Sopenharmony_ci		if (baud_rate >= 0
155462306a36Sopenharmony_ci		    && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
155562306a36Sopenharmony_ci					NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
155662306a36Sopenharmony_ci			p_priv->baud = baud_rate;
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci	}
155962306a36Sopenharmony_ci	/* set CTS/RTS handshake etc. */
156062306a36Sopenharmony_ci	p_priv->cflag = cflag;
156162306a36Sopenharmony_ci	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	keyspan_send_setup(port, 1);
156462306a36Sopenharmony_ci	/* mdelay(100); */
156562306a36Sopenharmony_ci	/* keyspan_set_termios(port, NULL); */
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	return 0;
156862306a36Sopenharmony_ci}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic void keyspan_dtr_rts(struct usb_serial_port *port, int on)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	p_priv->rts_state = on;
157562306a36Sopenharmony_ci	p_priv->dtr_state = on;
157662306a36Sopenharmony_ci	keyspan_send_setup(port, 0);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic void keyspan_close(struct usb_serial_port *port)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	int			i;
158262306a36Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	p_priv->rts_state = 0;
158762306a36Sopenharmony_ci	p_priv->dtr_state = 0;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	keyspan_send_setup(port, 2);
159062306a36Sopenharmony_ci	/* pilot-xfer seems to work best with this delay */
159162306a36Sopenharmony_ci	mdelay(100);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	p_priv->out_flip = 0;
159462306a36Sopenharmony_ci	p_priv->in_flip = 0;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	usb_kill_urb(p_priv->inack_urb);
159762306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
159862306a36Sopenharmony_ci		usb_kill_urb(p_priv->in_urbs[i]);
159962306a36Sopenharmony_ci		usb_kill_urb(p_priv->out_urbs[i]);
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci/* download the firmware to a pre-renumeration device */
160462306a36Sopenharmony_cistatic int keyspan_fake_startup(struct usb_serial *serial)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	char	*fw_name;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
160962306a36Sopenharmony_ci		le16_to_cpu(serial->dev->descriptor.bcdDevice),
161062306a36Sopenharmony_ci		le16_to_cpu(serial->dev->descriptor.idProduct));
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
161362306a36Sopenharmony_ci								!= 0x8000) {
161462306a36Sopenharmony_ci		dev_dbg(&serial->dev->dev, "Firmware already loaded.  Quitting.\n");
161562306a36Sopenharmony_ci		return 1;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		/* Select firmware image on the basis of idProduct */
161962306a36Sopenharmony_ci	switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
162062306a36Sopenharmony_ci	case keyspan_usa28_pre_product_id:
162162306a36Sopenharmony_ci		fw_name = "keyspan/usa28.fw";
162262306a36Sopenharmony_ci		break;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	case keyspan_usa28x_pre_product_id:
162562306a36Sopenharmony_ci		fw_name = "keyspan/usa28x.fw";
162662306a36Sopenharmony_ci		break;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	case keyspan_usa28xa_pre_product_id:
162962306a36Sopenharmony_ci		fw_name = "keyspan/usa28xa.fw";
163062306a36Sopenharmony_ci		break;
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	case keyspan_usa28xb_pre_product_id:
163362306a36Sopenharmony_ci		fw_name = "keyspan/usa28xb.fw";
163462306a36Sopenharmony_ci		break;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	case keyspan_usa19_pre_product_id:
163762306a36Sopenharmony_ci		fw_name = "keyspan/usa19.fw";
163862306a36Sopenharmony_ci		break;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	case keyspan_usa19qi_pre_product_id:
164162306a36Sopenharmony_ci		fw_name = "keyspan/usa19qi.fw";
164262306a36Sopenharmony_ci		break;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	case keyspan_mpr_pre_product_id:
164562306a36Sopenharmony_ci		fw_name = "keyspan/mpr.fw";
164662306a36Sopenharmony_ci		break;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	case keyspan_usa19qw_pre_product_id:
164962306a36Sopenharmony_ci		fw_name = "keyspan/usa19qw.fw";
165062306a36Sopenharmony_ci		break;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	case keyspan_usa18x_pre_product_id:
165362306a36Sopenharmony_ci		fw_name = "keyspan/usa18x.fw";
165462306a36Sopenharmony_ci		break;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	case keyspan_usa19w_pre_product_id:
165762306a36Sopenharmony_ci		fw_name = "keyspan/usa19w.fw";
165862306a36Sopenharmony_ci		break;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	case keyspan_usa49w_pre_product_id:
166162306a36Sopenharmony_ci		fw_name = "keyspan/usa49w.fw";
166262306a36Sopenharmony_ci		break;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	case keyspan_usa49wlc_pre_product_id:
166562306a36Sopenharmony_ci		fw_name = "keyspan/usa49wlc.fw";
166662306a36Sopenharmony_ci		break;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	default:
166962306a36Sopenharmony_ci		dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
167062306a36Sopenharmony_ci			le16_to_cpu(serial->dev->descriptor.idProduct));
167162306a36Sopenharmony_ci		return 1;
167262306a36Sopenharmony_ci	}
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
167762306a36Sopenharmony_ci		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
167862306a36Sopenharmony_ci			fw_name);
167962306a36Sopenharmony_ci		return -ENOENT;
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* after downloading firmware Renumeration will occur in a
168362306a36Sopenharmony_ci	  moment and the new device will bind to the real driver */
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	/* we don't want this device to have a driver assigned to it. */
168662306a36Sopenharmony_ci	return 1;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci/* Helper functions used by keyspan_setup_urbs */
169062306a36Sopenharmony_cistatic struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
169162306a36Sopenharmony_ci						     int endpoint)
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	struct usb_host_interface *iface_desc;
169462306a36Sopenharmony_ci	struct usb_endpoint_descriptor *ep;
169562306a36Sopenharmony_ci	int i;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	iface_desc = serial->interface->cur_altsetting;
169862306a36Sopenharmony_ci	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
169962306a36Sopenharmony_ci		ep = &iface_desc->endpoint[i].desc;
170062306a36Sopenharmony_ci		if (ep->bEndpointAddress == endpoint)
170162306a36Sopenharmony_ci			return ep;
170262306a36Sopenharmony_ci	}
170362306a36Sopenharmony_ci	dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
170462306a36Sopenharmony_ci			endpoint);
170562306a36Sopenharmony_ci	return NULL;
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
170962306a36Sopenharmony_ci				      int dir, void *ctx, char *buf, int len,
171062306a36Sopenharmony_ci				      void (*callback)(struct urb *))
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	struct urb *urb;
171362306a36Sopenharmony_ci	struct usb_endpoint_descriptor const *ep_desc;
171462306a36Sopenharmony_ci	char const *ep_type_name;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (endpoint == -1)
171762306a36Sopenharmony_ci		return NULL;		/* endpoint not needed */
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
172062306a36Sopenharmony_ci			__func__, endpoint);
172162306a36Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
172262306a36Sopenharmony_ci	if (!urb)
172362306a36Sopenharmony_ci		return NULL;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	if (endpoint == 0) {
172662306a36Sopenharmony_ci		/* control EP filled in when used */
172762306a36Sopenharmony_ci		return urb;
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	ep_desc = find_ep(serial, endpoint);
173162306a36Sopenharmony_ci	if (!ep_desc) {
173262306a36Sopenharmony_ci		usb_free_urb(urb);
173362306a36Sopenharmony_ci		return NULL;
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci	if (usb_endpoint_xfer_int(ep_desc)) {
173662306a36Sopenharmony_ci		ep_type_name = "INT";
173762306a36Sopenharmony_ci		usb_fill_int_urb(urb, serial->dev,
173862306a36Sopenharmony_ci				 usb_sndintpipe(serial->dev, endpoint) | dir,
173962306a36Sopenharmony_ci				 buf, len, callback, ctx,
174062306a36Sopenharmony_ci				 ep_desc->bInterval);
174162306a36Sopenharmony_ci	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
174262306a36Sopenharmony_ci		ep_type_name = "BULK";
174362306a36Sopenharmony_ci		usb_fill_bulk_urb(urb, serial->dev,
174462306a36Sopenharmony_ci				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
174562306a36Sopenharmony_ci				  buf, len, callback, ctx);
174662306a36Sopenharmony_ci	} else {
174762306a36Sopenharmony_ci		dev_warn(&serial->interface->dev,
174862306a36Sopenharmony_ci			 "unsupported endpoint type %x\n",
174962306a36Sopenharmony_ci			 usb_endpoint_type(ep_desc));
175062306a36Sopenharmony_ci		usb_free_urb(urb);
175162306a36Sopenharmony_ci		return NULL;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
175562306a36Sopenharmony_ci	    __func__, urb, ep_type_name, endpoint);
175662306a36Sopenharmony_ci	return urb;
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic struct callbacks {
176062306a36Sopenharmony_ci	void	(*instat_callback)(struct urb *);
176162306a36Sopenharmony_ci	void	(*glocont_callback)(struct urb *);
176262306a36Sopenharmony_ci	void	(*indat_callback)(struct urb *);
176362306a36Sopenharmony_ci	void	(*outdat_callback)(struct urb *);
176462306a36Sopenharmony_ci	void	(*inack_callback)(struct urb *);
176562306a36Sopenharmony_ci	void	(*outcont_callback)(struct urb *);
176662306a36Sopenharmony_ci} keyspan_callbacks[] = {
176762306a36Sopenharmony_ci	{
176862306a36Sopenharmony_ci		/* msg_usa26 callbacks */
176962306a36Sopenharmony_ci		.instat_callback =	usa26_instat_callback,
177062306a36Sopenharmony_ci		.glocont_callback =	usa26_glocont_callback,
177162306a36Sopenharmony_ci		.indat_callback =	usa26_indat_callback,
177262306a36Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
177362306a36Sopenharmony_ci		.inack_callback =	usa26_inack_callback,
177462306a36Sopenharmony_ci		.outcont_callback =	usa26_outcont_callback,
177562306a36Sopenharmony_ci	}, {
177662306a36Sopenharmony_ci		/* msg_usa28 callbacks */
177762306a36Sopenharmony_ci		.instat_callback =	usa28_instat_callback,
177862306a36Sopenharmony_ci		.glocont_callback =	usa28_glocont_callback,
177962306a36Sopenharmony_ci		.indat_callback =	usa28_indat_callback,
178062306a36Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
178162306a36Sopenharmony_ci		.inack_callback =	usa28_inack_callback,
178262306a36Sopenharmony_ci		.outcont_callback =	usa28_outcont_callback,
178362306a36Sopenharmony_ci	}, {
178462306a36Sopenharmony_ci		/* msg_usa49 callbacks */
178562306a36Sopenharmony_ci		.instat_callback =	usa49_instat_callback,
178662306a36Sopenharmony_ci		.glocont_callback =	usa49_glocont_callback,
178762306a36Sopenharmony_ci		.indat_callback =	usa49_indat_callback,
178862306a36Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
178962306a36Sopenharmony_ci		.inack_callback =	usa49_inack_callback,
179062306a36Sopenharmony_ci		.outcont_callback =	usa49_outcont_callback,
179162306a36Sopenharmony_ci	}, {
179262306a36Sopenharmony_ci		/* msg_usa90 callbacks */
179362306a36Sopenharmony_ci		.instat_callback =	usa90_instat_callback,
179462306a36Sopenharmony_ci		.glocont_callback =	usa28_glocont_callback,
179562306a36Sopenharmony_ci		.indat_callback =	usa90_indat_callback,
179662306a36Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
179762306a36Sopenharmony_ci		.inack_callback =	usa28_inack_callback,
179862306a36Sopenharmony_ci		.outcont_callback =	usa90_outcont_callback,
179962306a36Sopenharmony_ci	}, {
180062306a36Sopenharmony_ci		/* msg_usa67 callbacks */
180162306a36Sopenharmony_ci		.instat_callback =	usa67_instat_callback,
180262306a36Sopenharmony_ci		.glocont_callback =	usa67_glocont_callback,
180362306a36Sopenharmony_ci		.indat_callback =	usa26_indat_callback,
180462306a36Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
180562306a36Sopenharmony_ci		.inack_callback =	usa26_inack_callback,
180662306a36Sopenharmony_ci		.outcont_callback =	usa26_outcont_callback,
180762306a36Sopenharmony_ci	}
180862306a36Sopenharmony_ci};
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	/* Generic setup urbs function that uses
181162306a36Sopenharmony_ci	   data in device_details */
181262306a36Sopenharmony_cistatic void keyspan_setup_urbs(struct usb_serial *serial)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	struct keyspan_serial_private 	*s_priv;
181562306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
181662306a36Sopenharmony_ci	struct callbacks		*cback;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
181962306a36Sopenharmony_ci	d_details = s_priv->device_details;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	/* Setup values for the various callback routines */
182262306a36Sopenharmony_ci	cback = &keyspan_callbacks[d_details->msg_format];
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* Allocate and set up urbs for each one that is in use,
182562306a36Sopenharmony_ci	   starting with instat endpoints */
182662306a36Sopenharmony_ci	s_priv->instat_urb = keyspan_setup_urb
182762306a36Sopenharmony_ci		(serial, d_details->instat_endpoint, USB_DIR_IN,
182862306a36Sopenharmony_ci		 serial, s_priv->instat_buf, INSTAT_BUFLEN,
182962306a36Sopenharmony_ci		 cback->instat_callback);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	s_priv->indat_urb = keyspan_setup_urb
183262306a36Sopenharmony_ci		(serial, d_details->indat_endpoint, USB_DIR_IN,
183362306a36Sopenharmony_ci		 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
183462306a36Sopenharmony_ci		 usa49wg_indat_callback);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	s_priv->glocont_urb = keyspan_setup_urb
183762306a36Sopenharmony_ci		(serial, d_details->glocont_endpoint, USB_DIR_OUT,
183862306a36Sopenharmony_ci		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
183962306a36Sopenharmony_ci		 cback->glocont_callback);
184062306a36Sopenharmony_ci}
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci/* usa19 function doesn't require prescaler */
184362306a36Sopenharmony_cistatic int keyspan_usa19_calc_baud(struct usb_serial_port *port,
184462306a36Sopenharmony_ci				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
184562306a36Sopenharmony_ci				   u8 *rate_low, u8 *prescaler, int portnum)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
184862306a36Sopenharmony_ci		div,	/* divisor */
184962306a36Sopenharmony_ci		cnt;	/* inverse of divisor (programmed into 8051) */
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* prevent divide by zero...  */
185462306a36Sopenharmony_ci	b16 = baud_rate * 16L;
185562306a36Sopenharmony_ci	if (b16 == 0)
185662306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
185762306a36Sopenharmony_ci	/* Any "standard" rate over 57k6 is marginal on the USA-19
185862306a36Sopenharmony_ci	   as we run out of divisor resolution. */
185962306a36Sopenharmony_ci	if (baud_rate > 57600)
186062306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	/* calculate the divisor and the counter (its inverse) */
186362306a36Sopenharmony_ci	div = baudclk / b16;
186462306a36Sopenharmony_ci	if (div == 0)
186562306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
186662306a36Sopenharmony_ci	else
186762306a36Sopenharmony_ci		cnt = 0 - div;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	if (div > 0xffff)
187062306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
187162306a36Sopenharmony_ci
187262306a36Sopenharmony_ci	/* return the counter values if non-null */
187362306a36Sopenharmony_ci	if (rate_low)
187462306a36Sopenharmony_ci		*rate_low = (u8) (cnt & 0xff);
187562306a36Sopenharmony_ci	if (rate_hi)
187662306a36Sopenharmony_ci		*rate_hi = (u8) ((cnt >> 8) & 0xff);
187762306a36Sopenharmony_ci	if (rate_low && rate_hi)
187862306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
187962306a36Sopenharmony_ci				__func__, baud_rate, *rate_hi, *rate_low);
188062306a36Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci/* usa19hs function doesn't require prescaler */
188462306a36Sopenharmony_cistatic int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
188562306a36Sopenharmony_ci				     u32 baud_rate, u32 baudclk, u8 *rate_hi,
188662306a36Sopenharmony_ci				     u8 *rate_low, u8 *prescaler, int portnum)
188762306a36Sopenharmony_ci{
188862306a36Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
188962306a36Sopenharmony_ci			div;	/* divisor */
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/* prevent divide by zero...  */
189462306a36Sopenharmony_ci	b16 = baud_rate * 16L;
189562306a36Sopenharmony_ci	if (b16 == 0)
189662306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	/* calculate the divisor */
189962306a36Sopenharmony_ci	div = baudclk / b16;
190062306a36Sopenharmony_ci	if (div == 0)
190162306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	if (div > 0xffff)
190462306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	/* return the counter values if non-null */
190762306a36Sopenharmony_ci	if (rate_low)
190862306a36Sopenharmony_ci		*rate_low = (u8) (div & 0xff);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	if (rate_hi)
191162306a36Sopenharmony_ci		*rate_hi = (u8) ((div >> 8) & 0xff);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (rate_low && rate_hi)
191462306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
191562306a36Sopenharmony_ci			__func__, baud_rate, *rate_hi, *rate_low);
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
191862306a36Sopenharmony_ci}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_cistatic int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
192162306a36Sopenharmony_ci				    u32 baud_rate, u32 baudclk, u8 *rate_hi,
192262306a36Sopenharmony_ci				    u8 *rate_low, u8 *prescaler, int portnum)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
192562306a36Sopenharmony_ci		clk,	/* clock with 13/8 prescaler */
192662306a36Sopenharmony_ci		div,	/* divisor using 13/8 prescaler */
192762306a36Sopenharmony_ci		res,	/* resulting baud rate using 13/8 prescaler */
192862306a36Sopenharmony_ci		diff,	/* error using 13/8 prescaler */
192962306a36Sopenharmony_ci		smallest_diff;
193062306a36Sopenharmony_ci	u8	best_prescaler;
193162306a36Sopenharmony_ci	int	i;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	/* prevent divide by zero */
193662306a36Sopenharmony_ci	b16 = baud_rate * 16L;
193762306a36Sopenharmony_ci	if (b16 == 0)
193862306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	/* Calculate prescaler by trying them all and looking
194162306a36Sopenharmony_ci	   for best fit */
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	/* start with largest possible difference */
194462306a36Sopenharmony_ci	smallest_diff = 0xffffffff;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		/* 0 is an invalid prescaler, used as a flag */
194762306a36Sopenharmony_ci	best_prescaler = 0;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	for (i = 8; i <= 0xff; ++i) {
195062306a36Sopenharmony_ci		clk = (baudclk * 8) / (u32) i;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci		div = clk / b16;
195362306a36Sopenharmony_ci		if (div == 0)
195462306a36Sopenharmony_ci			continue;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci		res = clk / div;
195762306a36Sopenharmony_ci		diff = (res > b16) ? (res-b16) : (b16-res);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci		if (diff < smallest_diff) {
196062306a36Sopenharmony_ci			best_prescaler = i;
196162306a36Sopenharmony_ci			smallest_diff = diff;
196262306a36Sopenharmony_ci		}
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	if (best_prescaler == 0)
196662306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	clk = (baudclk * 8) / (u32) best_prescaler;
196962306a36Sopenharmony_ci	div = clk / b16;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	/* return the divisor and prescaler if non-null */
197262306a36Sopenharmony_ci	if (rate_low)
197362306a36Sopenharmony_ci		*rate_low = (u8) (div & 0xff);
197462306a36Sopenharmony_ci	if (rate_hi)
197562306a36Sopenharmony_ci		*rate_hi = (u8) ((div >> 8) & 0xff);
197662306a36Sopenharmony_ci	if (prescaler) {
197762306a36Sopenharmony_ci		*prescaler = best_prescaler;
197862306a36Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
197962306a36Sopenharmony_ci	}
198062306a36Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	/* USA-28 supports different maximum baud rates on each port */
198462306a36Sopenharmony_cistatic int keyspan_usa28_calc_baud(struct usb_serial_port *port,
198562306a36Sopenharmony_ci				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
198662306a36Sopenharmony_ci				   u8 *rate_low, u8 *prescaler, int portnum)
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
198962306a36Sopenharmony_ci		div,	/* divisor */
199062306a36Sopenharmony_ci		cnt;	/* inverse of divisor (programmed into 8051) */
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci		/* prevent divide by zero */
199562306a36Sopenharmony_ci	b16 = baud_rate * 16L;
199662306a36Sopenharmony_ci	if (b16 == 0)
199762306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	/* calculate the divisor and the counter (its inverse) */
200062306a36Sopenharmony_ci	div = KEYSPAN_USA28_BAUDCLK / b16;
200162306a36Sopenharmony_ci	if (div == 0)
200262306a36Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
200362306a36Sopenharmony_ci	else
200462306a36Sopenharmony_ci		cnt = 0 - div;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	/* check for out of range, based on portnum,
200762306a36Sopenharmony_ci	   and return result */
200862306a36Sopenharmony_ci	if (portnum == 0) {
200962306a36Sopenharmony_ci		if (div > 0xffff)
201062306a36Sopenharmony_ci			return KEYSPAN_INVALID_BAUD_RATE;
201162306a36Sopenharmony_ci	} else {
201262306a36Sopenharmony_ci		if (portnum == 1) {
201362306a36Sopenharmony_ci			if (div > 0xff)
201462306a36Sopenharmony_ci				return KEYSPAN_INVALID_BAUD_RATE;
201562306a36Sopenharmony_ci		} else
201662306a36Sopenharmony_ci			return KEYSPAN_INVALID_BAUD_RATE;
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci		/* return the counter values if not NULL
202062306a36Sopenharmony_ci		   (port 1 will ignore retHi) */
202162306a36Sopenharmony_ci	if (rate_low)
202262306a36Sopenharmony_ci		*rate_low = (u8) (cnt & 0xff);
202362306a36Sopenharmony_ci	if (rate_hi)
202462306a36Sopenharmony_ci		*rate_hi = (u8) ((cnt >> 8) & 0xff);
202562306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
202662306a36Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
202762306a36Sopenharmony_ci}
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic int keyspan_usa26_send_setup(struct usb_serial *serial,
203062306a36Sopenharmony_ci				    struct usb_serial_port *port,
203162306a36Sopenharmony_ci				    int reset_port)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	struct keyspan_usa26_portControlMessage	msg;
203462306a36Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
203562306a36Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
203662306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
203762306a36Sopenharmony_ci	struct urb				*this_urb;
203862306a36Sopenharmony_ci	int 					device_port, err;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
204362306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
204462306a36Sopenharmony_ci	d_details = s_priv->device_details;
204562306a36Sopenharmony_ci	device_port = port->port_number;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	this_urb = p_priv->outcont_urb;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		/* Make sure we have an urb then send the message */
205062306a36Sopenharmony_ci	if (this_urb == NULL) {
205162306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
205262306a36Sopenharmony_ci		return -1;
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - endpoint %x\n",
205662306a36Sopenharmony_ci			__func__, usb_pipeendpoint(this_urb->pipe));
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* Save reset port val for resend.
205962306a36Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
206062306a36Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
206162306a36Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
206262306a36Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
206362306a36Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
206462306a36Sopenharmony_ci		mdelay(5);
206562306a36Sopenharmony_ci		return -1;
206662306a36Sopenharmony_ci	}
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	/* Only set baud rate if it's changed */
207162306a36Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
207262306a36Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
207362306a36Sopenharmony_ci		msg.setClocking = 0xff;
207462306a36Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
207562306a36Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
207662306a36Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
207762306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
207862306a36Sopenharmony_ci				__func__, p_priv->baud);
207962306a36Sopenharmony_ci			msg.baudLo = 0;
208062306a36Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
208162306a36Sopenharmony_ci			msg.prescaler = 10;
208262306a36Sopenharmony_ci		}
208362306a36Sopenharmony_ci		msg.setPrescaler = 0xff;
208462306a36Sopenharmony_ci	}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
208762306a36Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
208862306a36Sopenharmony_ci	case CS5:
208962306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
209062306a36Sopenharmony_ci		break;
209162306a36Sopenharmony_ci	case CS6:
209262306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
209362306a36Sopenharmony_ci		break;
209462306a36Sopenharmony_ci	case CS7:
209562306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	case CS8:
209862306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
209962306a36Sopenharmony_ci		break;
210062306a36Sopenharmony_ci	}
210162306a36Sopenharmony_ci	if (p_priv->cflag & PARENB) {
210262306a36Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
210362306a36Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
210462306a36Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
210562306a36Sopenharmony_ci	}
210662306a36Sopenharmony_ci	msg.setLcr = 0xff;
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
210962306a36Sopenharmony_ci	msg.xonFlowControl = 0;
211062306a36Sopenharmony_ci	msg.setFlowControl = 0xff;
211162306a36Sopenharmony_ci	msg.forwardingLength = 16;
211262306a36Sopenharmony_ci	msg.xonChar = 17;
211362306a36Sopenharmony_ci	msg.xoffChar = 19;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/* Opening port */
211662306a36Sopenharmony_ci	if (reset_port == 1) {
211762306a36Sopenharmony_ci		msg._txOn = 1;
211862306a36Sopenharmony_ci		msg._txOff = 0;
211962306a36Sopenharmony_ci		msg.txFlush = 0;
212062306a36Sopenharmony_ci		msg.txBreak = 0;
212162306a36Sopenharmony_ci		msg.rxOn = 1;
212262306a36Sopenharmony_ci		msg.rxOff = 0;
212362306a36Sopenharmony_ci		msg.rxFlush = 1;
212462306a36Sopenharmony_ci		msg.rxForward = 0;
212562306a36Sopenharmony_ci		msg.returnStatus = 0;
212662306a36Sopenharmony_ci		msg.resetDataToggle = 0xff;
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	/* Closing port */
213062306a36Sopenharmony_ci	else if (reset_port == 2) {
213162306a36Sopenharmony_ci		msg._txOn = 0;
213262306a36Sopenharmony_ci		msg._txOff = 1;
213362306a36Sopenharmony_ci		msg.txFlush = 0;
213462306a36Sopenharmony_ci		msg.txBreak = 0;
213562306a36Sopenharmony_ci		msg.rxOn = 0;
213662306a36Sopenharmony_ci		msg.rxOff = 1;
213762306a36Sopenharmony_ci		msg.rxFlush = 1;
213862306a36Sopenharmony_ci		msg.rxForward = 0;
213962306a36Sopenharmony_ci		msg.returnStatus = 0;
214062306a36Sopenharmony_ci		msg.resetDataToggle = 0;
214162306a36Sopenharmony_ci	}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	/* Sending intermediate configs */
214462306a36Sopenharmony_ci	else {
214562306a36Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
214662306a36Sopenharmony_ci		msg._txOff = 0;
214762306a36Sopenharmony_ci		msg.txFlush = 0;
214862306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
214962306a36Sopenharmony_ci		msg.rxOn = 0;
215062306a36Sopenharmony_ci		msg.rxOff = 0;
215162306a36Sopenharmony_ci		msg.rxFlush = 0;
215262306a36Sopenharmony_ci		msg.rxForward = 0;
215362306a36Sopenharmony_ci		msg.returnStatus = 0;
215462306a36Sopenharmony_ci		msg.resetDataToggle = 0x0;
215562306a36Sopenharmony_ci	}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	/* Do handshaking outputs */
215862306a36Sopenharmony_ci	msg.setTxTriState_setRts = 0xff;
215962306a36Sopenharmony_ci	msg.txTriState_rts = p_priv->rts_state;
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	msg.setHskoa_setDtr = 0xff;
216262306a36Sopenharmony_ci	msg.hskoa_dtr = p_priv->dtr_state;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	p_priv->resend_cont = 0;
216562306a36Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	/* send the data out the device on control endpoint */
216862306a36Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
217162306a36Sopenharmony_ci	if (err != 0)
217262306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
217362306a36Sopenharmony_ci	return 0;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_cistatic int keyspan_usa28_send_setup(struct usb_serial *serial,
217762306a36Sopenharmony_ci				    struct usb_serial_port *port,
217862306a36Sopenharmony_ci				    int reset_port)
217962306a36Sopenharmony_ci{
218062306a36Sopenharmony_ci	struct keyspan_usa28_portControlMessage	msg;
218162306a36Sopenharmony_ci	struct keyspan_serial_private	 	*s_priv;
218262306a36Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
218362306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
218462306a36Sopenharmony_ci	struct urb				*this_urb;
218562306a36Sopenharmony_ci	int 					device_port, err;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
218862306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
218962306a36Sopenharmony_ci	d_details = s_priv->device_details;
219062306a36Sopenharmony_ci	device_port = port->port_number;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	/* only do something if we have a bulk out endpoint */
219362306a36Sopenharmony_ci	this_urb = p_priv->outcont_urb;
219462306a36Sopenharmony_ci	if (this_urb == NULL) {
219562306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
219662306a36Sopenharmony_ci		return -1;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	/* Save reset port val for resend.
220062306a36Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
220162306a36Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
220262306a36Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
220362306a36Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
220462306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s already writing\n", __func__);
220562306a36Sopenharmony_ci		mdelay(5);
220662306a36Sopenharmony_ci		return -1;
220762306a36Sopenharmony_ci	}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	msg.setBaudRate = 1;
221262306a36Sopenharmony_ci	if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
221362306a36Sopenharmony_ci					   &msg.baudHi, &msg.baudLo, NULL,
221462306a36Sopenharmony_ci					   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
221562306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
221662306a36Sopenharmony_ci						__func__, p_priv->baud);
221762306a36Sopenharmony_ci		msg.baudLo = 0xff;
221862306a36Sopenharmony_ci		msg.baudHi = 0xb2;	/* Values for 9600 baud */
221962306a36Sopenharmony_ci	}
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	/* If parity is enabled, we must calculate it ourselves. */
222262306a36Sopenharmony_ci	msg.parity = 0;		/* XXX for now */
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
222562306a36Sopenharmony_ci	msg.xonFlowControl = 0;
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	/* Do handshaking outputs, DTR is inverted relative to RTS */
222862306a36Sopenharmony_ci	msg.rts = p_priv->rts_state;
222962306a36Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	msg.forwardingLength = 16;
223262306a36Sopenharmony_ci	msg.forwardMs = 10;
223362306a36Sopenharmony_ci	msg.breakThreshold = 45;
223462306a36Sopenharmony_ci	msg.xonChar = 17;
223562306a36Sopenharmony_ci	msg.xoffChar = 19;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	/*msg.returnStatus = 1;
223862306a36Sopenharmony_ci	msg.resetDataToggle = 0xff;*/
223962306a36Sopenharmony_ci	/* Opening port */
224062306a36Sopenharmony_ci	if (reset_port == 1) {
224162306a36Sopenharmony_ci		msg._txOn = 1;
224262306a36Sopenharmony_ci		msg._txOff = 0;
224362306a36Sopenharmony_ci		msg.txFlush = 0;
224462306a36Sopenharmony_ci		msg.txForceXoff = 0;
224562306a36Sopenharmony_ci		msg.txBreak = 0;
224662306a36Sopenharmony_ci		msg.rxOn = 1;
224762306a36Sopenharmony_ci		msg.rxOff = 0;
224862306a36Sopenharmony_ci		msg.rxFlush = 1;
224962306a36Sopenharmony_ci		msg.rxForward = 0;
225062306a36Sopenharmony_ci		msg.returnStatus = 0;
225162306a36Sopenharmony_ci		msg.resetDataToggle = 0xff;
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci	/* Closing port */
225462306a36Sopenharmony_ci	else if (reset_port == 2) {
225562306a36Sopenharmony_ci		msg._txOn = 0;
225662306a36Sopenharmony_ci		msg._txOff = 1;
225762306a36Sopenharmony_ci		msg.txFlush = 0;
225862306a36Sopenharmony_ci		msg.txForceXoff = 0;
225962306a36Sopenharmony_ci		msg.txBreak = 0;
226062306a36Sopenharmony_ci		msg.rxOn = 0;
226162306a36Sopenharmony_ci		msg.rxOff = 1;
226262306a36Sopenharmony_ci		msg.rxFlush = 1;
226362306a36Sopenharmony_ci		msg.rxForward = 0;
226462306a36Sopenharmony_ci		msg.returnStatus = 0;
226562306a36Sopenharmony_ci		msg.resetDataToggle = 0;
226662306a36Sopenharmony_ci	}
226762306a36Sopenharmony_ci	/* Sending intermediate configs */
226862306a36Sopenharmony_ci	else {
226962306a36Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
227062306a36Sopenharmony_ci		msg._txOff = 0;
227162306a36Sopenharmony_ci		msg.txFlush = 0;
227262306a36Sopenharmony_ci		msg.txForceXoff = 0;
227362306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
227462306a36Sopenharmony_ci		msg.rxOn = 0;
227562306a36Sopenharmony_ci		msg.rxOff = 0;
227662306a36Sopenharmony_ci		msg.rxFlush = 0;
227762306a36Sopenharmony_ci		msg.rxForward = 0;
227862306a36Sopenharmony_ci		msg.returnStatus = 0;
227962306a36Sopenharmony_ci		msg.resetDataToggle = 0x0;
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	p_priv->resend_cont = 0;
228362306a36Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	/* send the data out the device on control endpoint */
228662306a36Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
228962306a36Sopenharmony_ci	if (err != 0)
229062306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	return 0;
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_cistatic int keyspan_usa49_send_setup(struct usb_serial *serial,
229662306a36Sopenharmony_ci				    struct usb_serial_port *port,
229762306a36Sopenharmony_ci				    int reset_port)
229862306a36Sopenharmony_ci{
229962306a36Sopenharmony_ci	struct keyspan_usa49_portControlMessage	msg;
230062306a36Sopenharmony_ci	struct usb_ctrlrequest 			*dr = NULL;
230162306a36Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
230262306a36Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
230362306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
230462306a36Sopenharmony_ci	struct urb				*this_urb;
230562306a36Sopenharmony_ci	int 					err, device_port;
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
230862306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
230962306a36Sopenharmony_ci	d_details = s_priv->device_details;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	this_urb = s_priv->glocont_urb;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	/* Work out which port within the device is being setup */
231462306a36Sopenharmony_ci	device_port = port->port_number;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* Make sure we have an urb then send the message */
231762306a36Sopenharmony_ci	if (this_urb == NULL) {
231862306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
231962306a36Sopenharmony_ci		return -1;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
232362306a36Sopenharmony_ci		__func__, usb_pipeendpoint(this_urb->pipe), device_port);
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	/* Save reset port val for resend.
232662306a36Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
232762306a36Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
232862306a36Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
233162306a36Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
233262306a36Sopenharmony_ci		mdelay(5);
233362306a36Sopenharmony_ci		return -1;
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	msg.portNumber = device_port;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	/* Only set baud rate if it's changed */
234162306a36Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
234262306a36Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
234362306a36Sopenharmony_ci		msg.setClocking = 0xff;
234462306a36Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
234562306a36Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
234662306a36Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
234762306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
234862306a36Sopenharmony_ci				__func__, p_priv->baud);
234962306a36Sopenharmony_ci			msg.baudLo = 0;
235062306a36Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
235162306a36Sopenharmony_ci			msg.prescaler = 10;
235262306a36Sopenharmony_ci		}
235362306a36Sopenharmony_ci		/* msg.setPrescaler = 0xff; */
235462306a36Sopenharmony_ci	}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
235762306a36Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
235862306a36Sopenharmony_ci	case CS5:
235962306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
236062306a36Sopenharmony_ci		break;
236162306a36Sopenharmony_ci	case CS6:
236262306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
236362306a36Sopenharmony_ci		break;
236462306a36Sopenharmony_ci	case CS7:
236562306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
236662306a36Sopenharmony_ci		break;
236762306a36Sopenharmony_ci	case CS8:
236862306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
236962306a36Sopenharmony_ci		break;
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci	if (p_priv->cflag & PARENB) {
237262306a36Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
237362306a36Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
237462306a36Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
237562306a36Sopenharmony_ci	}
237662306a36Sopenharmony_ci	msg.setLcr = 0xff;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
237962306a36Sopenharmony_ci	msg.xonFlowControl = 0;
238062306a36Sopenharmony_ci	msg.setFlowControl = 0xff;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	msg.forwardingLength = 16;
238362306a36Sopenharmony_ci	msg.xonChar = 17;
238462306a36Sopenharmony_ci	msg.xoffChar = 19;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	/* Opening port */
238762306a36Sopenharmony_ci	if (reset_port == 1) {
238862306a36Sopenharmony_ci		msg._txOn = 1;
238962306a36Sopenharmony_ci		msg._txOff = 0;
239062306a36Sopenharmony_ci		msg.txFlush = 0;
239162306a36Sopenharmony_ci		msg.txBreak = 0;
239262306a36Sopenharmony_ci		msg.rxOn = 1;
239362306a36Sopenharmony_ci		msg.rxOff = 0;
239462306a36Sopenharmony_ci		msg.rxFlush = 1;
239562306a36Sopenharmony_ci		msg.rxForward = 0;
239662306a36Sopenharmony_ci		msg.returnStatus = 0;
239762306a36Sopenharmony_ci		msg.resetDataToggle = 0xff;
239862306a36Sopenharmony_ci		msg.enablePort = 1;
239962306a36Sopenharmony_ci		msg.disablePort = 0;
240062306a36Sopenharmony_ci	}
240162306a36Sopenharmony_ci	/* Closing port */
240262306a36Sopenharmony_ci	else if (reset_port == 2) {
240362306a36Sopenharmony_ci		msg._txOn = 0;
240462306a36Sopenharmony_ci		msg._txOff = 1;
240562306a36Sopenharmony_ci		msg.txFlush = 0;
240662306a36Sopenharmony_ci		msg.txBreak = 0;
240762306a36Sopenharmony_ci		msg.rxOn = 0;
240862306a36Sopenharmony_ci		msg.rxOff = 1;
240962306a36Sopenharmony_ci		msg.rxFlush = 1;
241062306a36Sopenharmony_ci		msg.rxForward = 0;
241162306a36Sopenharmony_ci		msg.returnStatus = 0;
241262306a36Sopenharmony_ci		msg.resetDataToggle = 0;
241362306a36Sopenharmony_ci		msg.enablePort = 0;
241462306a36Sopenharmony_ci		msg.disablePort = 1;
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci	/* Sending intermediate configs */
241762306a36Sopenharmony_ci	else {
241862306a36Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
241962306a36Sopenharmony_ci		msg._txOff = 0;
242062306a36Sopenharmony_ci		msg.txFlush = 0;
242162306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
242262306a36Sopenharmony_ci		msg.rxOn = 0;
242362306a36Sopenharmony_ci		msg.rxOff = 0;
242462306a36Sopenharmony_ci		msg.rxFlush = 0;
242562306a36Sopenharmony_ci		msg.rxForward = 0;
242662306a36Sopenharmony_ci		msg.returnStatus = 0;
242762306a36Sopenharmony_ci		msg.resetDataToggle = 0x0;
242862306a36Sopenharmony_ci		msg.enablePort = 0;
242962306a36Sopenharmony_ci		msg.disablePort = 0;
243062306a36Sopenharmony_ci	}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	/* Do handshaking outputs */
243362306a36Sopenharmony_ci	msg.setRts = 0xff;
243462306a36Sopenharmony_ci	msg.rts = p_priv->rts_state;
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	msg.setDtr = 0xff;
243762306a36Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci	p_priv->resend_cont = 0;
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci	/* if the device is a 49wg, we send control message on usb
244262306a36Sopenharmony_ci	   control EP 0 */
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	if (d_details->product_id == keyspan_usa49wg_product_id) {
244562306a36Sopenharmony_ci		dr = (void *)(s_priv->ctrl_buf);
244662306a36Sopenharmony_ci		dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
244762306a36Sopenharmony_ci		dr->bRequest = 0xB0;	/* 49wg control message */
244862306a36Sopenharmony_ci		dr->wValue = 0;
244962306a36Sopenharmony_ci		dr->wIndex = 0;
245062306a36Sopenharmony_ci		dr->wLength = cpu_to_le16(sizeof(msg));
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci		memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci		usb_fill_control_urb(this_urb, serial->dev,
245562306a36Sopenharmony_ci				usb_sndctrlpipe(serial->dev, 0),
245662306a36Sopenharmony_ci				(unsigned char *)dr, s_priv->glocont_buf,
245762306a36Sopenharmony_ci				sizeof(msg), usa49_glocont_callback, serial);
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	} else {
246062306a36Sopenharmony_ci		memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci		/* send the data out the device on control endpoint */
246362306a36Sopenharmony_ci		this_urb->transfer_buffer_length = sizeof(msg);
246462306a36Sopenharmony_ci	}
246562306a36Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
246662306a36Sopenharmony_ci	if (err != 0)
246762306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	return 0;
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_cistatic int keyspan_usa90_send_setup(struct usb_serial *serial,
247362306a36Sopenharmony_ci				    struct usb_serial_port *port,
247462306a36Sopenharmony_ci				    int reset_port)
247562306a36Sopenharmony_ci{
247662306a36Sopenharmony_ci	struct keyspan_usa90_portControlMessage	msg;
247762306a36Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
247862306a36Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
247962306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
248062306a36Sopenharmony_ci	struct urb				*this_urb;
248162306a36Sopenharmony_ci	int 					err;
248262306a36Sopenharmony_ci	u8						prescaler;
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
248562306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
248662306a36Sopenharmony_ci	d_details = s_priv->device_details;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/* only do something if we have a bulk out endpoint */
248962306a36Sopenharmony_ci	this_urb = p_priv->outcont_urb;
249062306a36Sopenharmony_ci	if (this_urb == NULL) {
249162306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
249262306a36Sopenharmony_ci		return -1;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	/* Save reset port val for resend.
249662306a36Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
249762306a36Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
249862306a36Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
249962306a36Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
250062306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s already writing\n", __func__);
250162306a36Sopenharmony_ci		mdelay(5);
250262306a36Sopenharmony_ci		return -1;
250362306a36Sopenharmony_ci	}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci	/* Only set baud rate if it's changed */
250862306a36Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
250962306a36Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
251062306a36Sopenharmony_ci		msg.setClocking = 0x01;
251162306a36Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
251262306a36Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
251362306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
251462306a36Sopenharmony_ci				__func__, p_priv->baud);
251562306a36Sopenharmony_ci			p_priv->baud = 9600;
251662306a36Sopenharmony_ci			d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
251762306a36Sopenharmony_ci				&msg.baudHi, &msg.baudLo, &prescaler, 0);
251862306a36Sopenharmony_ci		}
251962306a36Sopenharmony_ci		msg.setRxMode = 1;
252062306a36Sopenharmony_ci		msg.setTxMode = 1;
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	/* modes must always be correctly specified */
252462306a36Sopenharmony_ci	if (p_priv->baud > 57600) {
252562306a36Sopenharmony_ci		msg.rxMode = RXMODE_DMA;
252662306a36Sopenharmony_ci		msg.txMode = TXMODE_DMA;
252762306a36Sopenharmony_ci	} else {
252862306a36Sopenharmony_ci		msg.rxMode = RXMODE_BYHAND;
252962306a36Sopenharmony_ci		msg.txMode = TXMODE_BYHAND;
253062306a36Sopenharmony_ci	}
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
253362306a36Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
253462306a36Sopenharmony_ci	case CS5:
253562306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
253662306a36Sopenharmony_ci		break;
253762306a36Sopenharmony_ci	case CS6:
253862306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
253962306a36Sopenharmony_ci		break;
254062306a36Sopenharmony_ci	case CS7:
254162306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
254262306a36Sopenharmony_ci		break;
254362306a36Sopenharmony_ci	case CS8:
254462306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
254562306a36Sopenharmony_ci		break;
254662306a36Sopenharmony_ci	}
254762306a36Sopenharmony_ci	if (p_priv->cflag & PARENB) {
254862306a36Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
254962306a36Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
255062306a36Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
255162306a36Sopenharmony_ci	}
255262306a36Sopenharmony_ci	if (p_priv->old_cflag != p_priv->cflag) {
255362306a36Sopenharmony_ci		p_priv->old_cflag = p_priv->cflag;
255462306a36Sopenharmony_ci		msg.setLcr = 0x01;
255562306a36Sopenharmony_ci	}
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	if (p_priv->flow_control == flow_cts)
255862306a36Sopenharmony_ci		msg.txFlowControl = TXFLOW_CTS;
255962306a36Sopenharmony_ci	msg.setTxFlowControl = 0x01;
256062306a36Sopenharmony_ci	msg.setRxFlowControl = 0x01;
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	msg.rxForwardingLength = 16;
256362306a36Sopenharmony_ci	msg.rxForwardingTimeout = 16;
256462306a36Sopenharmony_ci	msg.txAckSetting = 0;
256562306a36Sopenharmony_ci	msg.xonChar = 17;
256662306a36Sopenharmony_ci	msg.xoffChar = 19;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	/* Opening port */
256962306a36Sopenharmony_ci	if (reset_port == 1) {
257062306a36Sopenharmony_ci		msg.portEnabled = 1;
257162306a36Sopenharmony_ci		msg.rxFlush = 1;
257262306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
257362306a36Sopenharmony_ci	}
257462306a36Sopenharmony_ci	/* Closing port */
257562306a36Sopenharmony_ci	else if (reset_port == 2)
257662306a36Sopenharmony_ci		msg.portEnabled = 0;
257762306a36Sopenharmony_ci	/* Sending intermediate configs */
257862306a36Sopenharmony_ci	else {
257962306a36Sopenharmony_ci		msg.portEnabled = 1;
258062306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
258162306a36Sopenharmony_ci	}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	/* Do handshaking outputs */
258462306a36Sopenharmony_ci	msg.setRts = 0x01;
258562306a36Sopenharmony_ci	msg.rts = p_priv->rts_state;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	msg.setDtr = 0x01;
258862306a36Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	p_priv->resend_cont = 0;
259162306a36Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* send the data out the device on control endpoint */
259462306a36Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
259762306a36Sopenharmony_ci	if (err != 0)
259862306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
259962306a36Sopenharmony_ci	return 0;
260062306a36Sopenharmony_ci}
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_cistatic int keyspan_usa67_send_setup(struct usb_serial *serial,
260362306a36Sopenharmony_ci				    struct usb_serial_port *port,
260462306a36Sopenharmony_ci				    int reset_port)
260562306a36Sopenharmony_ci{
260662306a36Sopenharmony_ci	struct keyspan_usa67_portControlMessage	msg;
260762306a36Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
260862306a36Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
260962306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
261062306a36Sopenharmony_ci	struct urb				*this_urb;
261162306a36Sopenharmony_ci	int 					err, device_port;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
261462306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
261562306a36Sopenharmony_ci	d_details = s_priv->device_details;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	this_urb = s_priv->glocont_urb;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	/* Work out which port within the device is being setup */
262062306a36Sopenharmony_ci	device_port = port->port_number;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	/* Make sure we have an urb then send the message */
262362306a36Sopenharmony_ci	if (this_urb == NULL) {
262462306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
262562306a36Sopenharmony_ci		return -1;
262662306a36Sopenharmony_ci	}
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	/* Save reset port val for resend.
262962306a36Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
263062306a36Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
263162306a36Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
263262306a36Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
263362306a36Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
263462306a36Sopenharmony_ci		mdelay(5);
263562306a36Sopenharmony_ci		return -1;
263662306a36Sopenharmony_ci	}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	msg.port = device_port;
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_ci	/* Only set baud rate if it's changed */
264362306a36Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
264462306a36Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
264562306a36Sopenharmony_ci		msg.setClocking = 0xff;
264662306a36Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
264762306a36Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
264862306a36Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
264962306a36Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
265062306a36Sopenharmony_ci				__func__, p_priv->baud);
265162306a36Sopenharmony_ci			msg.baudLo = 0;
265262306a36Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
265362306a36Sopenharmony_ci			msg.prescaler = 10;
265462306a36Sopenharmony_ci		}
265562306a36Sopenharmony_ci		msg.setPrescaler = 0xff;
265662306a36Sopenharmony_ci	}
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
265962306a36Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
266062306a36Sopenharmony_ci	case CS5:
266162306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
266262306a36Sopenharmony_ci		break;
266362306a36Sopenharmony_ci	case CS6:
266462306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
266562306a36Sopenharmony_ci		break;
266662306a36Sopenharmony_ci	case CS7:
266762306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
266862306a36Sopenharmony_ci		break;
266962306a36Sopenharmony_ci	case CS8:
267062306a36Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
267162306a36Sopenharmony_ci		break;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci	if (p_priv->cflag & PARENB) {
267462306a36Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
267562306a36Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
267662306a36Sopenharmony_ci					USA_PARITY_ODD : USA_PARITY_EVEN;
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci	msg.setLcr = 0xff;
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
268162306a36Sopenharmony_ci	msg.xonFlowControl = 0;
268262306a36Sopenharmony_ci	msg.setFlowControl = 0xff;
268362306a36Sopenharmony_ci	msg.forwardingLength = 16;
268462306a36Sopenharmony_ci	msg.xonChar = 17;
268562306a36Sopenharmony_ci	msg.xoffChar = 19;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	if (reset_port == 1) {
268862306a36Sopenharmony_ci		/* Opening port */
268962306a36Sopenharmony_ci		msg._txOn = 1;
269062306a36Sopenharmony_ci		msg._txOff = 0;
269162306a36Sopenharmony_ci		msg.txFlush = 0;
269262306a36Sopenharmony_ci		msg.txBreak = 0;
269362306a36Sopenharmony_ci		msg.rxOn = 1;
269462306a36Sopenharmony_ci		msg.rxOff = 0;
269562306a36Sopenharmony_ci		msg.rxFlush = 1;
269662306a36Sopenharmony_ci		msg.rxForward = 0;
269762306a36Sopenharmony_ci		msg.returnStatus = 0;
269862306a36Sopenharmony_ci		msg.resetDataToggle = 0xff;
269962306a36Sopenharmony_ci	} else if (reset_port == 2) {
270062306a36Sopenharmony_ci		/* Closing port */
270162306a36Sopenharmony_ci		msg._txOn = 0;
270262306a36Sopenharmony_ci		msg._txOff = 1;
270362306a36Sopenharmony_ci		msg.txFlush = 0;
270462306a36Sopenharmony_ci		msg.txBreak = 0;
270562306a36Sopenharmony_ci		msg.rxOn = 0;
270662306a36Sopenharmony_ci		msg.rxOff = 1;
270762306a36Sopenharmony_ci		msg.rxFlush = 1;
270862306a36Sopenharmony_ci		msg.rxForward = 0;
270962306a36Sopenharmony_ci		msg.returnStatus = 0;
271062306a36Sopenharmony_ci		msg.resetDataToggle = 0;
271162306a36Sopenharmony_ci	} else {
271262306a36Sopenharmony_ci		/* Sending intermediate configs */
271362306a36Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
271462306a36Sopenharmony_ci		msg._txOff = 0;
271562306a36Sopenharmony_ci		msg.txFlush = 0;
271662306a36Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
271762306a36Sopenharmony_ci		msg.rxOn = 0;
271862306a36Sopenharmony_ci		msg.rxOff = 0;
271962306a36Sopenharmony_ci		msg.rxFlush = 0;
272062306a36Sopenharmony_ci		msg.rxForward = 0;
272162306a36Sopenharmony_ci		msg.returnStatus = 0;
272262306a36Sopenharmony_ci		msg.resetDataToggle = 0x0;
272362306a36Sopenharmony_ci	}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	/* Do handshaking outputs */
272662306a36Sopenharmony_ci	msg.setTxTriState_setRts = 0xff;
272762306a36Sopenharmony_ci	msg.txTriState_rts = p_priv->rts_state;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	msg.setHskoa_setDtr = 0xff;
273062306a36Sopenharmony_ci	msg.hskoa_dtr = p_priv->dtr_state;
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci	p_priv->resend_cont = 0;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	/* send the data out the device on control endpoint */
273762306a36Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
274062306a36Sopenharmony_ci	if (err != 0)
274162306a36Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
274262306a36Sopenharmony_ci	return 0;
274362306a36Sopenharmony_ci}
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_cistatic void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	struct usb_serial *serial = port->serial;
274862306a36Sopenharmony_ci	struct keyspan_serial_private *s_priv;
274962306a36Sopenharmony_ci	const struct keyspan_device_details *d_details;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
275262306a36Sopenharmony_ci	d_details = s_priv->device_details;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	switch (d_details->msg_format) {
275562306a36Sopenharmony_ci	case msg_usa26:
275662306a36Sopenharmony_ci		keyspan_usa26_send_setup(serial, port, reset_port);
275762306a36Sopenharmony_ci		break;
275862306a36Sopenharmony_ci	case msg_usa28:
275962306a36Sopenharmony_ci		keyspan_usa28_send_setup(serial, port, reset_port);
276062306a36Sopenharmony_ci		break;
276162306a36Sopenharmony_ci	case msg_usa49:
276262306a36Sopenharmony_ci		keyspan_usa49_send_setup(serial, port, reset_port);
276362306a36Sopenharmony_ci		break;
276462306a36Sopenharmony_ci	case msg_usa90:
276562306a36Sopenharmony_ci		keyspan_usa90_send_setup(serial, port, reset_port);
276662306a36Sopenharmony_ci		break;
276762306a36Sopenharmony_ci	case msg_usa67:
276862306a36Sopenharmony_ci		keyspan_usa67_send_setup(serial, port, reset_port);
276962306a36Sopenharmony_ci		break;
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci/* Gets called by the "real" driver (ie once firmware is loaded
277562306a36Sopenharmony_ci   and renumeration has taken place. */
277662306a36Sopenharmony_cistatic int keyspan_startup(struct usb_serial *serial)
277762306a36Sopenharmony_ci{
277862306a36Sopenharmony_ci	int				i, err;
277962306a36Sopenharmony_ci	struct keyspan_serial_private 	*s_priv;
278062306a36Sopenharmony_ci	const struct keyspan_device_details	*d_details;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
278362306a36Sopenharmony_ci		if (d_details->product_id ==
278462306a36Sopenharmony_ci				le16_to_cpu(serial->dev->descriptor.idProduct))
278562306a36Sopenharmony_ci			break;
278662306a36Sopenharmony_ci	if (d_details == NULL) {
278762306a36Sopenharmony_ci		dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
278862306a36Sopenharmony_ci		    __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
278962306a36Sopenharmony_ci		return -ENODEV;
279062306a36Sopenharmony_ci	}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	/* Setup private data for serial driver */
279362306a36Sopenharmony_ci	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
279462306a36Sopenharmony_ci	if (!s_priv)
279562306a36Sopenharmony_ci		return -ENOMEM;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
279862306a36Sopenharmony_ci	if (!s_priv->instat_buf)
279962306a36Sopenharmony_ci		goto err_instat_buf;
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
280262306a36Sopenharmony_ci	if (!s_priv->indat_buf)
280362306a36Sopenharmony_ci		goto err_indat_buf;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
280662306a36Sopenharmony_ci	if (!s_priv->glocont_buf)
280762306a36Sopenharmony_ci		goto err_glocont_buf;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
281062306a36Sopenharmony_ci	if (!s_priv->ctrl_buf)
281162306a36Sopenharmony_ci		goto err_ctrl_buf;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	s_priv->device_details = d_details;
281462306a36Sopenharmony_ci	usb_set_serial_data(serial, s_priv);
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	keyspan_setup_urbs(serial);
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	if (s_priv->instat_urb != NULL) {
281962306a36Sopenharmony_ci		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
282062306a36Sopenharmony_ci		if (err != 0)
282162306a36Sopenharmony_ci			dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
282262306a36Sopenharmony_ci	}
282362306a36Sopenharmony_ci	if (s_priv->indat_urb != NULL) {
282462306a36Sopenharmony_ci		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
282562306a36Sopenharmony_ci		if (err != 0)
282662306a36Sopenharmony_ci			dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
282762306a36Sopenharmony_ci	}
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	return 0;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_cierr_ctrl_buf:
283262306a36Sopenharmony_ci	kfree(s_priv->glocont_buf);
283362306a36Sopenharmony_cierr_glocont_buf:
283462306a36Sopenharmony_ci	kfree(s_priv->indat_buf);
283562306a36Sopenharmony_cierr_indat_buf:
283662306a36Sopenharmony_ci	kfree(s_priv->instat_buf);
283762306a36Sopenharmony_cierr_instat_buf:
283862306a36Sopenharmony_ci	kfree(s_priv);
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	return -ENOMEM;
284162306a36Sopenharmony_ci}
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_cistatic void keyspan_disconnect(struct usb_serial *serial)
284462306a36Sopenharmony_ci{
284562306a36Sopenharmony_ci	struct keyspan_serial_private *s_priv;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	usb_kill_urb(s_priv->instat_urb);
285062306a36Sopenharmony_ci	usb_kill_urb(s_priv->glocont_urb);
285162306a36Sopenharmony_ci	usb_kill_urb(s_priv->indat_urb);
285262306a36Sopenharmony_ci}
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_cistatic void keyspan_release(struct usb_serial *serial)
285562306a36Sopenharmony_ci{
285662306a36Sopenharmony_ci	struct keyspan_serial_private *s_priv;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	/* Make sure to unlink the URBs submitted in attach. */
286162306a36Sopenharmony_ci	usb_kill_urb(s_priv->instat_urb);
286262306a36Sopenharmony_ci	usb_kill_urb(s_priv->indat_urb);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	usb_free_urb(s_priv->instat_urb);
286562306a36Sopenharmony_ci	usb_free_urb(s_priv->indat_urb);
286662306a36Sopenharmony_ci	usb_free_urb(s_priv->glocont_urb);
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	kfree(s_priv->ctrl_buf);
286962306a36Sopenharmony_ci	kfree(s_priv->glocont_buf);
287062306a36Sopenharmony_ci	kfree(s_priv->indat_buf);
287162306a36Sopenharmony_ci	kfree(s_priv->instat_buf);
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	kfree(s_priv);
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic int keyspan_port_probe(struct usb_serial_port *port)
287762306a36Sopenharmony_ci{
287862306a36Sopenharmony_ci	struct usb_serial *serial = port->serial;
287962306a36Sopenharmony_ci	struct keyspan_serial_private *s_priv;
288062306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
288162306a36Sopenharmony_ci	const struct keyspan_device_details *d_details;
288262306a36Sopenharmony_ci	struct callbacks *cback;
288362306a36Sopenharmony_ci	int endp;
288462306a36Sopenharmony_ci	int port_num;
288562306a36Sopenharmony_ci	int i;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
288862306a36Sopenharmony_ci	d_details = s_priv->device_details;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
289162306a36Sopenharmony_ci	if (!p_priv)
289262306a36Sopenharmony_ci		return -ENOMEM;
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
289562306a36Sopenharmony_ci		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
289662306a36Sopenharmony_ci		if (!p_priv->in_buffer[i])
289762306a36Sopenharmony_ci			goto err_free_in_buffer;
289862306a36Sopenharmony_ci	}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
290162306a36Sopenharmony_ci		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
290262306a36Sopenharmony_ci		if (!p_priv->out_buffer[i])
290362306a36Sopenharmony_ci			goto err_free_out_buffer;
290462306a36Sopenharmony_ci	}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
290762306a36Sopenharmony_ci	if (!p_priv->inack_buffer)
290862306a36Sopenharmony_ci		goto err_free_out_buffer;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
291162306a36Sopenharmony_ci	if (!p_priv->outcont_buffer)
291262306a36Sopenharmony_ci		goto err_free_inack_buffer;
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	p_priv->device_details = d_details;
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	/* Setup values for the various callback routines */
291762306a36Sopenharmony_ci	cback = &keyspan_callbacks[d_details->msg_format];
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	port_num = port->port_number;
292062306a36Sopenharmony_ci
292162306a36Sopenharmony_ci	/* Do indat endpoints first, once for each flip */
292262306a36Sopenharmony_ci	endp = d_details->indat_endpoints[port_num];
292362306a36Sopenharmony_ci	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
292462306a36Sopenharmony_ci		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
292562306a36Sopenharmony_ci						USB_DIR_IN, port,
292662306a36Sopenharmony_ci						p_priv->in_buffer[i],
292762306a36Sopenharmony_ci						IN_BUFLEN,
292862306a36Sopenharmony_ci						cback->indat_callback);
292962306a36Sopenharmony_ci	}
293062306a36Sopenharmony_ci	/* outdat endpoints also have flip */
293162306a36Sopenharmony_ci	endp = d_details->outdat_endpoints[port_num];
293262306a36Sopenharmony_ci	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
293362306a36Sopenharmony_ci		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
293462306a36Sopenharmony_ci						USB_DIR_OUT, port,
293562306a36Sopenharmony_ci						p_priv->out_buffer[i],
293662306a36Sopenharmony_ci						OUT_BUFLEN,
293762306a36Sopenharmony_ci						cback->outdat_callback);
293862306a36Sopenharmony_ci	}
293962306a36Sopenharmony_ci	/* inack endpoint */
294062306a36Sopenharmony_ci	p_priv->inack_urb = keyspan_setup_urb(serial,
294162306a36Sopenharmony_ci					d_details->inack_endpoints[port_num],
294262306a36Sopenharmony_ci					USB_DIR_IN, port,
294362306a36Sopenharmony_ci					p_priv->inack_buffer,
294462306a36Sopenharmony_ci					INACK_BUFLEN,
294562306a36Sopenharmony_ci					cback->inack_callback);
294662306a36Sopenharmony_ci	/* outcont endpoint */
294762306a36Sopenharmony_ci	p_priv->outcont_urb = keyspan_setup_urb(serial,
294862306a36Sopenharmony_ci					d_details->outcont_endpoints[port_num],
294962306a36Sopenharmony_ci					USB_DIR_OUT, port,
295062306a36Sopenharmony_ci					p_priv->outcont_buffer,
295162306a36Sopenharmony_ci					OUTCONT_BUFLEN,
295262306a36Sopenharmony_ci					 cback->outcont_callback);
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	usb_set_serial_port_data(port, p_priv);
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	return 0;
295762306a36Sopenharmony_ci
295862306a36Sopenharmony_cierr_free_inack_buffer:
295962306a36Sopenharmony_ci	kfree(p_priv->inack_buffer);
296062306a36Sopenharmony_cierr_free_out_buffer:
296162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
296262306a36Sopenharmony_ci		kfree(p_priv->out_buffer[i]);
296362306a36Sopenharmony_cierr_free_in_buffer:
296462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
296562306a36Sopenharmony_ci		kfree(p_priv->in_buffer[i]);
296662306a36Sopenharmony_ci	kfree(p_priv);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	return -ENOMEM;
296962306a36Sopenharmony_ci}
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_cistatic void keyspan_port_remove(struct usb_serial_port *port)
297262306a36Sopenharmony_ci{
297362306a36Sopenharmony_ci	struct keyspan_port_private *p_priv;
297462306a36Sopenharmony_ci	int i;
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	usb_kill_urb(p_priv->inack_urb);
297962306a36Sopenharmony_ci	usb_kill_urb(p_priv->outcont_urb);
298062306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
298162306a36Sopenharmony_ci		usb_kill_urb(p_priv->in_urbs[i]);
298262306a36Sopenharmony_ci		usb_kill_urb(p_priv->out_urbs[i]);
298362306a36Sopenharmony_ci	}
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	usb_free_urb(p_priv->inack_urb);
298662306a36Sopenharmony_ci	usb_free_urb(p_priv->outcont_urb);
298762306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
298862306a36Sopenharmony_ci		usb_free_urb(p_priv->in_urbs[i]);
298962306a36Sopenharmony_ci		usb_free_urb(p_priv->out_urbs[i]);
299062306a36Sopenharmony_ci	}
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	kfree(p_priv->outcont_buffer);
299362306a36Sopenharmony_ci	kfree(p_priv->inack_buffer);
299462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
299562306a36Sopenharmony_ci		kfree(p_priv->out_buffer[i]);
299662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
299762306a36Sopenharmony_ci		kfree(p_priv->in_buffer[i]);
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	kfree(p_priv);
300062306a36Sopenharmony_ci}
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci/* Structs for the devices, pre and post renumeration. */
300362306a36Sopenharmony_cistatic struct usb_serial_driver keyspan_pre_device = {
300462306a36Sopenharmony_ci	.driver = {
300562306a36Sopenharmony_ci		.owner		= THIS_MODULE,
300662306a36Sopenharmony_ci		.name		= "keyspan_no_firm",
300762306a36Sopenharmony_ci	},
300862306a36Sopenharmony_ci	.description		= "Keyspan - (without firmware)",
300962306a36Sopenharmony_ci	.id_table		= keyspan_pre_ids,
301062306a36Sopenharmony_ci	.num_ports		= 1,
301162306a36Sopenharmony_ci	.attach			= keyspan_fake_startup,
301262306a36Sopenharmony_ci};
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_cistatic struct usb_serial_driver keyspan_1port_device = {
301562306a36Sopenharmony_ci	.driver = {
301662306a36Sopenharmony_ci		.owner		= THIS_MODULE,
301762306a36Sopenharmony_ci		.name		= "keyspan_1",
301862306a36Sopenharmony_ci	},
301962306a36Sopenharmony_ci	.description		= "Keyspan 1 port adapter",
302062306a36Sopenharmony_ci	.id_table		= keyspan_1port_ids,
302162306a36Sopenharmony_ci	.num_ports		= 1,
302262306a36Sopenharmony_ci	.open			= keyspan_open,
302362306a36Sopenharmony_ci	.close			= keyspan_close,
302462306a36Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
302562306a36Sopenharmony_ci	.write			= keyspan_write,
302662306a36Sopenharmony_ci	.write_room		= keyspan_write_room,
302762306a36Sopenharmony_ci	.set_termios		= keyspan_set_termios,
302862306a36Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
302962306a36Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
303062306a36Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
303162306a36Sopenharmony_ci	.attach			= keyspan_startup,
303262306a36Sopenharmony_ci	.disconnect		= keyspan_disconnect,
303362306a36Sopenharmony_ci	.release		= keyspan_release,
303462306a36Sopenharmony_ci	.port_probe		= keyspan_port_probe,
303562306a36Sopenharmony_ci	.port_remove		= keyspan_port_remove,
303662306a36Sopenharmony_ci};
303762306a36Sopenharmony_ci
303862306a36Sopenharmony_cistatic struct usb_serial_driver keyspan_2port_device = {
303962306a36Sopenharmony_ci	.driver = {
304062306a36Sopenharmony_ci		.owner		= THIS_MODULE,
304162306a36Sopenharmony_ci		.name		= "keyspan_2",
304262306a36Sopenharmony_ci	},
304362306a36Sopenharmony_ci	.description		= "Keyspan 2 port adapter",
304462306a36Sopenharmony_ci	.id_table		= keyspan_2port_ids,
304562306a36Sopenharmony_ci	.num_ports		= 2,
304662306a36Sopenharmony_ci	.open			= keyspan_open,
304762306a36Sopenharmony_ci	.close			= keyspan_close,
304862306a36Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
304962306a36Sopenharmony_ci	.write			= keyspan_write,
305062306a36Sopenharmony_ci	.write_room		= keyspan_write_room,
305162306a36Sopenharmony_ci	.set_termios		= keyspan_set_termios,
305262306a36Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
305362306a36Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
305462306a36Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
305562306a36Sopenharmony_ci	.attach			= keyspan_startup,
305662306a36Sopenharmony_ci	.disconnect		= keyspan_disconnect,
305762306a36Sopenharmony_ci	.release		= keyspan_release,
305862306a36Sopenharmony_ci	.port_probe		= keyspan_port_probe,
305962306a36Sopenharmony_ci	.port_remove		= keyspan_port_remove,
306062306a36Sopenharmony_ci};
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_cistatic struct usb_serial_driver keyspan_4port_device = {
306362306a36Sopenharmony_ci	.driver = {
306462306a36Sopenharmony_ci		.owner		= THIS_MODULE,
306562306a36Sopenharmony_ci		.name		= "keyspan_4",
306662306a36Sopenharmony_ci	},
306762306a36Sopenharmony_ci	.description		= "Keyspan 4 port adapter",
306862306a36Sopenharmony_ci	.id_table		= keyspan_4port_ids,
306962306a36Sopenharmony_ci	.num_ports		= 4,
307062306a36Sopenharmony_ci	.open			= keyspan_open,
307162306a36Sopenharmony_ci	.close			= keyspan_close,
307262306a36Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
307362306a36Sopenharmony_ci	.write			= keyspan_write,
307462306a36Sopenharmony_ci	.write_room		= keyspan_write_room,
307562306a36Sopenharmony_ci	.set_termios		= keyspan_set_termios,
307662306a36Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
307762306a36Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
307862306a36Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
307962306a36Sopenharmony_ci	.attach			= keyspan_startup,
308062306a36Sopenharmony_ci	.disconnect		= keyspan_disconnect,
308162306a36Sopenharmony_ci	.release		= keyspan_release,
308262306a36Sopenharmony_ci	.port_probe		= keyspan_port_probe,
308362306a36Sopenharmony_ci	.port_remove		= keyspan_port_remove,
308462306a36Sopenharmony_ci};
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = {
308762306a36Sopenharmony_ci	&keyspan_pre_device, &keyspan_1port_device,
308862306a36Sopenharmony_ci	&keyspan_2port_device, &keyspan_4port_device, NULL
308962306a36Sopenharmony_ci};
309062306a36Sopenharmony_ci
309162306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, keyspan_ids_combined);
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
309462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
309562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28.fw");
309862306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28x.fw");
309962306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28xa.fw");
310062306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28xb.fw");
310162306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19.fw");
310262306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19qi.fw");
310362306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/mpr.fw");
310462306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19qw.fw");
310562306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa18x.fw");
310662306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19w.fw");
310762306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa49w.fw");
310862306a36Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa49wlc.fw");
3109