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