18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci  Keyspan USB to Serial Converter driver
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci  (C) Copyright (C) 2000-2001	Hugh Blemings <hugh@blemings.org>
68c2ecf20Sopenharmony_ci  (C) Copyright (C) 2002	Greg Kroah-Hartman <greg@kroah.com>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci  See http://blemings.org/hugh/keyspan.html for more information.
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci  Code in this driver inspired by and in a number of places taken
118c2ecf20Sopenharmony_ci  from Brian Warner's original Keyspan-PDA driver.
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci  This driver has been put together with the support of Innosys, Inc.
148c2ecf20Sopenharmony_ci  and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
158c2ecf20Sopenharmony_ci  Thanks Guys :)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
188c2ecf20Sopenharmony_ci  of much nicer and/or completely new code and (perhaps most uniquely)
198c2ecf20Sopenharmony_ci  having the patience to sit down and explain why and where he'd changed
208c2ecf20Sopenharmony_ci  stuff.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci  Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
238c2ecf20Sopenharmony_ci  staff in their work on open source projects.
248c2ecf20Sopenharmony_ci*/
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <linux/kernel.h>
288c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
298c2ecf20Sopenharmony_ci#include <linux/errno.h>
308c2ecf20Sopenharmony_ci#include <linux/slab.h>
318c2ecf20Sopenharmony_ci#include <linux/tty.h>
328c2ecf20Sopenharmony_ci#include <linux/tty_driver.h>
338c2ecf20Sopenharmony_ci#include <linux/tty_flip.h>
348c2ecf20Sopenharmony_ci#include <linux/module.h>
358c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
368c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
378c2ecf20Sopenharmony_ci#include <linux/usb.h>
388c2ecf20Sopenharmony_ci#include <linux/usb/serial.h>
398c2ecf20Sopenharmony_ci#include <linux/usb/ezusb.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
428c2ecf20Sopenharmony_ci#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Function prototypes for Keyspan serial converter */
458c2ecf20Sopenharmony_cistatic int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port);
468c2ecf20Sopenharmony_cistatic void keyspan_close(struct usb_serial_port *port);
478c2ecf20Sopenharmony_cistatic void keyspan_dtr_rts(struct usb_serial_port *port, int on);
488c2ecf20Sopenharmony_cistatic int keyspan_startup(struct usb_serial *serial);
498c2ecf20Sopenharmony_cistatic void keyspan_disconnect(struct usb_serial *serial);
508c2ecf20Sopenharmony_cistatic void keyspan_release(struct usb_serial *serial);
518c2ecf20Sopenharmony_cistatic int keyspan_port_probe(struct usb_serial_port *port);
528c2ecf20Sopenharmony_cistatic int keyspan_port_remove(struct usb_serial_port *port);
538c2ecf20Sopenharmony_cistatic int keyspan_write_room(struct tty_struct *tty);
548c2ecf20Sopenharmony_cistatic int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port,
558c2ecf20Sopenharmony_ci			 const unsigned char *buf, int count);
568c2ecf20Sopenharmony_cistatic void keyspan_send_setup(struct usb_serial_port *port, int reset_port);
578c2ecf20Sopenharmony_cistatic void keyspan_set_termios(struct tty_struct *tty,
588c2ecf20Sopenharmony_ci				struct usb_serial_port *port,
598c2ecf20Sopenharmony_ci				struct ktermios *old);
608c2ecf20Sopenharmony_cistatic void keyspan_break_ctl(struct tty_struct *tty, int break_state);
618c2ecf20Sopenharmony_cistatic int keyspan_tiocmget(struct tty_struct *tty);
628c2ecf20Sopenharmony_cistatic int keyspan_tiocmset(struct tty_struct *tty, unsigned int set,
638c2ecf20Sopenharmony_ci			    unsigned int clear);
648c2ecf20Sopenharmony_cistatic int keyspan_fake_startup(struct usb_serial *serial);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int keyspan_usa19_calc_baud(struct usb_serial_port *port,
678c2ecf20Sopenharmony_ci				   u32 baud_rate, u32 baudclk,
688c2ecf20Sopenharmony_ci				   u8 *rate_hi, u8 *rate_low,
698c2ecf20Sopenharmony_ci				   u8 *prescaler, int portnum);
708c2ecf20Sopenharmony_cistatic int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
718c2ecf20Sopenharmony_ci				    u32 baud_rate, u32 baudclk,
728c2ecf20Sopenharmony_ci				    u8 *rate_hi, u8 *rate_low,
738c2ecf20Sopenharmony_ci				    u8 *prescaler, int portnum);
748c2ecf20Sopenharmony_cistatic int keyspan_usa28_calc_baud(struct usb_serial_port *port,
758c2ecf20Sopenharmony_ci				   u32 baud_rate, u32 baudclk,
768c2ecf20Sopenharmony_ci				   u8 *rate_hi, u8 *rate_low,
778c2ecf20Sopenharmony_ci				   u8 *prescaler, int portnum);
788c2ecf20Sopenharmony_cistatic int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
798c2ecf20Sopenharmony_ci				     u32 baud_rate, u32 baudclk,
808c2ecf20Sopenharmony_ci				     u8 *rate_hi, u8 *rate_low,
818c2ecf20Sopenharmony_ci				     u8 *prescaler, int portnum);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic int keyspan_usa28_send_setup(struct usb_serial *serial,
848c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
858c2ecf20Sopenharmony_ci				    int reset_port);
868c2ecf20Sopenharmony_cistatic int keyspan_usa26_send_setup(struct usb_serial *serial,
878c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
888c2ecf20Sopenharmony_ci				    int reset_port);
898c2ecf20Sopenharmony_cistatic int keyspan_usa49_send_setup(struct usb_serial *serial,
908c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
918c2ecf20Sopenharmony_ci				    int reset_port);
928c2ecf20Sopenharmony_cistatic int keyspan_usa90_send_setup(struct usb_serial *serial,
938c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
948c2ecf20Sopenharmony_ci				    int reset_port);
958c2ecf20Sopenharmony_cistatic int keyspan_usa67_send_setup(struct usb_serial *serial,
968c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
978c2ecf20Sopenharmony_ci				    int reset_port);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* Values used for baud rate calculation - device specific */
1008c2ecf20Sopenharmony_ci#define KEYSPAN_INVALID_BAUD_RATE		(-1)
1018c2ecf20Sopenharmony_ci#define KEYSPAN_BAUD_RATE_OK			(0)
1028c2ecf20Sopenharmony_ci#define KEYSPAN_USA18X_BAUDCLK			(12000000L)	/* a guess */
1038c2ecf20Sopenharmony_ci#define KEYSPAN_USA19_BAUDCLK			(12000000L)
1048c2ecf20Sopenharmony_ci#define KEYSPAN_USA19W_BAUDCLK			(24000000L)
1058c2ecf20Sopenharmony_ci#define KEYSPAN_USA19HS_BAUDCLK			(14769231L)
1068c2ecf20Sopenharmony_ci#define KEYSPAN_USA28_BAUDCLK			(1843200L)
1078c2ecf20Sopenharmony_ci#define KEYSPAN_USA28X_BAUDCLK			(12000000L)
1088c2ecf20Sopenharmony_ci#define KEYSPAN_USA49W_BAUDCLK			(48000000L)
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/* Some constants used to characterise each device.  */
1118c2ecf20Sopenharmony_ci#define KEYSPAN_MAX_NUM_PORTS			(4)
1128c2ecf20Sopenharmony_ci#define KEYSPAN_MAX_FLIPS			(2)
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/*
1158c2ecf20Sopenharmony_ci * Device info for the Keyspan serial converter, used by the overall
1168c2ecf20Sopenharmony_ci * usb-serial probe function.
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_ci#define KEYSPAN_VENDOR_ID			(0x06cd)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/* Product IDs for the products supported, pre-renumeration */
1218c2ecf20Sopenharmony_ci#define keyspan_usa18x_pre_product_id		0x0105
1228c2ecf20Sopenharmony_ci#define keyspan_usa19_pre_product_id		0x0103
1238c2ecf20Sopenharmony_ci#define keyspan_usa19qi_pre_product_id		0x010b
1248c2ecf20Sopenharmony_ci#define keyspan_mpr_pre_product_id		0x011b
1258c2ecf20Sopenharmony_ci#define keyspan_usa19qw_pre_product_id		0x0118
1268c2ecf20Sopenharmony_ci#define keyspan_usa19w_pre_product_id		0x0106
1278c2ecf20Sopenharmony_ci#define keyspan_usa28_pre_product_id		0x0101
1288c2ecf20Sopenharmony_ci#define keyspan_usa28x_pre_product_id		0x0102
1298c2ecf20Sopenharmony_ci#define keyspan_usa28xa_pre_product_id		0x0114
1308c2ecf20Sopenharmony_ci#define keyspan_usa28xb_pre_product_id		0x0113
1318c2ecf20Sopenharmony_ci#define keyspan_usa49w_pre_product_id		0x0109
1328c2ecf20Sopenharmony_ci#define keyspan_usa49wlc_pre_product_id		0x011a
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/*
1358c2ecf20Sopenharmony_ci * Product IDs post-renumeration.  Note that the 28x and 28xb have the same
1368c2ecf20Sopenharmony_ci * id's post-renumeration but behave identically so it's not an issue. As
1378c2ecf20Sopenharmony_ci * such, the 28xb is not listed in any of the device tables.
1388c2ecf20Sopenharmony_ci */
1398c2ecf20Sopenharmony_ci#define keyspan_usa18x_product_id		0x0112
1408c2ecf20Sopenharmony_ci#define keyspan_usa19_product_id		0x0107
1418c2ecf20Sopenharmony_ci#define keyspan_usa19qi_product_id		0x010c
1428c2ecf20Sopenharmony_ci#define keyspan_usa19hs_product_id		0x0121
1438c2ecf20Sopenharmony_ci#define keyspan_mpr_product_id			0x011c
1448c2ecf20Sopenharmony_ci#define keyspan_usa19qw_product_id		0x0119
1458c2ecf20Sopenharmony_ci#define keyspan_usa19w_product_id		0x0108
1468c2ecf20Sopenharmony_ci#define keyspan_usa28_product_id		0x010f
1478c2ecf20Sopenharmony_ci#define keyspan_usa28x_product_id		0x0110
1488c2ecf20Sopenharmony_ci#define keyspan_usa28xa_product_id		0x0115
1498c2ecf20Sopenharmony_ci#define keyspan_usa28xb_product_id		0x0110
1508c2ecf20Sopenharmony_ci#define keyspan_usa28xg_product_id		0x0135
1518c2ecf20Sopenharmony_ci#define keyspan_usa49w_product_id		0x010a
1528c2ecf20Sopenharmony_ci#define keyspan_usa49wlc_product_id		0x012a
1538c2ecf20Sopenharmony_ci#define keyspan_usa49wg_product_id		0x0131
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistruct keyspan_device_details {
1568c2ecf20Sopenharmony_ci	/* product ID value */
1578c2ecf20Sopenharmony_ci	int	product_id;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	enum	{msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		/* Number of physical ports */
1628c2ecf20Sopenharmony_ci	int	num_ports;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		/* 1 if endpoint flipping used on input, 0 if not */
1658c2ecf20Sopenharmony_ci	int	indat_endp_flip;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci		/* 1 if endpoint flipping used on output, 0 if not */
1688c2ecf20Sopenharmony_ci	int	outdat_endp_flip;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		/*
1718c2ecf20Sopenharmony_ci		 * Table mapping input data endpoint IDs to physical port
1728c2ecf20Sopenharmony_ci		 * number and flip if used
1738c2ecf20Sopenharmony_ci		 */
1748c2ecf20Sopenharmony_ci	int	indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		/* Same for output endpoints */
1778c2ecf20Sopenharmony_ci	int	outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		/* Input acknowledge endpoints */
1808c2ecf20Sopenharmony_ci	int	inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		/* Output control endpoints */
1838c2ecf20Sopenharmony_ci	int	outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		/* Endpoint used for input status */
1868c2ecf20Sopenharmony_ci	int	instat_endpoint;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		/* Endpoint used for input data 49WG only */
1898c2ecf20Sopenharmony_ci	int	indat_endpoint;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		/* Endpoint used for global control functions */
1928c2ecf20Sopenharmony_ci	int	glocont_endpoint;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	int	(*calculate_baud_rate)(struct usb_serial_port *port,
1958c2ecf20Sopenharmony_ci				       u32 baud_rate, u32 baudclk,
1968c2ecf20Sopenharmony_ci				       u8 *rate_hi, u8 *rate_low, u8 *prescaler,
1978c2ecf20Sopenharmony_ci				       int portnum);
1988c2ecf20Sopenharmony_ci	u32	baudclk;
1998c2ecf20Sopenharmony_ci};
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/*
2028c2ecf20Sopenharmony_ci * Now for each device type we setup the device detail structure with the
2038c2ecf20Sopenharmony_ci * appropriate information (provided in Keyspan's documentation)
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa18x_device_details = {
2078c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa18x_product_id,
2088c2ecf20Sopenharmony_ci	.msg_format		= msg_usa26,
2098c2ecf20Sopenharmony_ci	.num_ports		= 1,
2108c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
2118c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2128c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2138c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2148c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85},
2158c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05},
2168c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
2178c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
2188c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
2198c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
2208c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA18X_BAUDCLK,
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa19_device_details = {
2248c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa19_product_id,
2258c2ecf20Sopenharmony_ci	.msg_format		= msg_usa28,
2268c2ecf20Sopenharmony_ci	.num_ports		= 1,
2278c2ecf20Sopenharmony_ci	.indat_endp_flip	= 1,
2288c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2298c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2308c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2318c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x83},
2328c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x03},
2338c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x84,
2348c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
2358c2ecf20Sopenharmony_ci	.glocont_endpoint	= -1,
2368c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19_calc_baud,
2378c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
2388c2ecf20Sopenharmony_ci};
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa19qi_device_details = {
2418c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa19qi_product_id,
2428c2ecf20Sopenharmony_ci	.msg_format		= msg_usa28,
2438c2ecf20Sopenharmony_ci	.num_ports		= 1,
2448c2ecf20Sopenharmony_ci	.indat_endp_flip	= 1,
2458c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2468c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2478c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2488c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x83},
2498c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x03},
2508c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x84,
2518c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
2528c2ecf20Sopenharmony_ci	.glocont_endpoint	= -1,
2538c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
2548c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
2558c2ecf20Sopenharmony_ci};
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic const struct keyspan_device_details mpr_device_details = {
2588c2ecf20Sopenharmony_ci	.product_id		= keyspan_mpr_product_id,
2598c2ecf20Sopenharmony_ci	.msg_format		= msg_usa28,
2608c2ecf20Sopenharmony_ci	.num_ports		= 1,
2618c2ecf20Sopenharmony_ci	.indat_endp_flip	= 1,
2628c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2638c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2648c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2658c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x83},
2668c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x03},
2678c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x84,
2688c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
2698c2ecf20Sopenharmony_ci	.glocont_endpoint	= -1,
2708c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
2718c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19_BAUDCLK,
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa19qw_device_details = {
2758c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa19qw_product_id,
2768c2ecf20Sopenharmony_ci	.msg_format		= msg_usa26,
2778c2ecf20Sopenharmony_ci	.num_ports		= 1,
2788c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
2798c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2808c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2818c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2828c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85},
2838c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05},
2848c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
2858c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
2868c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
2878c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
2888c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa19w_device_details = {
2928c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa19w_product_id,
2938c2ecf20Sopenharmony_ci	.msg_format		= msg_usa26,
2948c2ecf20Sopenharmony_ci	.num_ports		= 1,
2958c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
2968c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
2978c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
2988c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
2998c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85},
3008c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05},
3018c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
3028c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3038c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
3048c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
3058c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
3068c2ecf20Sopenharmony_ci};
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa19hs_device_details = {
3098c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa19hs_product_id,
3108c2ecf20Sopenharmony_ci	.msg_format		= msg_usa90,
3118c2ecf20Sopenharmony_ci	.num_ports		= 1,
3128c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
3138c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 0,
3148c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81},
3158c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01},
3168c2ecf20Sopenharmony_ci	.inack_endpoints	= {-1},
3178c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x02},
3188c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x82,
3198c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3208c2ecf20Sopenharmony_ci	.glocont_endpoint	= -1,
3218c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19hs_calc_baud,
3228c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19HS_BAUDCLK,
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa28_device_details = {
3268c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa28_product_id,
3278c2ecf20Sopenharmony_ci	.msg_format		= msg_usa28,
3288c2ecf20Sopenharmony_ci	.num_ports		= 2,
3298c2ecf20Sopenharmony_ci	.indat_endp_flip	= 1,
3308c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
3318c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
3328c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
3338c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
3348c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
3358c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
3368c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3378c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
3388c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa28_calc_baud,
3398c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA28_BAUDCLK,
3408c2ecf20Sopenharmony_ci};
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa28x_device_details = {
3438c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa28x_product_id,
3448c2ecf20Sopenharmony_ci	.msg_format		= msg_usa26,
3458c2ecf20Sopenharmony_ci	.num_ports		= 2,
3468c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
3478c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
3488c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
3498c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
3508c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
3518c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
3528c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
3538c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3548c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
3558c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
3568c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
3578c2ecf20Sopenharmony_ci};
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa28xa_device_details = {
3608c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa28xa_product_id,
3618c2ecf20Sopenharmony_ci	.msg_format		= msg_usa26,
3628c2ecf20Sopenharmony_ci	.num_ports		= 2,
3638c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
3648c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 1,
3658c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81, 0x83},
3668c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x03},
3678c2ecf20Sopenharmony_ci	.inack_endpoints	= {0x85, 0x86},
3688c2ecf20Sopenharmony_ci	.outcont_endpoints	= {0x05, 0x06},
3698c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
3708c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3718c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
3728c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
3738c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
3748c2ecf20Sopenharmony_ci};
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa28xg_device_details = {
3778c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa28xg_product_id,
3788c2ecf20Sopenharmony_ci	.msg_format		= msg_usa67,
3798c2ecf20Sopenharmony_ci	.num_ports		= 2,
3808c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
3818c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 0,
3828c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x84, 0x88},
3838c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x02, 0x06},
3848c2ecf20Sopenharmony_ci	.inack_endpoints	= {-1, -1},
3858c2ecf20Sopenharmony_ci	.outcont_endpoints	= {-1, -1},
3868c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x81,
3878c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
3888c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x01,
3898c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
3908c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA28X_BAUDCLK,
3918c2ecf20Sopenharmony_ci};
3928c2ecf20Sopenharmony_ci/*
3938c2ecf20Sopenharmony_ci * We don't need a separate entry for the usa28xb as it appears as a 28x
3948c2ecf20Sopenharmony_ci * anyway.
3958c2ecf20Sopenharmony_ci */
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa49w_device_details = {
3988c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa49w_product_id,
3998c2ecf20Sopenharmony_ci	.msg_format		= msg_usa49,
4008c2ecf20Sopenharmony_ci	.num_ports		= 4,
4018c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
4028c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 0,
4038c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
4048c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
4058c2ecf20Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
4068c2ecf20Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
4078c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
4088c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
4098c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
4108c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
4118c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA49W_BAUDCLK,
4128c2ecf20Sopenharmony_ci};
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa49wlc_device_details = {
4158c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa49wlc_product_id,
4168c2ecf20Sopenharmony_ci	.msg_format		= msg_usa49,
4178c2ecf20Sopenharmony_ci	.num_ports		= 4,
4188c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
4198c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 0,
4208c2ecf20Sopenharmony_ci	.indat_endpoints	= {0x81, 0x82, 0x83, 0x84},
4218c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x03, 0x04},
4228c2ecf20Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
4238c2ecf20Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
4248c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x87,
4258c2ecf20Sopenharmony_ci	.indat_endpoint		= -1,
4268c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x07,
4278c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
4288c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
4298c2ecf20Sopenharmony_ci};
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic const struct keyspan_device_details usa49wg_device_details = {
4328c2ecf20Sopenharmony_ci	.product_id		= keyspan_usa49wg_product_id,
4338c2ecf20Sopenharmony_ci	.msg_format		= msg_usa49,
4348c2ecf20Sopenharmony_ci	.num_ports		= 4,
4358c2ecf20Sopenharmony_ci	.indat_endp_flip	= 0,
4368c2ecf20Sopenharmony_ci	.outdat_endp_flip	= 0,
4378c2ecf20Sopenharmony_ci	.indat_endpoints	= {-1, -1, -1, -1},	/* single 'global' data in EP */
4388c2ecf20Sopenharmony_ci	.outdat_endpoints	= {0x01, 0x02, 0x04, 0x06},
4398c2ecf20Sopenharmony_ci	.inack_endpoints	= {-1, -1, -1, -1},
4408c2ecf20Sopenharmony_ci	.outcont_endpoints	= {-1, -1, -1, -1},
4418c2ecf20Sopenharmony_ci	.instat_endpoint	= 0x81,
4428c2ecf20Sopenharmony_ci	.indat_endpoint		= 0x88,
4438c2ecf20Sopenharmony_ci	.glocont_endpoint	= 0x00,			/* uses control EP */
4448c2ecf20Sopenharmony_ci	.calculate_baud_rate	= keyspan_usa19w_calc_baud,
4458c2ecf20Sopenharmony_ci	.baudclk		= KEYSPAN_USA19W_BAUDCLK,
4468c2ecf20Sopenharmony_ci};
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic const struct keyspan_device_details *keyspan_devices[] = {
4498c2ecf20Sopenharmony_ci	&usa18x_device_details,
4508c2ecf20Sopenharmony_ci	&usa19_device_details,
4518c2ecf20Sopenharmony_ci	&usa19qi_device_details,
4528c2ecf20Sopenharmony_ci	&mpr_device_details,
4538c2ecf20Sopenharmony_ci	&usa19qw_device_details,
4548c2ecf20Sopenharmony_ci	&usa19w_device_details,
4558c2ecf20Sopenharmony_ci	&usa19hs_device_details,
4568c2ecf20Sopenharmony_ci	&usa28_device_details,
4578c2ecf20Sopenharmony_ci	&usa28x_device_details,
4588c2ecf20Sopenharmony_ci	&usa28xa_device_details,
4598c2ecf20Sopenharmony_ci	&usa28xg_device_details,
4608c2ecf20Sopenharmony_ci	/* 28xb not required as it renumerates as a 28x */
4618c2ecf20Sopenharmony_ci	&usa49w_device_details,
4628c2ecf20Sopenharmony_ci	&usa49wlc_device_details,
4638c2ecf20Sopenharmony_ci	&usa49wg_device_details,
4648c2ecf20Sopenharmony_ci	NULL,
4658c2ecf20Sopenharmony_ci};
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic const struct usb_device_id keyspan_ids_combined[] = {
4688c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
4698c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
4708c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
4718c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
4728c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
4738c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
4748c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
4758c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
4768c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
4778c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
4788c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
4798c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
4808c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
4818c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
4828c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
4838c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
4848c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
4858c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
4868c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
4878c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
4888c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
4898c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
4908c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
4918c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
4928c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
4938c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
4948c2ecf20Sopenharmony_ci	{ } /* Terminating entry */
4958c2ecf20Sopenharmony_ci};
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci/* usb_device_id table for the pre-firmware download keyspan devices */
5008c2ecf20Sopenharmony_cistatic const struct usb_device_id keyspan_pre_ids[] = {
5018c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
5028c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
5038c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
5048c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) },
5058c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
5068c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) },
5078c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
5088c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
5098c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
5108c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
5118c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
5128c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) },
5138c2ecf20Sopenharmony_ci	{ } /* Terminating entry */
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic const struct usb_device_id keyspan_1port_ids[] = {
5178c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
5188c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
5198c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
5208c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) },
5218c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) },
5228c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) },
5238c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) },
5248c2ecf20Sopenharmony_ci	{ } /* Terminating entry */
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic const struct usb_device_id keyspan_2port_ids[] = {
5288c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
5298c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
5308c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
5318c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
5328c2ecf20Sopenharmony_ci	{ } /* Terminating entry */
5338c2ecf20Sopenharmony_ci};
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic const struct usb_device_id keyspan_4port_ids[] = {
5368c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
5378c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
5388c2ecf20Sopenharmony_ci	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
5398c2ecf20Sopenharmony_ci	{ } /* Terminating entry */
5408c2ecf20Sopenharmony_ci};
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci#define INSTAT_BUFLEN	32
5438c2ecf20Sopenharmony_ci#define GLOCONT_BUFLEN	64
5448c2ecf20Sopenharmony_ci#define INDAT49W_BUFLEN	512
5458c2ecf20Sopenharmony_ci#define IN_BUFLEN	64
5468c2ecf20Sopenharmony_ci#define OUT_BUFLEN	64
5478c2ecf20Sopenharmony_ci#define INACK_BUFLEN	1
5488c2ecf20Sopenharmony_ci#define OUTCONT_BUFLEN	64
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* Per device and per port private data */
5518c2ecf20Sopenharmony_cistruct keyspan_serial_private {
5528c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*device_details;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	struct urb	*instat_urb;
5558c2ecf20Sopenharmony_ci	char		*instat_buf;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* added to support 49wg, where data from all 4 ports comes in
5588c2ecf20Sopenharmony_ci	   on 1 EP and high-speed supported */
5598c2ecf20Sopenharmony_ci	struct urb	*indat_urb;
5608c2ecf20Sopenharmony_ci	char		*indat_buf;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/* XXX this one probably will need a lock */
5638c2ecf20Sopenharmony_ci	struct urb	*glocont_urb;
5648c2ecf20Sopenharmony_ci	char		*glocont_buf;
5658c2ecf20Sopenharmony_ci	char		*ctrl_buf;	/* for EP0 control message */
5668c2ecf20Sopenharmony_ci};
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistruct keyspan_port_private {
5698c2ecf20Sopenharmony_ci	/* Keep track of which input & output endpoints to use */
5708c2ecf20Sopenharmony_ci	int		in_flip;
5718c2ecf20Sopenharmony_ci	int		out_flip;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* Keep duplicate of device details in each port
5748c2ecf20Sopenharmony_ci	   structure as well - simplifies some of the
5758c2ecf20Sopenharmony_ci	   callback functions etc. */
5768c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*device_details;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	/* Input endpoints and buffer for this port */
5798c2ecf20Sopenharmony_ci	struct urb	*in_urbs[2];
5808c2ecf20Sopenharmony_ci	char		*in_buffer[2];
5818c2ecf20Sopenharmony_ci	/* Output endpoints and buffer for this port */
5828c2ecf20Sopenharmony_ci	struct urb	*out_urbs[2];
5838c2ecf20Sopenharmony_ci	char		*out_buffer[2];
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* Input ack endpoint */
5868c2ecf20Sopenharmony_ci	struct urb	*inack_urb;
5878c2ecf20Sopenharmony_ci	char		*inack_buffer;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/* Output control endpoint */
5908c2ecf20Sopenharmony_ci	struct urb	*outcont_urb;
5918c2ecf20Sopenharmony_ci	char		*outcont_buffer;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* Settings for the port */
5948c2ecf20Sopenharmony_ci	int		baud;
5958c2ecf20Sopenharmony_ci	int		old_baud;
5968c2ecf20Sopenharmony_ci	unsigned int	cflag;
5978c2ecf20Sopenharmony_ci	unsigned int	old_cflag;
5988c2ecf20Sopenharmony_ci	enum		{flow_none, flow_cts, flow_xon} flow_control;
5998c2ecf20Sopenharmony_ci	int		rts_state;	/* Handshaking pins (outputs) */
6008c2ecf20Sopenharmony_ci	int		dtr_state;
6018c2ecf20Sopenharmony_ci	int		cts_state;	/* Handshaking pins (inputs) */
6028c2ecf20Sopenharmony_ci	int		dsr_state;
6038c2ecf20Sopenharmony_ci	int		dcd_state;
6048c2ecf20Sopenharmony_ci	int		ri_state;
6058c2ecf20Sopenharmony_ci	int		break_on;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	unsigned long	tx_start_time[2];
6088c2ecf20Sopenharmony_ci	int		resend_cont;	/* need to resend control packet */
6098c2ecf20Sopenharmony_ci};
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci/* Include Keyspan message headers.  All current Keyspan Adapters
6128c2ecf20Sopenharmony_ci   make use of one of five message formats which are referred
6138c2ecf20Sopenharmony_ci   to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and
6148c2ecf20Sopenharmony_ci   within this driver. */
6158c2ecf20Sopenharmony_ci#include "keyspan_usa26msg.h"
6168c2ecf20Sopenharmony_ci#include "keyspan_usa28msg.h"
6178c2ecf20Sopenharmony_ci#include "keyspan_usa49msg.h"
6188c2ecf20Sopenharmony_ci#include "keyspan_usa90msg.h"
6198c2ecf20Sopenharmony_ci#include "keyspan_usa67msg.h"
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic void keyspan_break_ctl(struct tty_struct *tty, int break_state)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
6258c2ecf20Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (break_state == -1)
6308c2ecf20Sopenharmony_ci		p_priv->break_on = 1;
6318c2ecf20Sopenharmony_ci	else
6328c2ecf20Sopenharmony_ci		p_priv->break_on = 0;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 0);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic void keyspan_set_termios(struct tty_struct *tty,
6398c2ecf20Sopenharmony_ci		struct usb_serial_port *port, struct ktermios *old_termios)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	int				baud_rate, device_port;
6428c2ecf20Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
6438c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
6448c2ecf20Sopenharmony_ci	unsigned int 			cflag;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
6478c2ecf20Sopenharmony_ci	d_details = p_priv->device_details;
6488c2ecf20Sopenharmony_ci	cflag = tty->termios.c_cflag;
6498c2ecf20Sopenharmony_ci	device_port = port->port_number;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* Baud rate calculation takes baud rate as an integer
6528c2ecf20Sopenharmony_ci	   so other rates can be generated if desired. */
6538c2ecf20Sopenharmony_ci	baud_rate = tty_get_baud_rate(tty);
6548c2ecf20Sopenharmony_ci	/* If no match or invalid, don't change */
6558c2ecf20Sopenharmony_ci	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
6568c2ecf20Sopenharmony_ci				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
6578c2ecf20Sopenharmony_ci		/* FIXME - more to do here to ensure rate changes cleanly */
6588c2ecf20Sopenharmony_ci		/* FIXME - calculate exact rate from divisor ? */
6598c2ecf20Sopenharmony_ci		p_priv->baud = baud_rate;
6608c2ecf20Sopenharmony_ci	} else
6618c2ecf20Sopenharmony_ci		baud_rate = tty_termios_baud_rate(old_termios);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	tty_encode_baud_rate(tty, baud_rate, baud_rate);
6648c2ecf20Sopenharmony_ci	/* set CTS/RTS handshake etc. */
6658c2ecf20Sopenharmony_ci	p_priv->cflag = cflag;
6668c2ecf20Sopenharmony_ci	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	/* Mark/Space not supported */
6698c2ecf20Sopenharmony_ci	tty->termios.c_cflag &= ~CMSPAR;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 0);
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic int keyspan_tiocmget(struct tty_struct *tty)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
6778c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6788c2ecf20Sopenharmony_ci	unsigned int			value;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
6818c2ecf20Sopenharmony_ci		((p_priv->dtr_state) ? TIOCM_DTR : 0) |
6828c2ecf20Sopenharmony_ci		((p_priv->cts_state) ? TIOCM_CTS : 0) |
6838c2ecf20Sopenharmony_ci		((p_priv->dsr_state) ? TIOCM_DSR : 0) |
6848c2ecf20Sopenharmony_ci		((p_priv->dcd_state) ? TIOCM_CAR : 0) |
6858c2ecf20Sopenharmony_ci		((p_priv->ri_state) ? TIOCM_RNG : 0);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return value;
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic int keyspan_tiocmset(struct tty_struct *tty,
6918c2ecf20Sopenharmony_ci			    unsigned int set, unsigned int clear)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
6948c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (set & TIOCM_RTS)
6978c2ecf20Sopenharmony_ci		p_priv->rts_state = 1;
6988c2ecf20Sopenharmony_ci	if (set & TIOCM_DTR)
6998c2ecf20Sopenharmony_ci		p_priv->dtr_state = 1;
7008c2ecf20Sopenharmony_ci	if (clear & TIOCM_RTS)
7018c2ecf20Sopenharmony_ci		p_priv->rts_state = 0;
7028c2ecf20Sopenharmony_ci	if (clear & TIOCM_DTR)
7038c2ecf20Sopenharmony_ci		p_priv->dtr_state = 0;
7048c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 0);
7058c2ecf20Sopenharmony_ci	return 0;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/* Write function is similar for the four protocols used
7098c2ecf20Sopenharmony_ci   with only a minor change for usa90 (usa19hs) required */
7108c2ecf20Sopenharmony_cistatic int keyspan_write(struct tty_struct *tty,
7118c2ecf20Sopenharmony_ci	struct usb_serial_port *port, const unsigned char *buf, int count)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
7148c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
7158c2ecf20Sopenharmony_ci	int				flip;
7168c2ecf20Sopenharmony_ci	int 				left, todo;
7178c2ecf20Sopenharmony_ci	struct urb			*this_urb;
7188c2ecf20Sopenharmony_ci	int 				err, maxDataLen, dataOffset;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
7218c2ecf20Sopenharmony_ci	d_details = p_priv->device_details;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (d_details->msg_format == msg_usa90) {
7248c2ecf20Sopenharmony_ci		maxDataLen = 64;
7258c2ecf20Sopenharmony_ci		dataOffset = 0;
7268c2ecf20Sopenharmony_ci	} else {
7278c2ecf20Sopenharmony_ci		maxDataLen = 63;
7288c2ecf20Sopenharmony_ci		dataOffset = 1;
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count,
7328c2ecf20Sopenharmony_ci		p_priv->out_flip);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	for (left = count; left > 0; left -= todo) {
7358c2ecf20Sopenharmony_ci		todo = left;
7368c2ecf20Sopenharmony_ci		if (todo > maxDataLen)
7378c2ecf20Sopenharmony_ci			todo = maxDataLen;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		flip = p_priv->out_flip;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		/* Check we have a valid urb/endpoint before we use it... */
7428c2ecf20Sopenharmony_ci		this_urb = p_priv->out_urbs[flip];
7438c2ecf20Sopenharmony_ci		if (this_urb == NULL) {
7448c2ecf20Sopenharmony_ci			/* no bulk out, so return 0 bytes written */
7458c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - no output urb :(\n", __func__);
7468c2ecf20Sopenharmony_ci			return count;
7478c2ecf20Sopenharmony_ci		}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - endpoint %x flip %d\n",
7508c2ecf20Sopenharmony_ci			__func__, usb_pipeendpoint(this_urb->pipe), flip);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci		if (this_urb->status == -EINPROGRESS) {
7538c2ecf20Sopenharmony_ci			if (time_before(jiffies,
7548c2ecf20Sopenharmony_ci					p_priv->tx_start_time[flip] + 10 * HZ))
7558c2ecf20Sopenharmony_ci				break;
7568c2ecf20Sopenharmony_ci			usb_unlink_urb(this_urb);
7578c2ecf20Sopenharmony_ci			break;
7588c2ecf20Sopenharmony_ci		}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci		/* First byte in buffer is "last flag" (except for usa19hx)
7618c2ecf20Sopenharmony_ci		   - unused so for now so set to zero */
7628c2ecf20Sopenharmony_ci		((char *)this_urb->transfer_buffer)[0] = 0;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		memcpy(this_urb->transfer_buffer + dataOffset, buf, todo);
7658c2ecf20Sopenharmony_ci		buf += todo;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		/* send the data out the bulk port */
7688c2ecf20Sopenharmony_ci		this_urb->transfer_buffer_length = todo + dataOffset;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		err = usb_submit_urb(this_urb, GFP_ATOMIC);
7718c2ecf20Sopenharmony_ci		if (err != 0)
7728c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err);
7738c2ecf20Sopenharmony_ci		p_priv->tx_start_time[flip] = jiffies;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		/* Flip for next time if usa26 or usa28 interface
7768c2ecf20Sopenharmony_ci		   (not used on usa49) */
7778c2ecf20Sopenharmony_ci		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	return count - left;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic void	usa26_indat_callback(struct urb *urb)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	int			i, err;
7868c2ecf20Sopenharmony_ci	int			endpoint;
7878c2ecf20Sopenharmony_ci	struct usb_serial_port	*port;
7888c2ecf20Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
7898c2ecf20Sopenharmony_ci	int status = urb->status;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (status) {
7948c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
7958c2ecf20Sopenharmony_ci			__func__, status, endpoint);
7968c2ecf20Sopenharmony_ci		return;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	port =  urb->context;
8008c2ecf20Sopenharmony_ci	if (urb->actual_length) {
8018c2ecf20Sopenharmony_ci		/* 0x80 bit is error flag */
8028c2ecf20Sopenharmony_ci		if ((data[0] & 0x80) == 0) {
8038c2ecf20Sopenharmony_ci			/* no errors on individual bytes, only
8048c2ecf20Sopenharmony_ci			   possible overrun err */
8058c2ecf20Sopenharmony_ci			if (data[0] & RXERROR_OVERRUN) {
8068c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port, 0,
8078c2ecf20Sopenharmony_ci								TTY_OVERRUN);
8088c2ecf20Sopenharmony_ci			}
8098c2ecf20Sopenharmony_ci			for (i = 1; i < urb->actual_length ; ++i)
8108c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i],
8118c2ecf20Sopenharmony_ci								TTY_NORMAL);
8128c2ecf20Sopenharmony_ci		} else {
8138c2ecf20Sopenharmony_ci			/* some bytes had errors, every byte has status */
8148c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
8158c2ecf20Sopenharmony_ci			for (i = 0; i + 1 < urb->actual_length; i += 2) {
8168c2ecf20Sopenharmony_ci				int stat = data[i];
8178c2ecf20Sopenharmony_ci				int flag = TTY_NORMAL;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
8208c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
8218c2ecf20Sopenharmony_ci								TTY_OVERRUN);
8228c2ecf20Sopenharmony_ci				}
8238c2ecf20Sopenharmony_ci				/* XXX should handle break (0x10) */
8248c2ecf20Sopenharmony_ci				if (stat & RXERROR_PARITY)
8258c2ecf20Sopenharmony_ci					flag = TTY_PARITY;
8268c2ecf20Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
8278c2ecf20Sopenharmony_ci					flag = TTY_FRAME;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
8308c2ecf20Sopenharmony_ci						flag);
8318c2ecf20Sopenharmony_ci			}
8328c2ecf20Sopenharmony_ci		}
8338c2ecf20Sopenharmony_ci		tty_flip_buffer_push(&port->port);
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
8378c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
8388c2ecf20Sopenharmony_ci	if (err != 0)
8398c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
8408c2ecf20Sopenharmony_ci}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci/* Outdat handling is common for all devices */
8438c2ecf20Sopenharmony_cistatic void	usa2x_outdat_callback(struct urb *urb)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
8468c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	port =  urb->context;
8498c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
8508c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	usb_serial_port_softint(port);
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic void	usa26_inack_callback(struct urb *urb)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_cistatic void	usa26_outcont_callback(struct urb *urb)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
8628c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	port =  urb->context;
8658c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	if (p_priv->resend_cont) {
8688c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
8698c2ecf20Sopenharmony_ci		keyspan_usa26_send_setup(port->serial, port,
8708c2ecf20Sopenharmony_ci						p_priv->resend_cont - 1);
8718c2ecf20Sopenharmony_ci	}
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic void	usa26_instat_callback(struct urb *urb)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
8778c2ecf20Sopenharmony_ci	struct keyspan_usa26_portStatusMessage	*msg;
8788c2ecf20Sopenharmony_ci	struct usb_serial			*serial;
8798c2ecf20Sopenharmony_ci	struct usb_serial_port			*port;
8808c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
8818c2ecf20Sopenharmony_ci	int old_dcd_state, err;
8828c2ecf20Sopenharmony_ci	int status = urb->status;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	serial =  urb->context;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (status) {
8878c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
8888c2ecf20Sopenharmony_ci				__func__, status);
8898c2ecf20Sopenharmony_ci		return;
8908c2ecf20Sopenharmony_ci	}
8918c2ecf20Sopenharmony_ci	if (urb->actual_length != 9) {
8928c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
8938c2ecf20Sopenharmony_ci		goto exit;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	msg = (struct keyspan_usa26_portStatusMessage *)data;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* Check port number from message and retrieve private data */
8998c2ecf20Sopenharmony_ci	if (msg->port >= serial->num_ports) {
9008c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
9018c2ecf20Sopenharmony_ci		goto exit;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci	port = serial->port[msg->port];
9048c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
9058c2ecf20Sopenharmony_ci	if (!p_priv)
9068c2ecf20Sopenharmony_ci		goto resubmit;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	/* Update handshaking pin state information */
9098c2ecf20Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
9108c2ecf20Sopenharmony_ci	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
9118c2ecf20Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
9128c2ecf20Sopenharmony_ci	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
9138c2ecf20Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state)
9168c2ecf20Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
9178c2ecf20Sopenharmony_ciresubmit:
9188c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
9198c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
9208c2ecf20Sopenharmony_ci	if (err != 0)
9218c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
9228c2ecf20Sopenharmony_ciexit: ;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic void	usa26_glocont_callback(struct urb *urb)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic void usa28_indat_callback(struct urb *urb)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	int                     err;
9338c2ecf20Sopenharmony_ci	struct usb_serial_port  *port;
9348c2ecf20Sopenharmony_ci	unsigned char           *data;
9358c2ecf20Sopenharmony_ci	struct keyspan_port_private             *p_priv;
9368c2ecf20Sopenharmony_ci	int status = urb->status;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	port =  urb->context;
9398c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
9408c2ecf20Sopenharmony_ci	data = urb->transfer_buffer;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (urb != p_priv->in_urbs[p_priv->in_flip])
9438c2ecf20Sopenharmony_ci		return;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	do {
9468c2ecf20Sopenharmony_ci		if (status) {
9478c2ecf20Sopenharmony_ci			dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
9488c2ecf20Sopenharmony_ci				__func__, status, usb_pipeendpoint(urb->pipe));
9498c2ecf20Sopenharmony_ci			return;
9508c2ecf20Sopenharmony_ci		}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci		port =  urb->context;
9538c2ecf20Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
9548c2ecf20Sopenharmony_ci		data = urb->transfer_buffer;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		if (urb->actual_length) {
9578c2ecf20Sopenharmony_ci			tty_insert_flip_string(&port->port, data,
9588c2ecf20Sopenharmony_ci					urb->actual_length);
9598c2ecf20Sopenharmony_ci			tty_flip_buffer_push(&port->port);
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		/* Resubmit urb so we continue receiving */
9638c2ecf20Sopenharmony_ci		err = usb_submit_urb(urb, GFP_ATOMIC);
9648c2ecf20Sopenharmony_ci		if (err != 0)
9658c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n",
9668c2ecf20Sopenharmony_ci							__func__, err);
9678c2ecf20Sopenharmony_ci		p_priv->in_flip ^= 1;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		urb = p_priv->in_urbs[p_priv->in_flip];
9708c2ecf20Sopenharmony_ci	} while (urb->status != -EINPROGRESS);
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistatic void	usa28_inack_callback(struct urb *urb)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic void	usa28_outcont_callback(struct urb *urb)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
9808c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	port =  urb->context;
9838c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (p_priv->resend_cont) {
9868c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - sending setup\n", __func__);
9878c2ecf20Sopenharmony_ci		keyspan_usa28_send_setup(port->serial, port,
9888c2ecf20Sopenharmony_ci						p_priv->resend_cont - 1);
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_cistatic void	usa28_instat_callback(struct urb *urb)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	int					err;
9958c2ecf20Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
9968c2ecf20Sopenharmony_ci	struct keyspan_usa28_portStatusMessage	*msg;
9978c2ecf20Sopenharmony_ci	struct usb_serial			*serial;
9988c2ecf20Sopenharmony_ci	struct usb_serial_port			*port;
9998c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
10008c2ecf20Sopenharmony_ci	int old_dcd_state;
10018c2ecf20Sopenharmony_ci	int status = urb->status;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	serial =  urb->context;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (status) {
10068c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
10078c2ecf20Sopenharmony_ci				__func__, status);
10088c2ecf20Sopenharmony_ci		return;
10098c2ecf20Sopenharmony_ci	}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
10128c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
10138c2ecf20Sopenharmony_ci		goto exit;
10148c2ecf20Sopenharmony_ci	}
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	msg = (struct keyspan_usa28_portStatusMessage *)data;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	/* Check port number from message and retrieve private data */
10198c2ecf20Sopenharmony_ci	if (msg->port >= serial->num_ports) {
10208c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
10218c2ecf20Sopenharmony_ci		goto exit;
10228c2ecf20Sopenharmony_ci	}
10238c2ecf20Sopenharmony_ci	port = serial->port[msg->port];
10248c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
10258c2ecf20Sopenharmony_ci	if (!p_priv)
10268c2ecf20Sopenharmony_ci		goto resubmit;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	/* Update handshaking pin state information */
10298c2ecf20Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
10308c2ecf20Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
10318c2ecf20Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
10328c2ecf20Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
10338c2ecf20Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
10368c2ecf20Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
10378c2ecf20Sopenharmony_ciresubmit:
10388c2ecf20Sopenharmony_ci		/* Resubmit urb so we continue receiving */
10398c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
10408c2ecf20Sopenharmony_ci	if (err != 0)
10418c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
10428c2ecf20Sopenharmony_ciexit: ;
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic void	usa28_glocont_callback(struct urb *urb)
10468c2ecf20Sopenharmony_ci{
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic void	usa49_glocont_callback(struct urb *urb)
10518c2ecf20Sopenharmony_ci{
10528c2ecf20Sopenharmony_ci	struct usb_serial *serial;
10538c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
10548c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
10558c2ecf20Sopenharmony_ci	int i;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	serial =  urb->context;
10588c2ecf20Sopenharmony_ci	for (i = 0; i < serial->num_ports; ++i) {
10598c2ecf20Sopenharmony_ci		port = serial->port[i];
10608c2ecf20Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
10618c2ecf20Sopenharmony_ci		if (!p_priv)
10628c2ecf20Sopenharmony_ci			continue;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		if (p_priv->resend_cont) {
10658c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
10668c2ecf20Sopenharmony_ci			keyspan_usa49_send_setup(serial, port,
10678c2ecf20Sopenharmony_ci						p_priv->resend_cont - 1);
10688c2ecf20Sopenharmony_ci			break;
10698c2ecf20Sopenharmony_ci		}
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	/* This is actually called glostat in the Keyspan
10748c2ecf20Sopenharmony_ci	   doco */
10758c2ecf20Sopenharmony_cistatic void	usa49_instat_callback(struct urb *urb)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	int					err;
10788c2ecf20Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
10798c2ecf20Sopenharmony_ci	struct keyspan_usa49_portStatusMessage	*msg;
10808c2ecf20Sopenharmony_ci	struct usb_serial			*serial;
10818c2ecf20Sopenharmony_ci	struct usb_serial_port			*port;
10828c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
10838c2ecf20Sopenharmony_ci	int old_dcd_state;
10848c2ecf20Sopenharmony_ci	int status = urb->status;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	serial =  urb->context;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (status) {
10898c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
10908c2ecf20Sopenharmony_ci				__func__, status);
10918c2ecf20Sopenharmony_ci		return;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	if (urb->actual_length !=
10958c2ecf20Sopenharmony_ci			sizeof(struct keyspan_usa49_portStatusMessage)) {
10968c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
10978c2ecf20Sopenharmony_ci		goto exit;
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	msg = (struct keyspan_usa49_portStatusMessage *)data;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	/* Check port number from message and retrieve private data */
11038c2ecf20Sopenharmony_ci	if (msg->portNumber >= serial->num_ports) {
11048c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
11058c2ecf20Sopenharmony_ci			__func__, msg->portNumber);
11068c2ecf20Sopenharmony_ci		goto exit;
11078c2ecf20Sopenharmony_ci	}
11088c2ecf20Sopenharmony_ci	port = serial->port[msg->portNumber];
11098c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
11108c2ecf20Sopenharmony_ci	if (!p_priv)
11118c2ecf20Sopenharmony_ci		goto resubmit;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	/* Update handshaking pin state information */
11148c2ecf20Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
11158c2ecf20Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
11168c2ecf20Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
11178c2ecf20Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
11188c2ecf20Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
11218c2ecf20Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
11228c2ecf20Sopenharmony_ciresubmit:
11238c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
11248c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
11258c2ecf20Sopenharmony_ci	if (err != 0)
11268c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11278c2ecf20Sopenharmony_ciexit:	;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_cistatic void	usa49_inack_callback(struct urb *urb)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cistatic void	usa49_indat_callback(struct urb *urb)
11358c2ecf20Sopenharmony_ci{
11368c2ecf20Sopenharmony_ci	int			i, err;
11378c2ecf20Sopenharmony_ci	int			endpoint;
11388c2ecf20Sopenharmony_ci	struct usb_serial_port	*port;
11398c2ecf20Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
11408c2ecf20Sopenharmony_ci	int status = urb->status;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	if (status) {
11458c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
11468c2ecf20Sopenharmony_ci			__func__, status, endpoint);
11478c2ecf20Sopenharmony_ci		return;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	port =  urb->context;
11518c2ecf20Sopenharmony_ci	if (urb->actual_length) {
11528c2ecf20Sopenharmony_ci		/* 0x80 bit is error flag */
11538c2ecf20Sopenharmony_ci		if ((data[0] & 0x80) == 0) {
11548c2ecf20Sopenharmony_ci			/* no error on any byte */
11558c2ecf20Sopenharmony_ci			tty_insert_flip_string(&port->port, data + 1,
11568c2ecf20Sopenharmony_ci						urb->actual_length - 1);
11578c2ecf20Sopenharmony_ci		} else {
11588c2ecf20Sopenharmony_ci			/* some bytes had errors, every byte has status */
11598c2ecf20Sopenharmony_ci			for (i = 0; i + 1 < urb->actual_length; i += 2) {
11608c2ecf20Sopenharmony_ci				int stat = data[i];
11618c2ecf20Sopenharmony_ci				int flag = TTY_NORMAL;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
11648c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
11658c2ecf20Sopenharmony_ci								TTY_OVERRUN);
11668c2ecf20Sopenharmony_ci				}
11678c2ecf20Sopenharmony_ci				/* XXX should handle break (0x10) */
11688c2ecf20Sopenharmony_ci				if (stat & RXERROR_PARITY)
11698c2ecf20Sopenharmony_ci					flag = TTY_PARITY;
11708c2ecf20Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
11718c2ecf20Sopenharmony_ci					flag = TTY_FRAME;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
11748c2ecf20Sopenharmony_ci						flag);
11758c2ecf20Sopenharmony_ci			}
11768c2ecf20Sopenharmony_ci		}
11778c2ecf20Sopenharmony_ci		tty_flip_buffer_push(&port->port);
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
11818c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
11828c2ecf20Sopenharmony_ci	if (err != 0)
11838c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic void usa49wg_indat_callback(struct urb *urb)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	int			i, len, x, err;
11898c2ecf20Sopenharmony_ci	struct usb_serial	*serial;
11908c2ecf20Sopenharmony_ci	struct usb_serial_port	*port;
11918c2ecf20Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
11928c2ecf20Sopenharmony_ci	int status = urb->status;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	serial = urb->context;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	if (status) {
11978c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
11988c2ecf20Sopenharmony_ci				__func__, status);
11998c2ecf20Sopenharmony_ci		return;
12008c2ecf20Sopenharmony_ci	}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	/* inbound data is in the form P#, len, status, data */
12038c2ecf20Sopenharmony_ci	i = 0;
12048c2ecf20Sopenharmony_ci	len = 0;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	while (i < urb->actual_length) {
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci		/* Check port number from message */
12098c2ecf20Sopenharmony_ci		if (data[i] >= serial->num_ports) {
12108c2ecf20Sopenharmony_ci			dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
12118c2ecf20Sopenharmony_ci				__func__, data[i]);
12128c2ecf20Sopenharmony_ci			return;
12138c2ecf20Sopenharmony_ci		}
12148c2ecf20Sopenharmony_ci		port = serial->port[data[i++]];
12158c2ecf20Sopenharmony_ci		len = data[i++];
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci		/* 0x80 bit is error flag */
12188c2ecf20Sopenharmony_ci		if ((data[i] & 0x80) == 0) {
12198c2ecf20Sopenharmony_ci			/* no error on any byte */
12208c2ecf20Sopenharmony_ci			i++;
12218c2ecf20Sopenharmony_ci			for (x = 1; x < len && i < urb->actual_length; ++x)
12228c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port,
12238c2ecf20Sopenharmony_ci						data[i++], 0);
12248c2ecf20Sopenharmony_ci		} else {
12258c2ecf20Sopenharmony_ci			/*
12268c2ecf20Sopenharmony_ci			 * some bytes had errors, every byte has status
12278c2ecf20Sopenharmony_ci			 */
12288c2ecf20Sopenharmony_ci			for (x = 0; x + 1 < len &&
12298c2ecf20Sopenharmony_ci				    i + 1 < urb->actual_length; x += 2) {
12308c2ecf20Sopenharmony_ci				int stat = data[i];
12318c2ecf20Sopenharmony_ci				int flag = TTY_NORMAL;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci				if (stat & RXERROR_OVERRUN) {
12348c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
12358c2ecf20Sopenharmony_ci								TTY_OVERRUN);
12368c2ecf20Sopenharmony_ci				}
12378c2ecf20Sopenharmony_ci				/* XXX should handle break (0x10) */
12388c2ecf20Sopenharmony_ci				if (stat & RXERROR_PARITY)
12398c2ecf20Sopenharmony_ci					flag = TTY_PARITY;
12408c2ecf20Sopenharmony_ci				else if (stat & RXERROR_FRAMING)
12418c2ecf20Sopenharmony_ci					flag = TTY_FRAME;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci				tty_insert_flip_char(&port->port, data[i+1],
12448c2ecf20Sopenharmony_ci						     flag);
12458c2ecf20Sopenharmony_ci				i += 2;
12468c2ecf20Sopenharmony_ci			}
12478c2ecf20Sopenharmony_ci		}
12488c2ecf20Sopenharmony_ci		tty_flip_buffer_push(&port->port);
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
12528c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
12538c2ecf20Sopenharmony_ci	if (err != 0)
12548c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci/* not used, usa-49 doesn't have per-port control endpoints */
12588c2ecf20Sopenharmony_cistatic void usa49_outcont_callback(struct urb *urb)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_cistatic void usa90_indat_callback(struct urb *urb)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	int			i, err;
12658c2ecf20Sopenharmony_ci	int			endpoint;
12668c2ecf20Sopenharmony_ci	struct usb_serial_port	*port;
12678c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
12688c2ecf20Sopenharmony_ci	unsigned char 		*data = urb->transfer_buffer;
12698c2ecf20Sopenharmony_ci	int status = urb->status;
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	endpoint = usb_pipeendpoint(urb->pipe);
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (status) {
12748c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n",
12758c2ecf20Sopenharmony_ci			__func__, status, endpoint);
12768c2ecf20Sopenharmony_ci		return;
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	port =  urb->context;
12808c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	if (urb->actual_length) {
12838c2ecf20Sopenharmony_ci		/* if current mode is DMA, looks like usa28 format
12848c2ecf20Sopenharmony_ci		   otherwise looks like usa26 data format */
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		if (p_priv->baud > 57600)
12878c2ecf20Sopenharmony_ci			tty_insert_flip_string(&port->port, data,
12888c2ecf20Sopenharmony_ci					urb->actual_length);
12898c2ecf20Sopenharmony_ci		else {
12908c2ecf20Sopenharmony_ci			/* 0x80 bit is error flag */
12918c2ecf20Sopenharmony_ci			if ((data[0] & 0x80) == 0) {
12928c2ecf20Sopenharmony_ci				/* no errors on individual bytes, only
12938c2ecf20Sopenharmony_ci				   possible overrun err*/
12948c2ecf20Sopenharmony_ci				if (data[0] & RXERROR_OVERRUN) {
12958c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port, 0,
12968c2ecf20Sopenharmony_ci								TTY_OVERRUN);
12978c2ecf20Sopenharmony_ci				}
12988c2ecf20Sopenharmony_ci				for (i = 1; i < urb->actual_length ; ++i)
12998c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port,
13008c2ecf20Sopenharmony_ci							data[i], TTY_NORMAL);
13018c2ecf20Sopenharmony_ci			}  else {
13028c2ecf20Sopenharmony_ci			/* some bytes had errors, every byte has status */
13038c2ecf20Sopenharmony_ci				dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__);
13048c2ecf20Sopenharmony_ci				for (i = 0; i + 1 < urb->actual_length; i += 2) {
13058c2ecf20Sopenharmony_ci					int stat = data[i];
13068c2ecf20Sopenharmony_ci					int flag = TTY_NORMAL;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci					if (stat & RXERROR_OVERRUN) {
13098c2ecf20Sopenharmony_ci						tty_insert_flip_char(
13108c2ecf20Sopenharmony_ci								&port->port, 0,
13118c2ecf20Sopenharmony_ci								TTY_OVERRUN);
13128c2ecf20Sopenharmony_ci					}
13138c2ecf20Sopenharmony_ci					/* XXX should handle break (0x10) */
13148c2ecf20Sopenharmony_ci					if (stat & RXERROR_PARITY)
13158c2ecf20Sopenharmony_ci						flag = TTY_PARITY;
13168c2ecf20Sopenharmony_ci					else if (stat & RXERROR_FRAMING)
13178c2ecf20Sopenharmony_ci						flag = TTY_FRAME;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci					tty_insert_flip_char(&port->port,
13208c2ecf20Sopenharmony_ci							data[i+1], flag);
13218c2ecf20Sopenharmony_ci				}
13228c2ecf20Sopenharmony_ci			}
13238c2ecf20Sopenharmony_ci		}
13248c2ecf20Sopenharmony_ci		tty_flip_buffer_push(&port->port);
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
13288c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
13298c2ecf20Sopenharmony_ci	if (err != 0)
13308c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13318c2ecf20Sopenharmony_ci}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_cistatic void	usa90_instat_callback(struct urb *urb)
13358c2ecf20Sopenharmony_ci{
13368c2ecf20Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
13378c2ecf20Sopenharmony_ci	struct keyspan_usa90_portStatusMessage	*msg;
13388c2ecf20Sopenharmony_ci	struct usb_serial			*serial;
13398c2ecf20Sopenharmony_ci	struct usb_serial_port			*port;
13408c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
13418c2ecf20Sopenharmony_ci	int old_dcd_state, err;
13428c2ecf20Sopenharmony_ci	int status = urb->status;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	serial =  urb->context;
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	if (status) {
13478c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
13488c2ecf20Sopenharmony_ci				__func__, status);
13498c2ecf20Sopenharmony_ci		return;
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci	if (urb->actual_length < 14) {
13528c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length);
13538c2ecf20Sopenharmony_ci		goto exit;
13548c2ecf20Sopenharmony_ci	}
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	msg = (struct keyspan_usa90_portStatusMessage *)data;
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	/* Now do something useful with the data */
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	port = serial->port[0];
13618c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
13628c2ecf20Sopenharmony_ci	if (!p_priv)
13638c2ecf20Sopenharmony_ci		goto resubmit;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	/* Update handshaking pin state information */
13668c2ecf20Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
13678c2ecf20Sopenharmony_ci	p_priv->cts_state = ((msg->cts) ? 1 : 0);
13688c2ecf20Sopenharmony_ci	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
13698c2ecf20Sopenharmony_ci	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
13708c2ecf20Sopenharmony_ci	p_priv->ri_state = ((msg->ri) ? 1 : 0);
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
13738c2ecf20Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
13748c2ecf20Sopenharmony_ciresubmit:
13758c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
13768c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
13778c2ecf20Sopenharmony_ci	if (err != 0)
13788c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
13798c2ecf20Sopenharmony_ciexit:
13808c2ecf20Sopenharmony_ci	;
13818c2ecf20Sopenharmony_ci}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_cistatic void	usa90_outcont_callback(struct urb *urb)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
13868c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	port =  urb->context;
13898c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (p_priv->resend_cont) {
13928c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__);
13938c2ecf20Sopenharmony_ci		keyspan_usa90_send_setup(port->serial, port,
13948c2ecf20Sopenharmony_ci						p_priv->resend_cont - 1);
13958c2ecf20Sopenharmony_ci	}
13968c2ecf20Sopenharmony_ci}
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci/* Status messages from the 28xg */
13998c2ecf20Sopenharmony_cistatic void	usa67_instat_callback(struct urb *urb)
14008c2ecf20Sopenharmony_ci{
14018c2ecf20Sopenharmony_ci	int					err;
14028c2ecf20Sopenharmony_ci	unsigned char 				*data = urb->transfer_buffer;
14038c2ecf20Sopenharmony_ci	struct keyspan_usa67_portStatusMessage	*msg;
14048c2ecf20Sopenharmony_ci	struct usb_serial			*serial;
14058c2ecf20Sopenharmony_ci	struct usb_serial_port			*port;
14068c2ecf20Sopenharmony_ci	struct keyspan_port_private	 	*p_priv;
14078c2ecf20Sopenharmony_ci	int old_dcd_state;
14088c2ecf20Sopenharmony_ci	int status = urb->status;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	serial = urb->context;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (status) {
14138c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n",
14148c2ecf20Sopenharmony_ci				__func__, status);
14158c2ecf20Sopenharmony_ci		return;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	if (urb->actual_length !=
14198c2ecf20Sopenharmony_ci			sizeof(struct keyspan_usa67_portStatusMessage)) {
14208c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length);
14218c2ecf20Sopenharmony_ci		return;
14228c2ecf20Sopenharmony_ci	}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	/* Now do something useful with the data */
14268c2ecf20Sopenharmony_ci	msg = (struct keyspan_usa67_portStatusMessage *)data;
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	/* Check port number from message and retrieve private data */
14298c2ecf20Sopenharmony_ci	if (msg->port >= serial->num_ports) {
14308c2ecf20Sopenharmony_ci		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port);
14318c2ecf20Sopenharmony_ci		return;
14328c2ecf20Sopenharmony_ci	}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	port = serial->port[msg->port];
14358c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
14368c2ecf20Sopenharmony_ci	if (!p_priv)
14378c2ecf20Sopenharmony_ci		goto resubmit;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	/* Update handshaking pin state information */
14408c2ecf20Sopenharmony_ci	old_dcd_state = p_priv->dcd_state;
14418c2ecf20Sopenharmony_ci	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
14428c2ecf20Sopenharmony_ci	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
14458c2ecf20Sopenharmony_ci		tty_port_tty_hangup(&port->port, true);
14468c2ecf20Sopenharmony_ciresubmit:
14478c2ecf20Sopenharmony_ci	/* Resubmit urb so we continue receiving */
14488c2ecf20Sopenharmony_ci	err = usb_submit_urb(urb, GFP_ATOMIC);
14498c2ecf20Sopenharmony_ci	if (err != 0)
14508c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err);
14518c2ecf20Sopenharmony_ci}
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_cistatic void usa67_glocont_callback(struct urb *urb)
14548c2ecf20Sopenharmony_ci{
14558c2ecf20Sopenharmony_ci	struct usb_serial *serial;
14568c2ecf20Sopenharmony_ci	struct usb_serial_port *port;
14578c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
14588c2ecf20Sopenharmony_ci	int i;
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	serial = urb->context;
14618c2ecf20Sopenharmony_ci	for (i = 0; i < serial->num_ports; ++i) {
14628c2ecf20Sopenharmony_ci		port = serial->port[i];
14638c2ecf20Sopenharmony_ci		p_priv = usb_get_serial_port_data(port);
14648c2ecf20Sopenharmony_ci		if (!p_priv)
14658c2ecf20Sopenharmony_ci			continue;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci		if (p_priv->resend_cont) {
14688c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - sending setup\n", __func__);
14698c2ecf20Sopenharmony_ci			keyspan_usa67_send_setup(serial, port,
14708c2ecf20Sopenharmony_ci						p_priv->resend_cont - 1);
14718c2ecf20Sopenharmony_ci			break;
14728c2ecf20Sopenharmony_ci		}
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci}
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_cistatic int keyspan_write_room(struct tty_struct *tty)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	struct usb_serial_port *port = tty->driver_data;
14798c2ecf20Sopenharmony_ci	struct keyspan_port_private	*p_priv;
14808c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
14818c2ecf20Sopenharmony_ci	int				flip;
14828c2ecf20Sopenharmony_ci	int				data_len;
14838c2ecf20Sopenharmony_ci	struct urb			*this_urb;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
14868c2ecf20Sopenharmony_ci	d_details = p_priv->device_details;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	/* FIXME: locking */
14898c2ecf20Sopenharmony_ci	if (d_details->msg_format == msg_usa90)
14908c2ecf20Sopenharmony_ci		data_len = 64;
14918c2ecf20Sopenharmony_ci	else
14928c2ecf20Sopenharmony_ci		data_len = 63;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	flip = p_priv->out_flip;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	/* Check both endpoints to see if any are available. */
14978c2ecf20Sopenharmony_ci	this_urb = p_priv->out_urbs[flip];
14988c2ecf20Sopenharmony_ci	if (this_urb != NULL) {
14998c2ecf20Sopenharmony_ci		if (this_urb->status != -EINPROGRESS)
15008c2ecf20Sopenharmony_ci			return data_len;
15018c2ecf20Sopenharmony_ci		flip = (flip + 1) & d_details->outdat_endp_flip;
15028c2ecf20Sopenharmony_ci		this_urb = p_priv->out_urbs[flip];
15038c2ecf20Sopenharmony_ci		if (this_urb != NULL) {
15048c2ecf20Sopenharmony_ci			if (this_urb->status != -EINPROGRESS)
15058c2ecf20Sopenharmony_ci				return data_len;
15068c2ecf20Sopenharmony_ci		}
15078c2ecf20Sopenharmony_ci	}
15088c2ecf20Sopenharmony_ci	return 0;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_cistatic int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
15138c2ecf20Sopenharmony_ci{
15148c2ecf20Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
15158c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
15168c2ecf20Sopenharmony_ci	int				i, err;
15178c2ecf20Sopenharmony_ci	int				baud_rate, device_port;
15188c2ecf20Sopenharmony_ci	struct urb			*urb;
15198c2ecf20Sopenharmony_ci	unsigned int			cflag = 0;
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
15228c2ecf20Sopenharmony_ci	d_details = p_priv->device_details;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	/* Set some sane defaults */
15258c2ecf20Sopenharmony_ci	p_priv->rts_state = 1;
15268c2ecf20Sopenharmony_ci	p_priv->dtr_state = 1;
15278c2ecf20Sopenharmony_ci	p_priv->baud = 9600;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	/* force baud and lcr to be set on open */
15308c2ecf20Sopenharmony_ci	p_priv->old_baud = 0;
15318c2ecf20Sopenharmony_ci	p_priv->old_cflag = 0;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	p_priv->out_flip = 0;
15348c2ecf20Sopenharmony_ci	p_priv->in_flip = 0;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	/* Reset low level data toggle and start reading from endpoints */
15378c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
15388c2ecf20Sopenharmony_ci		urb = p_priv->in_urbs[i];
15398c2ecf20Sopenharmony_ci		if (urb == NULL)
15408c2ecf20Sopenharmony_ci			continue;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci		/* make sure endpoint data toggle is synchronized
15438c2ecf20Sopenharmony_ci		   with the device */
15448c2ecf20Sopenharmony_ci		usb_clear_halt(urb->dev, urb->pipe);
15458c2ecf20Sopenharmony_ci		err = usb_submit_urb(urb, GFP_KERNEL);
15468c2ecf20Sopenharmony_ci		if (err != 0)
15478c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err);
15488c2ecf20Sopenharmony_ci	}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	/* Reset low level data toggle on out endpoints */
15518c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
15528c2ecf20Sopenharmony_ci		urb = p_priv->out_urbs[i];
15538c2ecf20Sopenharmony_ci		if (urb == NULL)
15548c2ecf20Sopenharmony_ci			continue;
15558c2ecf20Sopenharmony_ci		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
15568c2ecf20Sopenharmony_ci						usb_pipeout(urb->pipe), 0); */
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	/* get the terminal config for the setup message now so we don't
15608c2ecf20Sopenharmony_ci	 * need to send 2 of them */
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	device_port = port->port_number;
15638c2ecf20Sopenharmony_ci	if (tty) {
15648c2ecf20Sopenharmony_ci		cflag = tty->termios.c_cflag;
15658c2ecf20Sopenharmony_ci		/* Baud rate calculation takes baud rate as an integer
15668c2ecf20Sopenharmony_ci		   so other rates can be generated if desired. */
15678c2ecf20Sopenharmony_ci		baud_rate = tty_get_baud_rate(tty);
15688c2ecf20Sopenharmony_ci		/* If no match or invalid, leave as default */
15698c2ecf20Sopenharmony_ci		if (baud_rate >= 0
15708c2ecf20Sopenharmony_ci		    && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,
15718c2ecf20Sopenharmony_ci					NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
15728c2ecf20Sopenharmony_ci			p_priv->baud = baud_rate;
15738c2ecf20Sopenharmony_ci		}
15748c2ecf20Sopenharmony_ci	}
15758c2ecf20Sopenharmony_ci	/* set CTS/RTS handshake etc. */
15768c2ecf20Sopenharmony_ci	p_priv->cflag = cflag;
15778c2ecf20Sopenharmony_ci	p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 1);
15808c2ecf20Sopenharmony_ci	/* mdelay(100); */
15818c2ecf20Sopenharmony_ci	/* keyspan_set_termios(port, NULL); */
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	return 0;
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic void keyspan_dtr_rts(struct usb_serial_port *port, int on)
15878c2ecf20Sopenharmony_ci{
15888c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	p_priv->rts_state = on;
15918c2ecf20Sopenharmony_ci	p_priv->dtr_state = on;
15928c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 0);
15938c2ecf20Sopenharmony_ci}
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_cistatic void keyspan_close(struct usb_serial_port *port)
15968c2ecf20Sopenharmony_ci{
15978c2ecf20Sopenharmony_ci	int			i;
15988c2ecf20Sopenharmony_ci	struct keyspan_port_private 	*p_priv;
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	p_priv->rts_state = 0;
16038c2ecf20Sopenharmony_ci	p_priv->dtr_state = 0;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	keyspan_send_setup(port, 2);
16068c2ecf20Sopenharmony_ci	/* pilot-xfer seems to work best with this delay */
16078c2ecf20Sopenharmony_ci	mdelay(100);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	p_priv->out_flip = 0;
16108c2ecf20Sopenharmony_ci	p_priv->in_flip = 0;
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	usb_kill_urb(p_priv->inack_urb);
16138c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
16148c2ecf20Sopenharmony_ci		usb_kill_urb(p_priv->in_urbs[i]);
16158c2ecf20Sopenharmony_ci		usb_kill_urb(p_priv->out_urbs[i]);
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci}
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci/* download the firmware to a pre-renumeration device */
16208c2ecf20Sopenharmony_cistatic int keyspan_fake_startup(struct usb_serial *serial)
16218c2ecf20Sopenharmony_ci{
16228c2ecf20Sopenharmony_ci	char	*fw_name;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n",
16258c2ecf20Sopenharmony_ci		le16_to_cpu(serial->dev->descriptor.bcdDevice),
16268c2ecf20Sopenharmony_ci		le16_to_cpu(serial->dev->descriptor.idProduct));
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000)
16298c2ecf20Sopenharmony_ci								!= 0x8000) {
16308c2ecf20Sopenharmony_ci		dev_dbg(&serial->dev->dev, "Firmware already loaded.  Quitting.\n");
16318c2ecf20Sopenharmony_ci		return 1;
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci		/* Select firmware image on the basis of idProduct */
16358c2ecf20Sopenharmony_ci	switch (le16_to_cpu(serial->dev->descriptor.idProduct)) {
16368c2ecf20Sopenharmony_ci	case keyspan_usa28_pre_product_id:
16378c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa28.fw";
16388c2ecf20Sopenharmony_ci		break;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	case keyspan_usa28x_pre_product_id:
16418c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa28x.fw";
16428c2ecf20Sopenharmony_ci		break;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	case keyspan_usa28xa_pre_product_id:
16458c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa28xa.fw";
16468c2ecf20Sopenharmony_ci		break;
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	case keyspan_usa28xb_pre_product_id:
16498c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa28xb.fw";
16508c2ecf20Sopenharmony_ci		break;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	case keyspan_usa19_pre_product_id:
16538c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa19.fw";
16548c2ecf20Sopenharmony_ci		break;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	case keyspan_usa19qi_pre_product_id:
16578c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa19qi.fw";
16588c2ecf20Sopenharmony_ci		break;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	case keyspan_mpr_pre_product_id:
16618c2ecf20Sopenharmony_ci		fw_name = "keyspan/mpr.fw";
16628c2ecf20Sopenharmony_ci		break;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	case keyspan_usa19qw_pre_product_id:
16658c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa19qw.fw";
16668c2ecf20Sopenharmony_ci		break;
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	case keyspan_usa18x_pre_product_id:
16698c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa18x.fw";
16708c2ecf20Sopenharmony_ci		break;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	case keyspan_usa19w_pre_product_id:
16738c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa19w.fw";
16748c2ecf20Sopenharmony_ci		break;
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	case keyspan_usa49w_pre_product_id:
16778c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa49w.fw";
16788c2ecf20Sopenharmony_ci		break;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	case keyspan_usa49wlc_pre_product_id:
16818c2ecf20Sopenharmony_ci		fw_name = "keyspan/usa49wlc.fw";
16828c2ecf20Sopenharmony_ci		break;
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	default:
16858c2ecf20Sopenharmony_ci		dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n",
16868c2ecf20Sopenharmony_ci			le16_to_cpu(serial->dev->descriptor.idProduct));
16878c2ecf20Sopenharmony_ci		return 1;
16888c2ecf20Sopenharmony_ci	}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name);
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) {
16938c2ecf20Sopenharmony_ci		dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n",
16948c2ecf20Sopenharmony_ci			fw_name);
16958c2ecf20Sopenharmony_ci		return -ENOENT;
16968c2ecf20Sopenharmony_ci	}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	/* after downloading firmware Renumeration will occur in a
16998c2ecf20Sopenharmony_ci	  moment and the new device will bind to the real driver */
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	/* we don't want this device to have a driver assigned to it. */
17028c2ecf20Sopenharmony_ci	return 1;
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci/* Helper functions used by keyspan_setup_urbs */
17068c2ecf20Sopenharmony_cistatic struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
17078c2ecf20Sopenharmony_ci						     int endpoint)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	struct usb_host_interface *iface_desc;
17108c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor *ep;
17118c2ecf20Sopenharmony_ci	int i;
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	iface_desc = serial->interface->cur_altsetting;
17148c2ecf20Sopenharmony_ci	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
17158c2ecf20Sopenharmony_ci		ep = &iface_desc->endpoint[i].desc;
17168c2ecf20Sopenharmony_ci		if (ep->bEndpointAddress == endpoint)
17178c2ecf20Sopenharmony_ci			return ep;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci	dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n",
17208c2ecf20Sopenharmony_ci			endpoint);
17218c2ecf20Sopenharmony_ci	return NULL;
17228c2ecf20Sopenharmony_ci}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cistatic struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
17258c2ecf20Sopenharmony_ci				      int dir, void *ctx, char *buf, int len,
17268c2ecf20Sopenharmony_ci				      void (*callback)(struct urb *))
17278c2ecf20Sopenharmony_ci{
17288c2ecf20Sopenharmony_ci	struct urb *urb;
17298c2ecf20Sopenharmony_ci	struct usb_endpoint_descriptor const *ep_desc;
17308c2ecf20Sopenharmony_ci	char const *ep_type_name;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	if (endpoint == -1)
17338c2ecf20Sopenharmony_ci		return NULL;		/* endpoint not needed */
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n",
17368c2ecf20Sopenharmony_ci			__func__, endpoint);
17378c2ecf20Sopenharmony_ci	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */
17388c2ecf20Sopenharmony_ci	if (!urb)
17398c2ecf20Sopenharmony_ci		return NULL;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	if (endpoint == 0) {
17428c2ecf20Sopenharmony_ci		/* control EP filled in when used */
17438c2ecf20Sopenharmony_ci		return urb;
17448c2ecf20Sopenharmony_ci	}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	ep_desc = find_ep(serial, endpoint);
17478c2ecf20Sopenharmony_ci	if (!ep_desc) {
17488c2ecf20Sopenharmony_ci		usb_free_urb(urb);
17498c2ecf20Sopenharmony_ci		return NULL;
17508c2ecf20Sopenharmony_ci	}
17518c2ecf20Sopenharmony_ci	if (usb_endpoint_xfer_int(ep_desc)) {
17528c2ecf20Sopenharmony_ci		ep_type_name = "INT";
17538c2ecf20Sopenharmony_ci		usb_fill_int_urb(urb, serial->dev,
17548c2ecf20Sopenharmony_ci				 usb_sndintpipe(serial->dev, endpoint) | dir,
17558c2ecf20Sopenharmony_ci				 buf, len, callback, ctx,
17568c2ecf20Sopenharmony_ci				 ep_desc->bInterval);
17578c2ecf20Sopenharmony_ci	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
17588c2ecf20Sopenharmony_ci		ep_type_name = "BULK";
17598c2ecf20Sopenharmony_ci		usb_fill_bulk_urb(urb, serial->dev,
17608c2ecf20Sopenharmony_ci				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
17618c2ecf20Sopenharmony_ci				  buf, len, callback, ctx);
17628c2ecf20Sopenharmony_ci	} else {
17638c2ecf20Sopenharmony_ci		dev_warn(&serial->interface->dev,
17648c2ecf20Sopenharmony_ci			 "unsupported endpoint type %x\n",
17658c2ecf20Sopenharmony_ci			 usb_endpoint_type(ep_desc));
17668c2ecf20Sopenharmony_ci		usb_free_urb(urb);
17678c2ecf20Sopenharmony_ci		return NULL;
17688c2ecf20Sopenharmony_ci	}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n",
17718c2ecf20Sopenharmony_ci	    __func__, urb, ep_type_name, endpoint);
17728c2ecf20Sopenharmony_ci	return urb;
17738c2ecf20Sopenharmony_ci}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_cistatic struct callbacks {
17768c2ecf20Sopenharmony_ci	void	(*instat_callback)(struct urb *);
17778c2ecf20Sopenharmony_ci	void	(*glocont_callback)(struct urb *);
17788c2ecf20Sopenharmony_ci	void	(*indat_callback)(struct urb *);
17798c2ecf20Sopenharmony_ci	void	(*outdat_callback)(struct urb *);
17808c2ecf20Sopenharmony_ci	void	(*inack_callback)(struct urb *);
17818c2ecf20Sopenharmony_ci	void	(*outcont_callback)(struct urb *);
17828c2ecf20Sopenharmony_ci} keyspan_callbacks[] = {
17838c2ecf20Sopenharmony_ci	{
17848c2ecf20Sopenharmony_ci		/* msg_usa26 callbacks */
17858c2ecf20Sopenharmony_ci		.instat_callback =	usa26_instat_callback,
17868c2ecf20Sopenharmony_ci		.glocont_callback =	usa26_glocont_callback,
17878c2ecf20Sopenharmony_ci		.indat_callback =	usa26_indat_callback,
17888c2ecf20Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
17898c2ecf20Sopenharmony_ci		.inack_callback =	usa26_inack_callback,
17908c2ecf20Sopenharmony_ci		.outcont_callback =	usa26_outcont_callback,
17918c2ecf20Sopenharmony_ci	}, {
17928c2ecf20Sopenharmony_ci		/* msg_usa28 callbacks */
17938c2ecf20Sopenharmony_ci		.instat_callback =	usa28_instat_callback,
17948c2ecf20Sopenharmony_ci		.glocont_callback =	usa28_glocont_callback,
17958c2ecf20Sopenharmony_ci		.indat_callback =	usa28_indat_callback,
17968c2ecf20Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
17978c2ecf20Sopenharmony_ci		.inack_callback =	usa28_inack_callback,
17988c2ecf20Sopenharmony_ci		.outcont_callback =	usa28_outcont_callback,
17998c2ecf20Sopenharmony_ci	}, {
18008c2ecf20Sopenharmony_ci		/* msg_usa49 callbacks */
18018c2ecf20Sopenharmony_ci		.instat_callback =	usa49_instat_callback,
18028c2ecf20Sopenharmony_ci		.glocont_callback =	usa49_glocont_callback,
18038c2ecf20Sopenharmony_ci		.indat_callback =	usa49_indat_callback,
18048c2ecf20Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
18058c2ecf20Sopenharmony_ci		.inack_callback =	usa49_inack_callback,
18068c2ecf20Sopenharmony_ci		.outcont_callback =	usa49_outcont_callback,
18078c2ecf20Sopenharmony_ci	}, {
18088c2ecf20Sopenharmony_ci		/* msg_usa90 callbacks */
18098c2ecf20Sopenharmony_ci		.instat_callback =	usa90_instat_callback,
18108c2ecf20Sopenharmony_ci		.glocont_callback =	usa28_glocont_callback,
18118c2ecf20Sopenharmony_ci		.indat_callback =	usa90_indat_callback,
18128c2ecf20Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
18138c2ecf20Sopenharmony_ci		.inack_callback =	usa28_inack_callback,
18148c2ecf20Sopenharmony_ci		.outcont_callback =	usa90_outcont_callback,
18158c2ecf20Sopenharmony_ci	}, {
18168c2ecf20Sopenharmony_ci		/* msg_usa67 callbacks */
18178c2ecf20Sopenharmony_ci		.instat_callback =	usa67_instat_callback,
18188c2ecf20Sopenharmony_ci		.glocont_callback =	usa67_glocont_callback,
18198c2ecf20Sopenharmony_ci		.indat_callback =	usa26_indat_callback,
18208c2ecf20Sopenharmony_ci		.outdat_callback =	usa2x_outdat_callback,
18218c2ecf20Sopenharmony_ci		.inack_callback =	usa26_inack_callback,
18228c2ecf20Sopenharmony_ci		.outcont_callback =	usa26_outcont_callback,
18238c2ecf20Sopenharmony_ci	}
18248c2ecf20Sopenharmony_ci};
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	/* Generic setup urbs function that uses
18278c2ecf20Sopenharmony_ci	   data in device_details */
18288c2ecf20Sopenharmony_cistatic void keyspan_setup_urbs(struct usb_serial *serial)
18298c2ecf20Sopenharmony_ci{
18308c2ecf20Sopenharmony_ci	struct keyspan_serial_private 	*s_priv;
18318c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
18328c2ecf20Sopenharmony_ci	struct callbacks		*cback;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
18358c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	/* Setup values for the various callback routines */
18388c2ecf20Sopenharmony_ci	cback = &keyspan_callbacks[d_details->msg_format];
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci	/* Allocate and set up urbs for each one that is in use,
18418c2ecf20Sopenharmony_ci	   starting with instat endpoints */
18428c2ecf20Sopenharmony_ci	s_priv->instat_urb = keyspan_setup_urb
18438c2ecf20Sopenharmony_ci		(serial, d_details->instat_endpoint, USB_DIR_IN,
18448c2ecf20Sopenharmony_ci		 serial, s_priv->instat_buf, INSTAT_BUFLEN,
18458c2ecf20Sopenharmony_ci		 cback->instat_callback);
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	s_priv->indat_urb = keyspan_setup_urb
18488c2ecf20Sopenharmony_ci		(serial, d_details->indat_endpoint, USB_DIR_IN,
18498c2ecf20Sopenharmony_ci		 serial, s_priv->indat_buf, INDAT49W_BUFLEN,
18508c2ecf20Sopenharmony_ci		 usa49wg_indat_callback);
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	s_priv->glocont_urb = keyspan_setup_urb
18538c2ecf20Sopenharmony_ci		(serial, d_details->glocont_endpoint, USB_DIR_OUT,
18548c2ecf20Sopenharmony_ci		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
18558c2ecf20Sopenharmony_ci		 cback->glocont_callback);
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci/* usa19 function doesn't require prescaler */
18598c2ecf20Sopenharmony_cistatic int keyspan_usa19_calc_baud(struct usb_serial_port *port,
18608c2ecf20Sopenharmony_ci				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
18618c2ecf20Sopenharmony_ci				   u8 *rate_low, u8 *prescaler, int portnum)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
18648c2ecf20Sopenharmony_ci		div,	/* divisor */
18658c2ecf20Sopenharmony_ci		cnt;	/* inverse of divisor (programmed into 8051) */
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	/* prevent divide by zero...  */
18708c2ecf20Sopenharmony_ci	b16 = baud_rate * 16L;
18718c2ecf20Sopenharmony_ci	if (b16 == 0)
18728c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
18738c2ecf20Sopenharmony_ci	/* Any "standard" rate over 57k6 is marginal on the USA-19
18748c2ecf20Sopenharmony_ci	   as we run out of divisor resolution. */
18758c2ecf20Sopenharmony_ci	if (baud_rate > 57600)
18768c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/* calculate the divisor and the counter (its inverse) */
18798c2ecf20Sopenharmony_ci	div = baudclk / b16;
18808c2ecf20Sopenharmony_ci	if (div == 0)
18818c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
18828c2ecf20Sopenharmony_ci	else
18838c2ecf20Sopenharmony_ci		cnt = 0 - div;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	if (div > 0xffff)
18868c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	/* return the counter values if non-null */
18898c2ecf20Sopenharmony_ci	if (rate_low)
18908c2ecf20Sopenharmony_ci		*rate_low = (u8) (cnt & 0xff);
18918c2ecf20Sopenharmony_ci	if (rate_hi)
18928c2ecf20Sopenharmony_ci		*rate_hi = (u8) ((cnt >> 8) & 0xff);
18938c2ecf20Sopenharmony_ci	if (rate_low && rate_hi)
18948c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
18958c2ecf20Sopenharmony_ci				__func__, baud_rate, *rate_hi, *rate_low);
18968c2ecf20Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci/* usa19hs function doesn't require prescaler */
19008c2ecf20Sopenharmony_cistatic int keyspan_usa19hs_calc_baud(struct usb_serial_port *port,
19018c2ecf20Sopenharmony_ci				     u32 baud_rate, u32 baudclk, u8 *rate_hi,
19028c2ecf20Sopenharmony_ci				     u8 *rate_low, u8 *prescaler, int portnum)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19058c2ecf20Sopenharmony_ci			div;	/* divisor */
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	/* prevent divide by zero...  */
19108c2ecf20Sopenharmony_ci	b16 = baud_rate * 16L;
19118c2ecf20Sopenharmony_ci	if (b16 == 0)
19128c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	/* calculate the divisor */
19158c2ecf20Sopenharmony_ci	div = baudclk / b16;
19168c2ecf20Sopenharmony_ci	if (div == 0)
19178c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	if (div > 0xffff)
19208c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	/* return the counter values if non-null */
19238c2ecf20Sopenharmony_ci	if (rate_low)
19248c2ecf20Sopenharmony_ci		*rate_low = (u8) (div & 0xff);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci	if (rate_hi)
19278c2ecf20Sopenharmony_ci		*rate_hi = (u8) ((div >> 8) & 0xff);
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	if (rate_low && rate_hi)
19308c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - %d %02x %02x.\n",
19318c2ecf20Sopenharmony_ci			__func__, baud_rate, *rate_hi, *rate_low);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
19348c2ecf20Sopenharmony_ci}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_cistatic int keyspan_usa19w_calc_baud(struct usb_serial_port *port,
19378c2ecf20Sopenharmony_ci				    u32 baud_rate, u32 baudclk, u8 *rate_hi,
19388c2ecf20Sopenharmony_ci				    u8 *rate_low, u8 *prescaler, int portnum)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
19418c2ecf20Sopenharmony_ci		clk,	/* clock with 13/8 prescaler */
19428c2ecf20Sopenharmony_ci		div,	/* divisor using 13/8 prescaler */
19438c2ecf20Sopenharmony_ci		res,	/* resulting baud rate using 13/8 prescaler */
19448c2ecf20Sopenharmony_ci		diff,	/* error using 13/8 prescaler */
19458c2ecf20Sopenharmony_ci		smallest_diff;
19468c2ecf20Sopenharmony_ci	u8	best_prescaler;
19478c2ecf20Sopenharmony_ci	int	i;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	/* prevent divide by zero */
19528c2ecf20Sopenharmony_ci	b16 = baud_rate * 16L;
19538c2ecf20Sopenharmony_ci	if (b16 == 0)
19548c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	/* Calculate prescaler by trying them all and looking
19578c2ecf20Sopenharmony_ci	   for best fit */
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	/* start with largest possible difference */
19608c2ecf20Sopenharmony_ci	smallest_diff = 0xffffffff;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		/* 0 is an invalid prescaler, used as a flag */
19638c2ecf20Sopenharmony_ci	best_prescaler = 0;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	for (i = 8; i <= 0xff; ++i) {
19668c2ecf20Sopenharmony_ci		clk = (baudclk * 8) / (u32) i;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci		div = clk / b16;
19698c2ecf20Sopenharmony_ci		if (div == 0)
19708c2ecf20Sopenharmony_ci			continue;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci		res = clk / div;
19738c2ecf20Sopenharmony_ci		diff = (res > b16) ? (res-b16) : (b16-res);
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci		if (diff < smallest_diff) {
19768c2ecf20Sopenharmony_ci			best_prescaler = i;
19778c2ecf20Sopenharmony_ci			smallest_diff = diff;
19788c2ecf20Sopenharmony_ci		}
19798c2ecf20Sopenharmony_ci	}
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ci	if (best_prescaler == 0)
19828c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	clk = (baudclk * 8) / (u32) best_prescaler;
19858c2ecf20Sopenharmony_ci	div = clk / b16;
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci	/* return the divisor and prescaler if non-null */
19888c2ecf20Sopenharmony_ci	if (rate_low)
19898c2ecf20Sopenharmony_ci		*rate_low = (u8) (div & 0xff);
19908c2ecf20Sopenharmony_ci	if (rate_hi)
19918c2ecf20Sopenharmony_ci		*rate_hi = (u8) ((div >> 8) & 0xff);
19928c2ecf20Sopenharmony_ci	if (prescaler) {
19938c2ecf20Sopenharmony_ci		*prescaler = best_prescaler;
19948c2ecf20Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */
19958c2ecf20Sopenharmony_ci	}
19968c2ecf20Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
19978c2ecf20Sopenharmony_ci}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	/* USA-28 supports different maximum baud rates on each port */
20008c2ecf20Sopenharmony_cistatic int keyspan_usa28_calc_baud(struct usb_serial_port *port,
20018c2ecf20Sopenharmony_ci				   u32 baud_rate, u32 baudclk, u8 *rate_hi,
20028c2ecf20Sopenharmony_ci				   u8 *rate_low, u8 *prescaler, int portnum)
20038c2ecf20Sopenharmony_ci{
20048c2ecf20Sopenharmony_ci	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
20058c2ecf20Sopenharmony_ci		div,	/* divisor */
20068c2ecf20Sopenharmony_ci		cnt;	/* inverse of divisor (programmed into 8051) */
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate);
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci		/* prevent divide by zero */
20118c2ecf20Sopenharmony_ci	b16 = baud_rate * 16L;
20128c2ecf20Sopenharmony_ci	if (b16 == 0)
20138c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ci	/* calculate the divisor and the counter (its inverse) */
20168c2ecf20Sopenharmony_ci	div = KEYSPAN_USA28_BAUDCLK / b16;
20178c2ecf20Sopenharmony_ci	if (div == 0)
20188c2ecf20Sopenharmony_ci		return KEYSPAN_INVALID_BAUD_RATE;
20198c2ecf20Sopenharmony_ci	else
20208c2ecf20Sopenharmony_ci		cnt = 0 - div;
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	/* check for out of range, based on portnum,
20238c2ecf20Sopenharmony_ci	   and return result */
20248c2ecf20Sopenharmony_ci	if (portnum == 0) {
20258c2ecf20Sopenharmony_ci		if (div > 0xffff)
20268c2ecf20Sopenharmony_ci			return KEYSPAN_INVALID_BAUD_RATE;
20278c2ecf20Sopenharmony_ci	} else {
20288c2ecf20Sopenharmony_ci		if (portnum == 1) {
20298c2ecf20Sopenharmony_ci			if (div > 0xff)
20308c2ecf20Sopenharmony_ci				return KEYSPAN_INVALID_BAUD_RATE;
20318c2ecf20Sopenharmony_ci		} else
20328c2ecf20Sopenharmony_ci			return KEYSPAN_INVALID_BAUD_RATE;
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci		/* return the counter values if not NULL
20368c2ecf20Sopenharmony_ci		   (port 1 will ignore retHi) */
20378c2ecf20Sopenharmony_ci	if (rate_low)
20388c2ecf20Sopenharmony_ci		*rate_low = (u8) (cnt & 0xff);
20398c2ecf20Sopenharmony_ci	if (rate_hi)
20408c2ecf20Sopenharmony_ci		*rate_hi = (u8) ((cnt >> 8) & 0xff);
20418c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate);
20428c2ecf20Sopenharmony_ci	return KEYSPAN_BAUD_RATE_OK;
20438c2ecf20Sopenharmony_ci}
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_cistatic int keyspan_usa26_send_setup(struct usb_serial *serial,
20468c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
20478c2ecf20Sopenharmony_ci				    int reset_port)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	struct keyspan_usa26_portControlMessage	msg;
20508c2ecf20Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
20518c2ecf20Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
20528c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
20538c2ecf20Sopenharmony_ci	struct urb				*this_urb;
20548c2ecf20Sopenharmony_ci	int 					device_port, err;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
20598c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
20608c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
20618c2ecf20Sopenharmony_ci	device_port = port->port_number;
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci	this_urb = p_priv->outcont_urb;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci		/* Make sure we have an urb then send the message */
20668c2ecf20Sopenharmony_ci	if (this_urb == NULL) {
20678c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
20688c2ecf20Sopenharmony_ci		return -1;
20698c2ecf20Sopenharmony_ci	}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - endpoint %x\n",
20728c2ecf20Sopenharmony_ci			__func__, usb_pipeendpoint(this_urb->pipe));
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	/* Save reset port val for resend.
20758c2ecf20Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
20768c2ecf20Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
20778c2ecf20Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
20788c2ecf20Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
20798c2ecf20Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
20808c2ecf20Sopenharmony_ci		mdelay(5);
20818c2ecf20Sopenharmony_ci		return -1;
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage));
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	/* Only set baud rate if it's changed */
20878c2ecf20Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
20888c2ecf20Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
20898c2ecf20Sopenharmony_ci		msg.setClocking = 0xff;
20908c2ecf20Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
20918c2ecf20Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
20928c2ecf20Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
20938c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
20948c2ecf20Sopenharmony_ci				__func__, p_priv->baud);
20958c2ecf20Sopenharmony_ci			msg.baudLo = 0;
20968c2ecf20Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
20978c2ecf20Sopenharmony_ci			msg.prescaler = 10;
20988c2ecf20Sopenharmony_ci		}
20998c2ecf20Sopenharmony_ci		msg.setPrescaler = 0xff;
21008c2ecf20Sopenharmony_ci	}
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
21038c2ecf20Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
21048c2ecf20Sopenharmony_ci	case CS5:
21058c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
21068c2ecf20Sopenharmony_ci		break;
21078c2ecf20Sopenharmony_ci	case CS6:
21088c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
21098c2ecf20Sopenharmony_ci		break;
21108c2ecf20Sopenharmony_ci	case CS7:
21118c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
21128c2ecf20Sopenharmony_ci		break;
21138c2ecf20Sopenharmony_ci	case CS8:
21148c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
21158c2ecf20Sopenharmony_ci		break;
21168c2ecf20Sopenharmony_ci	}
21178c2ecf20Sopenharmony_ci	if (p_priv->cflag & PARENB) {
21188c2ecf20Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
21198c2ecf20Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
21208c2ecf20Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
21218c2ecf20Sopenharmony_ci	}
21228c2ecf20Sopenharmony_ci	msg.setLcr = 0xff;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
21258c2ecf20Sopenharmony_ci	msg.xonFlowControl = 0;
21268c2ecf20Sopenharmony_ci	msg.setFlowControl = 0xff;
21278c2ecf20Sopenharmony_ci	msg.forwardingLength = 16;
21288c2ecf20Sopenharmony_ci	msg.xonChar = 17;
21298c2ecf20Sopenharmony_ci	msg.xoffChar = 19;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci	/* Opening port */
21328c2ecf20Sopenharmony_ci	if (reset_port == 1) {
21338c2ecf20Sopenharmony_ci		msg._txOn = 1;
21348c2ecf20Sopenharmony_ci		msg._txOff = 0;
21358c2ecf20Sopenharmony_ci		msg.txFlush = 0;
21368c2ecf20Sopenharmony_ci		msg.txBreak = 0;
21378c2ecf20Sopenharmony_ci		msg.rxOn = 1;
21388c2ecf20Sopenharmony_ci		msg.rxOff = 0;
21398c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
21408c2ecf20Sopenharmony_ci		msg.rxForward = 0;
21418c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
21428c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0xff;
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	/* Closing port */
21468c2ecf20Sopenharmony_ci	else if (reset_port == 2) {
21478c2ecf20Sopenharmony_ci		msg._txOn = 0;
21488c2ecf20Sopenharmony_ci		msg._txOff = 1;
21498c2ecf20Sopenharmony_ci		msg.txFlush = 0;
21508c2ecf20Sopenharmony_ci		msg.txBreak = 0;
21518c2ecf20Sopenharmony_ci		msg.rxOn = 0;
21528c2ecf20Sopenharmony_ci		msg.rxOff = 1;
21538c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
21548c2ecf20Sopenharmony_ci		msg.rxForward = 0;
21558c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
21568c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0;
21578c2ecf20Sopenharmony_ci	}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	/* Sending intermediate configs */
21608c2ecf20Sopenharmony_ci	else {
21618c2ecf20Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
21628c2ecf20Sopenharmony_ci		msg._txOff = 0;
21638c2ecf20Sopenharmony_ci		msg.txFlush = 0;
21648c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
21658c2ecf20Sopenharmony_ci		msg.rxOn = 0;
21668c2ecf20Sopenharmony_ci		msg.rxOff = 0;
21678c2ecf20Sopenharmony_ci		msg.rxFlush = 0;
21688c2ecf20Sopenharmony_ci		msg.rxForward = 0;
21698c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
21708c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0x0;
21718c2ecf20Sopenharmony_ci	}
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	/* Do handshaking outputs */
21748c2ecf20Sopenharmony_ci	msg.setTxTriState_setRts = 0xff;
21758c2ecf20Sopenharmony_ci	msg.txTriState_rts = p_priv->rts_state;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	msg.setHskoa_setDtr = 0xff;
21788c2ecf20Sopenharmony_ci	msg.hskoa_dtr = p_priv->dtr_state;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	p_priv->resend_cont = 0;
21818c2ecf20Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	/* send the data out the device on control endpoint */
21848c2ecf20Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
21878c2ecf20Sopenharmony_ci	if (err != 0)
21888c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
21898c2ecf20Sopenharmony_ci	return 0;
21908c2ecf20Sopenharmony_ci}
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_cistatic int keyspan_usa28_send_setup(struct usb_serial *serial,
21938c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
21948c2ecf20Sopenharmony_ci				    int reset_port)
21958c2ecf20Sopenharmony_ci{
21968c2ecf20Sopenharmony_ci	struct keyspan_usa28_portControlMessage	msg;
21978c2ecf20Sopenharmony_ci	struct keyspan_serial_private	 	*s_priv;
21988c2ecf20Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
21998c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
22008c2ecf20Sopenharmony_ci	struct urb				*this_urb;
22018c2ecf20Sopenharmony_ci	int 					device_port, err;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
22048c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
22058c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
22068c2ecf20Sopenharmony_ci	device_port = port->port_number;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	/* only do something if we have a bulk out endpoint */
22098c2ecf20Sopenharmony_ci	this_urb = p_priv->outcont_urb;
22108c2ecf20Sopenharmony_ci	if (this_urb == NULL) {
22118c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
22128c2ecf20Sopenharmony_ci		return -1;
22138c2ecf20Sopenharmony_ci	}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	/* Save reset port val for resend.
22168c2ecf20Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
22178c2ecf20Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
22188c2ecf20Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
22198c2ecf20Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
22208c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s already writing\n", __func__);
22218c2ecf20Sopenharmony_ci		mdelay(5);
22228c2ecf20Sopenharmony_ci		return -1;
22238c2ecf20Sopenharmony_ci	}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage));
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	msg.setBaudRate = 1;
22288c2ecf20Sopenharmony_ci	if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
22298c2ecf20Sopenharmony_ci					   &msg.baudHi, &msg.baudLo, NULL,
22308c2ecf20Sopenharmony_ci					   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
22318c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n",
22328c2ecf20Sopenharmony_ci						__func__, p_priv->baud);
22338c2ecf20Sopenharmony_ci		msg.baudLo = 0xff;
22348c2ecf20Sopenharmony_ci		msg.baudHi = 0xb2;	/* Values for 9600 baud */
22358c2ecf20Sopenharmony_ci	}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	/* If parity is enabled, we must calculate it ourselves. */
22388c2ecf20Sopenharmony_ci	msg.parity = 0;		/* XXX for now */
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
22418c2ecf20Sopenharmony_ci	msg.xonFlowControl = 0;
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	/* Do handshaking outputs, DTR is inverted relative to RTS */
22448c2ecf20Sopenharmony_ci	msg.rts = p_priv->rts_state;
22458c2ecf20Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci	msg.forwardingLength = 16;
22488c2ecf20Sopenharmony_ci	msg.forwardMs = 10;
22498c2ecf20Sopenharmony_ci	msg.breakThreshold = 45;
22508c2ecf20Sopenharmony_ci	msg.xonChar = 17;
22518c2ecf20Sopenharmony_ci	msg.xoffChar = 19;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	/*msg.returnStatus = 1;
22548c2ecf20Sopenharmony_ci	msg.resetDataToggle = 0xff;*/
22558c2ecf20Sopenharmony_ci	/* Opening port */
22568c2ecf20Sopenharmony_ci	if (reset_port == 1) {
22578c2ecf20Sopenharmony_ci		msg._txOn = 1;
22588c2ecf20Sopenharmony_ci		msg._txOff = 0;
22598c2ecf20Sopenharmony_ci		msg.txFlush = 0;
22608c2ecf20Sopenharmony_ci		msg.txForceXoff = 0;
22618c2ecf20Sopenharmony_ci		msg.txBreak = 0;
22628c2ecf20Sopenharmony_ci		msg.rxOn = 1;
22638c2ecf20Sopenharmony_ci		msg.rxOff = 0;
22648c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
22658c2ecf20Sopenharmony_ci		msg.rxForward = 0;
22668c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
22678c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0xff;
22688c2ecf20Sopenharmony_ci	}
22698c2ecf20Sopenharmony_ci	/* Closing port */
22708c2ecf20Sopenharmony_ci	else if (reset_port == 2) {
22718c2ecf20Sopenharmony_ci		msg._txOn = 0;
22728c2ecf20Sopenharmony_ci		msg._txOff = 1;
22738c2ecf20Sopenharmony_ci		msg.txFlush = 0;
22748c2ecf20Sopenharmony_ci		msg.txForceXoff = 0;
22758c2ecf20Sopenharmony_ci		msg.txBreak = 0;
22768c2ecf20Sopenharmony_ci		msg.rxOn = 0;
22778c2ecf20Sopenharmony_ci		msg.rxOff = 1;
22788c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
22798c2ecf20Sopenharmony_ci		msg.rxForward = 0;
22808c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
22818c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0;
22828c2ecf20Sopenharmony_ci	}
22838c2ecf20Sopenharmony_ci	/* Sending intermediate configs */
22848c2ecf20Sopenharmony_ci	else {
22858c2ecf20Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
22868c2ecf20Sopenharmony_ci		msg._txOff = 0;
22878c2ecf20Sopenharmony_ci		msg.txFlush = 0;
22888c2ecf20Sopenharmony_ci		msg.txForceXoff = 0;
22898c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
22908c2ecf20Sopenharmony_ci		msg.rxOn = 0;
22918c2ecf20Sopenharmony_ci		msg.rxOff = 0;
22928c2ecf20Sopenharmony_ci		msg.rxFlush = 0;
22938c2ecf20Sopenharmony_ci		msg.rxForward = 0;
22948c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
22958c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0x0;
22968c2ecf20Sopenharmony_ci	}
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	p_priv->resend_cont = 0;
22998c2ecf20Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci	/* send the data out the device on control endpoint */
23028c2ecf20Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
23058c2ecf20Sopenharmony_ci	if (err != 0)
23068c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__);
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	return 0;
23098c2ecf20Sopenharmony_ci}
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_cistatic int keyspan_usa49_send_setup(struct usb_serial *serial,
23128c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
23138c2ecf20Sopenharmony_ci				    int reset_port)
23148c2ecf20Sopenharmony_ci{
23158c2ecf20Sopenharmony_ci	struct keyspan_usa49_portControlMessage	msg;
23168c2ecf20Sopenharmony_ci	struct usb_ctrlrequest 			*dr = NULL;
23178c2ecf20Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
23188c2ecf20Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
23198c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
23208c2ecf20Sopenharmony_ci	struct urb				*this_urb;
23218c2ecf20Sopenharmony_ci	int 					err, device_port;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
23248c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
23258c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci	this_urb = s_priv->glocont_urb;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	/* Work out which port within the device is being setup */
23308c2ecf20Sopenharmony_ci	device_port = port->port_number;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	/* Make sure we have an urb then send the message */
23338c2ecf20Sopenharmony_ci	if (this_urb == NULL) {
23348c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
23358c2ecf20Sopenharmony_ci		return -1;
23368c2ecf20Sopenharmony_ci	}
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	dev_dbg(&port->dev, "%s - endpoint %x (%d)\n",
23398c2ecf20Sopenharmony_ci		__func__, usb_pipeendpoint(this_urb->pipe), device_port);
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	/* Save reset port val for resend.
23428c2ecf20Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
23438c2ecf20Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
23448c2ecf20Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
23478c2ecf20Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
23488c2ecf20Sopenharmony_ci		mdelay(5);
23498c2ecf20Sopenharmony_ci		return -1;
23508c2ecf20Sopenharmony_ci	}
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage));
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_ci	msg.portNumber = device_port;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	/* Only set baud rate if it's changed */
23578c2ecf20Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
23588c2ecf20Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
23598c2ecf20Sopenharmony_ci		msg.setClocking = 0xff;
23608c2ecf20Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
23618c2ecf20Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
23628c2ecf20Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
23638c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
23648c2ecf20Sopenharmony_ci				__func__, p_priv->baud);
23658c2ecf20Sopenharmony_ci			msg.baudLo = 0;
23668c2ecf20Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
23678c2ecf20Sopenharmony_ci			msg.prescaler = 10;
23688c2ecf20Sopenharmony_ci		}
23698c2ecf20Sopenharmony_ci		/* msg.setPrescaler = 0xff; */
23708c2ecf20Sopenharmony_ci	}
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
23738c2ecf20Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
23748c2ecf20Sopenharmony_ci	case CS5:
23758c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
23768c2ecf20Sopenharmony_ci		break;
23778c2ecf20Sopenharmony_ci	case CS6:
23788c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
23798c2ecf20Sopenharmony_ci		break;
23808c2ecf20Sopenharmony_ci	case CS7:
23818c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
23828c2ecf20Sopenharmony_ci		break;
23838c2ecf20Sopenharmony_ci	case CS8:
23848c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
23858c2ecf20Sopenharmony_ci		break;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci	if (p_priv->cflag & PARENB) {
23888c2ecf20Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
23898c2ecf20Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
23908c2ecf20Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
23918c2ecf20Sopenharmony_ci	}
23928c2ecf20Sopenharmony_ci	msg.setLcr = 0xff;
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
23958c2ecf20Sopenharmony_ci	msg.xonFlowControl = 0;
23968c2ecf20Sopenharmony_ci	msg.setFlowControl = 0xff;
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	msg.forwardingLength = 16;
23998c2ecf20Sopenharmony_ci	msg.xonChar = 17;
24008c2ecf20Sopenharmony_ci	msg.xoffChar = 19;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	/* Opening port */
24038c2ecf20Sopenharmony_ci	if (reset_port == 1) {
24048c2ecf20Sopenharmony_ci		msg._txOn = 1;
24058c2ecf20Sopenharmony_ci		msg._txOff = 0;
24068c2ecf20Sopenharmony_ci		msg.txFlush = 0;
24078c2ecf20Sopenharmony_ci		msg.txBreak = 0;
24088c2ecf20Sopenharmony_ci		msg.rxOn = 1;
24098c2ecf20Sopenharmony_ci		msg.rxOff = 0;
24108c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
24118c2ecf20Sopenharmony_ci		msg.rxForward = 0;
24128c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
24138c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0xff;
24148c2ecf20Sopenharmony_ci		msg.enablePort = 1;
24158c2ecf20Sopenharmony_ci		msg.disablePort = 0;
24168c2ecf20Sopenharmony_ci	}
24178c2ecf20Sopenharmony_ci	/* Closing port */
24188c2ecf20Sopenharmony_ci	else if (reset_port == 2) {
24198c2ecf20Sopenharmony_ci		msg._txOn = 0;
24208c2ecf20Sopenharmony_ci		msg._txOff = 1;
24218c2ecf20Sopenharmony_ci		msg.txFlush = 0;
24228c2ecf20Sopenharmony_ci		msg.txBreak = 0;
24238c2ecf20Sopenharmony_ci		msg.rxOn = 0;
24248c2ecf20Sopenharmony_ci		msg.rxOff = 1;
24258c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
24268c2ecf20Sopenharmony_ci		msg.rxForward = 0;
24278c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
24288c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0;
24298c2ecf20Sopenharmony_ci		msg.enablePort = 0;
24308c2ecf20Sopenharmony_ci		msg.disablePort = 1;
24318c2ecf20Sopenharmony_ci	}
24328c2ecf20Sopenharmony_ci	/* Sending intermediate configs */
24338c2ecf20Sopenharmony_ci	else {
24348c2ecf20Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
24358c2ecf20Sopenharmony_ci		msg._txOff = 0;
24368c2ecf20Sopenharmony_ci		msg.txFlush = 0;
24378c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
24388c2ecf20Sopenharmony_ci		msg.rxOn = 0;
24398c2ecf20Sopenharmony_ci		msg.rxOff = 0;
24408c2ecf20Sopenharmony_ci		msg.rxFlush = 0;
24418c2ecf20Sopenharmony_ci		msg.rxForward = 0;
24428c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
24438c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0x0;
24448c2ecf20Sopenharmony_ci		msg.enablePort = 0;
24458c2ecf20Sopenharmony_ci		msg.disablePort = 0;
24468c2ecf20Sopenharmony_ci	}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	/* Do handshaking outputs */
24498c2ecf20Sopenharmony_ci	msg.setRts = 0xff;
24508c2ecf20Sopenharmony_ci	msg.rts = p_priv->rts_state;
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci	msg.setDtr = 0xff;
24538c2ecf20Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
24548c2ecf20Sopenharmony_ci
24558c2ecf20Sopenharmony_ci	p_priv->resend_cont = 0;
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci	/* if the device is a 49wg, we send control message on usb
24588c2ecf20Sopenharmony_ci	   control EP 0 */
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	if (d_details->product_id == keyspan_usa49wg_product_id) {
24618c2ecf20Sopenharmony_ci		dr = (void *)(s_priv->ctrl_buf);
24628c2ecf20Sopenharmony_ci		dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
24638c2ecf20Sopenharmony_ci		dr->bRequest = 0xB0;	/* 49wg control message */
24648c2ecf20Sopenharmony_ci		dr->wValue = 0;
24658c2ecf20Sopenharmony_ci		dr->wIndex = 0;
24668c2ecf20Sopenharmony_ci		dr->wLength = cpu_to_le16(sizeof(msg));
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci		memcpy(s_priv->glocont_buf, &msg, sizeof(msg));
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci		usb_fill_control_urb(this_urb, serial->dev,
24718c2ecf20Sopenharmony_ci				usb_sndctrlpipe(serial->dev, 0),
24728c2ecf20Sopenharmony_ci				(unsigned char *)dr, s_priv->glocont_buf,
24738c2ecf20Sopenharmony_ci				sizeof(msg), usa49_glocont_callback, serial);
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	} else {
24768c2ecf20Sopenharmony_ci		memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci		/* send the data out the device on control endpoint */
24798c2ecf20Sopenharmony_ci		this_urb->transfer_buffer_length = sizeof(msg);
24808c2ecf20Sopenharmony_ci	}
24818c2ecf20Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
24828c2ecf20Sopenharmony_ci	if (err != 0)
24838c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	return 0;
24868c2ecf20Sopenharmony_ci}
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_cistatic int keyspan_usa90_send_setup(struct usb_serial *serial,
24898c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
24908c2ecf20Sopenharmony_ci				    int reset_port)
24918c2ecf20Sopenharmony_ci{
24928c2ecf20Sopenharmony_ci	struct keyspan_usa90_portControlMessage	msg;
24938c2ecf20Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
24948c2ecf20Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
24958c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
24968c2ecf20Sopenharmony_ci	struct urb				*this_urb;
24978c2ecf20Sopenharmony_ci	int 					err;
24988c2ecf20Sopenharmony_ci	u8						prescaler;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
25018c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
25028c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	/* only do something if we have a bulk out endpoint */
25058c2ecf20Sopenharmony_ci	this_urb = p_priv->outcont_urb;
25068c2ecf20Sopenharmony_ci	if (this_urb == NULL) {
25078c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);
25088c2ecf20Sopenharmony_ci		return -1;
25098c2ecf20Sopenharmony_ci	}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	/* Save reset port val for resend.
25128c2ecf20Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
25138c2ecf20Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
25148c2ecf20Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
25158c2ecf20Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
25168c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s already writing\n", __func__);
25178c2ecf20Sopenharmony_ci		mdelay(5);
25188c2ecf20Sopenharmony_ci		return -1;
25198c2ecf20Sopenharmony_ci	}
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage));
25228c2ecf20Sopenharmony_ci
25238c2ecf20Sopenharmony_ci	/* Only set baud rate if it's changed */
25248c2ecf20Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
25258c2ecf20Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
25268c2ecf20Sopenharmony_ci		msg.setClocking = 0x01;
25278c2ecf20Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
25288c2ecf20Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) {
25298c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
25308c2ecf20Sopenharmony_ci				__func__, p_priv->baud);
25318c2ecf20Sopenharmony_ci			p_priv->baud = 9600;
25328c2ecf20Sopenharmony_ci			d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
25338c2ecf20Sopenharmony_ci				&msg.baudHi, &msg.baudLo, &prescaler, 0);
25348c2ecf20Sopenharmony_ci		}
25358c2ecf20Sopenharmony_ci		msg.setRxMode = 1;
25368c2ecf20Sopenharmony_ci		msg.setTxMode = 1;
25378c2ecf20Sopenharmony_ci	}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci	/* modes must always be correctly specified */
25408c2ecf20Sopenharmony_ci	if (p_priv->baud > 57600) {
25418c2ecf20Sopenharmony_ci		msg.rxMode = RXMODE_DMA;
25428c2ecf20Sopenharmony_ci		msg.txMode = TXMODE_DMA;
25438c2ecf20Sopenharmony_ci	} else {
25448c2ecf20Sopenharmony_ci		msg.rxMode = RXMODE_BYHAND;
25458c2ecf20Sopenharmony_ci		msg.txMode = TXMODE_BYHAND;
25468c2ecf20Sopenharmony_ci	}
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
25498c2ecf20Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
25508c2ecf20Sopenharmony_ci	case CS5:
25518c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
25528c2ecf20Sopenharmony_ci		break;
25538c2ecf20Sopenharmony_ci	case CS6:
25548c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
25558c2ecf20Sopenharmony_ci		break;
25568c2ecf20Sopenharmony_ci	case CS7:
25578c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
25588c2ecf20Sopenharmony_ci		break;
25598c2ecf20Sopenharmony_ci	case CS8:
25608c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
25618c2ecf20Sopenharmony_ci		break;
25628c2ecf20Sopenharmony_ci	}
25638c2ecf20Sopenharmony_ci	if (p_priv->cflag & PARENB) {
25648c2ecf20Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
25658c2ecf20Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
25668c2ecf20Sopenharmony_ci			USA_PARITY_ODD : USA_PARITY_EVEN;
25678c2ecf20Sopenharmony_ci	}
25688c2ecf20Sopenharmony_ci	if (p_priv->old_cflag != p_priv->cflag) {
25698c2ecf20Sopenharmony_ci		p_priv->old_cflag = p_priv->cflag;
25708c2ecf20Sopenharmony_ci		msg.setLcr = 0x01;
25718c2ecf20Sopenharmony_ci	}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	if (p_priv->flow_control == flow_cts)
25748c2ecf20Sopenharmony_ci		msg.txFlowControl = TXFLOW_CTS;
25758c2ecf20Sopenharmony_ci	msg.setTxFlowControl = 0x01;
25768c2ecf20Sopenharmony_ci	msg.setRxFlowControl = 0x01;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	msg.rxForwardingLength = 16;
25798c2ecf20Sopenharmony_ci	msg.rxForwardingTimeout = 16;
25808c2ecf20Sopenharmony_ci	msg.txAckSetting = 0;
25818c2ecf20Sopenharmony_ci	msg.xonChar = 17;
25828c2ecf20Sopenharmony_ci	msg.xoffChar = 19;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	/* Opening port */
25858c2ecf20Sopenharmony_ci	if (reset_port == 1) {
25868c2ecf20Sopenharmony_ci		msg.portEnabled = 1;
25878c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
25888c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
25898c2ecf20Sopenharmony_ci	}
25908c2ecf20Sopenharmony_ci	/* Closing port */
25918c2ecf20Sopenharmony_ci	else if (reset_port == 2)
25928c2ecf20Sopenharmony_ci		msg.portEnabled = 0;
25938c2ecf20Sopenharmony_ci	/* Sending intermediate configs */
25948c2ecf20Sopenharmony_ci	else {
25958c2ecf20Sopenharmony_ci		msg.portEnabled = 1;
25968c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
25978c2ecf20Sopenharmony_ci	}
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	/* Do handshaking outputs */
26008c2ecf20Sopenharmony_ci	msg.setRts = 0x01;
26018c2ecf20Sopenharmony_ci	msg.rts = p_priv->rts_state;
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	msg.setDtr = 0x01;
26048c2ecf20Sopenharmony_ci	msg.dtr = p_priv->dtr_state;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	p_priv->resend_cont = 0;
26078c2ecf20Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	/* send the data out the device on control endpoint */
26108c2ecf20Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
26138c2ecf20Sopenharmony_ci	if (err != 0)
26148c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
26158c2ecf20Sopenharmony_ci	return 0;
26168c2ecf20Sopenharmony_ci}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_cistatic int keyspan_usa67_send_setup(struct usb_serial *serial,
26198c2ecf20Sopenharmony_ci				    struct usb_serial_port *port,
26208c2ecf20Sopenharmony_ci				    int reset_port)
26218c2ecf20Sopenharmony_ci{
26228c2ecf20Sopenharmony_ci	struct keyspan_usa67_portControlMessage	msg;
26238c2ecf20Sopenharmony_ci	struct keyspan_serial_private 		*s_priv;
26248c2ecf20Sopenharmony_ci	struct keyspan_port_private 		*p_priv;
26258c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
26268c2ecf20Sopenharmony_ci	struct urb				*this_urb;
26278c2ecf20Sopenharmony_ci	int 					err, device_port;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
26308c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
26318c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ci	this_urb = s_priv->glocont_urb;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	/* Work out which port within the device is being setup */
26368c2ecf20Sopenharmony_ci	device_port = port->port_number;
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci	/* Make sure we have an urb then send the message */
26398c2ecf20Sopenharmony_ci	if (this_urb == NULL) {
26408c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__);
26418c2ecf20Sopenharmony_ci		return -1;
26428c2ecf20Sopenharmony_ci	}
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	/* Save reset port val for resend.
26458c2ecf20Sopenharmony_ci	   Don't overwrite resend for open/close condition. */
26468c2ecf20Sopenharmony_ci	if ((reset_port + 1) > p_priv->resend_cont)
26478c2ecf20Sopenharmony_ci		p_priv->resend_cont = reset_port + 1;
26488c2ecf20Sopenharmony_ci	if (this_urb->status == -EINPROGRESS) {
26498c2ecf20Sopenharmony_ci		/*  dev_dbg(&port->dev, "%s - already writing\n", __func__); */
26508c2ecf20Sopenharmony_ci		mdelay(5);
26518c2ecf20Sopenharmony_ci		return -1;
26528c2ecf20Sopenharmony_ci	}
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	msg.port = device_port;
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	/* Only set baud rate if it's changed */
26598c2ecf20Sopenharmony_ci	if (p_priv->old_baud != p_priv->baud) {
26608c2ecf20Sopenharmony_ci		p_priv->old_baud = p_priv->baud;
26618c2ecf20Sopenharmony_ci		msg.setClocking = 0xff;
26628c2ecf20Sopenharmony_ci		if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk,
26638c2ecf20Sopenharmony_ci						   &msg.baudHi, &msg.baudLo, &msg.prescaler,
26648c2ecf20Sopenharmony_ci						   device_port) == KEYSPAN_INVALID_BAUD_RATE) {
26658c2ecf20Sopenharmony_ci			dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n",
26668c2ecf20Sopenharmony_ci				__func__, p_priv->baud);
26678c2ecf20Sopenharmony_ci			msg.baudLo = 0;
26688c2ecf20Sopenharmony_ci			msg.baudHi = 125;	/* Values for 9600 baud */
26698c2ecf20Sopenharmony_ci			msg.prescaler = 10;
26708c2ecf20Sopenharmony_ci		}
26718c2ecf20Sopenharmony_ci		msg.setPrescaler = 0xff;
26728c2ecf20Sopenharmony_ci	}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
26758c2ecf20Sopenharmony_ci	switch (p_priv->cflag & CSIZE) {
26768c2ecf20Sopenharmony_ci	case CS5:
26778c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_5;
26788c2ecf20Sopenharmony_ci		break;
26798c2ecf20Sopenharmony_ci	case CS6:
26808c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_6;
26818c2ecf20Sopenharmony_ci		break;
26828c2ecf20Sopenharmony_ci	case CS7:
26838c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_7;
26848c2ecf20Sopenharmony_ci		break;
26858c2ecf20Sopenharmony_ci	case CS8:
26868c2ecf20Sopenharmony_ci		msg.lcr |= USA_DATABITS_8;
26878c2ecf20Sopenharmony_ci		break;
26888c2ecf20Sopenharmony_ci	}
26898c2ecf20Sopenharmony_ci	if (p_priv->cflag & PARENB) {
26908c2ecf20Sopenharmony_ci		/* note USA_PARITY_NONE == 0 */
26918c2ecf20Sopenharmony_ci		msg.lcr |= (p_priv->cflag & PARODD) ?
26928c2ecf20Sopenharmony_ci					USA_PARITY_ODD : USA_PARITY_EVEN;
26938c2ecf20Sopenharmony_ci	}
26948c2ecf20Sopenharmony_ci	msg.setLcr = 0xff;
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
26978c2ecf20Sopenharmony_ci	msg.xonFlowControl = 0;
26988c2ecf20Sopenharmony_ci	msg.setFlowControl = 0xff;
26998c2ecf20Sopenharmony_ci	msg.forwardingLength = 16;
27008c2ecf20Sopenharmony_ci	msg.xonChar = 17;
27018c2ecf20Sopenharmony_ci	msg.xoffChar = 19;
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	if (reset_port == 1) {
27048c2ecf20Sopenharmony_ci		/* Opening port */
27058c2ecf20Sopenharmony_ci		msg._txOn = 1;
27068c2ecf20Sopenharmony_ci		msg._txOff = 0;
27078c2ecf20Sopenharmony_ci		msg.txFlush = 0;
27088c2ecf20Sopenharmony_ci		msg.txBreak = 0;
27098c2ecf20Sopenharmony_ci		msg.rxOn = 1;
27108c2ecf20Sopenharmony_ci		msg.rxOff = 0;
27118c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
27128c2ecf20Sopenharmony_ci		msg.rxForward = 0;
27138c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
27148c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0xff;
27158c2ecf20Sopenharmony_ci	} else if (reset_port == 2) {
27168c2ecf20Sopenharmony_ci		/* Closing port */
27178c2ecf20Sopenharmony_ci		msg._txOn = 0;
27188c2ecf20Sopenharmony_ci		msg._txOff = 1;
27198c2ecf20Sopenharmony_ci		msg.txFlush = 0;
27208c2ecf20Sopenharmony_ci		msg.txBreak = 0;
27218c2ecf20Sopenharmony_ci		msg.rxOn = 0;
27228c2ecf20Sopenharmony_ci		msg.rxOff = 1;
27238c2ecf20Sopenharmony_ci		msg.rxFlush = 1;
27248c2ecf20Sopenharmony_ci		msg.rxForward = 0;
27258c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
27268c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0;
27278c2ecf20Sopenharmony_ci	} else {
27288c2ecf20Sopenharmony_ci		/* Sending intermediate configs */
27298c2ecf20Sopenharmony_ci		msg._txOn = (!p_priv->break_on);
27308c2ecf20Sopenharmony_ci		msg._txOff = 0;
27318c2ecf20Sopenharmony_ci		msg.txFlush = 0;
27328c2ecf20Sopenharmony_ci		msg.txBreak = (p_priv->break_on);
27338c2ecf20Sopenharmony_ci		msg.rxOn = 0;
27348c2ecf20Sopenharmony_ci		msg.rxOff = 0;
27358c2ecf20Sopenharmony_ci		msg.rxFlush = 0;
27368c2ecf20Sopenharmony_ci		msg.rxForward = 0;
27378c2ecf20Sopenharmony_ci		msg.returnStatus = 0;
27388c2ecf20Sopenharmony_ci		msg.resetDataToggle = 0x0;
27398c2ecf20Sopenharmony_ci	}
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_ci	/* Do handshaking outputs */
27428c2ecf20Sopenharmony_ci	msg.setTxTriState_setRts = 0xff;
27438c2ecf20Sopenharmony_ci	msg.txTriState_rts = p_priv->rts_state;
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	msg.setHskoa_setDtr = 0xff;
27468c2ecf20Sopenharmony_ci	msg.hskoa_dtr = p_priv->dtr_state;
27478c2ecf20Sopenharmony_ci
27488c2ecf20Sopenharmony_ci	p_priv->resend_cont = 0;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	/* send the data out the device on control endpoint */
27538c2ecf20Sopenharmony_ci	this_urb->transfer_buffer_length = sizeof(msg);
27548c2ecf20Sopenharmony_ci
27558c2ecf20Sopenharmony_ci	err = usb_submit_urb(this_urb, GFP_ATOMIC);
27568c2ecf20Sopenharmony_ci	if (err != 0)
27578c2ecf20Sopenharmony_ci		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
27588c2ecf20Sopenharmony_ci	return 0;
27598c2ecf20Sopenharmony_ci}
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_cistatic void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
27628c2ecf20Sopenharmony_ci{
27638c2ecf20Sopenharmony_ci	struct usb_serial *serial = port->serial;
27648c2ecf20Sopenharmony_ci	struct keyspan_serial_private *s_priv;
27658c2ecf20Sopenharmony_ci	const struct keyspan_device_details *d_details;
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
27688c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	switch (d_details->msg_format) {
27718c2ecf20Sopenharmony_ci	case msg_usa26:
27728c2ecf20Sopenharmony_ci		keyspan_usa26_send_setup(serial, port, reset_port);
27738c2ecf20Sopenharmony_ci		break;
27748c2ecf20Sopenharmony_ci	case msg_usa28:
27758c2ecf20Sopenharmony_ci		keyspan_usa28_send_setup(serial, port, reset_port);
27768c2ecf20Sopenharmony_ci		break;
27778c2ecf20Sopenharmony_ci	case msg_usa49:
27788c2ecf20Sopenharmony_ci		keyspan_usa49_send_setup(serial, port, reset_port);
27798c2ecf20Sopenharmony_ci		break;
27808c2ecf20Sopenharmony_ci	case msg_usa90:
27818c2ecf20Sopenharmony_ci		keyspan_usa90_send_setup(serial, port, reset_port);
27828c2ecf20Sopenharmony_ci		break;
27838c2ecf20Sopenharmony_ci	case msg_usa67:
27848c2ecf20Sopenharmony_ci		keyspan_usa67_send_setup(serial, port, reset_port);
27858c2ecf20Sopenharmony_ci		break;
27868c2ecf20Sopenharmony_ci	}
27878c2ecf20Sopenharmony_ci}
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci/* Gets called by the "real" driver (ie once firmware is loaded
27918c2ecf20Sopenharmony_ci   and renumeration has taken place. */
27928c2ecf20Sopenharmony_cistatic int keyspan_startup(struct usb_serial *serial)
27938c2ecf20Sopenharmony_ci{
27948c2ecf20Sopenharmony_ci	int				i, err;
27958c2ecf20Sopenharmony_ci	struct keyspan_serial_private 	*s_priv;
27968c2ecf20Sopenharmony_ci	const struct keyspan_device_details	*d_details;
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_ci	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
27998c2ecf20Sopenharmony_ci		if (d_details->product_id ==
28008c2ecf20Sopenharmony_ci				le16_to_cpu(serial->dev->descriptor.idProduct))
28018c2ecf20Sopenharmony_ci			break;
28028c2ecf20Sopenharmony_ci	if (d_details == NULL) {
28038c2ecf20Sopenharmony_ci		dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
28048c2ecf20Sopenharmony_ci		    __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
28058c2ecf20Sopenharmony_ci		return -ENODEV;
28068c2ecf20Sopenharmony_ci	}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci	/* Setup private data for serial driver */
28098c2ecf20Sopenharmony_ci	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
28108c2ecf20Sopenharmony_ci	if (!s_priv)
28118c2ecf20Sopenharmony_ci		return -ENOMEM;
28128c2ecf20Sopenharmony_ci
28138c2ecf20Sopenharmony_ci	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);
28148c2ecf20Sopenharmony_ci	if (!s_priv->instat_buf)
28158c2ecf20Sopenharmony_ci		goto err_instat_buf;
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL);
28188c2ecf20Sopenharmony_ci	if (!s_priv->indat_buf)
28198c2ecf20Sopenharmony_ci		goto err_indat_buf;
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL);
28228c2ecf20Sopenharmony_ci	if (!s_priv->glocont_buf)
28238c2ecf20Sopenharmony_ci		goto err_glocont_buf;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
28268c2ecf20Sopenharmony_ci	if (!s_priv->ctrl_buf)
28278c2ecf20Sopenharmony_ci		goto err_ctrl_buf;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	s_priv->device_details = d_details;
28308c2ecf20Sopenharmony_ci	usb_set_serial_data(serial, s_priv);
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	keyspan_setup_urbs(serial);
28338c2ecf20Sopenharmony_ci
28348c2ecf20Sopenharmony_ci	if (s_priv->instat_urb != NULL) {
28358c2ecf20Sopenharmony_ci		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
28368c2ecf20Sopenharmony_ci		if (err != 0)
28378c2ecf20Sopenharmony_ci			dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err);
28388c2ecf20Sopenharmony_ci	}
28398c2ecf20Sopenharmony_ci	if (s_priv->indat_urb != NULL) {
28408c2ecf20Sopenharmony_ci		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
28418c2ecf20Sopenharmony_ci		if (err != 0)
28428c2ecf20Sopenharmony_ci			dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err);
28438c2ecf20Sopenharmony_ci	}
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci	return 0;
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_cierr_ctrl_buf:
28488c2ecf20Sopenharmony_ci	kfree(s_priv->glocont_buf);
28498c2ecf20Sopenharmony_cierr_glocont_buf:
28508c2ecf20Sopenharmony_ci	kfree(s_priv->indat_buf);
28518c2ecf20Sopenharmony_cierr_indat_buf:
28528c2ecf20Sopenharmony_ci	kfree(s_priv->instat_buf);
28538c2ecf20Sopenharmony_cierr_instat_buf:
28548c2ecf20Sopenharmony_ci	kfree(s_priv);
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci	return -ENOMEM;
28578c2ecf20Sopenharmony_ci}
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_cistatic void keyspan_disconnect(struct usb_serial *serial)
28608c2ecf20Sopenharmony_ci{
28618c2ecf20Sopenharmony_ci	struct keyspan_serial_private *s_priv;
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	usb_kill_urb(s_priv->instat_urb);
28668c2ecf20Sopenharmony_ci	usb_kill_urb(s_priv->glocont_urb);
28678c2ecf20Sopenharmony_ci	usb_kill_urb(s_priv->indat_urb);
28688c2ecf20Sopenharmony_ci}
28698c2ecf20Sopenharmony_ci
28708c2ecf20Sopenharmony_cistatic void keyspan_release(struct usb_serial *serial)
28718c2ecf20Sopenharmony_ci{
28728c2ecf20Sopenharmony_ci	struct keyspan_serial_private *s_priv;
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_ci	/* Make sure to unlink the URBs submitted in attach. */
28778c2ecf20Sopenharmony_ci	usb_kill_urb(s_priv->instat_urb);
28788c2ecf20Sopenharmony_ci	usb_kill_urb(s_priv->indat_urb);
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	usb_free_urb(s_priv->instat_urb);
28818c2ecf20Sopenharmony_ci	usb_free_urb(s_priv->indat_urb);
28828c2ecf20Sopenharmony_ci	usb_free_urb(s_priv->glocont_urb);
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	kfree(s_priv->ctrl_buf);
28858c2ecf20Sopenharmony_ci	kfree(s_priv->glocont_buf);
28868c2ecf20Sopenharmony_ci	kfree(s_priv->indat_buf);
28878c2ecf20Sopenharmony_ci	kfree(s_priv->instat_buf);
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	kfree(s_priv);
28908c2ecf20Sopenharmony_ci}
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_cistatic int keyspan_port_probe(struct usb_serial_port *port)
28938c2ecf20Sopenharmony_ci{
28948c2ecf20Sopenharmony_ci	struct usb_serial *serial = port->serial;
28958c2ecf20Sopenharmony_ci	struct keyspan_serial_private *s_priv;
28968c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
28978c2ecf20Sopenharmony_ci	const struct keyspan_device_details *d_details;
28988c2ecf20Sopenharmony_ci	struct callbacks *cback;
28998c2ecf20Sopenharmony_ci	int endp;
29008c2ecf20Sopenharmony_ci	int port_num;
29018c2ecf20Sopenharmony_ci	int i;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	s_priv = usb_get_serial_data(serial);
29048c2ecf20Sopenharmony_ci	d_details = s_priv->device_details;
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci	p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL);
29078c2ecf20Sopenharmony_ci	if (!p_priv)
29088c2ecf20Sopenharmony_ci		return -ENOMEM;
29098c2ecf20Sopenharmony_ci
29108c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) {
29118c2ecf20Sopenharmony_ci		p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL);
29128c2ecf20Sopenharmony_ci		if (!p_priv->in_buffer[i])
29138c2ecf20Sopenharmony_ci			goto err_free_in_buffer;
29148c2ecf20Sopenharmony_ci	}
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) {
29178c2ecf20Sopenharmony_ci		p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL);
29188c2ecf20Sopenharmony_ci		if (!p_priv->out_buffer[i])
29198c2ecf20Sopenharmony_ci			goto err_free_out_buffer;
29208c2ecf20Sopenharmony_ci	}
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL);
29238c2ecf20Sopenharmony_ci	if (!p_priv->inack_buffer)
29248c2ecf20Sopenharmony_ci		goto err_free_out_buffer;
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci	p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL);
29278c2ecf20Sopenharmony_ci	if (!p_priv->outcont_buffer)
29288c2ecf20Sopenharmony_ci		goto err_free_inack_buffer;
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ci	p_priv->device_details = d_details;
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	/* Setup values for the various callback routines */
29338c2ecf20Sopenharmony_ci	cback = &keyspan_callbacks[d_details->msg_format];
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	port_num = port->port_number;
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	/* Do indat endpoints first, once for each flip */
29388c2ecf20Sopenharmony_ci	endp = d_details->indat_endpoints[port_num];
29398c2ecf20Sopenharmony_ci	for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) {
29408c2ecf20Sopenharmony_ci		p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp,
29418c2ecf20Sopenharmony_ci						USB_DIR_IN, port,
29428c2ecf20Sopenharmony_ci						p_priv->in_buffer[i],
29438c2ecf20Sopenharmony_ci						IN_BUFLEN,
29448c2ecf20Sopenharmony_ci						cback->indat_callback);
29458c2ecf20Sopenharmony_ci	}
29468c2ecf20Sopenharmony_ci	/* outdat endpoints also have flip */
29478c2ecf20Sopenharmony_ci	endp = d_details->outdat_endpoints[port_num];
29488c2ecf20Sopenharmony_ci	for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) {
29498c2ecf20Sopenharmony_ci		p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp,
29508c2ecf20Sopenharmony_ci						USB_DIR_OUT, port,
29518c2ecf20Sopenharmony_ci						p_priv->out_buffer[i],
29528c2ecf20Sopenharmony_ci						OUT_BUFLEN,
29538c2ecf20Sopenharmony_ci						cback->outdat_callback);
29548c2ecf20Sopenharmony_ci	}
29558c2ecf20Sopenharmony_ci	/* inack endpoint */
29568c2ecf20Sopenharmony_ci	p_priv->inack_urb = keyspan_setup_urb(serial,
29578c2ecf20Sopenharmony_ci					d_details->inack_endpoints[port_num],
29588c2ecf20Sopenharmony_ci					USB_DIR_IN, port,
29598c2ecf20Sopenharmony_ci					p_priv->inack_buffer,
29608c2ecf20Sopenharmony_ci					INACK_BUFLEN,
29618c2ecf20Sopenharmony_ci					cback->inack_callback);
29628c2ecf20Sopenharmony_ci	/* outcont endpoint */
29638c2ecf20Sopenharmony_ci	p_priv->outcont_urb = keyspan_setup_urb(serial,
29648c2ecf20Sopenharmony_ci					d_details->outcont_endpoints[port_num],
29658c2ecf20Sopenharmony_ci					USB_DIR_OUT, port,
29668c2ecf20Sopenharmony_ci					p_priv->outcont_buffer,
29678c2ecf20Sopenharmony_ci					OUTCONT_BUFLEN,
29688c2ecf20Sopenharmony_ci					 cback->outcont_callback);
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	usb_set_serial_port_data(port, p_priv);
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci	return 0;
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_cierr_free_inack_buffer:
29758c2ecf20Sopenharmony_ci	kfree(p_priv->inack_buffer);
29768c2ecf20Sopenharmony_cierr_free_out_buffer:
29778c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
29788c2ecf20Sopenharmony_ci		kfree(p_priv->out_buffer[i]);
29798c2ecf20Sopenharmony_cierr_free_in_buffer:
29808c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
29818c2ecf20Sopenharmony_ci		kfree(p_priv->in_buffer[i]);
29828c2ecf20Sopenharmony_ci	kfree(p_priv);
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	return -ENOMEM;
29858c2ecf20Sopenharmony_ci}
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_cistatic int keyspan_port_remove(struct usb_serial_port *port)
29888c2ecf20Sopenharmony_ci{
29898c2ecf20Sopenharmony_ci	struct keyspan_port_private *p_priv;
29908c2ecf20Sopenharmony_ci	int i;
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci	p_priv = usb_get_serial_port_data(port);
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	usb_kill_urb(p_priv->inack_urb);
29958c2ecf20Sopenharmony_ci	usb_kill_urb(p_priv->outcont_urb);
29968c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
29978c2ecf20Sopenharmony_ci		usb_kill_urb(p_priv->in_urbs[i]);
29988c2ecf20Sopenharmony_ci		usb_kill_urb(p_priv->out_urbs[i]);
29998c2ecf20Sopenharmony_ci	}
30008c2ecf20Sopenharmony_ci
30018c2ecf20Sopenharmony_ci	usb_free_urb(p_priv->inack_urb);
30028c2ecf20Sopenharmony_ci	usb_free_urb(p_priv->outcont_urb);
30038c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
30048c2ecf20Sopenharmony_ci		usb_free_urb(p_priv->in_urbs[i]);
30058c2ecf20Sopenharmony_ci		usb_free_urb(p_priv->out_urbs[i]);
30068c2ecf20Sopenharmony_ci	}
30078c2ecf20Sopenharmony_ci
30088c2ecf20Sopenharmony_ci	kfree(p_priv->outcont_buffer);
30098c2ecf20Sopenharmony_ci	kfree(p_priv->inack_buffer);
30108c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i)
30118c2ecf20Sopenharmony_ci		kfree(p_priv->out_buffer[i]);
30128c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i)
30138c2ecf20Sopenharmony_ci		kfree(p_priv->in_buffer[i]);
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	kfree(p_priv);
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_ci	return 0;
30188c2ecf20Sopenharmony_ci}
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci/* Structs for the devices, pre and post renumeration. */
30218c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_pre_device = {
30228c2ecf20Sopenharmony_ci	.driver = {
30238c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
30248c2ecf20Sopenharmony_ci		.name		= "keyspan_no_firm",
30258c2ecf20Sopenharmony_ci	},
30268c2ecf20Sopenharmony_ci	.description		= "Keyspan - (without firmware)",
30278c2ecf20Sopenharmony_ci	.id_table		= keyspan_pre_ids,
30288c2ecf20Sopenharmony_ci	.num_ports		= 1,
30298c2ecf20Sopenharmony_ci	.attach			= keyspan_fake_startup,
30308c2ecf20Sopenharmony_ci};
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_1port_device = {
30338c2ecf20Sopenharmony_ci	.driver = {
30348c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
30358c2ecf20Sopenharmony_ci		.name		= "keyspan_1",
30368c2ecf20Sopenharmony_ci	},
30378c2ecf20Sopenharmony_ci	.description		= "Keyspan 1 port adapter",
30388c2ecf20Sopenharmony_ci	.id_table		= keyspan_1port_ids,
30398c2ecf20Sopenharmony_ci	.num_ports		= 1,
30408c2ecf20Sopenharmony_ci	.open			= keyspan_open,
30418c2ecf20Sopenharmony_ci	.close			= keyspan_close,
30428c2ecf20Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
30438c2ecf20Sopenharmony_ci	.write			= keyspan_write,
30448c2ecf20Sopenharmony_ci	.write_room		= keyspan_write_room,
30458c2ecf20Sopenharmony_ci	.set_termios		= keyspan_set_termios,
30468c2ecf20Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
30478c2ecf20Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
30488c2ecf20Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
30498c2ecf20Sopenharmony_ci	.attach			= keyspan_startup,
30508c2ecf20Sopenharmony_ci	.disconnect		= keyspan_disconnect,
30518c2ecf20Sopenharmony_ci	.release		= keyspan_release,
30528c2ecf20Sopenharmony_ci	.port_probe		= keyspan_port_probe,
30538c2ecf20Sopenharmony_ci	.port_remove		= keyspan_port_remove,
30548c2ecf20Sopenharmony_ci};
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_2port_device = {
30578c2ecf20Sopenharmony_ci	.driver = {
30588c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
30598c2ecf20Sopenharmony_ci		.name		= "keyspan_2",
30608c2ecf20Sopenharmony_ci	},
30618c2ecf20Sopenharmony_ci	.description		= "Keyspan 2 port adapter",
30628c2ecf20Sopenharmony_ci	.id_table		= keyspan_2port_ids,
30638c2ecf20Sopenharmony_ci	.num_ports		= 2,
30648c2ecf20Sopenharmony_ci	.open			= keyspan_open,
30658c2ecf20Sopenharmony_ci	.close			= keyspan_close,
30668c2ecf20Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
30678c2ecf20Sopenharmony_ci	.write			= keyspan_write,
30688c2ecf20Sopenharmony_ci	.write_room		= keyspan_write_room,
30698c2ecf20Sopenharmony_ci	.set_termios		= keyspan_set_termios,
30708c2ecf20Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
30718c2ecf20Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
30728c2ecf20Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
30738c2ecf20Sopenharmony_ci	.attach			= keyspan_startup,
30748c2ecf20Sopenharmony_ci	.disconnect		= keyspan_disconnect,
30758c2ecf20Sopenharmony_ci	.release		= keyspan_release,
30768c2ecf20Sopenharmony_ci	.port_probe		= keyspan_port_probe,
30778c2ecf20Sopenharmony_ci	.port_remove		= keyspan_port_remove,
30788c2ecf20Sopenharmony_ci};
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_4port_device = {
30818c2ecf20Sopenharmony_ci	.driver = {
30828c2ecf20Sopenharmony_ci		.owner		= THIS_MODULE,
30838c2ecf20Sopenharmony_ci		.name		= "keyspan_4",
30848c2ecf20Sopenharmony_ci	},
30858c2ecf20Sopenharmony_ci	.description		= "Keyspan 4 port adapter",
30868c2ecf20Sopenharmony_ci	.id_table		= keyspan_4port_ids,
30878c2ecf20Sopenharmony_ci	.num_ports		= 4,
30888c2ecf20Sopenharmony_ci	.open			= keyspan_open,
30898c2ecf20Sopenharmony_ci	.close			= keyspan_close,
30908c2ecf20Sopenharmony_ci	.dtr_rts		= keyspan_dtr_rts,
30918c2ecf20Sopenharmony_ci	.write			= keyspan_write,
30928c2ecf20Sopenharmony_ci	.write_room		= keyspan_write_room,
30938c2ecf20Sopenharmony_ci	.set_termios		= keyspan_set_termios,
30948c2ecf20Sopenharmony_ci	.break_ctl		= keyspan_break_ctl,
30958c2ecf20Sopenharmony_ci	.tiocmget		= keyspan_tiocmget,
30968c2ecf20Sopenharmony_ci	.tiocmset		= keyspan_tiocmset,
30978c2ecf20Sopenharmony_ci	.attach			= keyspan_startup,
30988c2ecf20Sopenharmony_ci	.disconnect		= keyspan_disconnect,
30998c2ecf20Sopenharmony_ci	.release		= keyspan_release,
31008c2ecf20Sopenharmony_ci	.port_probe		= keyspan_port_probe,
31018c2ecf20Sopenharmony_ci	.port_remove		= keyspan_port_remove,
31028c2ecf20Sopenharmony_ci};
31038c2ecf20Sopenharmony_ci
31048c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = {
31058c2ecf20Sopenharmony_ci	&keyspan_pre_device, &keyspan_1port_device,
31068c2ecf20Sopenharmony_ci	&keyspan_2port_device, &keyspan_4port_device, NULL
31078c2ecf20Sopenharmony_ci};
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, keyspan_ids_combined);
31108c2ecf20Sopenharmony_ci
31118c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR);
31128c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
31138c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28.fw");
31168c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28x.fw");
31178c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28xa.fw");
31188c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa28xb.fw");
31198c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19.fw");
31208c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19qi.fw");
31218c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/mpr.fw");
31228c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19qw.fw");
31238c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa18x.fw");
31248c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa19w.fw");
31258c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa49w.fw");
31268c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan/usa49wlc.fw");
3127