15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds Keyspan USB to Serial Converter driver 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds (C) Copyright (C) 2000-2001 Hugh Blemings <hugh@blemings.org> 61da177e4SLinus Torvalds (C) Copyright (C) 2002 Greg Kroah-Hartman <greg@kroah.com> 71da177e4SLinus Torvalds 8631dd1a8SJustin P. Mattock See http://blemings.org/hugh/keyspan.html for more information. 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds Code in this driver inspired by and in a number of places taken 111da177e4SLinus Torvalds from Brian Warner's original Keyspan-PDA driver. 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds This driver has been put together with the support of Innosys, Inc. 141da177e4SLinus Torvalds and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. 151da177e4SLinus Torvalds Thanks Guys :) 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds Thanks to Paulus for miscellaneous tidy ups, some largish chunks 181da177e4SLinus Torvalds of much nicer and/or completely new code and (perhaps most uniquely) 191da177e4SLinus Torvalds having the patience to sit down and explain why and where he'd changed 201da177e4SLinus Torvalds stuff. 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds Tip 'o the hat to IBM (and previously Linuxcare :) for supporting 231da177e4SLinus Torvalds staff in their work on open source projects. 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <linux/kernel.h> 281da177e4SLinus Torvalds #include <linux/jiffies.h> 291da177e4SLinus Torvalds #include <linux/errno.h> 301da177e4SLinus Torvalds #include <linux/slab.h> 311da177e4SLinus Torvalds #include <linux/tty.h> 321da177e4SLinus Torvalds #include <linux/tty_driver.h> 331da177e4SLinus Torvalds #include <linux/tty_flip.h> 341da177e4SLinus Torvalds #include <linux/module.h> 351da177e4SLinus Torvalds #include <linux/spinlock.h> 36deb91685SAlan Cox #include <linux/uaccess.h> 371da177e4SLinus Torvalds #include <linux/usb.h> 38a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h> 39cc183e2aSRene Buergel #include <linux/usb/ezusb.h> 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" 421da177e4SLinus Torvalds #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" 431da177e4SLinus Torvalds 44beabdc3cSJohan Hovold static void keyspan_send_setup(struct usb_serial_port *port, int reset_port); 45beabdc3cSJohan Hovold 46beabdc3cSJohan Hovold static int keyspan_usa19_calc_baud(struct usb_serial_port *port, 47beabdc3cSJohan Hovold u32 baud_rate, u32 baudclk, 48beabdc3cSJohan Hovold u8 *rate_hi, u8 *rate_low, 49beabdc3cSJohan Hovold u8 *prescaler, int portnum); 50beabdc3cSJohan Hovold static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, 51beabdc3cSJohan Hovold u32 baud_rate, u32 baudclk, 52beabdc3cSJohan Hovold u8 *rate_hi, u8 *rate_low, 53beabdc3cSJohan Hovold u8 *prescaler, int portnum); 54beabdc3cSJohan Hovold static int keyspan_usa28_calc_baud(struct usb_serial_port *port, 55beabdc3cSJohan Hovold u32 baud_rate, u32 baudclk, 56beabdc3cSJohan Hovold u8 *rate_hi, u8 *rate_low, 57beabdc3cSJohan Hovold u8 *prescaler, int portnum); 58beabdc3cSJohan Hovold static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, 59beabdc3cSJohan Hovold u32 baud_rate, u32 baudclk, 60beabdc3cSJohan Hovold u8 *rate_hi, u8 *rate_low, 61beabdc3cSJohan Hovold u8 *prescaler, int portnum); 62beabdc3cSJohan Hovold 63beabdc3cSJohan Hovold static int keyspan_usa28_send_setup(struct usb_serial *serial, 64beabdc3cSJohan Hovold struct usb_serial_port *port, 65beabdc3cSJohan Hovold int reset_port); 66beabdc3cSJohan Hovold static int keyspan_usa26_send_setup(struct usb_serial *serial, 67beabdc3cSJohan Hovold struct usb_serial_port *port, 68beabdc3cSJohan Hovold int reset_port); 69beabdc3cSJohan Hovold static int keyspan_usa49_send_setup(struct usb_serial *serial, 70beabdc3cSJohan Hovold struct usb_serial_port *port, 71beabdc3cSJohan Hovold int reset_port); 72beabdc3cSJohan Hovold static int keyspan_usa90_send_setup(struct usb_serial *serial, 73beabdc3cSJohan Hovold struct usb_serial_port *port, 74beabdc3cSJohan Hovold int reset_port); 75beabdc3cSJohan Hovold static int keyspan_usa67_send_setup(struct usb_serial *serial, 76beabdc3cSJohan Hovold struct usb_serial_port *port, 77beabdc3cSJohan Hovold int reset_port); 78beabdc3cSJohan Hovold 79beabdc3cSJohan Hovold /* Values used for baud rate calculation - device specific */ 80beabdc3cSJohan Hovold #define KEYSPAN_INVALID_BAUD_RATE (-1) 81beabdc3cSJohan Hovold #define KEYSPAN_BAUD_RATE_OK (0) 82beabdc3cSJohan Hovold #define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ 83beabdc3cSJohan Hovold #define KEYSPAN_USA19_BAUDCLK (12000000L) 84beabdc3cSJohan Hovold #define KEYSPAN_USA19W_BAUDCLK (24000000L) 85beabdc3cSJohan Hovold #define KEYSPAN_USA19HS_BAUDCLK (14769231L) 86beabdc3cSJohan Hovold #define KEYSPAN_USA28_BAUDCLK (1843200L) 87beabdc3cSJohan Hovold #define KEYSPAN_USA28X_BAUDCLK (12000000L) 88beabdc3cSJohan Hovold #define KEYSPAN_USA49W_BAUDCLK (48000000L) 89beabdc3cSJohan Hovold 90beabdc3cSJohan Hovold /* Some constants used to characterise each device. */ 91beabdc3cSJohan Hovold #define KEYSPAN_MAX_NUM_PORTS (4) 92beabdc3cSJohan Hovold #define KEYSPAN_MAX_FLIPS (2) 93beabdc3cSJohan Hovold 94beabdc3cSJohan Hovold /* 95beabdc3cSJohan Hovold * Device info for the Keyspan serial converter, used by the overall 96beabdc3cSJohan Hovold * usb-serial probe function. 97beabdc3cSJohan Hovold */ 98beabdc3cSJohan Hovold #define KEYSPAN_VENDOR_ID (0x06cd) 99beabdc3cSJohan Hovold 100beabdc3cSJohan Hovold /* Product IDs for the products supported, pre-renumeration */ 101beabdc3cSJohan Hovold #define keyspan_usa18x_pre_product_id 0x0105 102beabdc3cSJohan Hovold #define keyspan_usa19_pre_product_id 0x0103 103beabdc3cSJohan Hovold #define keyspan_usa19qi_pre_product_id 0x010b 104beabdc3cSJohan Hovold #define keyspan_mpr_pre_product_id 0x011b 105beabdc3cSJohan Hovold #define keyspan_usa19qw_pre_product_id 0x0118 106beabdc3cSJohan Hovold #define keyspan_usa19w_pre_product_id 0x0106 107beabdc3cSJohan Hovold #define keyspan_usa28_pre_product_id 0x0101 108beabdc3cSJohan Hovold #define keyspan_usa28x_pre_product_id 0x0102 109beabdc3cSJohan Hovold #define keyspan_usa28xa_pre_product_id 0x0114 110beabdc3cSJohan Hovold #define keyspan_usa28xb_pre_product_id 0x0113 111beabdc3cSJohan Hovold #define keyspan_usa49w_pre_product_id 0x0109 112beabdc3cSJohan Hovold #define keyspan_usa49wlc_pre_product_id 0x011a 113beabdc3cSJohan Hovold 114beabdc3cSJohan Hovold /* 115beabdc3cSJohan Hovold * Product IDs post-renumeration. Note that the 28x and 28xb have the same 116beabdc3cSJohan Hovold * id's post-renumeration but behave identically so it's not an issue. As 117beabdc3cSJohan Hovold * such, the 28xb is not listed in any of the device tables. 118beabdc3cSJohan Hovold */ 119beabdc3cSJohan Hovold #define keyspan_usa18x_product_id 0x0112 120beabdc3cSJohan Hovold #define keyspan_usa19_product_id 0x0107 121beabdc3cSJohan Hovold #define keyspan_usa19qi_product_id 0x010c 122beabdc3cSJohan Hovold #define keyspan_usa19hs_product_id 0x0121 123beabdc3cSJohan Hovold #define keyspan_mpr_product_id 0x011c 124beabdc3cSJohan Hovold #define keyspan_usa19qw_product_id 0x0119 125beabdc3cSJohan Hovold #define keyspan_usa19w_product_id 0x0108 126beabdc3cSJohan Hovold #define keyspan_usa28_product_id 0x010f 127beabdc3cSJohan Hovold #define keyspan_usa28x_product_id 0x0110 128beabdc3cSJohan Hovold #define keyspan_usa28xa_product_id 0x0115 129beabdc3cSJohan Hovold #define keyspan_usa28xb_product_id 0x0110 130beabdc3cSJohan Hovold #define keyspan_usa28xg_product_id 0x0135 131beabdc3cSJohan Hovold #define keyspan_usa49w_product_id 0x010a 132beabdc3cSJohan Hovold #define keyspan_usa49wlc_product_id 0x012a 133beabdc3cSJohan Hovold #define keyspan_usa49wg_product_id 0x0131 134beabdc3cSJohan Hovold 135beabdc3cSJohan Hovold struct keyspan_device_details { 136beabdc3cSJohan Hovold /* product ID value */ 137beabdc3cSJohan Hovold int product_id; 138beabdc3cSJohan Hovold 139beabdc3cSJohan Hovold enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; 140beabdc3cSJohan Hovold 141beabdc3cSJohan Hovold /* Number of physical ports */ 142beabdc3cSJohan Hovold int num_ports; 143beabdc3cSJohan Hovold 144beabdc3cSJohan Hovold /* 1 if endpoint flipping used on input, 0 if not */ 145beabdc3cSJohan Hovold int indat_endp_flip; 146beabdc3cSJohan Hovold 147beabdc3cSJohan Hovold /* 1 if endpoint flipping used on output, 0 if not */ 148beabdc3cSJohan Hovold int outdat_endp_flip; 149beabdc3cSJohan Hovold 150beabdc3cSJohan Hovold /* 151beabdc3cSJohan Hovold * Table mapping input data endpoint IDs to physical port 152beabdc3cSJohan Hovold * number and flip if used 153beabdc3cSJohan Hovold */ 154beabdc3cSJohan Hovold int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; 155beabdc3cSJohan Hovold 156beabdc3cSJohan Hovold /* Same for output endpoints */ 157beabdc3cSJohan Hovold int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; 158beabdc3cSJohan Hovold 159beabdc3cSJohan Hovold /* Input acknowledge endpoints */ 160beabdc3cSJohan Hovold int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; 161beabdc3cSJohan Hovold 162beabdc3cSJohan Hovold /* Output control endpoints */ 163beabdc3cSJohan Hovold int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; 164beabdc3cSJohan Hovold 165beabdc3cSJohan Hovold /* Endpoint used for input status */ 166beabdc3cSJohan Hovold int instat_endpoint; 167beabdc3cSJohan Hovold 168beabdc3cSJohan Hovold /* Endpoint used for input data 49WG only */ 169beabdc3cSJohan Hovold int indat_endpoint; 170beabdc3cSJohan Hovold 171beabdc3cSJohan Hovold /* Endpoint used for global control functions */ 172beabdc3cSJohan Hovold int glocont_endpoint; 173beabdc3cSJohan Hovold 174beabdc3cSJohan Hovold int (*calculate_baud_rate)(struct usb_serial_port *port, 175beabdc3cSJohan Hovold u32 baud_rate, u32 baudclk, 176beabdc3cSJohan Hovold u8 *rate_hi, u8 *rate_low, u8 *prescaler, 177beabdc3cSJohan Hovold int portnum); 178beabdc3cSJohan Hovold u32 baudclk; 179beabdc3cSJohan Hovold }; 180beabdc3cSJohan Hovold 181beabdc3cSJohan Hovold /* 182beabdc3cSJohan Hovold * Now for each device type we setup the device detail structure with the 183beabdc3cSJohan Hovold * appropriate information (provided in Keyspan's documentation) 184beabdc3cSJohan Hovold */ 185beabdc3cSJohan Hovold 186beabdc3cSJohan Hovold static const struct keyspan_device_details usa18x_device_details = { 187beabdc3cSJohan Hovold .product_id = keyspan_usa18x_product_id, 188beabdc3cSJohan Hovold .msg_format = msg_usa26, 189beabdc3cSJohan Hovold .num_ports = 1, 190beabdc3cSJohan Hovold .indat_endp_flip = 0, 191beabdc3cSJohan Hovold .outdat_endp_flip = 1, 192beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 193beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 194beabdc3cSJohan Hovold .inack_endpoints = {0x85}, 195beabdc3cSJohan Hovold .outcont_endpoints = {0x05}, 196beabdc3cSJohan Hovold .instat_endpoint = 0x87, 197beabdc3cSJohan Hovold .indat_endpoint = -1, 198beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 199beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 200beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA18X_BAUDCLK, 201beabdc3cSJohan Hovold }; 202beabdc3cSJohan Hovold 203beabdc3cSJohan Hovold static const struct keyspan_device_details usa19_device_details = { 204beabdc3cSJohan Hovold .product_id = keyspan_usa19_product_id, 205beabdc3cSJohan Hovold .msg_format = msg_usa28, 206beabdc3cSJohan Hovold .num_ports = 1, 207beabdc3cSJohan Hovold .indat_endp_flip = 1, 208beabdc3cSJohan Hovold .outdat_endp_flip = 1, 209beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 210beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 211beabdc3cSJohan Hovold .inack_endpoints = {0x83}, 212beabdc3cSJohan Hovold .outcont_endpoints = {0x03}, 213beabdc3cSJohan Hovold .instat_endpoint = 0x84, 214beabdc3cSJohan Hovold .indat_endpoint = -1, 215beabdc3cSJohan Hovold .glocont_endpoint = -1, 216beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19_calc_baud, 217beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19_BAUDCLK, 218beabdc3cSJohan Hovold }; 219beabdc3cSJohan Hovold 220beabdc3cSJohan Hovold static const struct keyspan_device_details usa19qi_device_details = { 221beabdc3cSJohan Hovold .product_id = keyspan_usa19qi_product_id, 222beabdc3cSJohan Hovold .msg_format = msg_usa28, 223beabdc3cSJohan Hovold .num_ports = 1, 224beabdc3cSJohan Hovold .indat_endp_flip = 1, 225beabdc3cSJohan Hovold .outdat_endp_flip = 1, 226beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 227beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 228beabdc3cSJohan Hovold .inack_endpoints = {0x83}, 229beabdc3cSJohan Hovold .outcont_endpoints = {0x03}, 230beabdc3cSJohan Hovold .instat_endpoint = 0x84, 231beabdc3cSJohan Hovold .indat_endpoint = -1, 232beabdc3cSJohan Hovold .glocont_endpoint = -1, 233beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa28_calc_baud, 234beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19_BAUDCLK, 235beabdc3cSJohan Hovold }; 236beabdc3cSJohan Hovold 237beabdc3cSJohan Hovold static const struct keyspan_device_details mpr_device_details = { 238beabdc3cSJohan Hovold .product_id = keyspan_mpr_product_id, 239beabdc3cSJohan Hovold .msg_format = msg_usa28, 240beabdc3cSJohan Hovold .num_ports = 1, 241beabdc3cSJohan Hovold .indat_endp_flip = 1, 242beabdc3cSJohan Hovold .outdat_endp_flip = 1, 243beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 244beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 245beabdc3cSJohan Hovold .inack_endpoints = {0x83}, 246beabdc3cSJohan Hovold .outcont_endpoints = {0x03}, 247beabdc3cSJohan Hovold .instat_endpoint = 0x84, 248beabdc3cSJohan Hovold .indat_endpoint = -1, 249beabdc3cSJohan Hovold .glocont_endpoint = -1, 250beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa28_calc_baud, 251beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19_BAUDCLK, 252beabdc3cSJohan Hovold }; 253beabdc3cSJohan Hovold 254beabdc3cSJohan Hovold static const struct keyspan_device_details usa19qw_device_details = { 255beabdc3cSJohan Hovold .product_id = keyspan_usa19qw_product_id, 256beabdc3cSJohan Hovold .msg_format = msg_usa26, 257beabdc3cSJohan Hovold .num_ports = 1, 258beabdc3cSJohan Hovold .indat_endp_flip = 0, 259beabdc3cSJohan Hovold .outdat_endp_flip = 1, 260beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 261beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 262beabdc3cSJohan Hovold .inack_endpoints = {0x85}, 263beabdc3cSJohan Hovold .outcont_endpoints = {0x05}, 264beabdc3cSJohan Hovold .instat_endpoint = 0x87, 265beabdc3cSJohan Hovold .indat_endpoint = -1, 266beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 267beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 268beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19W_BAUDCLK, 269beabdc3cSJohan Hovold }; 270beabdc3cSJohan Hovold 271beabdc3cSJohan Hovold static const struct keyspan_device_details usa19w_device_details = { 272beabdc3cSJohan Hovold .product_id = keyspan_usa19w_product_id, 273beabdc3cSJohan Hovold .msg_format = msg_usa26, 274beabdc3cSJohan Hovold .num_ports = 1, 275beabdc3cSJohan Hovold .indat_endp_flip = 0, 276beabdc3cSJohan Hovold .outdat_endp_flip = 1, 277beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 278beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 279beabdc3cSJohan Hovold .inack_endpoints = {0x85}, 280beabdc3cSJohan Hovold .outcont_endpoints = {0x05}, 281beabdc3cSJohan Hovold .instat_endpoint = 0x87, 282beabdc3cSJohan Hovold .indat_endpoint = -1, 283beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 284beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 285beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19W_BAUDCLK, 286beabdc3cSJohan Hovold }; 287beabdc3cSJohan Hovold 288beabdc3cSJohan Hovold static const struct keyspan_device_details usa19hs_device_details = { 289beabdc3cSJohan Hovold .product_id = keyspan_usa19hs_product_id, 290beabdc3cSJohan Hovold .msg_format = msg_usa90, 291beabdc3cSJohan Hovold .num_ports = 1, 292beabdc3cSJohan Hovold .indat_endp_flip = 0, 293beabdc3cSJohan Hovold .outdat_endp_flip = 0, 294beabdc3cSJohan Hovold .indat_endpoints = {0x81}, 295beabdc3cSJohan Hovold .outdat_endpoints = {0x01}, 296beabdc3cSJohan Hovold .inack_endpoints = {-1}, 297beabdc3cSJohan Hovold .outcont_endpoints = {0x02}, 298beabdc3cSJohan Hovold .instat_endpoint = 0x82, 299beabdc3cSJohan Hovold .indat_endpoint = -1, 300beabdc3cSJohan Hovold .glocont_endpoint = -1, 301beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19hs_calc_baud, 302beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19HS_BAUDCLK, 303beabdc3cSJohan Hovold }; 304beabdc3cSJohan Hovold 305beabdc3cSJohan Hovold static const struct keyspan_device_details usa28_device_details = { 306beabdc3cSJohan Hovold .product_id = keyspan_usa28_product_id, 307beabdc3cSJohan Hovold .msg_format = msg_usa28, 308beabdc3cSJohan Hovold .num_ports = 2, 309beabdc3cSJohan Hovold .indat_endp_flip = 1, 310beabdc3cSJohan Hovold .outdat_endp_flip = 1, 311beabdc3cSJohan Hovold .indat_endpoints = {0x81, 0x83}, 312beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x03}, 313beabdc3cSJohan Hovold .inack_endpoints = {0x85, 0x86}, 314beabdc3cSJohan Hovold .outcont_endpoints = {0x05, 0x06}, 315beabdc3cSJohan Hovold .instat_endpoint = 0x87, 316beabdc3cSJohan Hovold .indat_endpoint = -1, 317beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 318beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa28_calc_baud, 319beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA28_BAUDCLK, 320beabdc3cSJohan Hovold }; 321beabdc3cSJohan Hovold 322beabdc3cSJohan Hovold static const struct keyspan_device_details usa28x_device_details = { 323beabdc3cSJohan Hovold .product_id = keyspan_usa28x_product_id, 324beabdc3cSJohan Hovold .msg_format = msg_usa26, 325beabdc3cSJohan Hovold .num_ports = 2, 326beabdc3cSJohan Hovold .indat_endp_flip = 0, 327beabdc3cSJohan Hovold .outdat_endp_flip = 1, 328beabdc3cSJohan Hovold .indat_endpoints = {0x81, 0x83}, 329beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x03}, 330beabdc3cSJohan Hovold .inack_endpoints = {0x85, 0x86}, 331beabdc3cSJohan Hovold .outcont_endpoints = {0x05, 0x06}, 332beabdc3cSJohan Hovold .instat_endpoint = 0x87, 333beabdc3cSJohan Hovold .indat_endpoint = -1, 334beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 335beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 336beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA28X_BAUDCLK, 337beabdc3cSJohan Hovold }; 338beabdc3cSJohan Hovold 339beabdc3cSJohan Hovold static const struct keyspan_device_details usa28xa_device_details = { 340beabdc3cSJohan Hovold .product_id = keyspan_usa28xa_product_id, 341beabdc3cSJohan Hovold .msg_format = msg_usa26, 342beabdc3cSJohan Hovold .num_ports = 2, 343beabdc3cSJohan Hovold .indat_endp_flip = 0, 344beabdc3cSJohan Hovold .outdat_endp_flip = 1, 345beabdc3cSJohan Hovold .indat_endpoints = {0x81, 0x83}, 346beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x03}, 347beabdc3cSJohan Hovold .inack_endpoints = {0x85, 0x86}, 348beabdc3cSJohan Hovold .outcont_endpoints = {0x05, 0x06}, 349beabdc3cSJohan Hovold .instat_endpoint = 0x87, 350beabdc3cSJohan Hovold .indat_endpoint = -1, 351beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 352beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 353beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA28X_BAUDCLK, 354beabdc3cSJohan Hovold }; 355beabdc3cSJohan Hovold 356beabdc3cSJohan Hovold static const struct keyspan_device_details usa28xg_device_details = { 357beabdc3cSJohan Hovold .product_id = keyspan_usa28xg_product_id, 358beabdc3cSJohan Hovold .msg_format = msg_usa67, 359beabdc3cSJohan Hovold .num_ports = 2, 360beabdc3cSJohan Hovold .indat_endp_flip = 0, 361beabdc3cSJohan Hovold .outdat_endp_flip = 0, 362beabdc3cSJohan Hovold .indat_endpoints = {0x84, 0x88}, 363beabdc3cSJohan Hovold .outdat_endpoints = {0x02, 0x06}, 364beabdc3cSJohan Hovold .inack_endpoints = {-1, -1}, 365beabdc3cSJohan Hovold .outcont_endpoints = {-1, -1}, 366beabdc3cSJohan Hovold .instat_endpoint = 0x81, 367beabdc3cSJohan Hovold .indat_endpoint = -1, 368beabdc3cSJohan Hovold .glocont_endpoint = 0x01, 369beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 370beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA28X_BAUDCLK, 371beabdc3cSJohan Hovold }; 372beabdc3cSJohan Hovold /* 373beabdc3cSJohan Hovold * We don't need a separate entry for the usa28xb as it appears as a 28x 374beabdc3cSJohan Hovold * anyway. 375beabdc3cSJohan Hovold */ 376beabdc3cSJohan Hovold 377beabdc3cSJohan Hovold static const struct keyspan_device_details usa49w_device_details = { 378beabdc3cSJohan Hovold .product_id = keyspan_usa49w_product_id, 379beabdc3cSJohan Hovold .msg_format = msg_usa49, 380beabdc3cSJohan Hovold .num_ports = 4, 381beabdc3cSJohan Hovold .indat_endp_flip = 0, 382beabdc3cSJohan Hovold .outdat_endp_flip = 0, 383beabdc3cSJohan Hovold .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, 384beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, 385beabdc3cSJohan Hovold .inack_endpoints = {-1, -1, -1, -1}, 386beabdc3cSJohan Hovold .outcont_endpoints = {-1, -1, -1, -1}, 387beabdc3cSJohan Hovold .instat_endpoint = 0x87, 388beabdc3cSJohan Hovold .indat_endpoint = -1, 389beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 390beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 391beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA49W_BAUDCLK, 392beabdc3cSJohan Hovold }; 393beabdc3cSJohan Hovold 394beabdc3cSJohan Hovold static const struct keyspan_device_details usa49wlc_device_details = { 395beabdc3cSJohan Hovold .product_id = keyspan_usa49wlc_product_id, 396beabdc3cSJohan Hovold .msg_format = msg_usa49, 397beabdc3cSJohan Hovold .num_ports = 4, 398beabdc3cSJohan Hovold .indat_endp_flip = 0, 399beabdc3cSJohan Hovold .outdat_endp_flip = 0, 400beabdc3cSJohan Hovold .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, 401beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, 402beabdc3cSJohan Hovold .inack_endpoints = {-1, -1, -1, -1}, 403beabdc3cSJohan Hovold .outcont_endpoints = {-1, -1, -1, -1}, 404beabdc3cSJohan Hovold .instat_endpoint = 0x87, 405beabdc3cSJohan Hovold .indat_endpoint = -1, 406beabdc3cSJohan Hovold .glocont_endpoint = 0x07, 407beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 408beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19W_BAUDCLK, 409beabdc3cSJohan Hovold }; 410beabdc3cSJohan Hovold 411beabdc3cSJohan Hovold static const struct keyspan_device_details usa49wg_device_details = { 412beabdc3cSJohan Hovold .product_id = keyspan_usa49wg_product_id, 413beabdc3cSJohan Hovold .msg_format = msg_usa49, 414beabdc3cSJohan Hovold .num_ports = 4, 415beabdc3cSJohan Hovold .indat_endp_flip = 0, 416beabdc3cSJohan Hovold .outdat_endp_flip = 0, 417beabdc3cSJohan Hovold .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ 418beabdc3cSJohan Hovold .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, 419beabdc3cSJohan Hovold .inack_endpoints = {-1, -1, -1, -1}, 420beabdc3cSJohan Hovold .outcont_endpoints = {-1, -1, -1, -1}, 421beabdc3cSJohan Hovold .instat_endpoint = 0x81, 422beabdc3cSJohan Hovold .indat_endpoint = 0x88, 423beabdc3cSJohan Hovold .glocont_endpoint = 0x00, /* uses control EP */ 424beabdc3cSJohan Hovold .calculate_baud_rate = keyspan_usa19w_calc_baud, 425beabdc3cSJohan Hovold .baudclk = KEYSPAN_USA19W_BAUDCLK, 426beabdc3cSJohan Hovold }; 427beabdc3cSJohan Hovold 428beabdc3cSJohan Hovold static const struct keyspan_device_details *keyspan_devices[] = { 429beabdc3cSJohan Hovold &usa18x_device_details, 430beabdc3cSJohan Hovold &usa19_device_details, 431beabdc3cSJohan Hovold &usa19qi_device_details, 432beabdc3cSJohan Hovold &mpr_device_details, 433beabdc3cSJohan Hovold &usa19qw_device_details, 434beabdc3cSJohan Hovold &usa19w_device_details, 435beabdc3cSJohan Hovold &usa19hs_device_details, 436beabdc3cSJohan Hovold &usa28_device_details, 437beabdc3cSJohan Hovold &usa28x_device_details, 438beabdc3cSJohan Hovold &usa28xa_device_details, 439beabdc3cSJohan Hovold &usa28xg_device_details, 440beabdc3cSJohan Hovold /* 28xb not required as it renumerates as a 28x */ 441beabdc3cSJohan Hovold &usa49w_device_details, 442beabdc3cSJohan Hovold &usa49wlc_device_details, 443beabdc3cSJohan Hovold &usa49wg_device_details, 444beabdc3cSJohan Hovold NULL, 445beabdc3cSJohan Hovold }; 446beabdc3cSJohan Hovold 447beabdc3cSJohan Hovold static const struct usb_device_id keyspan_ids_combined[] = { 448beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, 449beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, 450beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, 451beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, 452beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, 453beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, 454beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, 455beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, 456beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, 457beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, 458beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, 459beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, 460beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, 461beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, 462beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, 463beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, 464beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, 465beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, 466beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, 467beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, 468beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, 469beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, 470beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, 471beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, 472beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, 473beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, 474beabdc3cSJohan Hovold { } /* Terminating entry */ 475beabdc3cSJohan Hovold }; 476beabdc3cSJohan Hovold 477beabdc3cSJohan Hovold MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); 478beabdc3cSJohan Hovold 479beabdc3cSJohan Hovold /* usb_device_id table for the pre-firmware download keyspan devices */ 480beabdc3cSJohan Hovold static const struct usb_device_id keyspan_pre_ids[] = { 481beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, 482beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, 483beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, 484beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, 485beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, 486beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, 487beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, 488beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, 489beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, 490beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, 491beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, 492beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, 493beabdc3cSJohan Hovold { } /* Terminating entry */ 494beabdc3cSJohan Hovold }; 495beabdc3cSJohan Hovold 496beabdc3cSJohan Hovold static const struct usb_device_id keyspan_1port_ids[] = { 497beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, 498beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, 499beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, 500beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, 501beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, 502beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, 503beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, 504beabdc3cSJohan Hovold { } /* Terminating entry */ 505beabdc3cSJohan Hovold }; 506beabdc3cSJohan Hovold 507beabdc3cSJohan Hovold static const struct usb_device_id keyspan_2port_ids[] = { 508beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, 509beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, 510beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, 511beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, 512beabdc3cSJohan Hovold { } /* Terminating entry */ 513beabdc3cSJohan Hovold }; 514beabdc3cSJohan Hovold 515beabdc3cSJohan Hovold static const struct usb_device_id keyspan_4port_ids[] = { 516beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, 517beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, 518beabdc3cSJohan Hovold { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, 519beabdc3cSJohan Hovold { } /* Terminating entry */ 520beabdc3cSJohan Hovold }; 521beabdc3cSJohan Hovold 5221da177e4SLinus Torvalds #define INSTAT_BUFLEN 32 5231da177e4SLinus Torvalds #define GLOCONT_BUFLEN 64 5240ca1268eSLucy McCoy #define INDAT49W_BUFLEN 512 525bad41a5bSJohan Hovold #define IN_BUFLEN 64 526bad41a5bSJohan Hovold #define OUT_BUFLEN 64 527bad41a5bSJohan Hovold #define INACK_BUFLEN 1 528bad41a5bSJohan Hovold #define OUTCONT_BUFLEN 64 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds /* Per device and per port private data */ 5311da177e4SLinus Torvalds struct keyspan_serial_private { 5321da177e4SLinus Torvalds const struct keyspan_device_details *device_details; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds struct urb *instat_urb; 5352fcd1c9bSJohan Hovold char *instat_buf; 5361da177e4SLinus Torvalds 537deb91685SAlan Cox /* added to support 49wg, where data from all 4 ports comes in 538deb91685SAlan Cox on 1 EP and high-speed supported */ 5390ca1268eSLucy McCoy struct urb *indat_urb; 5402fcd1c9bSJohan Hovold char *indat_buf; 5410ca1268eSLucy McCoy 5421da177e4SLinus Torvalds /* XXX this one probably will need a lock */ 5431da177e4SLinus Torvalds struct urb *glocont_urb; 5442fcd1c9bSJohan Hovold char *glocont_buf; 5452fcd1c9bSJohan Hovold char *ctrl_buf; /* for EP0 control message */ 5461da177e4SLinus Torvalds }; 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds struct keyspan_port_private { 5491da177e4SLinus Torvalds /* Keep track of which input & output endpoints to use */ 5501da177e4SLinus Torvalds int in_flip; 5511da177e4SLinus Torvalds int out_flip; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* Keep duplicate of device details in each port 5541da177e4SLinus Torvalds structure as well - simplifies some of the 5551da177e4SLinus Torvalds callback functions etc. */ 5561da177e4SLinus Torvalds const struct keyspan_device_details *device_details; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* Input endpoints and buffer for this port */ 5591da177e4SLinus Torvalds struct urb *in_urbs[2]; 560bad41a5bSJohan Hovold char *in_buffer[2]; 5611da177e4SLinus Torvalds /* Output endpoints and buffer for this port */ 5621da177e4SLinus Torvalds struct urb *out_urbs[2]; 563bad41a5bSJohan Hovold char *out_buffer[2]; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds /* Input ack endpoint */ 5661da177e4SLinus Torvalds struct urb *inack_urb; 567bad41a5bSJohan Hovold char *inack_buffer; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* Output control endpoint */ 5701da177e4SLinus Torvalds struct urb *outcont_urb; 571bad41a5bSJohan Hovold char *outcont_buffer; 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds /* Settings for the port */ 5741da177e4SLinus Torvalds int baud; 5751da177e4SLinus Torvalds int old_baud; 5761da177e4SLinus Torvalds unsigned int cflag; 5771da177e4SLinus Torvalds unsigned int old_cflag; 5781da177e4SLinus Torvalds enum {flow_none, flow_cts, flow_xon} flow_control; 5791da177e4SLinus Torvalds int rts_state; /* Handshaking pins (outputs) */ 5801da177e4SLinus Torvalds int dtr_state; 5811da177e4SLinus Torvalds int cts_state; /* Handshaking pins (inputs) */ 5821da177e4SLinus Torvalds int dsr_state; 5831da177e4SLinus Torvalds int dcd_state; 5841da177e4SLinus Torvalds int ri_state; 5851da177e4SLinus Torvalds int break_on; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds unsigned long tx_start_time[2]; 5881da177e4SLinus Torvalds int resend_cont; /* need to resend control packet */ 5891da177e4SLinus Torvalds }; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* Include Keyspan message headers. All current Keyspan Adapters 5920ca1268eSLucy McCoy make use of one of five message formats which are referred 593deb91685SAlan Cox to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and 594deb91685SAlan Cox within this driver. */ 5951da177e4SLinus Torvalds #include "keyspan_usa26msg.h" 5961da177e4SLinus Torvalds #include "keyspan_usa28msg.h" 5971da177e4SLinus Torvalds #include "keyspan_usa49msg.h" 5981da177e4SLinus Torvalds #include "keyspan_usa90msg.h" 5990ca1268eSLucy McCoy #include "keyspan_usa67msg.h" 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds 60295da310eSAlan Cox static void keyspan_break_ctl(struct tty_struct *tty, int break_state) 6031da177e4SLinus Torvalds { 60495da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 6051da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds if (break_state == -1) 6101da177e4SLinus Torvalds p_priv->break_on = 1; 6111da177e4SLinus Torvalds else 6121da177e4SLinus Torvalds p_priv->break_on = 0; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds keyspan_send_setup(port, 0); 6151da177e4SLinus Torvalds } 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds 61895da310eSAlan Cox static void keyspan_set_termios(struct tty_struct *tty, 619*f6d47fe5SIlpo Järvinen struct usb_serial_port *port, 620*f6d47fe5SIlpo Järvinen const struct ktermios *old_termios) 6211da177e4SLinus Torvalds { 6221da177e4SLinus Torvalds int baud_rate, device_port; 6231da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 6241da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 6251da177e4SLinus Torvalds unsigned int cflag; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 6281da177e4SLinus Torvalds d_details = p_priv->device_details; 629adc8d746SAlan Cox cflag = tty->termios.c_cflag; 6301143832eSGreg Kroah-Hartman device_port = port->port_number; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /* Baud rate calculation takes baud rate as an integer 6331da177e4SLinus Torvalds so other rates can be generated if desired. */ 63474240b07SAlan Cox baud_rate = tty_get_baud_rate(tty); 6351da177e4SLinus Torvalds /* If no match or invalid, don't change */ 636049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, 6371da177e4SLinus Torvalds NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { 6381da177e4SLinus Torvalds /* FIXME - more to do here to ensure rate changes cleanly */ 639cd8c5053SRahul Bedarkar /* FIXME - calculate exact rate from divisor ? */ 6401da177e4SLinus Torvalds p_priv->baud = baud_rate; 64174240b07SAlan Cox } else 64274240b07SAlan Cox baud_rate = tty_termios_baud_rate(old_termios); 6431da177e4SLinus Torvalds 64474240b07SAlan Cox tty_encode_baud_rate(tty, baud_rate, baud_rate); 6451da177e4SLinus Torvalds /* set CTS/RTS handshake etc. */ 6461da177e4SLinus Torvalds p_priv->cflag = cflag; 6471da177e4SLinus Torvalds p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none; 6481da177e4SLinus Torvalds 64974240b07SAlan Cox /* Mark/Space not supported */ 650adc8d746SAlan Cox tty->termios.c_cflag &= ~CMSPAR; 65174240b07SAlan Cox 6521da177e4SLinus Torvalds keyspan_send_setup(port, 0); 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 65560b33c13SAlan Cox static int keyspan_tiocmget(struct tty_struct *tty) 6561da177e4SLinus Torvalds { 65795da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 65895da310eSAlan Cox struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); 6591da177e4SLinus Torvalds unsigned int value; 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds value = ((p_priv->rts_state) ? TIOCM_RTS : 0) | 6621da177e4SLinus Torvalds ((p_priv->dtr_state) ? TIOCM_DTR : 0) | 6631da177e4SLinus Torvalds ((p_priv->cts_state) ? TIOCM_CTS : 0) | 6641da177e4SLinus Torvalds ((p_priv->dsr_state) ? TIOCM_DSR : 0) | 6651da177e4SLinus Torvalds ((p_priv->dcd_state) ? TIOCM_CAR : 0) | 6661da177e4SLinus Torvalds ((p_priv->ri_state) ? TIOCM_RNG : 0); 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds return value; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 67120b9d177SAlan Cox static int keyspan_tiocmset(struct tty_struct *tty, 6721da177e4SLinus Torvalds unsigned int set, unsigned int clear) 6731da177e4SLinus Torvalds { 67495da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 67595da310eSAlan Cox struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds if (set & TIOCM_RTS) 6781da177e4SLinus Torvalds p_priv->rts_state = 1; 6791da177e4SLinus Torvalds if (set & TIOCM_DTR) 6801da177e4SLinus Torvalds p_priv->dtr_state = 1; 6811da177e4SLinus Torvalds if (clear & TIOCM_RTS) 6821da177e4SLinus Torvalds p_priv->rts_state = 0; 6831da177e4SLinus Torvalds if (clear & TIOCM_DTR) 6841da177e4SLinus Torvalds p_priv->dtr_state = 0; 6851da177e4SLinus Torvalds keyspan_send_setup(port, 0); 6861da177e4SLinus Torvalds return 0; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* Write function is similar for the four protocols used 6901da177e4SLinus Torvalds with only a minor change for usa90 (usa19hs) required */ 69195da310eSAlan Cox static int keyspan_write(struct tty_struct *tty, 69295da310eSAlan Cox struct usb_serial_port *port, const unsigned char *buf, int count) 6931da177e4SLinus Torvalds { 6941da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 6951da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 6961da177e4SLinus Torvalds int flip; 6971da177e4SLinus Torvalds int left, todo; 6981da177e4SLinus Torvalds struct urb *this_urb; 6991da177e4SLinus Torvalds int err, maxDataLen, dataOffset; 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 7021da177e4SLinus Torvalds d_details = p_priv->device_details; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds if (d_details->msg_format == msg_usa90) { 7051da177e4SLinus Torvalds maxDataLen = 64; 7061da177e4SLinus Torvalds dataOffset = 0; 7071da177e4SLinus Torvalds } else { 7081da177e4SLinus Torvalds maxDataLen = 63; 7091da177e4SLinus Torvalds dataOffset = 1; 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121143832eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d chars, flip=%d\n", __func__, count, 7131143832eSGreg Kroah-Hartman p_priv->out_flip); 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds for (left = count; left > 0; left -= todo) { 7161da177e4SLinus Torvalds todo = left; 7171da177e4SLinus Torvalds if (todo > maxDataLen) 7181da177e4SLinus Torvalds todo = maxDataLen; 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds flip = p_priv->out_flip; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* Check we have a valid urb/endpoint before we use it... */ 723deb91685SAlan Cox this_urb = p_priv->out_urbs[flip]; 724deb91685SAlan Cox if (this_urb == NULL) { 7251da177e4SLinus Torvalds /* no bulk out, so return 0 bytes written */ 726049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - no output urb :(\n", __func__); 7271da177e4SLinus Torvalds return count; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 7300cd782b0SJohan Hovold dev_dbg(&port->dev, "%s - endpoint %x flip %d\n", 731deb91685SAlan Cox __func__, usb_pipeendpoint(this_urb->pipe), flip); 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds if (this_urb->status == -EINPROGRESS) { 734deb91685SAlan Cox if (time_before(jiffies, 735deb91685SAlan Cox p_priv->tx_start_time[flip] + 10 * HZ)) 7361da177e4SLinus Torvalds break; 7371da177e4SLinus Torvalds usb_unlink_urb(this_urb); 7381da177e4SLinus Torvalds break; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 741deb91685SAlan Cox /* First byte in buffer is "last flag" (except for usa19hx) 742deb91685SAlan Cox - unused so for now so set to zero */ 7431da177e4SLinus Torvalds ((char *)this_urb->transfer_buffer)[0] = 0; 7441da177e4SLinus Torvalds 7451da177e4SLinus Torvalds memcpy(this_urb->transfer_buffer + dataOffset, buf, todo); 7461da177e4SLinus Torvalds buf += todo; 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* send the data out the bulk port */ 7491da177e4SLinus Torvalds this_urb->transfer_buffer_length = todo + dataOffset; 7501da177e4SLinus Torvalds 751deb91685SAlan Cox err = usb_submit_urb(this_urb, GFP_ATOMIC); 752deb91685SAlan Cox if (err != 0) 753049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed (%d)\n", err); 7541da177e4SLinus Torvalds p_priv->tx_start_time[flip] = jiffies; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds /* Flip for next time if usa26 or usa28 interface 7571da177e4SLinus Torvalds (not used on usa49) */ 7581da177e4SLinus Torvalds p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds return count - left; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7647d12e780SDavid Howells static void usa26_indat_callback(struct urb *urb) 7651da177e4SLinus Torvalds { 7661da177e4SLinus Torvalds int i, err; 7671da177e4SLinus Torvalds int endpoint; 7681da177e4SLinus Torvalds struct usb_serial_port *port; 7691da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 77095b93454SGreg Kroah-Hartman int status = urb->status; 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds endpoint = usb_pipeendpoint(urb->pipe); 7731da177e4SLinus Torvalds 77495b93454SGreg Kroah-Hartman if (status) { 7750cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", 776441b62c1SHarvey Harrison __func__, status, endpoint); 7771da177e4SLinus Torvalds return; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 780cdc97792SMing Lei port = urb->context; 7812e124b4aSJiri Slaby if (urb->actual_length) { 7821da177e4SLinus Torvalds /* 0x80 bit is error flag */ 7831da177e4SLinus Torvalds if ((data[0] & 0x80) == 0) { 784deb91685SAlan Cox /* no errors on individual bytes, only 785deb91685SAlan Cox possible overrun err */ 786855515a6SJohan Hovold if (data[0] & RXERROR_OVERRUN) { 787855515a6SJohan Hovold tty_insert_flip_char(&port->port, 0, 788855515a6SJohan Hovold TTY_OVERRUN); 789855515a6SJohan Hovold } 790deb91685SAlan Cox for (i = 1; i < urb->actual_length ; ++i) 791855515a6SJohan Hovold tty_insert_flip_char(&port->port, data[i], 792855515a6SJohan Hovold TTY_NORMAL); 7931da177e4SLinus Torvalds } else { 7941da177e4SLinus Torvalds /* some bytes had errors, every byte has status */ 795049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); 7961da177e4SLinus Torvalds for (i = 0; i + 1 < urb->actual_length; i += 2) { 7975d1678a3SJohan Hovold int stat = data[i]; 7985d1678a3SJohan Hovold int flag = TTY_NORMAL; 7995d1678a3SJohan Hovold 8005d1678a3SJohan Hovold if (stat & RXERROR_OVERRUN) { 8015d1678a3SJohan Hovold tty_insert_flip_char(&port->port, 0, 8025d1678a3SJohan Hovold TTY_OVERRUN); 8035d1678a3SJohan Hovold } 8041da177e4SLinus Torvalds /* XXX should handle break (0x10) */ 8055d1678a3SJohan Hovold if (stat & RXERROR_PARITY) 8065d1678a3SJohan Hovold flag = TTY_PARITY; 8075d1678a3SJohan Hovold else if (stat & RXERROR_FRAMING) 8085d1678a3SJohan Hovold flag = TTY_FRAME; 8095d1678a3SJohan Hovold 81092a19f9cSJiri Slaby tty_insert_flip_char(&port->port, data[i+1], 81192a19f9cSJiri Slaby flag); 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds } 8142e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 818deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 819deb91685SAlan Cox if (err != 0) 820049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 8211da177e4SLinus Torvalds } 8221da177e4SLinus Torvalds 8231da177e4SLinus Torvalds /* Outdat handling is common for all devices */ 8247d12e780SDavid Howells static void usa2x_outdat_callback(struct urb *urb) 8251da177e4SLinus Torvalds { 8261da177e4SLinus Torvalds struct usb_serial_port *port; 8271da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 8281da177e4SLinus Torvalds 829cdc97792SMing Lei port = urb->context; 8301da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 831049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - urb %d\n", __func__, urb == p_priv->out_urbs[1]); 8321da177e4SLinus Torvalds 833cf2c7481SPete Zaitcev usb_serial_port_softint(port); 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8367d12e780SDavid Howells static void usa26_inack_callback(struct urb *urb) 8371da177e4SLinus Torvalds { 8381da177e4SLinus Torvalds } 8391da177e4SLinus Torvalds 8407d12e780SDavid Howells static void usa26_outcont_callback(struct urb *urb) 8411da177e4SLinus Torvalds { 8421da177e4SLinus Torvalds struct usb_serial_port *port; 8431da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 8441da177e4SLinus Torvalds 845cdc97792SMing Lei port = urb->context; 8461da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds if (p_priv->resend_cont) { 849049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - sending setup\n", __func__); 850deb91685SAlan Cox keyspan_usa26_send_setup(port->serial, port, 851deb91685SAlan Cox p_priv->resend_cont - 1); 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds 8557d12e780SDavid Howells static void usa26_instat_callback(struct urb *urb) 8561da177e4SLinus Torvalds { 8571da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 8581da177e4SLinus Torvalds struct keyspan_usa26_portStatusMessage *msg; 8591da177e4SLinus Torvalds struct usb_serial *serial; 8601da177e4SLinus Torvalds struct usb_serial_port *port; 8611da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 8621da177e4SLinus Torvalds int old_dcd_state, err; 86395b93454SGreg Kroah-Hartman int status = urb->status; 8641da177e4SLinus Torvalds 865cdc97792SMing Lei serial = urb->context; 8661da177e4SLinus Torvalds 86795b93454SGreg Kroah-Hartman if (status) { 8680cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 8690cd782b0SJohan Hovold __func__, status); 8701da177e4SLinus Torvalds return; 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds if (urb->actual_length != 9) { 873049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); 8741da177e4SLinus Torvalds goto exit; 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds msg = (struct keyspan_usa26_portStatusMessage *)data; 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds /* Check port number from message and retrieve private data */ 8801da177e4SLinus Torvalds if (msg->port >= serial->num_ports) { 881049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); 8821da177e4SLinus Torvalds goto exit; 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds port = serial->port[msg->port]; 8851da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 886b5122236SJohan Hovold if (!p_priv) 887b5122236SJohan Hovold goto resubmit; 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds /* Update handshaking pin state information */ 8901da177e4SLinus Torvalds old_dcd_state = p_priv->dcd_state; 8911da177e4SLinus Torvalds p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); 8921da177e4SLinus Torvalds p_priv->dsr_state = ((msg->dsr) ? 1 : 0); 8931da177e4SLinus Torvalds p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); 8941da177e4SLinus Torvalds p_priv->ri_state = ((msg->ri) ? 1 : 0); 8951da177e4SLinus Torvalds 896aa27a094SJiri Slaby if (old_dcd_state != p_priv->dcd_state) 897aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true); 898b5122236SJohan Hovold resubmit: 8991da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 900deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 901deb91685SAlan Cox if (err != 0) 902049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 9031da177e4SLinus Torvalds exit: ; 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 9067d12e780SDavid Howells static void usa26_glocont_callback(struct urb *urb) 9071da177e4SLinus Torvalds { 9081da177e4SLinus Torvalds } 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds 9117d12e780SDavid Howells static void usa28_indat_callback(struct urb *urb) 9121da177e4SLinus Torvalds { 913f035a8adSAlan Cox int err; 9141da177e4SLinus Torvalds struct usb_serial_port *port; 9151da177e4SLinus Torvalds unsigned char *data; 9161da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 91795b93454SGreg Kroah-Hartman int status = urb->status; 9181da177e4SLinus Torvalds 919cdc97792SMing Lei port = urb->context; 9201da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 9211da177e4SLinus Torvalds data = urb->transfer_buffer; 9221da177e4SLinus Torvalds 9231da177e4SLinus Torvalds if (urb != p_priv->in_urbs[p_priv->in_flip]) 9241da177e4SLinus Torvalds return; 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds do { 92795b93454SGreg Kroah-Hartman if (status) { 9280cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", 929441b62c1SHarvey Harrison __func__, status, usb_pipeendpoint(urb->pipe)); 9301da177e4SLinus Torvalds return; 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds 933cdc97792SMing Lei port = urb->context; 9341da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 9351da177e4SLinus Torvalds data = urb->transfer_buffer; 9361da177e4SLinus Torvalds 9372e124b4aSJiri Slaby if (urb->actual_length) { 93805c7cd39SJiri Slaby tty_insert_flip_string(&port->port, data, 93905c7cd39SJiri Slaby urb->actual_length); 9402e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 944deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 945deb91685SAlan Cox if (err != 0) 946049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", 947deb91685SAlan Cox __func__, err); 9481da177e4SLinus Torvalds p_priv->in_flip ^= 1; 9491da177e4SLinus Torvalds 9501da177e4SLinus Torvalds urb = p_priv->in_urbs[p_priv->in_flip]; 9511da177e4SLinus Torvalds } while (urb->status != -EINPROGRESS); 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds 9547d12e780SDavid Howells static void usa28_inack_callback(struct urb *urb) 9551da177e4SLinus Torvalds { 9561da177e4SLinus Torvalds } 9571da177e4SLinus Torvalds 9587d12e780SDavid Howells static void usa28_outcont_callback(struct urb *urb) 9591da177e4SLinus Torvalds { 9601da177e4SLinus Torvalds struct usb_serial_port *port; 9611da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 9621da177e4SLinus Torvalds 963cdc97792SMing Lei port = urb->context; 9641da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds if (p_priv->resend_cont) { 967049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - sending setup\n", __func__); 968deb91685SAlan Cox keyspan_usa28_send_setup(port->serial, port, 969deb91685SAlan Cox p_priv->resend_cont - 1); 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds } 9721da177e4SLinus Torvalds 9737d12e780SDavid Howells static void usa28_instat_callback(struct urb *urb) 9741da177e4SLinus Torvalds { 9751da177e4SLinus Torvalds int err; 9761da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 9771da177e4SLinus Torvalds struct keyspan_usa28_portStatusMessage *msg; 9781da177e4SLinus Torvalds struct usb_serial *serial; 9791da177e4SLinus Torvalds struct usb_serial_port *port; 9801da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 9811da177e4SLinus Torvalds int old_dcd_state; 98295b93454SGreg Kroah-Hartman int status = urb->status; 9831da177e4SLinus Torvalds 984cdc97792SMing Lei serial = urb->context; 9851da177e4SLinus Torvalds 98695b93454SGreg Kroah-Hartman if (status) { 9870cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 9880cd782b0SJohan Hovold __func__, status); 9891da177e4SLinus Torvalds return; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) { 993049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); 9941da177e4SLinus Torvalds goto exit; 9951da177e4SLinus Torvalds } 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds msg = (struct keyspan_usa28_portStatusMessage *)data; 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds /* Check port number from message and retrieve private data */ 10001da177e4SLinus Torvalds if (msg->port >= serial->num_ports) { 1001049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); 10021da177e4SLinus Torvalds goto exit; 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds port = serial->port[msg->port]; 10051da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 1006b5122236SJohan Hovold if (!p_priv) 1007b5122236SJohan Hovold goto resubmit; 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds /* Update handshaking pin state information */ 10101da177e4SLinus Torvalds old_dcd_state = p_priv->dcd_state; 10111da177e4SLinus Torvalds p_priv->cts_state = ((msg->cts) ? 1 : 0); 10121da177e4SLinus Torvalds p_priv->dsr_state = ((msg->dsr) ? 1 : 0); 10131da177e4SLinus Torvalds p_priv->dcd_state = ((msg->dcd) ? 1 : 0); 10141da177e4SLinus Torvalds p_priv->ri_state = ((msg->ri) ? 1 : 0); 10151da177e4SLinus Torvalds 1016aa27a094SJiri Slaby if (old_dcd_state != p_priv->dcd_state && old_dcd_state) 1017aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true); 1018b5122236SJohan Hovold resubmit: 10191da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 1020deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 1021deb91685SAlan Cox if (err != 0) 1022049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 10231da177e4SLinus Torvalds exit: ; 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds 10267d12e780SDavid Howells static void usa28_glocont_callback(struct urb *urb) 10271da177e4SLinus Torvalds { 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 10301da177e4SLinus Torvalds 10317d12e780SDavid Howells static void usa49_glocont_callback(struct urb *urb) 10321da177e4SLinus Torvalds { 10331da177e4SLinus Torvalds struct usb_serial *serial; 10341da177e4SLinus Torvalds struct usb_serial_port *port; 10351da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 10361da177e4SLinus Torvalds int i; 10371da177e4SLinus Torvalds 1038cdc97792SMing Lei serial = urb->context; 10391da177e4SLinus Torvalds for (i = 0; i < serial->num_ports; ++i) { 10401da177e4SLinus Torvalds port = serial->port[i]; 10411da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 10423018dd3fSJohan Hovold if (!p_priv) 10433018dd3fSJohan Hovold continue; 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds if (p_priv->resend_cont) { 1046049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - sending setup\n", __func__); 1047deb91685SAlan Cox keyspan_usa49_send_setup(serial, port, 1048deb91685SAlan Cox p_priv->resend_cont - 1); 10491da177e4SLinus Torvalds break; 10501da177e4SLinus Torvalds } 10511da177e4SLinus Torvalds } 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds 10541da177e4SLinus Torvalds /* This is actually called glostat in the Keyspan 10551da177e4SLinus Torvalds doco */ 10567d12e780SDavid Howells static void usa49_instat_callback(struct urb *urb) 10571da177e4SLinus Torvalds { 10581da177e4SLinus Torvalds int err; 10591da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 10601da177e4SLinus Torvalds struct keyspan_usa49_portStatusMessage *msg; 10611da177e4SLinus Torvalds struct usb_serial *serial; 10621da177e4SLinus Torvalds struct usb_serial_port *port; 10631da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 10641da177e4SLinus Torvalds int old_dcd_state; 106595b93454SGreg Kroah-Hartman int status = urb->status; 10661da177e4SLinus Torvalds 1067cdc97792SMing Lei serial = urb->context; 10681da177e4SLinus Torvalds 106995b93454SGreg Kroah-Hartman if (status) { 10700cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 10710cd782b0SJohan Hovold __func__, status); 10721da177e4SLinus Torvalds return; 10731da177e4SLinus Torvalds } 10741da177e4SLinus Torvalds 1075deb91685SAlan Cox if (urb->actual_length != 1076deb91685SAlan Cox sizeof(struct keyspan_usa49_portStatusMessage)) { 1077049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); 10781da177e4SLinus Torvalds goto exit; 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 10811da177e4SLinus Torvalds msg = (struct keyspan_usa49_portStatusMessage *)data; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds /* Check port number from message and retrieve private data */ 10841da177e4SLinus Torvalds if (msg->portNumber >= serial->num_ports) { 1085049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", 1086deb91685SAlan Cox __func__, msg->portNumber); 10871da177e4SLinus Torvalds goto exit; 10881da177e4SLinus Torvalds } 10891da177e4SLinus Torvalds port = serial->port[msg->portNumber]; 10901da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 1091b5122236SJohan Hovold if (!p_priv) 1092b5122236SJohan Hovold goto resubmit; 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds /* Update handshaking pin state information */ 10951da177e4SLinus Torvalds old_dcd_state = p_priv->dcd_state; 10961da177e4SLinus Torvalds p_priv->cts_state = ((msg->cts) ? 1 : 0); 10971da177e4SLinus Torvalds p_priv->dsr_state = ((msg->dsr) ? 1 : 0); 10981da177e4SLinus Torvalds p_priv->dcd_state = ((msg->dcd) ? 1 : 0); 10991da177e4SLinus Torvalds p_priv->ri_state = ((msg->ri) ? 1 : 0); 11001da177e4SLinus Torvalds 1101aa27a094SJiri Slaby if (old_dcd_state != p_priv->dcd_state && old_dcd_state) 1102aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true); 1103b5122236SJohan Hovold resubmit: 11041da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 1105deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 1106deb91685SAlan Cox if (err != 0) 1107049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 11081da177e4SLinus Torvalds exit: ; 11091da177e4SLinus Torvalds } 11101da177e4SLinus Torvalds 11117d12e780SDavid Howells static void usa49_inack_callback(struct urb *urb) 11121da177e4SLinus Torvalds { 11131da177e4SLinus Torvalds } 11141da177e4SLinus Torvalds 11157d12e780SDavid Howells static void usa49_indat_callback(struct urb *urb) 11161da177e4SLinus Torvalds { 11171da177e4SLinus Torvalds int i, err; 11181da177e4SLinus Torvalds int endpoint; 11191da177e4SLinus Torvalds struct usb_serial_port *port; 11201da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 112195b93454SGreg Kroah-Hartman int status = urb->status; 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds endpoint = usb_pipeendpoint(urb->pipe); 11241da177e4SLinus Torvalds 112595b93454SGreg Kroah-Hartman if (status) { 11260cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", 1127049c6b4eSGreg Kroah-Hartman __func__, status, endpoint); 11281da177e4SLinus Torvalds return; 11291da177e4SLinus Torvalds } 11301da177e4SLinus Torvalds 1131cdc97792SMing Lei port = urb->context; 11322e124b4aSJiri Slaby if (urb->actual_length) { 11331da177e4SLinus Torvalds /* 0x80 bit is error flag */ 11341da177e4SLinus Torvalds if ((data[0] & 0x80) == 0) { 11351da177e4SLinus Torvalds /* no error on any byte */ 113605c7cd39SJiri Slaby tty_insert_flip_string(&port->port, data + 1, 1137f035a8adSAlan Cox urb->actual_length - 1); 11381da177e4SLinus Torvalds } else { 11391da177e4SLinus Torvalds /* some bytes had errors, every byte has status */ 11401da177e4SLinus Torvalds for (i = 0; i + 1 < urb->actual_length; i += 2) { 11415d1678a3SJohan Hovold int stat = data[i]; 11425d1678a3SJohan Hovold int flag = TTY_NORMAL; 11435d1678a3SJohan Hovold 11445d1678a3SJohan Hovold if (stat & RXERROR_OVERRUN) { 11455d1678a3SJohan Hovold tty_insert_flip_char(&port->port, 0, 11465d1678a3SJohan Hovold TTY_OVERRUN); 11475d1678a3SJohan Hovold } 11481da177e4SLinus Torvalds /* XXX should handle break (0x10) */ 11495d1678a3SJohan Hovold if (stat & RXERROR_PARITY) 11505d1678a3SJohan Hovold flag = TTY_PARITY; 11515d1678a3SJohan Hovold else if (stat & RXERROR_FRAMING) 11525d1678a3SJohan Hovold flag = TTY_FRAME; 11535d1678a3SJohan Hovold 115492a19f9cSJiri Slaby tty_insert_flip_char(&port->port, data[i+1], 115592a19f9cSJiri Slaby flag); 11561da177e4SLinus Torvalds } 11571da177e4SLinus Torvalds } 11582e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 1162deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 1163deb91685SAlan Cox if (err != 0) 1164049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 11670ca1268eSLucy McCoy static void usa49wg_indat_callback(struct urb *urb) 11680ca1268eSLucy McCoy { 11690ca1268eSLucy McCoy int i, len, x, err; 11700ca1268eSLucy McCoy struct usb_serial *serial; 11710ca1268eSLucy McCoy struct usb_serial_port *port; 11720ca1268eSLucy McCoy unsigned char *data = urb->transfer_buffer; 117395b93454SGreg Kroah-Hartman int status = urb->status; 11740ca1268eSLucy McCoy 11750ca1268eSLucy McCoy serial = urb->context; 11760ca1268eSLucy McCoy 117795b93454SGreg Kroah-Hartman if (status) { 11780cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 11790cd782b0SJohan Hovold __func__, status); 11800ca1268eSLucy McCoy return; 11810ca1268eSLucy McCoy } 11820ca1268eSLucy McCoy 11830ca1268eSLucy McCoy /* inbound data is in the form P#, len, status, data */ 11840ca1268eSLucy McCoy i = 0; 11850ca1268eSLucy McCoy len = 0; 11860ca1268eSLucy McCoy 11870ca1268eSLucy McCoy while (i < urb->actual_length) { 11880ca1268eSLucy McCoy 11890ca1268eSLucy McCoy /* Check port number from message */ 11900ca1268eSLucy McCoy if (data[i] >= serial->num_ports) { 1191049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", 1192441b62c1SHarvey Harrison __func__, data[i]); 11930ca1268eSLucy McCoy return; 11940ca1268eSLucy McCoy } 11950ca1268eSLucy McCoy port = serial->port[data[i++]]; 11960ca1268eSLucy McCoy len = data[i++]; 11970ca1268eSLucy McCoy 11980ca1268eSLucy McCoy /* 0x80 bit is error flag */ 11990ca1268eSLucy McCoy if ((data[i] & 0x80) == 0) { 12000ca1268eSLucy McCoy /* no error on any byte */ 12010ca1268eSLucy McCoy i++; 120201a60e76SDan Carpenter for (x = 1; x < len && i < urb->actual_length; ++x) 120392a19f9cSJiri Slaby tty_insert_flip_char(&port->port, 120492a19f9cSJiri Slaby data[i++], 0); 12050ca1268eSLucy McCoy } else { 12060ca1268eSLucy McCoy /* 12070ca1268eSLucy McCoy * some bytes had errors, every byte has status 12080ca1268eSLucy McCoy */ 120901a60e76SDan Carpenter for (x = 0; x + 1 < len && 121001a60e76SDan Carpenter i + 1 < urb->actual_length; x += 2) { 12115d1678a3SJohan Hovold int stat = data[i]; 12125d1678a3SJohan Hovold int flag = TTY_NORMAL; 12136a3ae841SDan Carpenter 12145d1678a3SJohan Hovold if (stat & RXERROR_OVERRUN) { 12155d1678a3SJohan Hovold tty_insert_flip_char(&port->port, 0, 12165d1678a3SJohan Hovold TTY_OVERRUN); 12175d1678a3SJohan Hovold } 12180ca1268eSLucy McCoy /* XXX should handle break (0x10) */ 12195d1678a3SJohan Hovold if (stat & RXERROR_PARITY) 12205d1678a3SJohan Hovold flag = TTY_PARITY; 12215d1678a3SJohan Hovold else if (stat & RXERROR_FRAMING) 12225d1678a3SJohan Hovold flag = TTY_FRAME; 12235d1678a3SJohan Hovold 12246a3ae841SDan Carpenter tty_insert_flip_char(&port->port, data[i+1], 12256a3ae841SDan Carpenter flag); 12260ca1268eSLucy McCoy i += 2; 12270ca1268eSLucy McCoy } 12280ca1268eSLucy McCoy } 12292e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 12300ca1268eSLucy McCoy } 12310ca1268eSLucy McCoy 12320ca1268eSLucy McCoy /* Resubmit urb so we continue receiving */ 12330ca1268eSLucy McCoy err = usb_submit_urb(urb, GFP_ATOMIC); 12340ca1268eSLucy McCoy if (err != 0) 1235049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 12360ca1268eSLucy McCoy } 12370ca1268eSLucy McCoy 12381da177e4SLinus Torvalds /* not used, usa-49 doesn't have per-port control endpoints */ 12397d12e780SDavid Howells static void usa49_outcont_callback(struct urb *urb) 12401da177e4SLinus Torvalds { 12411da177e4SLinus Torvalds } 12421da177e4SLinus Torvalds 12437d12e780SDavid Howells static void usa90_indat_callback(struct urb *urb) 12441da177e4SLinus Torvalds { 12451da177e4SLinus Torvalds int i, err; 12461da177e4SLinus Torvalds int endpoint; 12471da177e4SLinus Torvalds struct usb_serial_port *port; 12481da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 12491da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 125095b93454SGreg Kroah-Hartman int status = urb->status; 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds endpoint = usb_pipeendpoint(urb->pipe); 12531da177e4SLinus Torvalds 125495b93454SGreg Kroah-Hartman if (status) { 12550cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status %d on endpoint %x\n", 1256441b62c1SHarvey Harrison __func__, status, endpoint); 12571da177e4SLinus Torvalds return; 12581da177e4SLinus Torvalds } 12591da177e4SLinus Torvalds 1260cdc97792SMing Lei port = urb->context; 12611da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds if (urb->actual_length) { 12641da177e4SLinus Torvalds /* if current mode is DMA, looks like usa28 format 12651da177e4SLinus Torvalds otherwise looks like usa26 data format */ 12661da177e4SLinus Torvalds 1267f035a8adSAlan Cox if (p_priv->baud > 57600) 126805c7cd39SJiri Slaby tty_insert_flip_string(&port->port, data, 126905c7cd39SJiri Slaby urb->actual_length); 1270f035a8adSAlan Cox else { 12711da177e4SLinus Torvalds /* 0x80 bit is error flag */ 12721da177e4SLinus Torvalds if ((data[0] & 0x80) == 0) { 1273deb91685SAlan Cox /* no errors on individual bytes, only 1274deb91685SAlan Cox possible overrun err*/ 1275855515a6SJohan Hovold if (data[0] & RXERROR_OVERRUN) { 1276855515a6SJohan Hovold tty_insert_flip_char(&port->port, 0, 1277855515a6SJohan Hovold TTY_OVERRUN); 1278855515a6SJohan Hovold } 12791da177e4SLinus Torvalds for (i = 1; i < urb->actual_length ; ++i) 128092a19f9cSJiri Slaby tty_insert_flip_char(&port->port, 1281855515a6SJohan Hovold data[i], TTY_NORMAL); 1282deb91685SAlan Cox } else { 12831da177e4SLinus Torvalds /* some bytes had errors, every byte has status */ 1284049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); 12851da177e4SLinus Torvalds for (i = 0; i + 1 < urb->actual_length; i += 2) { 12865d1678a3SJohan Hovold int stat = data[i]; 12875d1678a3SJohan Hovold int flag = TTY_NORMAL; 12885d1678a3SJohan Hovold 12895d1678a3SJohan Hovold if (stat & RXERROR_OVERRUN) { 12905d1678a3SJohan Hovold tty_insert_flip_char( 12915d1678a3SJohan Hovold &port->port, 0, 12925d1678a3SJohan Hovold TTY_OVERRUN); 12935d1678a3SJohan Hovold } 12941da177e4SLinus Torvalds /* XXX should handle break (0x10) */ 12955d1678a3SJohan Hovold if (stat & RXERROR_PARITY) 12965d1678a3SJohan Hovold flag = TTY_PARITY; 12975d1678a3SJohan Hovold else if (stat & RXERROR_FRAMING) 12985d1678a3SJohan Hovold flag = TTY_FRAME; 12995d1678a3SJohan Hovold 130092a19f9cSJiri Slaby tty_insert_flip_char(&port->port, 130192a19f9cSJiri Slaby data[i+1], flag); 13021da177e4SLinus Torvalds } 13031da177e4SLinus Torvalds } 13041da177e4SLinus Torvalds } 13052e124b4aSJiri Slaby tty_flip_buffer_push(&port->port); 13061da177e4SLinus Torvalds } 13071da177e4SLinus Torvalds 13081da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 1309deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 1310deb91685SAlan Cox if (err != 0) 1311049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 13121da177e4SLinus Torvalds } 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds 13157d12e780SDavid Howells static void usa90_instat_callback(struct urb *urb) 13161da177e4SLinus Torvalds { 13171da177e4SLinus Torvalds unsigned char *data = urb->transfer_buffer; 13181da177e4SLinus Torvalds struct keyspan_usa90_portStatusMessage *msg; 13191da177e4SLinus Torvalds struct usb_serial *serial; 13201da177e4SLinus Torvalds struct usb_serial_port *port; 13211da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 13221da177e4SLinus Torvalds int old_dcd_state, err; 132395b93454SGreg Kroah-Hartman int status = urb->status; 13241da177e4SLinus Torvalds 1325cdc97792SMing Lei serial = urb->context; 13261da177e4SLinus Torvalds 132795b93454SGreg Kroah-Hartman if (status) { 13280cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 13290cd782b0SJohan Hovold __func__, status); 13301da177e4SLinus Torvalds return; 13311da177e4SLinus Torvalds } 13321da177e4SLinus Torvalds if (urb->actual_length < 14) { 1333049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - %d byte report??\n", __func__, urb->actual_length); 13341da177e4SLinus Torvalds goto exit; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds msg = (struct keyspan_usa90_portStatusMessage *)data; 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds /* Now do something useful with the data */ 13401da177e4SLinus Torvalds 13411da177e4SLinus Torvalds port = serial->port[0]; 13421da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 1343b5122236SJohan Hovold if (!p_priv) 1344b5122236SJohan Hovold goto resubmit; 13451da177e4SLinus Torvalds 13461da177e4SLinus Torvalds /* Update handshaking pin state information */ 13471da177e4SLinus Torvalds old_dcd_state = p_priv->dcd_state; 13481da177e4SLinus Torvalds p_priv->cts_state = ((msg->cts) ? 1 : 0); 13491da177e4SLinus Torvalds p_priv->dsr_state = ((msg->dsr) ? 1 : 0); 13501da177e4SLinus Torvalds p_priv->dcd_state = ((msg->dcd) ? 1 : 0); 13511da177e4SLinus Torvalds p_priv->ri_state = ((msg->ri) ? 1 : 0); 13521da177e4SLinus Torvalds 1353aa27a094SJiri Slaby if (old_dcd_state != p_priv->dcd_state && old_dcd_state) 1354aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true); 1355b5122236SJohan Hovold resubmit: 13561da177e4SLinus Torvalds /* Resubmit urb so we continue receiving */ 1357deb91685SAlan Cox err = usb_submit_urb(urb, GFP_ATOMIC); 1358deb91685SAlan Cox if (err != 0) 1359049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 13601da177e4SLinus Torvalds exit: 13611da177e4SLinus Torvalds ; 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds 13647d12e780SDavid Howells static void usa90_outcont_callback(struct urb *urb) 13651da177e4SLinus Torvalds { 13661da177e4SLinus Torvalds struct usb_serial_port *port; 13671da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 13681da177e4SLinus Torvalds 1369cdc97792SMing Lei port = urb->context; 13701da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 13711da177e4SLinus Torvalds 13721da177e4SLinus Torvalds if (p_priv->resend_cont) { 1373049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - sending setup\n", __func__); 1374deb91685SAlan Cox keyspan_usa90_send_setup(port->serial, port, 1375deb91685SAlan Cox p_priv->resend_cont - 1); 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds } 13781da177e4SLinus Torvalds 13790ca1268eSLucy McCoy /* Status messages from the 28xg */ 13800ca1268eSLucy McCoy static void usa67_instat_callback(struct urb *urb) 13810ca1268eSLucy McCoy { 13820ca1268eSLucy McCoy int err; 13830ca1268eSLucy McCoy unsigned char *data = urb->transfer_buffer; 13840ca1268eSLucy McCoy struct keyspan_usa67_portStatusMessage *msg; 13850ca1268eSLucy McCoy struct usb_serial *serial; 13860ca1268eSLucy McCoy struct usb_serial_port *port; 13870ca1268eSLucy McCoy struct keyspan_port_private *p_priv; 13880ca1268eSLucy McCoy int old_dcd_state; 138995b93454SGreg Kroah-Hartman int status = urb->status; 13900ca1268eSLucy McCoy 13910ca1268eSLucy McCoy serial = urb->context; 13920ca1268eSLucy McCoy 139395b93454SGreg Kroah-Hartman if (status) { 13940cd782b0SJohan Hovold dev_dbg(&urb->dev->dev, "%s - nonzero status: %d\n", 13950cd782b0SJohan Hovold __func__, status); 13960ca1268eSLucy McCoy return; 13970ca1268eSLucy McCoy } 13980ca1268eSLucy McCoy 1399deb91685SAlan Cox if (urb->actual_length != 1400deb91685SAlan Cox sizeof(struct keyspan_usa67_portStatusMessage)) { 1401049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - bad length %d\n", __func__, urb->actual_length); 14020ca1268eSLucy McCoy return; 14030ca1268eSLucy McCoy } 14040ca1268eSLucy McCoy 14050ca1268eSLucy McCoy 14060ca1268eSLucy McCoy /* Now do something useful with the data */ 14070ca1268eSLucy McCoy msg = (struct keyspan_usa67_portStatusMessage *)data; 14080ca1268eSLucy McCoy 14090ca1268eSLucy McCoy /* Check port number from message and retrieve private data */ 14100ca1268eSLucy McCoy if (msg->port >= serial->num_ports) { 1411049c6b4eSGreg Kroah-Hartman dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); 14120ca1268eSLucy McCoy return; 14130ca1268eSLucy McCoy } 14140ca1268eSLucy McCoy 14150ca1268eSLucy McCoy port = serial->port[msg->port]; 14160ca1268eSLucy McCoy p_priv = usb_get_serial_port_data(port); 1417b5122236SJohan Hovold if (!p_priv) 1418b5122236SJohan Hovold goto resubmit; 14190ca1268eSLucy McCoy 14200ca1268eSLucy McCoy /* Update handshaking pin state information */ 14210ca1268eSLucy McCoy old_dcd_state = p_priv->dcd_state; 14220ca1268eSLucy McCoy p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); 14230ca1268eSLucy McCoy p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); 14240ca1268eSLucy McCoy 1425aa27a094SJiri Slaby if (old_dcd_state != p_priv->dcd_state && old_dcd_state) 1426aa27a094SJiri Slaby tty_port_tty_hangup(&port->port, true); 1427b5122236SJohan Hovold resubmit: 14280ca1268eSLucy McCoy /* Resubmit urb so we continue receiving */ 14290ca1268eSLucy McCoy err = usb_submit_urb(urb, GFP_ATOMIC); 14300ca1268eSLucy McCoy if (err != 0) 1431049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - resubmit read urb failed. (%d)\n", __func__, err); 14320ca1268eSLucy McCoy } 14330ca1268eSLucy McCoy 14340ca1268eSLucy McCoy static void usa67_glocont_callback(struct urb *urb) 14350ca1268eSLucy McCoy { 14360ca1268eSLucy McCoy struct usb_serial *serial; 14370ca1268eSLucy McCoy struct usb_serial_port *port; 14380ca1268eSLucy McCoy struct keyspan_port_private *p_priv; 14390ca1268eSLucy McCoy int i; 14400ca1268eSLucy McCoy 14410ca1268eSLucy McCoy serial = urb->context; 14420ca1268eSLucy McCoy for (i = 0; i < serial->num_ports; ++i) { 14430ca1268eSLucy McCoy port = serial->port[i]; 14440ca1268eSLucy McCoy p_priv = usb_get_serial_port_data(port); 14453018dd3fSJohan Hovold if (!p_priv) 14463018dd3fSJohan Hovold continue; 14470ca1268eSLucy McCoy 14480ca1268eSLucy McCoy if (p_priv->resend_cont) { 1449049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - sending setup\n", __func__); 14500ca1268eSLucy McCoy keyspan_usa67_send_setup(serial, port, 14510ca1268eSLucy McCoy p_priv->resend_cont - 1); 14520ca1268eSLucy McCoy break; 14530ca1268eSLucy McCoy } 14540ca1268eSLucy McCoy } 14550ca1268eSLucy McCoy } 14560ca1268eSLucy McCoy 145794cc7aeaSJiri Slaby static unsigned int keyspan_write_room(struct tty_struct *tty) 14581da177e4SLinus Torvalds { 145995da310eSAlan Cox struct usb_serial_port *port = tty->driver_data; 14601da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 14611da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 14621da177e4SLinus Torvalds int flip; 146394cc7aeaSJiri Slaby unsigned int data_len; 14641da177e4SLinus Torvalds struct urb *this_urb; 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 14671da177e4SLinus Torvalds d_details = p_priv->device_details; 14681da177e4SLinus Torvalds 1469a5b6f60cSAlan Cox /* FIXME: locking */ 14701da177e4SLinus Torvalds if (d_details->msg_format == msg_usa90) 14711da177e4SLinus Torvalds data_len = 64; 14721da177e4SLinus Torvalds else 14731da177e4SLinus Torvalds data_len = 63; 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds flip = p_priv->out_flip; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds /* Check both endpoints to see if any are available. */ 1478deb91685SAlan Cox this_urb = p_priv->out_urbs[flip]; 1479deb91685SAlan Cox if (this_urb != NULL) { 14801da177e4SLinus Torvalds if (this_urb->status != -EINPROGRESS) 1481deb91685SAlan Cox return data_len; 14821da177e4SLinus Torvalds flip = (flip + 1) & d_details->outdat_endp_flip; 1483deb91685SAlan Cox this_urb = p_priv->out_urbs[flip]; 1484deb91685SAlan Cox if (this_urb != NULL) { 14851da177e4SLinus Torvalds if (this_urb->status != -EINPROGRESS) 1486deb91685SAlan Cox return data_len; 1487deb91685SAlan Cox } 14881da177e4SLinus Torvalds } 1489a5b6f60cSAlan Cox return 0; 14901da177e4SLinus Torvalds } 14911da177e4SLinus Torvalds 14921da177e4SLinus Torvalds 1493a509a7e4SAlan Cox static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) 14941da177e4SLinus Torvalds { 14951da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 14961da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 14971da177e4SLinus Torvalds int i, err; 1498f78ba157SAndrew Morton int baud_rate, device_port; 14991da177e4SLinus Torvalds struct urb *urb; 150095da310eSAlan Cox unsigned int cflag = 0; 15011da177e4SLinus Torvalds 15021da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 15031da177e4SLinus Torvalds d_details = p_priv->device_details; 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds /* Set some sane defaults */ 15061da177e4SLinus Torvalds p_priv->rts_state = 1; 15071da177e4SLinus Torvalds p_priv->dtr_state = 1; 15081da177e4SLinus Torvalds p_priv->baud = 9600; 15091da177e4SLinus Torvalds 15101da177e4SLinus Torvalds /* force baud and lcr to be set on open */ 15111da177e4SLinus Torvalds p_priv->old_baud = 0; 15121da177e4SLinus Torvalds p_priv->old_cflag = 0; 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds p_priv->out_flip = 0; 15151da177e4SLinus Torvalds p_priv->in_flip = 0; 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds /* Reset low level data toggle and start reading from endpoints */ 15181da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 1519deb91685SAlan Cox urb = p_priv->in_urbs[i]; 1520deb91685SAlan Cox if (urb == NULL) 15211da177e4SLinus Torvalds continue; 15221da177e4SLinus Torvalds 1523deb91685SAlan Cox /* make sure endpoint data toggle is synchronized 1524deb91685SAlan Cox with the device */ 15251da177e4SLinus Torvalds usb_clear_halt(urb->dev, urb->pipe); 1526deb91685SAlan Cox err = usb_submit_urb(urb, GFP_KERNEL); 1527deb91685SAlan Cox if (err != 0) 1528049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - submit urb %d failed (%d)\n", __func__, i, err); 15291da177e4SLinus Torvalds } 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds /* Reset low level data toggle on out endpoints */ 15321da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 1533deb91685SAlan Cox urb = p_priv->out_urbs[i]; 1534deb91685SAlan Cox if (urb == NULL) 15351da177e4SLinus Torvalds continue; 1536deb91685SAlan Cox /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), 1537deb91685SAlan Cox usb_pipeout(urb->pipe), 0); */ 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds 1540f78ba157SAndrew Morton /* get the terminal config for the setup message now so we don't 1541f78ba157SAndrew Morton * need to send 2 of them */ 1542f78ba157SAndrew Morton 15431143832eSGreg Kroah-Hartman device_port = port->port_number; 154495da310eSAlan Cox if (tty) { 1545adc8d746SAlan Cox cflag = tty->termios.c_cflag; 1546f78ba157SAndrew Morton /* Baud rate calculation takes baud rate as an integer 1547f78ba157SAndrew Morton so other rates can be generated if desired. */ 154895da310eSAlan Cox baud_rate = tty_get_baud_rate(tty); 1549f78ba157SAndrew Morton /* If no match or invalid, leave as default */ 1550f78ba157SAndrew Morton if (baud_rate >= 0 1551049c6b4eSGreg Kroah-Hartman && d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk, 1552f78ba157SAndrew Morton NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { 1553f78ba157SAndrew Morton p_priv->baud = baud_rate; 1554f78ba157SAndrew Morton } 155595da310eSAlan Cox } 1556f78ba157SAndrew Morton /* set CTS/RTS handshake etc. */ 1557f78ba157SAndrew Morton p_priv->cflag = cflag; 1558f78ba157SAndrew Morton p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none; 1559f78ba157SAndrew Morton 1560f78ba157SAndrew Morton keyspan_send_setup(port, 1); 1561deb91685SAlan Cox /* mdelay(100); */ 1562deb91685SAlan Cox /* keyspan_set_termios(port, NULL); */ 1563f78ba157SAndrew Morton 1564a5b6f60cSAlan Cox return 0; 15651da177e4SLinus Torvalds } 15661da177e4SLinus Torvalds 1567335f8514SAlan Cox static void keyspan_dtr_rts(struct usb_serial_port *port, int on) 1568335f8514SAlan Cox { 1569335f8514SAlan Cox struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); 1570335f8514SAlan Cox 1571335f8514SAlan Cox p_priv->rts_state = on; 1572335f8514SAlan Cox p_priv->dtr_state = on; 1573335f8514SAlan Cox keyspan_send_setup(port, 0); 1574335f8514SAlan Cox } 1575335f8514SAlan Cox 1576335f8514SAlan Cox static void keyspan_close(struct usb_serial_port *port) 15771da177e4SLinus Torvalds { 15781da177e4SLinus Torvalds int i; 15791da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds p_priv->rts_state = 0; 15841da177e4SLinus Torvalds p_priv->dtr_state = 0; 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds keyspan_send_setup(port, 2); 15871da177e4SLinus Torvalds /* pilot-xfer seems to work best with this delay */ 15881da177e4SLinus Torvalds mdelay(100); 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds p_priv->out_flip = 0; 15911da177e4SLinus Torvalds p_priv->in_flip = 0; 15921da177e4SLinus Torvalds 159361924505SJohan Hovold usb_kill_urb(p_priv->inack_urb); 15941da177e4SLinus Torvalds for (i = 0; i < 2; i++) { 159561924505SJohan Hovold usb_kill_urb(p_priv->in_urbs[i]); 159661924505SJohan Hovold usb_kill_urb(p_priv->out_urbs[i]); 15971da177e4SLinus Torvalds } 15981da177e4SLinus Torvalds } 15991da177e4SLinus Torvalds 16001da177e4SLinus Torvalds /* download the firmware to a pre-renumeration device */ 16011da177e4SLinus Torvalds static int keyspan_fake_startup(struct usb_serial *serial) 16021da177e4SLinus Torvalds { 16031da177e4SLinus Torvalds char *fw_name; 16041da177e4SLinus Torvalds 1605049c6b4eSGreg Kroah-Hartman dev_dbg(&serial->dev->dev, "Keyspan startup version %04x product %04x\n", 16061da177e4SLinus Torvalds le16_to_cpu(serial->dev->descriptor.bcdDevice), 16071da177e4SLinus Torvalds le16_to_cpu(serial->dev->descriptor.idProduct)); 16081da177e4SLinus Torvalds 1609deb91685SAlan Cox if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000) 1610deb91685SAlan Cox != 0x8000) { 1611049c6b4eSGreg Kroah-Hartman dev_dbg(&serial->dev->dev, "Firmware already loaded. Quitting.\n"); 1612deb91685SAlan Cox return 1; 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds 16151da177e4SLinus Torvalds /* Select firmware image on the basis of idProduct */ 16161da177e4SLinus Torvalds switch (le16_to_cpu(serial->dev->descriptor.idProduct)) { 16171da177e4SLinus Torvalds case keyspan_usa28_pre_product_id: 16182971c579SDavid Woodhouse fw_name = "keyspan/usa28.fw"; 16191da177e4SLinus Torvalds break; 16201da177e4SLinus Torvalds 16211da177e4SLinus Torvalds case keyspan_usa28x_pre_product_id: 16222971c579SDavid Woodhouse fw_name = "keyspan/usa28x.fw"; 16231da177e4SLinus Torvalds break; 16241da177e4SLinus Torvalds 16251da177e4SLinus Torvalds case keyspan_usa28xa_pre_product_id: 16262971c579SDavid Woodhouse fw_name = "keyspan/usa28xa.fw"; 16271da177e4SLinus Torvalds break; 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds case keyspan_usa28xb_pre_product_id: 16302971c579SDavid Woodhouse fw_name = "keyspan/usa28xb.fw"; 16311da177e4SLinus Torvalds break; 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds case keyspan_usa19_pre_product_id: 16342971c579SDavid Woodhouse fw_name = "keyspan/usa19.fw"; 16351da177e4SLinus Torvalds break; 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds case keyspan_usa19qi_pre_product_id: 16382971c579SDavid Woodhouse fw_name = "keyspan/usa19qi.fw"; 16391da177e4SLinus Torvalds break; 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds case keyspan_mpr_pre_product_id: 16422971c579SDavid Woodhouse fw_name = "keyspan/mpr.fw"; 16431da177e4SLinus Torvalds break; 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds case keyspan_usa19qw_pre_product_id: 16462971c579SDavid Woodhouse fw_name = "keyspan/usa19qw.fw"; 16471da177e4SLinus Torvalds break; 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds case keyspan_usa18x_pre_product_id: 16502971c579SDavid Woodhouse fw_name = "keyspan/usa18x.fw"; 16511da177e4SLinus Torvalds break; 16521da177e4SLinus Torvalds 16531da177e4SLinus Torvalds case keyspan_usa19w_pre_product_id: 16542971c579SDavid Woodhouse fw_name = "keyspan/usa19w.fw"; 16551da177e4SLinus Torvalds break; 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds case keyspan_usa49w_pre_product_id: 16582971c579SDavid Woodhouse fw_name = "keyspan/usa49w.fw"; 16591da177e4SLinus Torvalds break; 16601da177e4SLinus Torvalds 16611da177e4SLinus Torvalds case keyspan_usa49wlc_pre_product_id: 16622971c579SDavid Woodhouse fw_name = "keyspan/usa49wlc.fw"; 16631da177e4SLinus Torvalds break; 16641da177e4SLinus Torvalds 16651da177e4SLinus Torvalds default: 16662971c579SDavid Woodhouse dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n", 16672971c579SDavid Woodhouse le16_to_cpu(serial->dev->descriptor.idProduct)); 16682971c579SDavid Woodhouse return 1; 16691da177e4SLinus Torvalds } 16701da177e4SLinus Torvalds 1671049c6b4eSGreg Kroah-Hartman dev_dbg(&serial->dev->dev, "Uploading Keyspan %s firmware.\n", fw_name); 16721da177e4SLinus Torvalds 16738d733e26SRene Buergel if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { 16748d733e26SRene Buergel dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", 16758d733e26SRene Buergel fw_name); 16768d733e26SRene Buergel return -ENOENT; 16771da177e4SLinus Torvalds } 16781da177e4SLinus Torvalds 16798d733e26SRene Buergel /* after downloading firmware Renumeration will occur in a 16801da177e4SLinus Torvalds moment and the new device will bind to the real driver */ 16811da177e4SLinus Torvalds 16821da177e4SLinus Torvalds /* we don't want this device to have a driver assigned to it. */ 1683deb91685SAlan Cox return 1; 16841da177e4SLinus Torvalds } 16851da177e4SLinus Torvalds 16861da177e4SLinus Torvalds /* Helper functions used by keyspan_setup_urbs */ 1687fdcba53eSRainer Weikusat static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, 1688fdcba53eSRainer Weikusat int endpoint) 1689fdcba53eSRainer Weikusat { 1690fdcba53eSRainer Weikusat struct usb_host_interface *iface_desc; 1691fdcba53eSRainer Weikusat struct usb_endpoint_descriptor *ep; 1692fdcba53eSRainer Weikusat int i; 1693fdcba53eSRainer Weikusat 1694fdcba53eSRainer Weikusat iface_desc = serial->interface->cur_altsetting; 1695fdcba53eSRainer Weikusat for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 1696fdcba53eSRainer Weikusat ep = &iface_desc->endpoint[i].desc; 1697fdcba53eSRainer Weikusat if (ep->bEndpointAddress == endpoint) 1698fdcba53eSRainer Weikusat return ep; 1699fdcba53eSRainer Weikusat } 17000cd782b0SJohan Hovold dev_warn(&serial->interface->dev, "found no endpoint descriptor for endpoint %x\n", 17010cd782b0SJohan Hovold endpoint); 1702fdcba53eSRainer Weikusat return NULL; 1703fdcba53eSRainer Weikusat } 1704fdcba53eSRainer Weikusat 17051da177e4SLinus Torvalds static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, 17061da177e4SLinus Torvalds int dir, void *ctx, char *buf, int len, 17077d12e780SDavid Howells void (*callback)(struct urb *)) 17081da177e4SLinus Torvalds { 17091da177e4SLinus Torvalds struct urb *urb; 1710fdcba53eSRainer Weikusat struct usb_endpoint_descriptor const *ep_desc; 1711fdcba53eSRainer Weikusat char const *ep_type_name; 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds if (endpoint == -1) 17141da177e4SLinus Torvalds return NULL; /* endpoint not needed */ 17151da177e4SLinus Torvalds 17160cd782b0SJohan Hovold dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %x\n", 17170cd782b0SJohan Hovold __func__, endpoint); 17181da177e4SLinus Torvalds urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ 171910c642d0SJohan Hovold if (!urb) 17201da177e4SLinus Torvalds return NULL; 17211da177e4SLinus Torvalds 17220ca1268eSLucy McCoy if (endpoint == 0) { 17230ca1268eSLucy McCoy /* control EP filled in when used */ 17240ca1268eSLucy McCoy return urb; 17250ca1268eSLucy McCoy } 17260ca1268eSLucy McCoy 1727fdcba53eSRainer Weikusat ep_desc = find_ep(serial, endpoint); 1728fdcba53eSRainer Weikusat if (!ep_desc) { 17297d7e21faSJohan Hovold usb_free_urb(urb); 17307d7e21faSJohan Hovold return NULL; 1731fdcba53eSRainer Weikusat } 1732fdcba53eSRainer Weikusat if (usb_endpoint_xfer_int(ep_desc)) { 1733fdcba53eSRainer Weikusat ep_type_name = "INT"; 1734fdcba53eSRainer Weikusat usb_fill_int_urb(urb, serial->dev, 1735fdcba53eSRainer Weikusat usb_sndintpipe(serial->dev, endpoint) | dir, 1736fdcba53eSRainer Weikusat buf, len, callback, ctx, 1737fdcba53eSRainer Weikusat ep_desc->bInterval); 1738fdcba53eSRainer Weikusat } else if (usb_endpoint_xfer_bulk(ep_desc)) { 1739fdcba53eSRainer Weikusat ep_type_name = "BULK"; 17401da177e4SLinus Torvalds usb_fill_bulk_urb(urb, serial->dev, 17411da177e4SLinus Torvalds usb_sndbulkpipe(serial->dev, endpoint) | dir, 17421da177e4SLinus Torvalds buf, len, callback, ctx); 1743fdcba53eSRainer Weikusat } else { 1744fdcba53eSRainer Weikusat dev_warn(&serial->interface->dev, 1745fdcba53eSRainer Weikusat "unsupported endpoint type %x\n", 17462e0fe709SJulia Lawall usb_endpoint_type(ep_desc)); 1747fdcba53eSRainer Weikusat usb_free_urb(urb); 1748fdcba53eSRainer Weikusat return NULL; 1749fdcba53eSRainer Weikusat } 17501da177e4SLinus Torvalds 1751049c6b4eSGreg Kroah-Hartman dev_dbg(&serial->interface->dev, "%s - using urb %p for %s endpoint %x\n", 1752fdcba53eSRainer Weikusat __func__, urb, ep_type_name, endpoint); 17531da177e4SLinus Torvalds return urb; 17541da177e4SLinus Torvalds } 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds static struct callbacks { 17577d12e780SDavid Howells void (*instat_callback)(struct urb *); 17587d12e780SDavid Howells void (*glocont_callback)(struct urb *); 17597d12e780SDavid Howells void (*indat_callback)(struct urb *); 17607d12e780SDavid Howells void (*outdat_callback)(struct urb *); 17617d12e780SDavid Howells void (*inack_callback)(struct urb *); 17627d12e780SDavid Howells void (*outcont_callback)(struct urb *); 17631da177e4SLinus Torvalds } keyspan_callbacks[] = { 17641da177e4SLinus Torvalds { 17651da177e4SLinus Torvalds /* msg_usa26 callbacks */ 17661da177e4SLinus Torvalds .instat_callback = usa26_instat_callback, 17671da177e4SLinus Torvalds .glocont_callback = usa26_glocont_callback, 17681da177e4SLinus Torvalds .indat_callback = usa26_indat_callback, 17691da177e4SLinus Torvalds .outdat_callback = usa2x_outdat_callback, 17701da177e4SLinus Torvalds .inack_callback = usa26_inack_callback, 17711da177e4SLinus Torvalds .outcont_callback = usa26_outcont_callback, 17721da177e4SLinus Torvalds }, { 17731da177e4SLinus Torvalds /* msg_usa28 callbacks */ 17741da177e4SLinus Torvalds .instat_callback = usa28_instat_callback, 17751da177e4SLinus Torvalds .glocont_callback = usa28_glocont_callback, 17761da177e4SLinus Torvalds .indat_callback = usa28_indat_callback, 17771da177e4SLinus Torvalds .outdat_callback = usa2x_outdat_callback, 17781da177e4SLinus Torvalds .inack_callback = usa28_inack_callback, 17791da177e4SLinus Torvalds .outcont_callback = usa28_outcont_callback, 17801da177e4SLinus Torvalds }, { 17811da177e4SLinus Torvalds /* msg_usa49 callbacks */ 17821da177e4SLinus Torvalds .instat_callback = usa49_instat_callback, 17831da177e4SLinus Torvalds .glocont_callback = usa49_glocont_callback, 17841da177e4SLinus Torvalds .indat_callback = usa49_indat_callback, 17851da177e4SLinus Torvalds .outdat_callback = usa2x_outdat_callback, 17861da177e4SLinus Torvalds .inack_callback = usa49_inack_callback, 17871da177e4SLinus Torvalds .outcont_callback = usa49_outcont_callback, 17881da177e4SLinus Torvalds }, { 17891da177e4SLinus Torvalds /* msg_usa90 callbacks */ 17901da177e4SLinus Torvalds .instat_callback = usa90_instat_callback, 17911da177e4SLinus Torvalds .glocont_callback = usa28_glocont_callback, 17921da177e4SLinus Torvalds .indat_callback = usa90_indat_callback, 17931da177e4SLinus Torvalds .outdat_callback = usa2x_outdat_callback, 17941da177e4SLinus Torvalds .inack_callback = usa28_inack_callback, 17951da177e4SLinus Torvalds .outcont_callback = usa90_outcont_callback, 17960ca1268eSLucy McCoy }, { 17970ca1268eSLucy McCoy /* msg_usa67 callbacks */ 17980ca1268eSLucy McCoy .instat_callback = usa67_instat_callback, 17990ca1268eSLucy McCoy .glocont_callback = usa67_glocont_callback, 18000ca1268eSLucy McCoy .indat_callback = usa26_indat_callback, 18010ca1268eSLucy McCoy .outdat_callback = usa2x_outdat_callback, 18020ca1268eSLucy McCoy .inack_callback = usa26_inack_callback, 18030ca1268eSLucy McCoy .outcont_callback = usa26_outcont_callback, 18041da177e4SLinus Torvalds } 18051da177e4SLinus Torvalds }; 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds /* Generic setup urbs function that uses 18081da177e4SLinus Torvalds data in device_details */ 18091da177e4SLinus Torvalds static void keyspan_setup_urbs(struct usb_serial *serial) 18101da177e4SLinus Torvalds { 18111da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 18121da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 18131da177e4SLinus Torvalds struct callbacks *cback; 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 18161da177e4SLinus Torvalds d_details = s_priv->device_details; 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds /* Setup values for the various callback routines */ 18191da177e4SLinus Torvalds cback = &keyspan_callbacks[d_details->msg_format]; 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds /* Allocate and set up urbs for each one that is in use, 18221da177e4SLinus Torvalds starting with instat endpoints */ 18231da177e4SLinus Torvalds s_priv->instat_urb = keyspan_setup_urb 18241da177e4SLinus Torvalds (serial, d_details->instat_endpoint, USB_DIR_IN, 18251da177e4SLinus Torvalds serial, s_priv->instat_buf, INSTAT_BUFLEN, 18261da177e4SLinus Torvalds cback->instat_callback); 18271da177e4SLinus Torvalds 18280ca1268eSLucy McCoy s_priv->indat_urb = keyspan_setup_urb 18290ca1268eSLucy McCoy (serial, d_details->indat_endpoint, USB_DIR_IN, 18300ca1268eSLucy McCoy serial, s_priv->indat_buf, INDAT49W_BUFLEN, 18310ca1268eSLucy McCoy usa49wg_indat_callback); 18320ca1268eSLucy McCoy 18331da177e4SLinus Torvalds s_priv->glocont_urb = keyspan_setup_urb 18341da177e4SLinus Torvalds (serial, d_details->glocont_endpoint, USB_DIR_OUT, 18351da177e4SLinus Torvalds serial, s_priv->glocont_buf, GLOCONT_BUFLEN, 18361da177e4SLinus Torvalds cback->glocont_callback); 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds /* usa19 function doesn't require prescaler */ 1840049c6b4eSGreg Kroah-Hartman static int keyspan_usa19_calc_baud(struct usb_serial_port *port, 1841049c6b4eSGreg Kroah-Hartman u32 baud_rate, u32 baudclk, u8 *rate_hi, 18421da177e4SLinus Torvalds u8 *rate_low, u8 *prescaler, int portnum) 18431da177e4SLinus Torvalds { 18441da177e4SLinus Torvalds u32 b16, /* baud rate times 16 (actual rate used internally) */ 18451da177e4SLinus Torvalds div, /* divisor */ 18461da177e4SLinus Torvalds cnt; /* inverse of divisor (programmed into 8051) */ 18471da177e4SLinus Torvalds 1848049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds /* prevent divide by zero... */ 1851deb91685SAlan Cox b16 = baud_rate * 16L; 1852deb91685SAlan Cox if (b16 == 0) 1853deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 18541da177e4SLinus Torvalds /* Any "standard" rate over 57k6 is marginal on the USA-19 18551da177e4SLinus Torvalds as we run out of divisor resolution. */ 1856deb91685SAlan Cox if (baud_rate > 57600) 1857deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds /* calculate the divisor and the counter (its inverse) */ 1860deb91685SAlan Cox div = baudclk / b16; 1861deb91685SAlan Cox if (div == 0) 1862deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 1863deb91685SAlan Cox else 18641da177e4SLinus Torvalds cnt = 0 - div; 18651da177e4SLinus Torvalds 1866deb91685SAlan Cox if (div > 0xffff) 1867deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 18681da177e4SLinus Torvalds 18691da177e4SLinus Torvalds /* return the counter values if non-null */ 1870deb91685SAlan Cox if (rate_low) 18711da177e4SLinus Torvalds *rate_low = (u8) (cnt & 0xff); 1872deb91685SAlan Cox if (rate_hi) 18731da177e4SLinus Torvalds *rate_hi = (u8) ((cnt >> 8) & 0xff); 1874deb91685SAlan Cox if (rate_low && rate_hi) 1875049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d %02x %02x.\n", 1876deb91685SAlan Cox __func__, baud_rate, *rate_hi, *rate_low); 1877deb91685SAlan Cox return KEYSPAN_BAUD_RATE_OK; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds /* usa19hs function doesn't require prescaler */ 1881049c6b4eSGreg Kroah-Hartman static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, 1882049c6b4eSGreg Kroah-Hartman u32 baud_rate, u32 baudclk, u8 *rate_hi, 18831da177e4SLinus Torvalds u8 *rate_low, u8 *prescaler, int portnum) 18841da177e4SLinus Torvalds { 18851da177e4SLinus Torvalds u32 b16, /* baud rate times 16 (actual rate used internally) */ 18861da177e4SLinus Torvalds div; /* divisor */ 18871da177e4SLinus Torvalds 1888049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); 18891da177e4SLinus Torvalds 18901da177e4SLinus Torvalds /* prevent divide by zero... */ 1891deb91685SAlan Cox b16 = baud_rate * 16L; 1892deb91685SAlan Cox if (b16 == 0) 1893deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 18941da177e4SLinus Torvalds 18951da177e4SLinus Torvalds /* calculate the divisor */ 1896deb91685SAlan Cox div = baudclk / b16; 1897deb91685SAlan Cox if (div == 0) 1898deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 18991da177e4SLinus Torvalds 19001da177e4SLinus Torvalds if (div > 0xffff) 1901deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 19021da177e4SLinus Torvalds 19031da177e4SLinus Torvalds /* return the counter values if non-null */ 19041da177e4SLinus Torvalds if (rate_low) 19051da177e4SLinus Torvalds *rate_low = (u8) (div & 0xff); 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds if (rate_hi) 19081da177e4SLinus Torvalds *rate_hi = (u8) ((div >> 8) & 0xff); 19091da177e4SLinus Torvalds 19101da177e4SLinus Torvalds if (rate_low && rate_hi) 1911049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d %02x %02x.\n", 1912deb91685SAlan Cox __func__, baud_rate, *rate_hi, *rate_low); 19131da177e4SLinus Torvalds 1914deb91685SAlan Cox return KEYSPAN_BAUD_RATE_OK; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds 1917049c6b4eSGreg Kroah-Hartman static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, 1918049c6b4eSGreg Kroah-Hartman u32 baud_rate, u32 baudclk, u8 *rate_hi, 19191da177e4SLinus Torvalds u8 *rate_low, u8 *prescaler, int portnum) 19201da177e4SLinus Torvalds { 19211da177e4SLinus Torvalds u32 b16, /* baud rate times 16 (actual rate used internally) */ 19221da177e4SLinus Torvalds clk, /* clock with 13/8 prescaler */ 19231da177e4SLinus Torvalds div, /* divisor using 13/8 prescaler */ 19241da177e4SLinus Torvalds res, /* resulting baud rate using 13/8 prescaler */ 19251da177e4SLinus Torvalds diff, /* error using 13/8 prescaler */ 19261da177e4SLinus Torvalds smallest_diff; 19271da177e4SLinus Torvalds u8 best_prescaler; 19281da177e4SLinus Torvalds int i; 19291da177e4SLinus Torvalds 1930049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); 19311da177e4SLinus Torvalds 19321da177e4SLinus Torvalds /* prevent divide by zero */ 1933deb91685SAlan Cox b16 = baud_rate * 16L; 1934deb91685SAlan Cox if (b16 == 0) 1935deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 19361da177e4SLinus Torvalds 19371da177e4SLinus Torvalds /* Calculate prescaler by trying them all and looking 19381da177e4SLinus Torvalds for best fit */ 19391da177e4SLinus Torvalds 19401da177e4SLinus Torvalds /* start with largest possible difference */ 19411da177e4SLinus Torvalds smallest_diff = 0xffffffff; 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds /* 0 is an invalid prescaler, used as a flag */ 19441da177e4SLinus Torvalds best_prescaler = 0; 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds for (i = 8; i <= 0xff; ++i) { 19471da177e4SLinus Torvalds clk = (baudclk * 8) / (u32) i; 19481da177e4SLinus Torvalds 1949deb91685SAlan Cox div = clk / b16; 1950deb91685SAlan Cox if (div == 0) 19511da177e4SLinus Torvalds continue; 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds res = clk / div; 19541da177e4SLinus Torvalds diff = (res > b16) ? (res-b16) : (b16-res); 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds if (diff < smallest_diff) { 19571da177e4SLinus Torvalds best_prescaler = i; 19581da177e4SLinus Torvalds smallest_diff = diff; 19591da177e4SLinus Torvalds } 19601da177e4SLinus Torvalds } 19611da177e4SLinus Torvalds 1962deb91685SAlan Cox if (best_prescaler == 0) 1963deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds clk = (baudclk * 8) / (u32) best_prescaler; 19661da177e4SLinus Torvalds div = clk / b16; 19671da177e4SLinus Torvalds 19681da177e4SLinus Torvalds /* return the divisor and prescaler if non-null */ 1969deb91685SAlan Cox if (rate_low) 19701da177e4SLinus Torvalds *rate_low = (u8) (div & 0xff); 1971deb91685SAlan Cox if (rate_hi) 19721da177e4SLinus Torvalds *rate_hi = (u8) ((div >> 8) & 0xff); 19731da177e4SLinus Torvalds if (prescaler) { 19741da177e4SLinus Torvalds *prescaler = best_prescaler; 1975049c6b4eSGreg Kroah-Hartman /* dev_dbg(&port->dev, "%s - %d %d\n", __func__, *prescaler, div); */ 19761da177e4SLinus Torvalds } 1977deb91685SAlan Cox return KEYSPAN_BAUD_RATE_OK; 19781da177e4SLinus Torvalds } 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds /* USA-28 supports different maximum baud rates on each port */ 1981049c6b4eSGreg Kroah-Hartman static int keyspan_usa28_calc_baud(struct usb_serial_port *port, 1982049c6b4eSGreg Kroah-Hartman u32 baud_rate, u32 baudclk, u8 *rate_hi, 19831da177e4SLinus Torvalds u8 *rate_low, u8 *prescaler, int portnum) 19841da177e4SLinus Torvalds { 19851da177e4SLinus Torvalds u32 b16, /* baud rate times 16 (actual rate used internally) */ 19861da177e4SLinus Torvalds div, /* divisor */ 19871da177e4SLinus Torvalds cnt; /* inverse of divisor (programmed into 8051) */ 19881da177e4SLinus Torvalds 1989049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d.\n", __func__, baud_rate); 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds /* prevent divide by zero */ 1992deb91685SAlan Cox b16 = baud_rate * 16L; 1993deb91685SAlan Cox if (b16 == 0) 1994deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds /* calculate the divisor and the counter (its inverse) */ 1997deb91685SAlan Cox div = KEYSPAN_USA28_BAUDCLK / b16; 1998deb91685SAlan Cox if (div == 0) 1999deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 2000deb91685SAlan Cox else 20011da177e4SLinus Torvalds cnt = 0 - div; 20021da177e4SLinus Torvalds 20031da177e4SLinus Torvalds /* check for out of range, based on portnum, 20041da177e4SLinus Torvalds and return result */ 20051da177e4SLinus Torvalds if (portnum == 0) { 20061da177e4SLinus Torvalds if (div > 0xffff) 2007deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 2008deb91685SAlan Cox } else { 20091da177e4SLinus Torvalds if (portnum == 1) { 2010deb91685SAlan Cox if (div > 0xff) 2011deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 2012deb91685SAlan Cox } else 2013deb91685SAlan Cox return KEYSPAN_INVALID_BAUD_RATE; 20141da177e4SLinus Torvalds } 20151da177e4SLinus Torvalds 20161da177e4SLinus Torvalds /* return the counter values if not NULL 20171da177e4SLinus Torvalds (port 1 will ignore retHi) */ 2018deb91685SAlan Cox if (rate_low) 20191da177e4SLinus Torvalds *rate_low = (u8) (cnt & 0xff); 2020deb91685SAlan Cox if (rate_hi) 20211da177e4SLinus Torvalds *rate_hi = (u8) ((cnt >> 8) & 0xff); 2022049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - %d OK.\n", __func__, baud_rate); 2023deb91685SAlan Cox return KEYSPAN_BAUD_RATE_OK; 20241da177e4SLinus Torvalds } 20251da177e4SLinus Torvalds 20261da177e4SLinus Torvalds static int keyspan_usa26_send_setup(struct usb_serial *serial, 20271da177e4SLinus Torvalds struct usb_serial_port *port, 20281da177e4SLinus Torvalds int reset_port) 20291da177e4SLinus Torvalds { 20301da177e4SLinus Torvalds struct keyspan_usa26_portControlMessage msg; 20311da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 20321da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 20331da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 20341da177e4SLinus Torvalds struct urb *this_urb; 20351da177e4SLinus Torvalds int device_port, err; 20361da177e4SLinus Torvalds 2037049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s reset=%d\n", __func__, reset_port); 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 20401da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 20411da177e4SLinus Torvalds d_details = s_priv->device_details; 20421143832eSGreg Kroah-Hartman device_port = port->port_number; 20431da177e4SLinus Torvalds 20441da177e4SLinus Torvalds this_urb = p_priv->outcont_urb; 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds /* Make sure we have an urb then send the message */ 20471da177e4SLinus Torvalds if (this_urb == NULL) { 2048049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); 20491da177e4SLinus Torvalds return -1; 20501da177e4SLinus Torvalds } 20511da177e4SLinus Torvalds 20520cd782b0SJohan Hovold dev_dbg(&port->dev, "%s - endpoint %x\n", 20530cd782b0SJohan Hovold __func__, usb_pipeendpoint(this_urb->pipe)); 2054d5afce82SRickard Strandqvist 20551da177e4SLinus Torvalds /* Save reset port val for resend. 20560ca1268eSLucy McCoy Don't overwrite resend for open/close condition. */ 20570ca1268eSLucy McCoy if ((reset_port + 1) > p_priv->resend_cont) 20581da177e4SLinus Torvalds p_priv->resend_cont = reset_port + 1; 20591da177e4SLinus Torvalds if (this_urb->status == -EINPROGRESS) { 2060049c6b4eSGreg Kroah-Hartman /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ 20611da177e4SLinus Torvalds mdelay(5); 2062deb91685SAlan Cox return -1; 20631da177e4SLinus Torvalds } 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage)); 20661da177e4SLinus Torvalds 20671da177e4SLinus Torvalds /* Only set baud rate if it's changed */ 20681da177e4SLinus Torvalds if (p_priv->old_baud != p_priv->baud) { 20691da177e4SLinus Torvalds p_priv->old_baud = p_priv->baud; 20701da177e4SLinus Torvalds msg.setClocking = 0xff; 2071049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 2072049c6b4eSGreg Kroah-Hartman &msg.baudHi, &msg.baudLo, &msg.prescaler, 2073049c6b4eSGreg Kroah-Hartman device_port) == KEYSPAN_INVALID_BAUD_RATE) { 2074049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", 2075deb91685SAlan Cox __func__, p_priv->baud); 20761da177e4SLinus Torvalds msg.baudLo = 0; 20771da177e4SLinus Torvalds msg.baudHi = 125; /* Values for 9600 baud */ 20781da177e4SLinus Torvalds msg.prescaler = 10; 20791da177e4SLinus Torvalds } 20801da177e4SLinus Torvalds msg.setPrescaler = 0xff; 20811da177e4SLinus Torvalds } 20821da177e4SLinus Torvalds 20831da177e4SLinus Torvalds msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; 20841da177e4SLinus Torvalds switch (p_priv->cflag & CSIZE) { 20851da177e4SLinus Torvalds case CS5: 20861da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_5; 20871da177e4SLinus Torvalds break; 20881da177e4SLinus Torvalds case CS6: 20891da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_6; 20901da177e4SLinus Torvalds break; 20911da177e4SLinus Torvalds case CS7: 20921da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_7; 20931da177e4SLinus Torvalds break; 20941da177e4SLinus Torvalds case CS8: 20951da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_8; 20961da177e4SLinus Torvalds break; 20971da177e4SLinus Torvalds } 20981da177e4SLinus Torvalds if (p_priv->cflag & PARENB) { 20991da177e4SLinus Torvalds /* note USA_PARITY_NONE == 0 */ 21001da177e4SLinus Torvalds msg.lcr |= (p_priv->cflag & PARODD) ? 21011da177e4SLinus Torvalds USA_PARITY_ODD : USA_PARITY_EVEN; 21021da177e4SLinus Torvalds } 21031da177e4SLinus Torvalds msg.setLcr = 0xff; 21041da177e4SLinus Torvalds 21051da177e4SLinus Torvalds msg.ctsFlowControl = (p_priv->flow_control == flow_cts); 21061da177e4SLinus Torvalds msg.xonFlowControl = 0; 21071da177e4SLinus Torvalds msg.setFlowControl = 0xff; 21081da177e4SLinus Torvalds msg.forwardingLength = 16; 21091da177e4SLinus Torvalds msg.xonChar = 17; 21101da177e4SLinus Torvalds msg.xoffChar = 19; 21111da177e4SLinus Torvalds 21121da177e4SLinus Torvalds /* Opening port */ 21131da177e4SLinus Torvalds if (reset_port == 1) { 21141da177e4SLinus Torvalds msg._txOn = 1; 21151da177e4SLinus Torvalds msg._txOff = 0; 21161da177e4SLinus Torvalds msg.txFlush = 0; 21171da177e4SLinus Torvalds msg.txBreak = 0; 21181da177e4SLinus Torvalds msg.rxOn = 1; 21191da177e4SLinus Torvalds msg.rxOff = 0; 21201da177e4SLinus Torvalds msg.rxFlush = 1; 21211da177e4SLinus Torvalds msg.rxForward = 0; 21221da177e4SLinus Torvalds msg.returnStatus = 0; 21231da177e4SLinus Torvalds msg.resetDataToggle = 0xff; 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds /* Closing port */ 21271da177e4SLinus Torvalds else if (reset_port == 2) { 21281da177e4SLinus Torvalds msg._txOn = 0; 21291da177e4SLinus Torvalds msg._txOff = 1; 21301da177e4SLinus Torvalds msg.txFlush = 0; 21311da177e4SLinus Torvalds msg.txBreak = 0; 21321da177e4SLinus Torvalds msg.rxOn = 0; 21331da177e4SLinus Torvalds msg.rxOff = 1; 21341da177e4SLinus Torvalds msg.rxFlush = 1; 21351da177e4SLinus Torvalds msg.rxForward = 0; 21361da177e4SLinus Torvalds msg.returnStatus = 0; 21371da177e4SLinus Torvalds msg.resetDataToggle = 0; 21381da177e4SLinus Torvalds } 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds /* Sending intermediate configs */ 21411da177e4SLinus Torvalds else { 21421da177e4SLinus Torvalds msg._txOn = (!p_priv->break_on); 21431da177e4SLinus Torvalds msg._txOff = 0; 21441da177e4SLinus Torvalds msg.txFlush = 0; 21451da177e4SLinus Torvalds msg.txBreak = (p_priv->break_on); 21461da177e4SLinus Torvalds msg.rxOn = 0; 21471da177e4SLinus Torvalds msg.rxOff = 0; 21481da177e4SLinus Torvalds msg.rxFlush = 0; 21491da177e4SLinus Torvalds msg.rxForward = 0; 21501da177e4SLinus Torvalds msg.returnStatus = 0; 21511da177e4SLinus Torvalds msg.resetDataToggle = 0x0; 21521da177e4SLinus Torvalds } 21531da177e4SLinus Torvalds 21541da177e4SLinus Torvalds /* Do handshaking outputs */ 21551da177e4SLinus Torvalds msg.setTxTriState_setRts = 0xff; 21561da177e4SLinus Torvalds msg.txTriState_rts = p_priv->rts_state; 21571da177e4SLinus Torvalds 21581da177e4SLinus Torvalds msg.setHskoa_setDtr = 0xff; 21591da177e4SLinus Torvalds msg.hskoa_dtr = p_priv->dtr_state; 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds p_priv->resend_cont = 0; 21621da177e4SLinus Torvalds memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds /* send the data out the device on control endpoint */ 21651da177e4SLinus Torvalds this_urb->transfer_buffer_length = sizeof(msg); 21661da177e4SLinus Torvalds 2167deb91685SAlan Cox err = usb_submit_urb(this_urb, GFP_ATOMIC); 2168deb91685SAlan Cox if (err != 0) 2169049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); 2170a5b6f60cSAlan Cox return 0; 21711da177e4SLinus Torvalds } 21721da177e4SLinus Torvalds 21731da177e4SLinus Torvalds static int keyspan_usa28_send_setup(struct usb_serial *serial, 21741da177e4SLinus Torvalds struct usb_serial_port *port, 21751da177e4SLinus Torvalds int reset_port) 21761da177e4SLinus Torvalds { 21771da177e4SLinus Torvalds struct keyspan_usa28_portControlMessage msg; 21781da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 21791da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 21801da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 21811da177e4SLinus Torvalds struct urb *this_urb; 21821da177e4SLinus Torvalds int device_port, err; 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 21851da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 21861da177e4SLinus Torvalds d_details = s_priv->device_details; 21871143832eSGreg Kroah-Hartman device_port = port->port_number; 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2190deb91685SAlan Cox this_urb = p_priv->outcont_urb; 2191deb91685SAlan Cox if (this_urb == NULL) { 2192049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); 21931da177e4SLinus Torvalds return -1; 21941da177e4SLinus Torvalds } 21951da177e4SLinus Torvalds 21961da177e4SLinus Torvalds /* Save reset port val for resend. 21970ca1268eSLucy McCoy Don't overwrite resend for open/close condition. */ 21980ca1268eSLucy McCoy if ((reset_port + 1) > p_priv->resend_cont) 21991da177e4SLinus Torvalds p_priv->resend_cont = reset_port + 1; 22001da177e4SLinus Torvalds if (this_urb->status == -EINPROGRESS) { 2201049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s already writing\n", __func__); 22021da177e4SLinus Torvalds mdelay(5); 2203deb91685SAlan Cox return -1; 22041da177e4SLinus Torvalds } 22051da177e4SLinus Torvalds 22061da177e4SLinus Torvalds memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage)); 22071da177e4SLinus Torvalds 22081da177e4SLinus Torvalds msg.setBaudRate = 1; 2209049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 2210049c6b4eSGreg Kroah-Hartman &msg.baudHi, &msg.baudLo, NULL, 2211049c6b4eSGreg Kroah-Hartman device_port) == KEYSPAN_INVALID_BAUD_RATE) { 2212049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - Invalid baud rate requested %d.\n", 2213deb91685SAlan Cox __func__, p_priv->baud); 22141da177e4SLinus Torvalds msg.baudLo = 0xff; 22151da177e4SLinus Torvalds msg.baudHi = 0xb2; /* Values for 9600 baud */ 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds /* If parity is enabled, we must calculate it ourselves. */ 22191da177e4SLinus Torvalds msg.parity = 0; /* XXX for now */ 22201da177e4SLinus Torvalds 22211da177e4SLinus Torvalds msg.ctsFlowControl = (p_priv->flow_control == flow_cts); 22221da177e4SLinus Torvalds msg.xonFlowControl = 0; 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds /* Do handshaking outputs, DTR is inverted relative to RTS */ 22251da177e4SLinus Torvalds msg.rts = p_priv->rts_state; 22261da177e4SLinus Torvalds msg.dtr = p_priv->dtr_state; 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds msg.forwardingLength = 16; 22291da177e4SLinus Torvalds msg.forwardMs = 10; 22301da177e4SLinus Torvalds msg.breakThreshold = 45; 22311da177e4SLinus Torvalds msg.xonChar = 17; 22321da177e4SLinus Torvalds msg.xoffChar = 19; 22331da177e4SLinus Torvalds 22341da177e4SLinus Torvalds /*msg.returnStatus = 1; 22351da177e4SLinus Torvalds msg.resetDataToggle = 0xff;*/ 22361da177e4SLinus Torvalds /* Opening port */ 22371da177e4SLinus Torvalds if (reset_port == 1) { 22381da177e4SLinus Torvalds msg._txOn = 1; 22391da177e4SLinus Torvalds msg._txOff = 0; 22401da177e4SLinus Torvalds msg.txFlush = 0; 22411da177e4SLinus Torvalds msg.txForceXoff = 0; 22421da177e4SLinus Torvalds msg.txBreak = 0; 22431da177e4SLinus Torvalds msg.rxOn = 1; 22441da177e4SLinus Torvalds msg.rxOff = 0; 22451da177e4SLinus Torvalds msg.rxFlush = 1; 22461da177e4SLinus Torvalds msg.rxForward = 0; 22471da177e4SLinus Torvalds msg.returnStatus = 0; 22481da177e4SLinus Torvalds msg.resetDataToggle = 0xff; 22491da177e4SLinus Torvalds } 22501da177e4SLinus Torvalds /* Closing port */ 22511da177e4SLinus Torvalds else if (reset_port == 2) { 22521da177e4SLinus Torvalds msg._txOn = 0; 22531da177e4SLinus Torvalds msg._txOff = 1; 22541da177e4SLinus Torvalds msg.txFlush = 0; 22551da177e4SLinus Torvalds msg.txForceXoff = 0; 22561da177e4SLinus Torvalds msg.txBreak = 0; 22571da177e4SLinus Torvalds msg.rxOn = 0; 22581da177e4SLinus Torvalds msg.rxOff = 1; 22591da177e4SLinus Torvalds msg.rxFlush = 1; 22601da177e4SLinus Torvalds msg.rxForward = 0; 22611da177e4SLinus Torvalds msg.returnStatus = 0; 22621da177e4SLinus Torvalds msg.resetDataToggle = 0; 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds /* Sending intermediate configs */ 22651da177e4SLinus Torvalds else { 22661da177e4SLinus Torvalds msg._txOn = (!p_priv->break_on); 22671da177e4SLinus Torvalds msg._txOff = 0; 22681da177e4SLinus Torvalds msg.txFlush = 0; 22691da177e4SLinus Torvalds msg.txForceXoff = 0; 22701da177e4SLinus Torvalds msg.txBreak = (p_priv->break_on); 22711da177e4SLinus Torvalds msg.rxOn = 0; 22721da177e4SLinus Torvalds msg.rxOff = 0; 22731da177e4SLinus Torvalds msg.rxFlush = 0; 22741da177e4SLinus Torvalds msg.rxForward = 0; 22751da177e4SLinus Torvalds msg.returnStatus = 0; 22761da177e4SLinus Torvalds msg.resetDataToggle = 0x0; 22771da177e4SLinus Torvalds } 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds p_priv->resend_cont = 0; 22801da177e4SLinus Torvalds memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); 22811da177e4SLinus Torvalds 22821da177e4SLinus Torvalds /* send the data out the device on control endpoint */ 22831da177e4SLinus Torvalds this_urb->transfer_buffer_length = sizeof(msg); 22841da177e4SLinus Torvalds 2285deb91685SAlan Cox err = usb_submit_urb(this_urb, GFP_ATOMIC); 2286deb91685SAlan Cox if (err != 0) 2287049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__); 22881da177e4SLinus Torvalds 2289a5b6f60cSAlan Cox return 0; 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 22921da177e4SLinus Torvalds static int keyspan_usa49_send_setup(struct usb_serial *serial, 22931da177e4SLinus Torvalds struct usb_serial_port *port, 22941da177e4SLinus Torvalds int reset_port) 22951da177e4SLinus Torvalds { 22961da177e4SLinus Torvalds struct keyspan_usa49_portControlMessage msg; 22970ca1268eSLucy McCoy struct usb_ctrlrequest *dr = NULL; 22981da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 22991da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 23001da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 23011da177e4SLinus Torvalds struct urb *this_urb; 23021da177e4SLinus Torvalds int err, device_port; 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 23051da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 23061da177e4SLinus Torvalds d_details = s_priv->device_details; 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds this_urb = s_priv->glocont_urb; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds /* Work out which port within the device is being setup */ 23111143832eSGreg Kroah-Hartman device_port = port->port_number; 23121da177e4SLinus Torvalds 23131da177e4SLinus Torvalds /* Make sure we have an urb then send the message */ 23141da177e4SLinus Torvalds if (this_urb == NULL) { 23151143832eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__); 23161da177e4SLinus Torvalds return -1; 23171da177e4SLinus Torvalds } 23181da177e4SLinus Torvalds 23190cd782b0SJohan Hovold dev_dbg(&port->dev, "%s - endpoint %x (%d)\n", 23201143832eSGreg Kroah-Hartman __func__, usb_pipeendpoint(this_urb->pipe), device_port); 2321d866150aSHuzaifa Sidhpurwala 23221da177e4SLinus Torvalds /* Save reset port val for resend. 23230ca1268eSLucy McCoy Don't overwrite resend for open/close condition. */ 23240ca1268eSLucy McCoy if ((reset_port + 1) > p_priv->resend_cont) 23251da177e4SLinus Torvalds p_priv->resend_cont = reset_port + 1; 23260ca1268eSLucy McCoy 23271da177e4SLinus Torvalds if (this_urb->status == -EINPROGRESS) { 2328049c6b4eSGreg Kroah-Hartman /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ 23291da177e4SLinus Torvalds mdelay(5); 2330deb91685SAlan Cox return -1; 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds 23331da177e4SLinus Torvalds memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage)); 23341da177e4SLinus Torvalds 23351da177e4SLinus Torvalds msg.portNumber = device_port; 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds /* Only set baud rate if it's changed */ 23381da177e4SLinus Torvalds if (p_priv->old_baud != p_priv->baud) { 23391da177e4SLinus Torvalds p_priv->old_baud = p_priv->baud; 23401da177e4SLinus Torvalds msg.setClocking = 0xff; 2341049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 2342049c6b4eSGreg Kroah-Hartman &msg.baudHi, &msg.baudLo, &msg.prescaler, 2343049c6b4eSGreg Kroah-Hartman device_port) == KEYSPAN_INVALID_BAUD_RATE) { 2344049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", 2345deb91685SAlan Cox __func__, p_priv->baud); 23461da177e4SLinus Torvalds msg.baudLo = 0; 23471da177e4SLinus Torvalds msg.baudHi = 125; /* Values for 9600 baud */ 23481da177e4SLinus Torvalds msg.prescaler = 10; 23491da177e4SLinus Torvalds } 2350deb91685SAlan Cox /* msg.setPrescaler = 0xff; */ 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; 23541da177e4SLinus Torvalds switch (p_priv->cflag & CSIZE) { 23551da177e4SLinus Torvalds case CS5: 23561da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_5; 23571da177e4SLinus Torvalds break; 23581da177e4SLinus Torvalds case CS6: 23591da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_6; 23601da177e4SLinus Torvalds break; 23611da177e4SLinus Torvalds case CS7: 23621da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_7; 23631da177e4SLinus Torvalds break; 23641da177e4SLinus Torvalds case CS8: 23651da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_8; 23661da177e4SLinus Torvalds break; 23671da177e4SLinus Torvalds } 23681da177e4SLinus Torvalds if (p_priv->cflag & PARENB) { 23691da177e4SLinus Torvalds /* note USA_PARITY_NONE == 0 */ 23701da177e4SLinus Torvalds msg.lcr |= (p_priv->cflag & PARODD) ? 23711da177e4SLinus Torvalds USA_PARITY_ODD : USA_PARITY_EVEN; 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds msg.setLcr = 0xff; 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds msg.ctsFlowControl = (p_priv->flow_control == flow_cts); 23761da177e4SLinus Torvalds msg.xonFlowControl = 0; 23771da177e4SLinus Torvalds msg.setFlowControl = 0xff; 23781da177e4SLinus Torvalds 23791da177e4SLinus Torvalds msg.forwardingLength = 16; 23801da177e4SLinus Torvalds msg.xonChar = 17; 23811da177e4SLinus Torvalds msg.xoffChar = 19; 23821da177e4SLinus Torvalds 23831da177e4SLinus Torvalds /* Opening port */ 23841da177e4SLinus Torvalds if (reset_port == 1) { 23851da177e4SLinus Torvalds msg._txOn = 1; 23861da177e4SLinus Torvalds msg._txOff = 0; 23871da177e4SLinus Torvalds msg.txFlush = 0; 23881da177e4SLinus Torvalds msg.txBreak = 0; 23891da177e4SLinus Torvalds msg.rxOn = 1; 23901da177e4SLinus Torvalds msg.rxOff = 0; 23911da177e4SLinus Torvalds msg.rxFlush = 1; 23921da177e4SLinus Torvalds msg.rxForward = 0; 23931da177e4SLinus Torvalds msg.returnStatus = 0; 23941da177e4SLinus Torvalds msg.resetDataToggle = 0xff; 23951da177e4SLinus Torvalds msg.enablePort = 1; 23961da177e4SLinus Torvalds msg.disablePort = 0; 23971da177e4SLinus Torvalds } 23981da177e4SLinus Torvalds /* Closing port */ 23991da177e4SLinus Torvalds else if (reset_port == 2) { 24001da177e4SLinus Torvalds msg._txOn = 0; 24011da177e4SLinus Torvalds msg._txOff = 1; 24021da177e4SLinus Torvalds msg.txFlush = 0; 24031da177e4SLinus Torvalds msg.txBreak = 0; 24041da177e4SLinus Torvalds msg.rxOn = 0; 24051da177e4SLinus Torvalds msg.rxOff = 1; 24061da177e4SLinus Torvalds msg.rxFlush = 1; 24071da177e4SLinus Torvalds msg.rxForward = 0; 24081da177e4SLinus Torvalds msg.returnStatus = 0; 24091da177e4SLinus Torvalds msg.resetDataToggle = 0; 24101da177e4SLinus Torvalds msg.enablePort = 0; 24111da177e4SLinus Torvalds msg.disablePort = 1; 24121da177e4SLinus Torvalds } 24131da177e4SLinus Torvalds /* Sending intermediate configs */ 24141da177e4SLinus Torvalds else { 24151da177e4SLinus Torvalds msg._txOn = (!p_priv->break_on); 24161da177e4SLinus Torvalds msg._txOff = 0; 24171da177e4SLinus Torvalds msg.txFlush = 0; 24181da177e4SLinus Torvalds msg.txBreak = (p_priv->break_on); 24191da177e4SLinus Torvalds msg.rxOn = 0; 24201da177e4SLinus Torvalds msg.rxOff = 0; 24211da177e4SLinus Torvalds msg.rxFlush = 0; 24221da177e4SLinus Torvalds msg.rxForward = 0; 24231da177e4SLinus Torvalds msg.returnStatus = 0; 24241da177e4SLinus Torvalds msg.resetDataToggle = 0x0; 24251da177e4SLinus Torvalds msg.enablePort = 0; 24261da177e4SLinus Torvalds msg.disablePort = 0; 24271da177e4SLinus Torvalds } 24281da177e4SLinus Torvalds 24291da177e4SLinus Torvalds /* Do handshaking outputs */ 24301da177e4SLinus Torvalds msg.setRts = 0xff; 24311da177e4SLinus Torvalds msg.rts = p_priv->rts_state; 24321da177e4SLinus Torvalds 24331da177e4SLinus Torvalds msg.setDtr = 0xff; 24341da177e4SLinus Torvalds msg.dtr = p_priv->dtr_state; 24351da177e4SLinus Torvalds 24361da177e4SLinus Torvalds p_priv->resend_cont = 0; 24370ca1268eSLucy McCoy 2438deb91685SAlan Cox /* if the device is a 49wg, we send control message on usb 2439deb91685SAlan Cox control EP 0 */ 24400ca1268eSLucy McCoy 24410ca1268eSLucy McCoy if (d_details->product_id == keyspan_usa49wg_product_id) { 24420ca1268eSLucy McCoy dr = (void *)(s_priv->ctrl_buf); 24430ca1268eSLucy McCoy dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT; 24446424839cSMathieu OTHACEHE dr->bRequest = 0xB0; /* 49wg control message */ 24450ca1268eSLucy McCoy dr->wValue = 0; 24460ca1268eSLucy McCoy dr->wIndex = 0; 24470ca1268eSLucy McCoy dr->wLength = cpu_to_le16(sizeof(msg)); 24480ca1268eSLucy McCoy 24490ca1268eSLucy McCoy memcpy(s_priv->glocont_buf, &msg, sizeof(msg)); 24500ca1268eSLucy McCoy 2451deb91685SAlan Cox usb_fill_control_urb(this_urb, serial->dev, 2452deb91685SAlan Cox usb_sndctrlpipe(serial->dev, 0), 2453deb91685SAlan Cox (unsigned char *)dr, s_priv->glocont_buf, 2454deb91685SAlan Cox sizeof(msg), usa49_glocont_callback, serial); 24550ca1268eSLucy McCoy 24560ca1268eSLucy McCoy } else { 24571da177e4SLinus Torvalds memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); 24581da177e4SLinus Torvalds 24591da177e4SLinus Torvalds /* send the data out the device on control endpoint */ 24601da177e4SLinus Torvalds this_urb->transfer_buffer_length = sizeof(msg); 24610ca1268eSLucy McCoy } 2462deb91685SAlan Cox err = usb_submit_urb(this_urb, GFP_ATOMIC); 2463deb91685SAlan Cox if (err != 0) 2464049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); 24651da177e4SLinus Torvalds 2466a5b6f60cSAlan Cox return 0; 24671da177e4SLinus Torvalds } 24681da177e4SLinus Torvalds 24691da177e4SLinus Torvalds static int keyspan_usa90_send_setup(struct usb_serial *serial, 24701da177e4SLinus Torvalds struct usb_serial_port *port, 24711da177e4SLinus Torvalds int reset_port) 24721da177e4SLinus Torvalds { 24731da177e4SLinus Torvalds struct keyspan_usa90_portControlMessage msg; 24741da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 24751da177e4SLinus Torvalds struct keyspan_port_private *p_priv; 24761da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 24771da177e4SLinus Torvalds struct urb *this_urb; 24781da177e4SLinus Torvalds int err; 24791da177e4SLinus Torvalds u8 prescaler; 24801da177e4SLinus Torvalds 24811da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 24821da177e4SLinus Torvalds p_priv = usb_get_serial_port_data(port); 24831da177e4SLinus Torvalds d_details = s_priv->device_details; 24841da177e4SLinus Torvalds 24851da177e4SLinus Torvalds /* only do something if we have a bulk out endpoint */ 2486deb91685SAlan Cox this_urb = p_priv->outcont_urb; 2487deb91685SAlan Cox if (this_urb == NULL) { 2488049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - oops no urb.\n", __func__); 24891da177e4SLinus Torvalds return -1; 24901da177e4SLinus Torvalds } 24911da177e4SLinus Torvalds 24921da177e4SLinus Torvalds /* Save reset port val for resend. 24931da177e4SLinus Torvalds Don't overwrite resend for open/close condition. */ 24941da177e4SLinus Torvalds if ((reset_port + 1) > p_priv->resend_cont) 24951da177e4SLinus Torvalds p_priv->resend_cont = reset_port + 1; 24961da177e4SLinus Torvalds if (this_urb->status == -EINPROGRESS) { 2497049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s already writing\n", __func__); 24981da177e4SLinus Torvalds mdelay(5); 2499deb91685SAlan Cox return -1; 25001da177e4SLinus Torvalds } 25011da177e4SLinus Torvalds 25021da177e4SLinus Torvalds memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage)); 25031da177e4SLinus Torvalds 25041da177e4SLinus Torvalds /* Only set baud rate if it's changed */ 25051da177e4SLinus Torvalds if (p_priv->old_baud != p_priv->baud) { 25061da177e4SLinus Torvalds p_priv->old_baud = p_priv->baud; 25071da177e4SLinus Torvalds msg.setClocking = 0x01; 2508049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 2509049c6b4eSGreg Kroah-Hartman &msg.baudHi, &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { 2510049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", 2511deb91685SAlan Cox __func__, p_priv->baud); 25121da177e4SLinus Torvalds p_priv->baud = 9600; 2513049c6b4eSGreg Kroah-Hartman d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 25141da177e4SLinus Torvalds &msg.baudHi, &msg.baudLo, &prescaler, 0); 25151da177e4SLinus Torvalds } 25161da177e4SLinus Torvalds msg.setRxMode = 1; 25171da177e4SLinus Torvalds msg.setTxMode = 1; 25181da177e4SLinus Torvalds } 25191da177e4SLinus Torvalds 25201da177e4SLinus Torvalds /* modes must always be correctly specified */ 2521deb91685SAlan Cox if (p_priv->baud > 57600) { 25221da177e4SLinus Torvalds msg.rxMode = RXMODE_DMA; 25231da177e4SLinus Torvalds msg.txMode = TXMODE_DMA; 2524deb91685SAlan Cox } else { 25251da177e4SLinus Torvalds msg.rxMode = RXMODE_BYHAND; 25261da177e4SLinus Torvalds msg.txMode = TXMODE_BYHAND; 25271da177e4SLinus Torvalds } 25281da177e4SLinus Torvalds 25291da177e4SLinus Torvalds msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; 25301da177e4SLinus Torvalds switch (p_priv->cflag & CSIZE) { 25311da177e4SLinus Torvalds case CS5: 25321da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_5; 25331da177e4SLinus Torvalds break; 25341da177e4SLinus Torvalds case CS6: 25351da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_6; 25361da177e4SLinus Torvalds break; 25371da177e4SLinus Torvalds case CS7: 25381da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_7; 25391da177e4SLinus Torvalds break; 25401da177e4SLinus Torvalds case CS8: 25411da177e4SLinus Torvalds msg.lcr |= USA_DATABITS_8; 25421da177e4SLinus Torvalds break; 25431da177e4SLinus Torvalds } 25441da177e4SLinus Torvalds if (p_priv->cflag & PARENB) { 25451da177e4SLinus Torvalds /* note USA_PARITY_NONE == 0 */ 25461da177e4SLinus Torvalds msg.lcr |= (p_priv->cflag & PARODD) ? 25471da177e4SLinus Torvalds USA_PARITY_ODD : USA_PARITY_EVEN; 25481da177e4SLinus Torvalds } 25491da177e4SLinus Torvalds if (p_priv->old_cflag != p_priv->cflag) { 25501da177e4SLinus Torvalds p_priv->old_cflag = p_priv->cflag; 25511da177e4SLinus Torvalds msg.setLcr = 0x01; 25521da177e4SLinus Torvalds } 25531da177e4SLinus Torvalds 25541da177e4SLinus Torvalds if (p_priv->flow_control == flow_cts) 25551da177e4SLinus Torvalds msg.txFlowControl = TXFLOW_CTS; 25561da177e4SLinus Torvalds msg.setTxFlowControl = 0x01; 25571da177e4SLinus Torvalds msg.setRxFlowControl = 0x01; 25581da177e4SLinus Torvalds 25591da177e4SLinus Torvalds msg.rxForwardingLength = 16; 25601da177e4SLinus Torvalds msg.rxForwardingTimeout = 16; 25611da177e4SLinus Torvalds msg.txAckSetting = 0; 25621da177e4SLinus Torvalds msg.xonChar = 17; 25631da177e4SLinus Torvalds msg.xoffChar = 19; 25641da177e4SLinus Torvalds 25651da177e4SLinus Torvalds /* Opening port */ 25661da177e4SLinus Torvalds if (reset_port == 1) { 25671da177e4SLinus Torvalds msg.portEnabled = 1; 25681da177e4SLinus Torvalds msg.rxFlush = 1; 25691da177e4SLinus Torvalds msg.txBreak = (p_priv->break_on); 25701da177e4SLinus Torvalds } 25711da177e4SLinus Torvalds /* Closing port */ 2572deb91685SAlan Cox else if (reset_port == 2) 25731da177e4SLinus Torvalds msg.portEnabled = 0; 25741da177e4SLinus Torvalds /* Sending intermediate configs */ 25751da177e4SLinus Torvalds else { 25761da177e4SLinus Torvalds msg.portEnabled = 1; 25771da177e4SLinus Torvalds msg.txBreak = (p_priv->break_on); 25781da177e4SLinus Torvalds } 25791da177e4SLinus Torvalds 25801da177e4SLinus Torvalds /* Do handshaking outputs */ 25811da177e4SLinus Torvalds msg.setRts = 0x01; 25821da177e4SLinus Torvalds msg.rts = p_priv->rts_state; 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds msg.setDtr = 0x01; 25851da177e4SLinus Torvalds msg.dtr = p_priv->dtr_state; 25861da177e4SLinus Torvalds 25871da177e4SLinus Torvalds p_priv->resend_cont = 0; 25881da177e4SLinus Torvalds memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); 25891da177e4SLinus Torvalds 25901da177e4SLinus Torvalds /* send the data out the device on control endpoint */ 25911da177e4SLinus Torvalds this_urb->transfer_buffer_length = sizeof(msg); 25921da177e4SLinus Torvalds 2593deb91685SAlan Cox err = usb_submit_urb(this_urb, GFP_ATOMIC); 2594deb91685SAlan Cox if (err != 0) 2595049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); 2596a5b6f60cSAlan Cox return 0; 25971da177e4SLinus Torvalds } 25981da177e4SLinus Torvalds 25990ca1268eSLucy McCoy static int keyspan_usa67_send_setup(struct usb_serial *serial, 26000ca1268eSLucy McCoy struct usb_serial_port *port, 26010ca1268eSLucy McCoy int reset_port) 26020ca1268eSLucy McCoy { 26030ca1268eSLucy McCoy struct keyspan_usa67_portControlMessage msg; 26040ca1268eSLucy McCoy struct keyspan_serial_private *s_priv; 26050ca1268eSLucy McCoy struct keyspan_port_private *p_priv; 26060ca1268eSLucy McCoy const struct keyspan_device_details *d_details; 26070ca1268eSLucy McCoy struct urb *this_urb; 26080ca1268eSLucy McCoy int err, device_port; 26090ca1268eSLucy McCoy 26100ca1268eSLucy McCoy s_priv = usb_get_serial_data(serial); 26110ca1268eSLucy McCoy p_priv = usb_get_serial_port_data(port); 26120ca1268eSLucy McCoy d_details = s_priv->device_details; 26130ca1268eSLucy McCoy 26140ca1268eSLucy McCoy this_urb = s_priv->glocont_urb; 26150ca1268eSLucy McCoy 26160ca1268eSLucy McCoy /* Work out which port within the device is being setup */ 26171143832eSGreg Kroah-Hartman device_port = port->port_number; 26180ca1268eSLucy McCoy 26190ca1268eSLucy McCoy /* Make sure we have an urb then send the message */ 26200ca1268eSLucy McCoy if (this_urb == NULL) { 26211143832eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - oops no urb for port.\n", __func__); 26220ca1268eSLucy McCoy return -1; 26230ca1268eSLucy McCoy } 26240ca1268eSLucy McCoy 26250ca1268eSLucy McCoy /* Save reset port val for resend. 26260ca1268eSLucy McCoy Don't overwrite resend for open/close condition. */ 26270ca1268eSLucy McCoy if ((reset_port + 1) > p_priv->resend_cont) 26280ca1268eSLucy McCoy p_priv->resend_cont = reset_port + 1; 26290ca1268eSLucy McCoy if (this_urb->status == -EINPROGRESS) { 2630049c6b4eSGreg Kroah-Hartman /* dev_dbg(&port->dev, "%s - already writing\n", __func__); */ 26310ca1268eSLucy McCoy mdelay(5); 2632deb91685SAlan Cox return -1; 26330ca1268eSLucy McCoy } 26340ca1268eSLucy McCoy 26350ca1268eSLucy McCoy memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage)); 26360ca1268eSLucy McCoy 26370ca1268eSLucy McCoy msg.port = device_port; 26380ca1268eSLucy McCoy 26390ca1268eSLucy McCoy /* Only set baud rate if it's changed */ 26400ca1268eSLucy McCoy if (p_priv->old_baud != p_priv->baud) { 26410ca1268eSLucy McCoy p_priv->old_baud = p_priv->baud; 26420ca1268eSLucy McCoy msg.setClocking = 0xff; 2643049c6b4eSGreg Kroah-Hartman if (d_details->calculate_baud_rate(port, p_priv->baud, d_details->baudclk, 2644049c6b4eSGreg Kroah-Hartman &msg.baudHi, &msg.baudLo, &msg.prescaler, 2645049c6b4eSGreg Kroah-Hartman device_port) == KEYSPAN_INVALID_BAUD_RATE) { 2646049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - Invalid baud rate %d requested, using 9600.\n", 2647deb91685SAlan Cox __func__, p_priv->baud); 26480ca1268eSLucy McCoy msg.baudLo = 0; 26490ca1268eSLucy McCoy msg.baudHi = 125; /* Values for 9600 baud */ 26500ca1268eSLucy McCoy msg.prescaler = 10; 26510ca1268eSLucy McCoy } 26520ca1268eSLucy McCoy msg.setPrescaler = 0xff; 26530ca1268eSLucy McCoy } 26540ca1268eSLucy McCoy 26550ca1268eSLucy McCoy msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; 26560ca1268eSLucy McCoy switch (p_priv->cflag & CSIZE) { 26570ca1268eSLucy McCoy case CS5: 26580ca1268eSLucy McCoy msg.lcr |= USA_DATABITS_5; 26590ca1268eSLucy McCoy break; 26600ca1268eSLucy McCoy case CS6: 26610ca1268eSLucy McCoy msg.lcr |= USA_DATABITS_6; 26620ca1268eSLucy McCoy break; 26630ca1268eSLucy McCoy case CS7: 26640ca1268eSLucy McCoy msg.lcr |= USA_DATABITS_7; 26650ca1268eSLucy McCoy break; 26660ca1268eSLucy McCoy case CS8: 26670ca1268eSLucy McCoy msg.lcr |= USA_DATABITS_8; 26680ca1268eSLucy McCoy break; 26690ca1268eSLucy McCoy } 26700ca1268eSLucy McCoy if (p_priv->cflag & PARENB) { 26710ca1268eSLucy McCoy /* note USA_PARITY_NONE == 0 */ 26720ca1268eSLucy McCoy msg.lcr |= (p_priv->cflag & PARODD) ? 26730ca1268eSLucy McCoy USA_PARITY_ODD : USA_PARITY_EVEN; 26740ca1268eSLucy McCoy } 26750ca1268eSLucy McCoy msg.setLcr = 0xff; 26760ca1268eSLucy McCoy 26770ca1268eSLucy McCoy msg.ctsFlowControl = (p_priv->flow_control == flow_cts); 26780ca1268eSLucy McCoy msg.xonFlowControl = 0; 26790ca1268eSLucy McCoy msg.setFlowControl = 0xff; 26800ca1268eSLucy McCoy msg.forwardingLength = 16; 26810ca1268eSLucy McCoy msg.xonChar = 17; 26820ca1268eSLucy McCoy msg.xoffChar = 19; 26830ca1268eSLucy McCoy 26840ca1268eSLucy McCoy if (reset_port == 1) { 26850ca1268eSLucy McCoy /* Opening port */ 26860ca1268eSLucy McCoy msg._txOn = 1; 26870ca1268eSLucy McCoy msg._txOff = 0; 26880ca1268eSLucy McCoy msg.txFlush = 0; 26890ca1268eSLucy McCoy msg.txBreak = 0; 26900ca1268eSLucy McCoy msg.rxOn = 1; 26910ca1268eSLucy McCoy msg.rxOff = 0; 26920ca1268eSLucy McCoy msg.rxFlush = 1; 26930ca1268eSLucy McCoy msg.rxForward = 0; 26940ca1268eSLucy McCoy msg.returnStatus = 0; 26950ca1268eSLucy McCoy msg.resetDataToggle = 0xff; 26960ca1268eSLucy McCoy } else if (reset_port == 2) { 26970ca1268eSLucy McCoy /* Closing port */ 26980ca1268eSLucy McCoy msg._txOn = 0; 26990ca1268eSLucy McCoy msg._txOff = 1; 27000ca1268eSLucy McCoy msg.txFlush = 0; 27010ca1268eSLucy McCoy msg.txBreak = 0; 27020ca1268eSLucy McCoy msg.rxOn = 0; 27030ca1268eSLucy McCoy msg.rxOff = 1; 27040ca1268eSLucy McCoy msg.rxFlush = 1; 27050ca1268eSLucy McCoy msg.rxForward = 0; 27060ca1268eSLucy McCoy msg.returnStatus = 0; 27070ca1268eSLucy McCoy msg.resetDataToggle = 0; 27080ca1268eSLucy McCoy } else { 27090ca1268eSLucy McCoy /* Sending intermediate configs */ 27100ca1268eSLucy McCoy msg._txOn = (!p_priv->break_on); 27110ca1268eSLucy McCoy msg._txOff = 0; 27120ca1268eSLucy McCoy msg.txFlush = 0; 27130ca1268eSLucy McCoy msg.txBreak = (p_priv->break_on); 27140ca1268eSLucy McCoy msg.rxOn = 0; 27150ca1268eSLucy McCoy msg.rxOff = 0; 27160ca1268eSLucy McCoy msg.rxFlush = 0; 27170ca1268eSLucy McCoy msg.rxForward = 0; 27180ca1268eSLucy McCoy msg.returnStatus = 0; 27190ca1268eSLucy McCoy msg.resetDataToggle = 0x0; 27200ca1268eSLucy McCoy } 27210ca1268eSLucy McCoy 27220ca1268eSLucy McCoy /* Do handshaking outputs */ 27230ca1268eSLucy McCoy msg.setTxTriState_setRts = 0xff; 27240ca1268eSLucy McCoy msg.txTriState_rts = p_priv->rts_state; 27250ca1268eSLucy McCoy 27260ca1268eSLucy McCoy msg.setHskoa_setDtr = 0xff; 27270ca1268eSLucy McCoy msg.hskoa_dtr = p_priv->dtr_state; 27280ca1268eSLucy McCoy 27290ca1268eSLucy McCoy p_priv->resend_cont = 0; 27300ca1268eSLucy McCoy 27310ca1268eSLucy McCoy memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); 27320ca1268eSLucy McCoy 27330ca1268eSLucy McCoy /* send the data out the device on control endpoint */ 27340ca1268eSLucy McCoy this_urb->transfer_buffer_length = sizeof(msg); 27350ca1268eSLucy McCoy 27360ca1268eSLucy McCoy err = usb_submit_urb(this_urb, GFP_ATOMIC); 27370ca1268eSLucy McCoy if (err != 0) 2738049c6b4eSGreg Kroah-Hartman dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); 2739a5b6f60cSAlan Cox return 0; 27400ca1268eSLucy McCoy } 27410ca1268eSLucy McCoy 27421da177e4SLinus Torvalds static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) 27431da177e4SLinus Torvalds { 27441da177e4SLinus Torvalds struct usb_serial *serial = port->serial; 27451da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 27461da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 27471da177e4SLinus Torvalds 27481da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 27491da177e4SLinus Torvalds d_details = s_priv->device_details; 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds switch (d_details->msg_format) { 27521da177e4SLinus Torvalds case msg_usa26: 27531da177e4SLinus Torvalds keyspan_usa26_send_setup(serial, port, reset_port); 27541da177e4SLinus Torvalds break; 27551da177e4SLinus Torvalds case msg_usa28: 27561da177e4SLinus Torvalds keyspan_usa28_send_setup(serial, port, reset_port); 27571da177e4SLinus Torvalds break; 27581da177e4SLinus Torvalds case msg_usa49: 27591da177e4SLinus Torvalds keyspan_usa49_send_setup(serial, port, reset_port); 27601da177e4SLinus Torvalds break; 27611da177e4SLinus Torvalds case msg_usa90: 27621da177e4SLinus Torvalds keyspan_usa90_send_setup(serial, port, reset_port); 27631da177e4SLinus Torvalds break; 27640ca1268eSLucy McCoy case msg_usa67: 27650ca1268eSLucy McCoy keyspan_usa67_send_setup(serial, port, reset_port); 27660ca1268eSLucy McCoy break; 27671da177e4SLinus Torvalds } 27681da177e4SLinus Torvalds } 27691da177e4SLinus Torvalds 27701da177e4SLinus Torvalds 27711da177e4SLinus Torvalds /* Gets called by the "real" driver (ie once firmware is loaded 27721da177e4SLinus Torvalds and renumeration has taken place. */ 27731da177e4SLinus Torvalds static int keyspan_startup(struct usb_serial *serial) 27741da177e4SLinus Torvalds { 27751da177e4SLinus Torvalds int i, err; 27761da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 27771da177e4SLinus Torvalds const struct keyspan_device_details *d_details; 27781da177e4SLinus Torvalds 27791da177e4SLinus Torvalds for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) 2780deb91685SAlan Cox if (d_details->product_id == 2781deb91685SAlan Cox le16_to_cpu(serial->dev->descriptor.idProduct)) 27821da177e4SLinus Torvalds break; 27831da177e4SLinus Torvalds if (d_details == NULL) { 2784deb91685SAlan Cox dev_err(&serial->dev->dev, "%s - unknown product id %x\n", 2785deb91685SAlan Cox __func__, le16_to_cpu(serial->dev->descriptor.idProduct)); 2786ff8a43c1SJohan Hovold return -ENODEV; 27871da177e4SLinus Torvalds } 27881da177e4SLinus Torvalds 27891da177e4SLinus Torvalds /* Setup private data for serial driver */ 279080b6ca48SEric Sesterhenn s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); 279110c642d0SJohan Hovold if (!s_priv) 27921da177e4SLinus Torvalds return -ENOMEM; 27931da177e4SLinus Torvalds 27942fcd1c9bSJohan Hovold s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL); 27952fcd1c9bSJohan Hovold if (!s_priv->instat_buf) 27962fcd1c9bSJohan Hovold goto err_instat_buf; 27972fcd1c9bSJohan Hovold 27982fcd1c9bSJohan Hovold s_priv->indat_buf = kzalloc(INDAT49W_BUFLEN, GFP_KERNEL); 27992fcd1c9bSJohan Hovold if (!s_priv->indat_buf) 28002fcd1c9bSJohan Hovold goto err_indat_buf; 28012fcd1c9bSJohan Hovold 28022fcd1c9bSJohan Hovold s_priv->glocont_buf = kzalloc(GLOCONT_BUFLEN, GFP_KERNEL); 28032fcd1c9bSJohan Hovold if (!s_priv->glocont_buf) 28042fcd1c9bSJohan Hovold goto err_glocont_buf; 28052fcd1c9bSJohan Hovold 28062fcd1c9bSJohan Hovold s_priv->ctrl_buf = kzalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); 28072fcd1c9bSJohan Hovold if (!s_priv->ctrl_buf) 28082fcd1c9bSJohan Hovold goto err_ctrl_buf; 28092fcd1c9bSJohan Hovold 28101da177e4SLinus Torvalds s_priv->device_details = d_details; 28111da177e4SLinus Torvalds usb_set_serial_data(serial, s_priv); 28121da177e4SLinus Torvalds 28131da177e4SLinus Torvalds keyspan_setup_urbs(serial); 28141da177e4SLinus Torvalds 28150ca1268eSLucy McCoy if (s_priv->instat_urb != NULL) { 28160ca1268eSLucy McCoy err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL); 28170ca1268eSLucy McCoy if (err != 0) 28187ebcb334SGreg Kroah-Hartman dev_dbg(&serial->dev->dev, "%s - submit instat urb failed %d\n", __func__, err); 28190ca1268eSLucy McCoy } 28200ca1268eSLucy McCoy if (s_priv->indat_urb != NULL) { 28210ca1268eSLucy McCoy err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL); 28220ca1268eSLucy McCoy if (err != 0) 28237ebcb334SGreg Kroah-Hartman dev_dbg(&serial->dev->dev, "%s - submit indat urb failed %d\n", __func__, err); 28241da177e4SLinus Torvalds } 28251da177e4SLinus Torvalds 2826a5b6f60cSAlan Cox return 0; 28272fcd1c9bSJohan Hovold 28282fcd1c9bSJohan Hovold err_ctrl_buf: 28292fcd1c9bSJohan Hovold kfree(s_priv->glocont_buf); 28302fcd1c9bSJohan Hovold err_glocont_buf: 28312fcd1c9bSJohan Hovold kfree(s_priv->indat_buf); 28322fcd1c9bSJohan Hovold err_indat_buf: 28332fcd1c9bSJohan Hovold kfree(s_priv->instat_buf); 28342fcd1c9bSJohan Hovold err_instat_buf: 28352fcd1c9bSJohan Hovold kfree(s_priv); 28362fcd1c9bSJohan Hovold 28372fcd1c9bSJohan Hovold return -ENOMEM; 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds 2840f9c99bb8SAlan Stern static void keyspan_disconnect(struct usb_serial *serial) 28411da177e4SLinus Torvalds { 28421da177e4SLinus Torvalds struct keyspan_serial_private *s_priv; 28431da177e4SLinus Torvalds 28441da177e4SLinus Torvalds s_priv = usb_get_serial_data(serial); 28451da177e4SLinus Torvalds 284661924505SJohan Hovold usb_kill_urb(s_priv->instat_urb); 284761924505SJohan Hovold usb_kill_urb(s_priv->glocont_urb); 284861924505SJohan Hovold usb_kill_urb(s_priv->indat_urb); 2849f9c99bb8SAlan Stern } 2850f9c99bb8SAlan Stern 2851f9c99bb8SAlan Stern static void keyspan_release(struct usb_serial *serial) 2852f9c99bb8SAlan Stern { 2853f9c99bb8SAlan Stern struct keyspan_serial_private *s_priv; 2854f9c99bb8SAlan Stern 2855f9c99bb8SAlan Stern s_priv = usb_get_serial_data(serial); 28561da177e4SLinus Torvalds 285735be1a71SJohan Hovold /* Make sure to unlink the URBs submitted in attach. */ 285835be1a71SJohan Hovold usb_kill_urb(s_priv->instat_urb); 285935be1a71SJohan Hovold usb_kill_urb(s_priv->indat_urb); 286035be1a71SJohan Hovold 2861f79b2d0fSJohan Hovold usb_free_urb(s_priv->instat_urb); 2862f79b2d0fSJohan Hovold usb_free_urb(s_priv->indat_urb); 2863f79b2d0fSJohan Hovold usb_free_urb(s_priv->glocont_urb); 28641da177e4SLinus Torvalds 28652fcd1c9bSJohan Hovold kfree(s_priv->ctrl_buf); 28662fcd1c9bSJohan Hovold kfree(s_priv->glocont_buf); 28672fcd1c9bSJohan Hovold kfree(s_priv->indat_buf); 28682fcd1c9bSJohan Hovold kfree(s_priv->instat_buf); 28692fcd1c9bSJohan Hovold 2870f79b2d0fSJohan Hovold kfree(s_priv); 28711da177e4SLinus Torvalds } 2872f79b2d0fSJohan Hovold 2873f79b2d0fSJohan Hovold static int keyspan_port_probe(struct usb_serial_port *port) 2874f79b2d0fSJohan Hovold { 2875f79b2d0fSJohan Hovold struct usb_serial *serial = port->serial; 2876f0e3e35cSBjørn Mork struct keyspan_serial_private *s_priv; 2877f79b2d0fSJohan Hovold struct keyspan_port_private *p_priv; 2878f79b2d0fSJohan Hovold const struct keyspan_device_details *d_details; 2879f79b2d0fSJohan Hovold struct callbacks *cback; 2880f79b2d0fSJohan Hovold int endp; 2881f79b2d0fSJohan Hovold int port_num; 2882f79b2d0fSJohan Hovold int i; 2883f79b2d0fSJohan Hovold 2884f79b2d0fSJohan Hovold s_priv = usb_get_serial_data(serial); 2885f79b2d0fSJohan Hovold d_details = s_priv->device_details; 2886f79b2d0fSJohan Hovold 2887f79b2d0fSJohan Hovold p_priv = kzalloc(sizeof(*p_priv), GFP_KERNEL); 2888f79b2d0fSJohan Hovold if (!p_priv) 2889f79b2d0fSJohan Hovold return -ENOMEM; 2890f79b2d0fSJohan Hovold 2891bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) { 2892bad41a5bSJohan Hovold p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL); 2893bad41a5bSJohan Hovold if (!p_priv->in_buffer[i]) 2894910c9963SWang Hai goto err_free_in_buffer; 2895bad41a5bSJohan Hovold } 2896bad41a5bSJohan Hovold 2897bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) { 2898bad41a5bSJohan Hovold p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL); 2899bad41a5bSJohan Hovold if (!p_priv->out_buffer[i]) 2900910c9963SWang Hai goto err_free_out_buffer; 2901bad41a5bSJohan Hovold } 2902bad41a5bSJohan Hovold 2903bad41a5bSJohan Hovold p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL); 2904bad41a5bSJohan Hovold if (!p_priv->inack_buffer) 2905910c9963SWang Hai goto err_free_out_buffer; 2906bad41a5bSJohan Hovold 2907bad41a5bSJohan Hovold p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL); 2908bad41a5bSJohan Hovold if (!p_priv->outcont_buffer) 2909910c9963SWang Hai goto err_free_inack_buffer; 2910bad41a5bSJohan Hovold 2911f79b2d0fSJohan Hovold p_priv->device_details = d_details; 2912f79b2d0fSJohan Hovold 2913f79b2d0fSJohan Hovold /* Setup values for the various callback routines */ 2914f79b2d0fSJohan Hovold cback = &keyspan_callbacks[d_details->msg_format]; 2915f79b2d0fSJohan Hovold 29161143832eSGreg Kroah-Hartman port_num = port->port_number; 2917f79b2d0fSJohan Hovold 2918f79b2d0fSJohan Hovold /* Do indat endpoints first, once for each flip */ 2919f79b2d0fSJohan Hovold endp = d_details->indat_endpoints[port_num]; 2920f79b2d0fSJohan Hovold for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { 2921f79b2d0fSJohan Hovold p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, 2922f79b2d0fSJohan Hovold USB_DIR_IN, port, 2923bad41a5bSJohan Hovold p_priv->in_buffer[i], 2924bad41a5bSJohan Hovold IN_BUFLEN, 2925f79b2d0fSJohan Hovold cback->indat_callback); 2926f79b2d0fSJohan Hovold } 2927f79b2d0fSJohan Hovold /* outdat endpoints also have flip */ 2928f79b2d0fSJohan Hovold endp = d_details->outdat_endpoints[port_num]; 2929f79b2d0fSJohan Hovold for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { 2930f79b2d0fSJohan Hovold p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, 2931f79b2d0fSJohan Hovold USB_DIR_OUT, port, 2932bad41a5bSJohan Hovold p_priv->out_buffer[i], 2933bad41a5bSJohan Hovold OUT_BUFLEN, 2934f79b2d0fSJohan Hovold cback->outdat_callback); 2935f79b2d0fSJohan Hovold } 2936f79b2d0fSJohan Hovold /* inack endpoint */ 2937f79b2d0fSJohan Hovold p_priv->inack_urb = keyspan_setup_urb(serial, 2938f79b2d0fSJohan Hovold d_details->inack_endpoints[port_num], 2939f79b2d0fSJohan Hovold USB_DIR_IN, port, 2940bad41a5bSJohan Hovold p_priv->inack_buffer, 2941bad41a5bSJohan Hovold INACK_BUFLEN, 2942f79b2d0fSJohan Hovold cback->inack_callback); 2943f79b2d0fSJohan Hovold /* outcont endpoint */ 2944f79b2d0fSJohan Hovold p_priv->outcont_urb = keyspan_setup_urb(serial, 2945f79b2d0fSJohan Hovold d_details->outcont_endpoints[port_num], 2946f79b2d0fSJohan Hovold USB_DIR_OUT, port, 2947bad41a5bSJohan Hovold p_priv->outcont_buffer, 2948bad41a5bSJohan Hovold OUTCONT_BUFLEN, 2949f79b2d0fSJohan Hovold cback->outcont_callback); 2950f79b2d0fSJohan Hovold 2951f79b2d0fSJohan Hovold usb_set_serial_port_data(port, p_priv); 2952f79b2d0fSJohan Hovold 2953f79b2d0fSJohan Hovold return 0; 2954bad41a5bSJohan Hovold 2955910c9963SWang Hai err_free_inack_buffer: 2956bad41a5bSJohan Hovold kfree(p_priv->inack_buffer); 2957910c9963SWang Hai err_free_out_buffer: 2958bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) 2959bad41a5bSJohan Hovold kfree(p_priv->out_buffer[i]); 2960910c9963SWang Hai err_free_in_buffer: 2961bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) 2962bad41a5bSJohan Hovold kfree(p_priv->in_buffer[i]); 2963bad41a5bSJohan Hovold kfree(p_priv); 2964bad41a5bSJohan Hovold 2965bad41a5bSJohan Hovold return -ENOMEM; 2966f79b2d0fSJohan Hovold } 2967f79b2d0fSJohan Hovold 2968c5d1448fSUwe Kleine-König static void keyspan_port_remove(struct usb_serial_port *port) 2969f79b2d0fSJohan Hovold { 2970f79b2d0fSJohan Hovold struct keyspan_port_private *p_priv; 2971f79b2d0fSJohan Hovold int i; 2972f79b2d0fSJohan Hovold 2973f79b2d0fSJohan Hovold p_priv = usb_get_serial_port_data(port); 2974f79b2d0fSJohan Hovold 297561924505SJohan Hovold usb_kill_urb(p_priv->inack_urb); 297661924505SJohan Hovold usb_kill_urb(p_priv->outcont_urb); 2977f79b2d0fSJohan Hovold for (i = 0; i < 2; i++) { 297861924505SJohan Hovold usb_kill_urb(p_priv->in_urbs[i]); 297961924505SJohan Hovold usb_kill_urb(p_priv->out_urbs[i]); 2980f79b2d0fSJohan Hovold } 2981f79b2d0fSJohan Hovold 2982f79b2d0fSJohan Hovold usb_free_urb(p_priv->inack_urb); 2983f79b2d0fSJohan Hovold usb_free_urb(p_priv->outcont_urb); 2984f79b2d0fSJohan Hovold for (i = 0; i < 2; i++) { 2985f79b2d0fSJohan Hovold usb_free_urb(p_priv->in_urbs[i]); 2986f79b2d0fSJohan Hovold usb_free_urb(p_priv->out_urbs[i]); 2987f79b2d0fSJohan Hovold } 2988f79b2d0fSJohan Hovold 2989bad41a5bSJohan Hovold kfree(p_priv->outcont_buffer); 2990bad41a5bSJohan Hovold kfree(p_priv->inack_buffer); 2991bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) 2992bad41a5bSJohan Hovold kfree(p_priv->out_buffer[i]); 2993bad41a5bSJohan Hovold for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) 2994bad41a5bSJohan Hovold kfree(p_priv->in_buffer[i]); 2995bad41a5bSJohan Hovold 2996f79b2d0fSJohan Hovold kfree(p_priv); 29971da177e4SLinus Torvalds } 29981da177e4SLinus Torvalds 2999beabdc3cSJohan Hovold /* Structs for the devices, pre and post renumeration. */ 3000beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_pre_device = { 3001beabdc3cSJohan Hovold .driver = { 3002beabdc3cSJohan Hovold .owner = THIS_MODULE, 3003beabdc3cSJohan Hovold .name = "keyspan_no_firm", 3004beabdc3cSJohan Hovold }, 3005beabdc3cSJohan Hovold .description = "Keyspan - (without firmware)", 3006beabdc3cSJohan Hovold .id_table = keyspan_pre_ids, 3007beabdc3cSJohan Hovold .num_ports = 1, 3008beabdc3cSJohan Hovold .attach = keyspan_fake_startup, 3009beabdc3cSJohan Hovold }; 3010beabdc3cSJohan Hovold 3011beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_1port_device = { 3012beabdc3cSJohan Hovold .driver = { 3013beabdc3cSJohan Hovold .owner = THIS_MODULE, 3014beabdc3cSJohan Hovold .name = "keyspan_1", 3015beabdc3cSJohan Hovold }, 3016beabdc3cSJohan Hovold .description = "Keyspan 1 port adapter", 3017beabdc3cSJohan Hovold .id_table = keyspan_1port_ids, 3018beabdc3cSJohan Hovold .num_ports = 1, 3019beabdc3cSJohan Hovold .open = keyspan_open, 3020beabdc3cSJohan Hovold .close = keyspan_close, 3021beabdc3cSJohan Hovold .dtr_rts = keyspan_dtr_rts, 3022beabdc3cSJohan Hovold .write = keyspan_write, 3023beabdc3cSJohan Hovold .write_room = keyspan_write_room, 3024beabdc3cSJohan Hovold .set_termios = keyspan_set_termios, 3025beabdc3cSJohan Hovold .break_ctl = keyspan_break_ctl, 3026beabdc3cSJohan Hovold .tiocmget = keyspan_tiocmget, 3027beabdc3cSJohan Hovold .tiocmset = keyspan_tiocmset, 3028beabdc3cSJohan Hovold .attach = keyspan_startup, 3029beabdc3cSJohan Hovold .disconnect = keyspan_disconnect, 3030beabdc3cSJohan Hovold .release = keyspan_release, 3031beabdc3cSJohan Hovold .port_probe = keyspan_port_probe, 3032beabdc3cSJohan Hovold .port_remove = keyspan_port_remove, 3033beabdc3cSJohan Hovold }; 3034beabdc3cSJohan Hovold 3035beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_2port_device = { 3036beabdc3cSJohan Hovold .driver = { 3037beabdc3cSJohan Hovold .owner = THIS_MODULE, 3038beabdc3cSJohan Hovold .name = "keyspan_2", 3039beabdc3cSJohan Hovold }, 3040beabdc3cSJohan Hovold .description = "Keyspan 2 port adapter", 3041beabdc3cSJohan Hovold .id_table = keyspan_2port_ids, 3042beabdc3cSJohan Hovold .num_ports = 2, 3043beabdc3cSJohan Hovold .open = keyspan_open, 3044beabdc3cSJohan Hovold .close = keyspan_close, 3045beabdc3cSJohan Hovold .dtr_rts = keyspan_dtr_rts, 3046beabdc3cSJohan Hovold .write = keyspan_write, 3047beabdc3cSJohan Hovold .write_room = keyspan_write_room, 3048beabdc3cSJohan Hovold .set_termios = keyspan_set_termios, 3049beabdc3cSJohan Hovold .break_ctl = keyspan_break_ctl, 3050beabdc3cSJohan Hovold .tiocmget = keyspan_tiocmget, 3051beabdc3cSJohan Hovold .tiocmset = keyspan_tiocmset, 3052beabdc3cSJohan Hovold .attach = keyspan_startup, 3053beabdc3cSJohan Hovold .disconnect = keyspan_disconnect, 3054beabdc3cSJohan Hovold .release = keyspan_release, 3055beabdc3cSJohan Hovold .port_probe = keyspan_port_probe, 3056beabdc3cSJohan Hovold .port_remove = keyspan_port_remove, 3057beabdc3cSJohan Hovold }; 3058beabdc3cSJohan Hovold 3059beabdc3cSJohan Hovold static struct usb_serial_driver keyspan_4port_device = { 3060beabdc3cSJohan Hovold .driver = { 3061beabdc3cSJohan Hovold .owner = THIS_MODULE, 3062beabdc3cSJohan Hovold .name = "keyspan_4", 3063beabdc3cSJohan Hovold }, 3064beabdc3cSJohan Hovold .description = "Keyspan 4 port adapter", 3065beabdc3cSJohan Hovold .id_table = keyspan_4port_ids, 3066beabdc3cSJohan Hovold .num_ports = 4, 3067beabdc3cSJohan Hovold .open = keyspan_open, 3068beabdc3cSJohan Hovold .close = keyspan_close, 3069beabdc3cSJohan Hovold .dtr_rts = keyspan_dtr_rts, 3070beabdc3cSJohan Hovold .write = keyspan_write, 3071beabdc3cSJohan Hovold .write_room = keyspan_write_room, 3072beabdc3cSJohan Hovold .set_termios = keyspan_set_termios, 3073beabdc3cSJohan Hovold .break_ctl = keyspan_break_ctl, 3074beabdc3cSJohan Hovold .tiocmget = keyspan_tiocmget, 3075beabdc3cSJohan Hovold .tiocmset = keyspan_tiocmset, 3076beabdc3cSJohan Hovold .attach = keyspan_startup, 3077beabdc3cSJohan Hovold .disconnect = keyspan_disconnect, 3078beabdc3cSJohan Hovold .release = keyspan_release, 3079beabdc3cSJohan Hovold .port_probe = keyspan_port_probe, 3080beabdc3cSJohan Hovold .port_remove = keyspan_port_remove, 3081beabdc3cSJohan Hovold }; 3082beabdc3cSJohan Hovold 3083beabdc3cSJohan Hovold static struct usb_serial_driver * const serial_drivers[] = { 3084beabdc3cSJohan Hovold &keyspan_pre_device, &keyspan_1port_device, 3085beabdc3cSJohan Hovold &keyspan_2port_device, &keyspan_4port_device, NULL 3086beabdc3cSJohan Hovold }; 3087beabdc3cSJohan Hovold 3088beabdc3cSJohan Hovold module_usb_serial_driver(serial_drivers, keyspan_ids_combined); 3089beabdc3cSJohan Hovold 30901da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR); 30911da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC); 30921da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 30931da177e4SLinus Torvalds 30942971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28.fw"); 30952971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28x.fw"); 30962971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xa.fw"); 30972971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa28xb.fw"); 30982971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19.fw"); 30992971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qi.fw"); 31002971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/mpr.fw"); 31012971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19qw.fw"); 31022971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa18x.fw"); 31032971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa19w.fw"); 31042971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49w.fw"); 31052971c579SDavid Woodhouse MODULE_FIRMWARE("keyspan/usa49wlc.fw"); 3106