18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * USB Keyspan PDA / Xircom / Entrega Converter driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999 - 2001 Greg Kroah-Hartman <greg@kroah.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000 Brian Warner <warner@lothar.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2000 Al Borchers <borchers@steinerpoint.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * See Documentation/usb/usb-serial.rst for more information on using this 108c2ecf20Sopenharmony_ci * driver 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/tty.h> 188c2ecf20Sopenharmony_ci#include <linux/tty_driver.h> 198c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 228c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <linux/usb.h> 258c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 268c2ecf20Sopenharmony_ci#include <linux/usb/ezusb.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* make a simple define to handle if we are compiling keyspan_pda or xircom support */ 298c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_SERIAL_KEYSPAN_PDA) 308c2ecf20Sopenharmony_ci #define KEYSPAN 318c2ecf20Sopenharmony_ci#else 328c2ecf20Sopenharmony_ci #undef KEYSPAN 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_SERIAL_XIRCOM) 358c2ecf20Sopenharmony_ci #define XIRCOM 368c2ecf20Sopenharmony_ci#else 378c2ecf20Sopenharmony_ci #undef XIRCOM 388c2ecf20Sopenharmony_ci#endif 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Brian Warner <warner@lothar.com>" 418c2ecf20Sopenharmony_ci#define DRIVER_DESC "USB Keyspan PDA Converter driver" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define KEYSPAN_TX_THRESHOLD 16 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct keyspan_pda_private { 468c2ecf20Sopenharmony_ci int tx_room; 478c2ecf20Sopenharmony_ci int tx_throttled; 488c2ecf20Sopenharmony_ci struct work_struct unthrottle_work; 498c2ecf20Sopenharmony_ci struct usb_serial *serial; 508c2ecf20Sopenharmony_ci struct usb_serial_port *port; 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define KEYSPAN_VENDOR_ID 0x06cd 558c2ecf20Sopenharmony_ci#define KEYSPAN_PDA_FAKE_ID 0x0103 568c2ecf20Sopenharmony_ci#define KEYSPAN_PDA_ID 0x0104 /* no clue */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* For Xircom PGSDB9 and older Entrega version of the same device */ 598c2ecf20Sopenharmony_ci#define XIRCOM_VENDOR_ID 0x085a 608c2ecf20Sopenharmony_ci#define XIRCOM_FAKE_ID 0x8027 618c2ecf20Sopenharmony_ci#define XIRCOM_FAKE_ID_2 0x8025 /* "PGMFHUB" serial */ 628c2ecf20Sopenharmony_ci#define ENTREGA_VENDOR_ID 0x1645 638c2ecf20Sopenharmony_ci#define ENTREGA_FAKE_ID 0x8093 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table_combined[] = { 668c2ecf20Sopenharmony_ci#ifdef KEYSPAN 678c2ecf20Sopenharmony_ci { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, 688c2ecf20Sopenharmony_ci#endif 698c2ecf20Sopenharmony_ci#ifdef XIRCOM 708c2ecf20Sopenharmony_ci { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, 718c2ecf20Sopenharmony_ci { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, 728c2ecf20Sopenharmony_ci { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, 738c2ecf20Sopenharmony_ci#endif 748c2ecf20Sopenharmony_ci { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, 758c2ecf20Sopenharmony_ci { } /* Terminating entry */ 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table_combined); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table_std[] = { 818c2ecf20Sopenharmony_ci { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, 828c2ecf20Sopenharmony_ci { } /* Terminating entry */ 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#ifdef KEYSPAN 868c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table_fake[] = { 878c2ecf20Sopenharmony_ci { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, 888c2ecf20Sopenharmony_ci { } /* Terminating entry */ 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#ifdef XIRCOM 938c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table_fake_xircom[] = { 948c2ecf20Sopenharmony_ci { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, 958c2ecf20Sopenharmony_ci { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) }, 968c2ecf20Sopenharmony_ci { USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) }, 978c2ecf20Sopenharmony_ci { } 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void keyspan_pda_request_unthrottle(struct work_struct *work) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv = 1048c2ecf20Sopenharmony_ci container_of(work, struct keyspan_pda_private, unthrottle_work); 1058c2ecf20Sopenharmony_ci struct usb_serial *serial = priv->serial; 1068c2ecf20Sopenharmony_ci int result; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* ask the device to tell us when the tx buffer becomes 1098c2ecf20Sopenharmony_ci sufficiently empty */ 1108c2ecf20Sopenharmony_ci result = usb_control_msg(serial->dev, 1118c2ecf20Sopenharmony_ci usb_sndctrlpipe(serial->dev, 0), 1128c2ecf20Sopenharmony_ci 7, /* request_unthrottle */ 1138c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_INTERFACE 1148c2ecf20Sopenharmony_ci | USB_DIR_OUT, 1158c2ecf20Sopenharmony_ci KEYSPAN_TX_THRESHOLD, 1168c2ecf20Sopenharmony_ci 0, /* index */ 1178c2ecf20Sopenharmony_ci NULL, 1188c2ecf20Sopenharmony_ci 0, 1198c2ecf20Sopenharmony_ci 2000); 1208c2ecf20Sopenharmony_ci if (result < 0) 1218c2ecf20Sopenharmony_ci dev_dbg(&serial->dev->dev, "%s - error %d from usb_control_msg\n", 1228c2ecf20Sopenharmony_ci __func__, result); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void keyspan_pda_rx_interrupt(struct urb *urb) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 1298c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 1308c2ecf20Sopenharmony_ci unsigned int len = urb->actual_length; 1318c2ecf20Sopenharmony_ci int retval; 1328c2ecf20Sopenharmony_ci int status = urb->status; 1338c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 1348c2ecf20Sopenharmony_ci unsigned long flags; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci switch (status) { 1398c2ecf20Sopenharmony_ci case 0: 1408c2ecf20Sopenharmony_ci /* success */ 1418c2ecf20Sopenharmony_ci break; 1428c2ecf20Sopenharmony_ci case -ECONNRESET: 1438c2ecf20Sopenharmony_ci case -ENOENT: 1448c2ecf20Sopenharmony_ci case -ESHUTDOWN: 1458c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 1468c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", __func__, status); 1478c2ecf20Sopenharmony_ci return; 1488c2ecf20Sopenharmony_ci default: 1498c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status); 1508c2ecf20Sopenharmony_ci goto exit; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (len < 1) { 1548c2ecf20Sopenharmony_ci dev_warn(&port->dev, "short message received\n"); 1558c2ecf20Sopenharmony_ci goto exit; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* see if the message is data or a status interrupt */ 1598c2ecf20Sopenharmony_ci switch (data[0]) { 1608c2ecf20Sopenharmony_ci case 0: 1618c2ecf20Sopenharmony_ci /* rest of message is rx data */ 1628c2ecf20Sopenharmony_ci if (len < 2) 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci tty_insert_flip_string(&port->port, data + 1, len - 1); 1658c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case 1: 1688c2ecf20Sopenharmony_ci /* status interrupt */ 1698c2ecf20Sopenharmony_ci if (len < 2) { 1708c2ecf20Sopenharmony_ci dev_warn(&port->dev, "short interrupt message received\n"); 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "rx int, d1=%d\n", data[1]); 1748c2ecf20Sopenharmony_ci switch (data[1]) { 1758c2ecf20Sopenharmony_ci case 1: /* modemline change */ 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case 2: /* tx unthrottle interrupt */ 1788c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 1798c2ecf20Sopenharmony_ci priv->tx_throttled = 0; 1808c2ecf20Sopenharmony_ci priv->tx_room = max(priv->tx_room, KEYSPAN_TX_THRESHOLD); 1818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 1828c2ecf20Sopenharmony_ci /* queue up a wakeup at scheduler time */ 1838c2ecf20Sopenharmony_ci usb_serial_port_softint(port); 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci default: 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci default: 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciexit: 1948c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 1958c2ecf20Sopenharmony_ci if (retval) 1968c2ecf20Sopenharmony_ci dev_err(&port->dev, 1978c2ecf20Sopenharmony_ci "%s - usb_submit_urb failed with result %d\n", 1988c2ecf20Sopenharmony_ci __func__, retval); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void keyspan_pda_rx_throttle(struct tty_struct *tty) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci /* stop receiving characters. We just turn off the URB request, and 2058c2ecf20Sopenharmony_ci let chars pile up in the device. If we're doing hardware 2068c2ecf20Sopenharmony_ci flowcontrol, the device will signal the other end when its buffer 2078c2ecf20Sopenharmony_ci fills up. If we're doing XON/XOFF, this would be a good time to 2088c2ecf20Sopenharmony_ci send an XOFF, although it might make sense to foist that off 2098c2ecf20Sopenharmony_ci upon the device too. */ 2108c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void keyspan_pda_rx_unthrottle(struct tty_struct *tty) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 2198c2ecf20Sopenharmony_ci /* just restart the receive interrupt URB */ 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) 2228c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n"); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int rc; 2298c2ecf20Sopenharmony_ci int bindex; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci switch (baud) { 2328c2ecf20Sopenharmony_ci case 110: 2338c2ecf20Sopenharmony_ci bindex = 0; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case 300: 2368c2ecf20Sopenharmony_ci bindex = 1; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci case 1200: 2398c2ecf20Sopenharmony_ci bindex = 2; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case 2400: 2428c2ecf20Sopenharmony_ci bindex = 3; 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case 4800: 2458c2ecf20Sopenharmony_ci bindex = 4; 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case 9600: 2488c2ecf20Sopenharmony_ci bindex = 5; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci case 19200: 2518c2ecf20Sopenharmony_ci bindex = 6; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case 38400: 2548c2ecf20Sopenharmony_ci bindex = 7; 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci case 57600: 2578c2ecf20Sopenharmony_ci bindex = 8; 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci case 115200: 2608c2ecf20Sopenharmony_ci bindex = 9; 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci default: 2638c2ecf20Sopenharmony_ci bindex = 5; /* Default to 9600 */ 2648c2ecf20Sopenharmony_ci baud = 9600; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* rather than figure out how to sleep while waiting for this 2688c2ecf20Sopenharmony_ci to complete, I just use the "legacy" API. */ 2698c2ecf20Sopenharmony_ci rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 2708c2ecf20Sopenharmony_ci 0, /* set baud */ 2718c2ecf20Sopenharmony_ci USB_TYPE_VENDOR 2728c2ecf20Sopenharmony_ci | USB_RECIP_INTERFACE 2738c2ecf20Sopenharmony_ci | USB_DIR_OUT, /* type */ 2748c2ecf20Sopenharmony_ci bindex, /* value */ 2758c2ecf20Sopenharmony_ci 0, /* index */ 2768c2ecf20Sopenharmony_ci NULL, /* &data */ 2778c2ecf20Sopenharmony_ci 0, /* size */ 2788c2ecf20Sopenharmony_ci 2000); /* timeout */ 2798c2ecf20Sopenharmony_ci if (rc < 0) 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci return baud; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 2888c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 2898c2ecf20Sopenharmony_ci int value; 2908c2ecf20Sopenharmony_ci int result; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (break_state == -1) 2938c2ecf20Sopenharmony_ci value = 1; /* start break */ 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci value = 0; /* clear break */ 2968c2ecf20Sopenharmony_ci result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 2978c2ecf20Sopenharmony_ci 4, /* set break */ 2988c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, 2998c2ecf20Sopenharmony_ci value, 0, NULL, 0, 2000); 3008c2ecf20Sopenharmony_ci if (result < 0) 3018c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - error %d from usb_control_msg\n", 3028c2ecf20Sopenharmony_ci __func__, result); 3038c2ecf20Sopenharmony_ci /* there is something funky about this.. the TCSBRK that 'cu' performs 3048c2ecf20Sopenharmony_ci ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 3058c2ecf20Sopenharmony_ci seconds apart, but it feels like the break sent isn't as long as it 3068c2ecf20Sopenharmony_ci is on /dev/ttyS0 */ 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic void keyspan_pda_set_termios(struct tty_struct *tty, 3118c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios *old_termios) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 3148c2ecf20Sopenharmony_ci speed_t speed; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* cflag specifies lots of stuff: number of stop bits, parity, number 3178c2ecf20Sopenharmony_ci of data bits, baud. What can the device actually handle?: 3188c2ecf20Sopenharmony_ci CSTOPB (1 stop bit or 2) 3198c2ecf20Sopenharmony_ci PARENB (parity) 3208c2ecf20Sopenharmony_ci CSIZE (5bit .. 8bit) 3218c2ecf20Sopenharmony_ci There is minimal hw support for parity (a PSW bit seems to hold the 3228c2ecf20Sopenharmony_ci parity of whatever is in the accumulator). The UART either deals 3238c2ecf20Sopenharmony_ci with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data, 3248c2ecf20Sopenharmony_ci 1 special, stop). So, with firmware changes, we could do: 3258c2ecf20Sopenharmony_ci 8N1: 10 bit 3268c2ecf20Sopenharmony_ci 8N2: 11 bit, extra bit always (mark?) 3278c2ecf20Sopenharmony_ci 8[EOMS]1: 11 bit, extra bit is parity 3288c2ecf20Sopenharmony_ci 7[EOMS]1: 10 bit, b0/b7 is parity 3298c2ecf20Sopenharmony_ci 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS 3328c2ecf20Sopenharmony_ci bit. 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci For now, just do baud. */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci speed = tty_get_baud_rate(tty); 3378c2ecf20Sopenharmony_ci speed = keyspan_pda_setbaud(serial, speed); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (speed == 0) { 3408c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "can't handle requested baud rate\n"); 3418c2ecf20Sopenharmony_ci /* It hasn't changed so.. */ 3428c2ecf20Sopenharmony_ci speed = tty_termios_baud_rate(old_termios); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci /* Only speed can change so copy the old h/w parameters 3458c2ecf20Sopenharmony_ci then encode the new speed */ 3468c2ecf20Sopenharmony_ci tty_termios_copy_hw(&tty->termios, old_termios); 3478c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, speed, speed); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* modem control pins: DTR and RTS are outputs and can be controlled. 3528c2ecf20Sopenharmony_ci DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be 3538c2ecf20Sopenharmony_ci read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */ 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int keyspan_pda_get_modem_info(struct usb_serial *serial, 3568c2ecf20Sopenharmony_ci unsigned char *value) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci int rc; 3598c2ecf20Sopenharmony_ci u8 *data; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci data = kmalloc(1, GFP_KERNEL); 3628c2ecf20Sopenharmony_ci if (!data) 3638c2ecf20Sopenharmony_ci return -ENOMEM; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 3668c2ecf20Sopenharmony_ci 3, /* get pins */ 3678c2ecf20Sopenharmony_ci USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN, 3688c2ecf20Sopenharmony_ci 0, 0, data, 1, 2000); 3698c2ecf20Sopenharmony_ci if (rc == 1) 3708c2ecf20Sopenharmony_ci *value = *data; 3718c2ecf20Sopenharmony_ci else if (rc >= 0) 3728c2ecf20Sopenharmony_ci rc = -EIO; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci kfree(data); 3758c2ecf20Sopenharmony_ci return rc; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int keyspan_pda_set_modem_info(struct usb_serial *serial, 3808c2ecf20Sopenharmony_ci unsigned char value) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int rc; 3838c2ecf20Sopenharmony_ci rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 3848c2ecf20Sopenharmony_ci 3, /* set pins */ 3858c2ecf20Sopenharmony_ci USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT, 3868c2ecf20Sopenharmony_ci value, 0, NULL, 0, 2000); 3878c2ecf20Sopenharmony_ci return rc; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int keyspan_pda_tiocmget(struct tty_struct *tty) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 3938c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 3948c2ecf20Sopenharmony_ci int rc; 3958c2ecf20Sopenharmony_ci unsigned char status; 3968c2ecf20Sopenharmony_ci int value; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci rc = keyspan_pda_get_modem_info(serial, &status); 3998c2ecf20Sopenharmony_ci if (rc < 0) 4008c2ecf20Sopenharmony_ci return rc; 4018c2ecf20Sopenharmony_ci value = 4028c2ecf20Sopenharmony_ci ((status & (1<<7)) ? TIOCM_DTR : 0) | 4038c2ecf20Sopenharmony_ci ((status & (1<<6)) ? TIOCM_CAR : 0) | 4048c2ecf20Sopenharmony_ci ((status & (1<<5)) ? TIOCM_RNG : 0) | 4058c2ecf20Sopenharmony_ci ((status & (1<<4)) ? TIOCM_DSR : 0) | 4068c2ecf20Sopenharmony_ci ((status & (1<<3)) ? TIOCM_CTS : 0) | 4078c2ecf20Sopenharmony_ci ((status & (1<<2)) ? TIOCM_RTS : 0); 4088c2ecf20Sopenharmony_ci return value; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int keyspan_pda_tiocmset(struct tty_struct *tty, 4128c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 4158c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 4168c2ecf20Sopenharmony_ci int rc; 4178c2ecf20Sopenharmony_ci unsigned char status; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci rc = keyspan_pda_get_modem_info(serial, &status); 4208c2ecf20Sopenharmony_ci if (rc < 0) 4218c2ecf20Sopenharmony_ci return rc; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 4248c2ecf20Sopenharmony_ci status |= (1<<2); 4258c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) 4268c2ecf20Sopenharmony_ci status |= (1<<7); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 4298c2ecf20Sopenharmony_ci status &= ~(1<<2); 4308c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) 4318c2ecf20Sopenharmony_ci status &= ~(1<<7); 4328c2ecf20Sopenharmony_ci rc = keyspan_pda_set_modem_info(serial, status); 4338c2ecf20Sopenharmony_ci return rc; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int keyspan_pda_write(struct tty_struct *tty, 4378c2ecf20Sopenharmony_ci struct usb_serial_port *port, const unsigned char *buf, int count) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 4408c2ecf20Sopenharmony_ci int request_unthrottle = 0; 4418c2ecf20Sopenharmony_ci int rc = 0; 4428c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 4438c2ecf20Sopenharmony_ci unsigned long flags; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 4468c2ecf20Sopenharmony_ci /* guess how much room is left in the device's ring buffer, and if we 4478c2ecf20Sopenharmony_ci want to send more than that, check first, updating our notion of 4488c2ecf20Sopenharmony_ci what is left. If our write will result in no room left, ask the 4498c2ecf20Sopenharmony_ci device to give us an interrupt when the room available rises above 4508c2ecf20Sopenharmony_ci a threshold, and hold off all writers (eventually, those using 4518c2ecf20Sopenharmony_ci select() or poll() too) until we receive that unthrottle interrupt. 4528c2ecf20Sopenharmony_ci Block if we can't write anything at all, otherwise write as much as 4538c2ecf20Sopenharmony_ci we can. */ 4548c2ecf20Sopenharmony_ci if (count == 0) { 4558c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "write request of 0 bytes\n"); 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* we might block because of: 4608c2ecf20Sopenharmony_ci the TX urb is in-flight (wait until it completes) 4618c2ecf20Sopenharmony_ci the device is full (wait until it says there is room) 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 4648c2ecf20Sopenharmony_ci if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) { 4658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci clear_bit(0, &port->write_urbs_free); 4698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* At this point the URB is in our control, nobody else can submit it 4728c2ecf20Sopenharmony_ci again (the only sudden transition was the one from EINPROGRESS to 4738c2ecf20Sopenharmony_ci finished). Also, the tx process is not throttled. So we are 4748c2ecf20Sopenharmony_ci ready to write. */ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci count = (count > port->bulk_out_size) ? port->bulk_out_size : count; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* Check if we might overrun the Tx buffer. If so, ask the 4798c2ecf20Sopenharmony_ci device how much room it really has. This is done only on 4808c2ecf20Sopenharmony_ci scheduler time, since usb_control_msg() sleeps. */ 4818c2ecf20Sopenharmony_ci if (count > priv->tx_room && !in_interrupt()) { 4828c2ecf20Sopenharmony_ci u8 *room; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci room = kmalloc(1, GFP_KERNEL); 4858c2ecf20Sopenharmony_ci if (!room) { 4868c2ecf20Sopenharmony_ci rc = -ENOMEM; 4878c2ecf20Sopenharmony_ci goto exit; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci rc = usb_control_msg(serial->dev, 4918c2ecf20Sopenharmony_ci usb_rcvctrlpipe(serial->dev, 0), 4928c2ecf20Sopenharmony_ci 6, /* write_room */ 4938c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_INTERFACE 4948c2ecf20Sopenharmony_ci | USB_DIR_IN, 4958c2ecf20Sopenharmony_ci 0, /* value: 0 means "remaining room" */ 4968c2ecf20Sopenharmony_ci 0, /* index */ 4978c2ecf20Sopenharmony_ci room, 4988c2ecf20Sopenharmony_ci 1, 4998c2ecf20Sopenharmony_ci 2000); 5008c2ecf20Sopenharmony_ci if (rc > 0) { 5018c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "roomquery says %d\n", *room); 5028c2ecf20Sopenharmony_ci priv->tx_room = *room; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci kfree(room); 5058c2ecf20Sopenharmony_ci if (rc < 0) { 5068c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "roomquery failed\n"); 5078c2ecf20Sopenharmony_ci goto exit; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci if (rc == 0) { 5108c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "roomquery returned 0 bytes\n"); 5118c2ecf20Sopenharmony_ci rc = -EIO; /* device didn't return any data */ 5128c2ecf20Sopenharmony_ci goto exit; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (count >= priv->tx_room) { 5178c2ecf20Sopenharmony_ci /* we're about to completely fill the Tx buffer, so 5188c2ecf20Sopenharmony_ci we'll be throttled afterwards. */ 5198c2ecf20Sopenharmony_ci count = priv->tx_room; 5208c2ecf20Sopenharmony_ci request_unthrottle = 1; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (count) { 5248c2ecf20Sopenharmony_ci /* now transfer data */ 5258c2ecf20Sopenharmony_ci memcpy(port->write_urb->transfer_buffer, buf, count); 5268c2ecf20Sopenharmony_ci /* send the data out the bulk port */ 5278c2ecf20Sopenharmony_ci port->write_urb->transfer_buffer_length = count; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci priv->tx_room -= count; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); 5328c2ecf20Sopenharmony_ci if (rc) { 5338c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "usb_submit_urb(write bulk) failed\n"); 5348c2ecf20Sopenharmony_ci goto exit; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci } else { 5378c2ecf20Sopenharmony_ci /* There wasn't any room left, so we are throttled until 5388c2ecf20Sopenharmony_ci the buffer empties a bit */ 5398c2ecf20Sopenharmony_ci request_unthrottle = 1; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (request_unthrottle) { 5438c2ecf20Sopenharmony_ci priv->tx_throttled = 1; /* block writers */ 5448c2ecf20Sopenharmony_ci schedule_work(&priv->unthrottle_work); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci rc = count; 5488c2ecf20Sopenharmony_ciexit: 5498c2ecf20Sopenharmony_ci if (rc <= 0) 5508c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 5518c2ecf20Sopenharmony_ci return rc; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic void keyspan_pda_write_bulk_callback(struct urb *urb) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci set_bit(0, &port->write_urbs_free); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* queue up a wakeup at scheduler time */ 5628c2ecf20Sopenharmony_ci usb_serial_port_softint(port); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int keyspan_pda_write_room(struct tty_struct *tty) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 5698c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv = usb_get_serial_port_data(port); 5708c2ecf20Sopenharmony_ci unsigned long flags; 5718c2ecf20Sopenharmony_ci int room = 0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 5748c2ecf20Sopenharmony_ci if (test_bit(0, &port->write_urbs_free) && !priv->tx_throttled) 5758c2ecf20Sopenharmony_ci room = priv->tx_room; 5768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return room; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic int keyspan_pda_chars_in_buffer(struct tty_struct *tty) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 5848c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 5858c2ecf20Sopenharmony_ci unsigned long flags; 5868c2ecf20Sopenharmony_ci int ret = 0; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* when throttled, return at least WAKEUP_CHARS to tell select() (via 5918c2ecf20Sopenharmony_ci n_tty.c:normal_poll() ) that we're not writeable. */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 5948c2ecf20Sopenharmony_ci if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) 5958c2ecf20Sopenharmony_ci ret = 256; 5968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 5978c2ecf20Sopenharmony_ci return ret; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (on) 6068c2ecf20Sopenharmony_ci keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2)); 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci keyspan_pda_set_modem_info(serial, 0); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int keyspan_pda_open(struct tty_struct *tty, 6138c2ecf20Sopenharmony_ci struct usb_serial_port *port) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 6168c2ecf20Sopenharmony_ci u8 *room; 6178c2ecf20Sopenharmony_ci int rc = 0; 6188c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* find out how much room is in the Tx ring */ 6218c2ecf20Sopenharmony_ci room = kmalloc(1, GFP_KERNEL); 6228c2ecf20Sopenharmony_ci if (!room) 6238c2ecf20Sopenharmony_ci return -ENOMEM; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 6268c2ecf20Sopenharmony_ci 6, /* write_room */ 6278c2ecf20Sopenharmony_ci USB_TYPE_VENDOR | USB_RECIP_INTERFACE 6288c2ecf20Sopenharmony_ci | USB_DIR_IN, 6298c2ecf20Sopenharmony_ci 0, /* value */ 6308c2ecf20Sopenharmony_ci 0, /* index */ 6318c2ecf20Sopenharmony_ci room, 6328c2ecf20Sopenharmony_ci 1, 6338c2ecf20Sopenharmony_ci 2000); 6348c2ecf20Sopenharmony_ci if (rc < 0) { 6358c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - roomquery failed\n", __func__); 6368c2ecf20Sopenharmony_ci goto error; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci if (rc == 0) { 6398c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - roomquery returned 0 bytes\n", __func__); 6408c2ecf20Sopenharmony_ci rc = -EIO; 6418c2ecf20Sopenharmony_ci goto error; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 6448c2ecf20Sopenharmony_ci priv->tx_room = *room; 6458c2ecf20Sopenharmony_ci priv->tx_throttled = *room ? 0 : 1; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /*Start reading from the device*/ 6488c2ecf20Sopenharmony_ci rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 6498c2ecf20Sopenharmony_ci if (rc) { 6508c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - usb_submit_urb(read int) failed\n", __func__); 6518c2ecf20Sopenharmony_ci goto error; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_cierror: 6548c2ecf20Sopenharmony_ci kfree(room); 6558c2ecf20Sopenharmony_ci return rc; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_cistatic void keyspan_pda_close(struct usb_serial_port *port) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv = usb_get_serial_port_data(port); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci usb_kill_urb(port->write_urb); 6628c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci cancel_work_sync(&priv->unthrottle_work); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/* download the firmware to a "fake" device (pre-renumeration) */ 6698c2ecf20Sopenharmony_cistatic int keyspan_pda_fake_startup(struct usb_serial *serial) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci const char *fw_name; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* download the firmware here ... */ 6748c2ecf20Sopenharmony_ci ezusb_fx1_set_reset(serial->dev, 1); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (0) { ; } 6778c2ecf20Sopenharmony_ci#ifdef KEYSPAN 6788c2ecf20Sopenharmony_ci else if (le16_to_cpu(serial->dev->descriptor.idVendor) == KEYSPAN_VENDOR_ID) 6798c2ecf20Sopenharmony_ci fw_name = "keyspan_pda/keyspan_pda.fw"; 6808c2ecf20Sopenharmony_ci#endif 6818c2ecf20Sopenharmony_ci#ifdef XIRCOM 6828c2ecf20Sopenharmony_ci else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) || 6838c2ecf20Sopenharmony_ci (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGA_VENDOR_ID)) 6848c2ecf20Sopenharmony_ci fw_name = "keyspan_pda/xircom_pgs.fw"; 6858c2ecf20Sopenharmony_ci#endif 6868c2ecf20Sopenharmony_ci else { 6878c2ecf20Sopenharmony_ci dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n", 6888c2ecf20Sopenharmony_ci __func__); 6898c2ecf20Sopenharmony_ci return -ENODEV; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (ezusb_fx1_ihex_firmware_download(serial->dev, fw_name) < 0) { 6938c2ecf20Sopenharmony_ci dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", 6948c2ecf20Sopenharmony_ci fw_name); 6958c2ecf20Sopenharmony_ci return -ENOENT; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* after downloading firmware Renumeration will occur in a 6998c2ecf20Sopenharmony_ci moment and the new device will bind to the real driver */ 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* we want this device to fail to have a driver assigned to it. */ 7028c2ecf20Sopenharmony_ci return 1; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci#ifdef KEYSPAN 7068c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); 7078c2ecf20Sopenharmony_ci#endif 7088c2ecf20Sopenharmony_ci#ifdef XIRCOM 7098c2ecf20Sopenharmony_ciMODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); 7108c2ecf20Sopenharmony_ci#endif 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int keyspan_pda_port_probe(struct usb_serial_port *port) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci priv = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); 7188c2ecf20Sopenharmony_ci if (!priv) 7198c2ecf20Sopenharmony_ci return -ENOMEM; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); 7228c2ecf20Sopenharmony_ci priv->serial = port->serial; 7238c2ecf20Sopenharmony_ci priv->port = port; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int keyspan_pda_port_remove(struct usb_serial_port *port) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct keyspan_pda_private *priv; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci priv = usb_get_serial_port_data(port); 7358c2ecf20Sopenharmony_ci kfree(priv); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return 0; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci#ifdef KEYSPAN 7418c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_pda_fake_device = { 7428c2ecf20Sopenharmony_ci .driver = { 7438c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7448c2ecf20Sopenharmony_ci .name = "keyspan_pda_pre", 7458c2ecf20Sopenharmony_ci }, 7468c2ecf20Sopenharmony_ci .description = "Keyspan PDA - (prerenumeration)", 7478c2ecf20Sopenharmony_ci .id_table = id_table_fake, 7488c2ecf20Sopenharmony_ci .num_ports = 1, 7498c2ecf20Sopenharmony_ci .attach = keyspan_pda_fake_startup, 7508c2ecf20Sopenharmony_ci}; 7518c2ecf20Sopenharmony_ci#endif 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci#ifdef XIRCOM 7548c2ecf20Sopenharmony_cistatic struct usb_serial_driver xircom_pgs_fake_device = { 7558c2ecf20Sopenharmony_ci .driver = { 7568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7578c2ecf20Sopenharmony_ci .name = "xircom_no_firm", 7588c2ecf20Sopenharmony_ci }, 7598c2ecf20Sopenharmony_ci .description = "Xircom / Entrega PGS - (prerenumeration)", 7608c2ecf20Sopenharmony_ci .id_table = id_table_fake_xircom, 7618c2ecf20Sopenharmony_ci .num_ports = 1, 7628c2ecf20Sopenharmony_ci .attach = keyspan_pda_fake_startup, 7638c2ecf20Sopenharmony_ci}; 7648c2ecf20Sopenharmony_ci#endif 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic struct usb_serial_driver keyspan_pda_device = { 7678c2ecf20Sopenharmony_ci .driver = { 7688c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7698c2ecf20Sopenharmony_ci .name = "keyspan_pda", 7708c2ecf20Sopenharmony_ci }, 7718c2ecf20Sopenharmony_ci .description = "Keyspan PDA", 7728c2ecf20Sopenharmony_ci .id_table = id_table_std, 7738c2ecf20Sopenharmony_ci .num_ports = 1, 7748c2ecf20Sopenharmony_ci .num_bulk_out = 1, 7758c2ecf20Sopenharmony_ci .num_interrupt_in = 1, 7768c2ecf20Sopenharmony_ci .dtr_rts = keyspan_pda_dtr_rts, 7778c2ecf20Sopenharmony_ci .open = keyspan_pda_open, 7788c2ecf20Sopenharmony_ci .close = keyspan_pda_close, 7798c2ecf20Sopenharmony_ci .write = keyspan_pda_write, 7808c2ecf20Sopenharmony_ci .write_room = keyspan_pda_write_room, 7818c2ecf20Sopenharmony_ci .write_bulk_callback = keyspan_pda_write_bulk_callback, 7828c2ecf20Sopenharmony_ci .read_int_callback = keyspan_pda_rx_interrupt, 7838c2ecf20Sopenharmony_ci .chars_in_buffer = keyspan_pda_chars_in_buffer, 7848c2ecf20Sopenharmony_ci .throttle = keyspan_pda_rx_throttle, 7858c2ecf20Sopenharmony_ci .unthrottle = keyspan_pda_rx_unthrottle, 7868c2ecf20Sopenharmony_ci .set_termios = keyspan_pda_set_termios, 7878c2ecf20Sopenharmony_ci .break_ctl = keyspan_pda_break_ctl, 7888c2ecf20Sopenharmony_ci .tiocmget = keyspan_pda_tiocmget, 7898c2ecf20Sopenharmony_ci .tiocmset = keyspan_pda_tiocmset, 7908c2ecf20Sopenharmony_ci .port_probe = keyspan_pda_port_probe, 7918c2ecf20Sopenharmony_ci .port_remove = keyspan_pda_port_remove, 7928c2ecf20Sopenharmony_ci}; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 7958c2ecf20Sopenharmony_ci &keyspan_pda_device, 7968c2ecf20Sopenharmony_ci#ifdef KEYSPAN 7978c2ecf20Sopenharmony_ci &keyspan_pda_fake_device, 7988c2ecf20Sopenharmony_ci#endif 7998c2ecf20Sopenharmony_ci#ifdef XIRCOM 8008c2ecf20Sopenharmony_ci &xircom_pgs_fake_device, 8018c2ecf20Sopenharmony_ci#endif 8028c2ecf20Sopenharmony_ci NULL 8038c2ecf20Sopenharmony_ci}; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table_combined); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 8088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 8098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 810