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