18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Prolific PL2303 USB to serial adaptor driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 IBM Corp. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Original driver for 2.2.x by anonymous 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * See Documentation/usb/usb-serial.rst for more information on using this 118c2ecf20Sopenharmony_ci * driver 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/serial.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 258c2ecf20Sopenharmony_ci#include <linux/usb.h> 268c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 278c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 288c2ecf20Sopenharmony_ci#include "pl2303.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) 328c2ecf20Sopenharmony_ci#define PL2303_QUIRK_LEGACY BIT(1) 338c2ecf20Sopenharmony_ci#define PL2303_QUIRK_ENDPOINT_HACK BIT(2) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 368c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID), 378c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 388c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, 398c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, 408c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, 418c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_CHILITAG) }, 428c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, 438c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, 448c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, 458c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, 468c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, 478c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, 488c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, 498c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, 508c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GC) }, 518c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GB) }, 528c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GT) }, 538c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) }, 548c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) }, 558c2ecf20Sopenharmony_ci { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) }, 568c2ecf20Sopenharmony_ci { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, 578c2ecf20Sopenharmony_ci { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, 588c2ecf20Sopenharmony_ci { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), 598c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 608c2ecf20Sopenharmony_ci { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485), 618c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 628c2ecf20Sopenharmony_ci { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC232B), 638c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 648c2ecf20Sopenharmony_ci { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) }, 658c2ecf20Sopenharmony_ci { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, 668c2ecf20Sopenharmony_ci { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, 678c2ecf20Sopenharmony_ci { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, 688c2ecf20Sopenharmony_ci { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, 698c2ecf20Sopenharmony_ci { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, 708c2ecf20Sopenharmony_ci { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, 718c2ecf20Sopenharmony_ci { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, 728c2ecf20Sopenharmony_ci { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, 738c2ecf20Sopenharmony_ci { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, 748c2ecf20Sopenharmony_ci { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, 758c2ecf20Sopenharmony_ci { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, 768c2ecf20Sopenharmony_ci { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, 778c2ecf20Sopenharmony_ci { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), 788c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 798c2ecf20Sopenharmony_ci { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), 808c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 818c2ecf20Sopenharmony_ci { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), 828c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 838c2ecf20Sopenharmony_ci { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81), 848c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 858c2ecf20Sopenharmony_ci { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ 868c2ecf20Sopenharmony_ci { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 878c2ecf20Sopenharmony_ci { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, 888c2ecf20Sopenharmony_ci { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, 898c2ecf20Sopenharmony_ci { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, 908c2ecf20Sopenharmony_ci { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, 918c2ecf20Sopenharmony_ci { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, 928c2ecf20Sopenharmony_ci { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, 938c2ecf20Sopenharmony_ci { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, 948c2ecf20Sopenharmony_ci { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID), 958c2ecf20Sopenharmony_ci .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, 968c2ecf20Sopenharmony_ci { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, 978c2ecf20Sopenharmony_ci { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, 988c2ecf20Sopenharmony_ci { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, 998c2ecf20Sopenharmony_ci { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, 1008c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, 1018c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) }, 1028c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD381_PRODUCT_ID) }, 1038c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD381GC_PRODUCT_ID) }, 1048c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, 1058c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) }, 1068c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, 1078c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) }, 1088c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) }, 1098c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LM930_PRODUCT_ID) }, 1108c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) }, 1118c2ecf20Sopenharmony_ci { USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) }, 1128c2ecf20Sopenharmony_ci { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, 1138c2ecf20Sopenharmony_ci { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, 1148c2ecf20Sopenharmony_ci { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, 1158c2ecf20Sopenharmony_ci { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, 1168c2ecf20Sopenharmony_ci { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, 1178c2ecf20Sopenharmony_ci { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530GC_PRODUCT_ID) }, 1188c2ecf20Sopenharmony_ci { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, 1198c2ecf20Sopenharmony_ci { USB_DEVICE(AT_VENDOR_ID, AT_VTKIT3_PRODUCT_ID) }, 1208c2ecf20Sopenharmony_ci { USB_DEVICE(IBM_VENDOR_ID, IBM_PRODUCT_ID) }, 1218c2ecf20Sopenharmony_ci { } /* Terminating entry */ 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define SET_LINE_REQUEST_TYPE 0x21 1278c2ecf20Sopenharmony_ci#define SET_LINE_REQUEST 0x20 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define SET_CONTROL_REQUEST_TYPE 0x21 1308c2ecf20Sopenharmony_ci#define SET_CONTROL_REQUEST 0x22 1318c2ecf20Sopenharmony_ci#define CONTROL_DTR 0x01 1328c2ecf20Sopenharmony_ci#define CONTROL_RTS 0x02 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define BREAK_REQUEST_TYPE 0x21 1358c2ecf20Sopenharmony_ci#define BREAK_REQUEST 0x23 1368c2ecf20Sopenharmony_ci#define BREAK_ON 0xffff 1378c2ecf20Sopenharmony_ci#define BREAK_OFF 0x0000 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define GET_LINE_REQUEST_TYPE 0xa1 1408c2ecf20Sopenharmony_ci#define GET_LINE_REQUEST 0x21 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci#define VENDOR_WRITE_REQUEST_TYPE 0x40 1438c2ecf20Sopenharmony_ci#define VENDOR_WRITE_REQUEST 0x01 1448c2ecf20Sopenharmony_ci#define VENDOR_WRITE_NREQUEST 0x80 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#define VENDOR_READ_REQUEST_TYPE 0xc0 1478c2ecf20Sopenharmony_ci#define VENDOR_READ_REQUEST 0x01 1488c2ecf20Sopenharmony_ci#define VENDOR_READ_NREQUEST 0x81 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define UART_STATE_INDEX 8 1518c2ecf20Sopenharmony_ci#define UART_STATE_MSR_MASK 0x8b 1528c2ecf20Sopenharmony_ci#define UART_STATE_TRANSIENT_MASK 0x74 1538c2ecf20Sopenharmony_ci#define UART_DCD 0x01 1548c2ecf20Sopenharmony_ci#define UART_DSR 0x02 1558c2ecf20Sopenharmony_ci#define UART_BREAK_ERROR 0x04 1568c2ecf20Sopenharmony_ci#define UART_RING 0x08 1578c2ecf20Sopenharmony_ci#define UART_FRAME_ERROR 0x10 1588c2ecf20Sopenharmony_ci#define UART_PARITY_ERROR 0x20 1598c2ecf20Sopenharmony_ci#define UART_OVERRUN_ERROR 0x40 1608c2ecf20Sopenharmony_ci#define UART_CTS 0x80 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define PL2303_FLOWCTRL_MASK 0xf0 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define PL2303_READ_TYPE_HX_STATUS 0x8080 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define PL2303_HXN_RESET_REG 0x07 1678c2ecf20Sopenharmony_ci#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 1688c2ecf20Sopenharmony_ci#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define PL2303_HXN_FLOWCTRL_REG 0x0a 1718c2ecf20Sopenharmony_ci#define PL2303_HXN_FLOWCTRL_MASK 0x1c 1728c2ecf20Sopenharmony_ci#define PL2303_HXN_FLOWCTRL_NONE 0x1c 1738c2ecf20Sopenharmony_ci#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 1748c2ecf20Sopenharmony_ci#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void pl2303_set_break(struct usb_serial_port *port, bool enable); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cienum pl2303_type { 1798c2ecf20Sopenharmony_ci TYPE_01, /* Type 0 and 1 (difference unknown) */ 1808c2ecf20Sopenharmony_ci TYPE_HX, /* HX version of the pl2303 chip */ 1818c2ecf20Sopenharmony_ci TYPE_HXN, /* HXN version of the pl2303 chip */ 1828c2ecf20Sopenharmony_ci TYPE_COUNT 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistruct pl2303_type_data { 1868c2ecf20Sopenharmony_ci speed_t max_baud_rate; 1878c2ecf20Sopenharmony_ci unsigned long quirks; 1888c2ecf20Sopenharmony_ci unsigned int no_autoxonxoff:1; 1898c2ecf20Sopenharmony_ci unsigned int no_divisors:1; 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistruct pl2303_serial_private { 1938c2ecf20Sopenharmony_ci const struct pl2303_type_data *type; 1948c2ecf20Sopenharmony_ci unsigned long quirks; 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistruct pl2303_private { 1988c2ecf20Sopenharmony_ci spinlock_t lock; 1998c2ecf20Sopenharmony_ci u8 line_control; 2008c2ecf20Sopenharmony_ci u8 line_status; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci u8 line_settings[7]; 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { 2068c2ecf20Sopenharmony_ci [TYPE_01] = { 2078c2ecf20Sopenharmony_ci .max_baud_rate = 1228800, 2088c2ecf20Sopenharmony_ci .quirks = PL2303_QUIRK_LEGACY, 2098c2ecf20Sopenharmony_ci .no_autoxonxoff = true, 2108c2ecf20Sopenharmony_ci }, 2118c2ecf20Sopenharmony_ci [TYPE_HX] = { 2128c2ecf20Sopenharmony_ci .max_baud_rate = 12000000, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci [TYPE_HXN] = { 2158c2ecf20Sopenharmony_ci .max_baud_rate = 12000000, 2168c2ecf20Sopenharmony_ci .no_divisors = true, 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int pl2303_vendor_read(struct usb_serial *serial, u16 value, 2218c2ecf20Sopenharmony_ci unsigned char buf[1]) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 2248c2ecf20Sopenharmony_ci struct device *dev = &serial->interface->dev; 2258c2ecf20Sopenharmony_ci u8 request; 2268c2ecf20Sopenharmony_ci int res; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) 2298c2ecf20Sopenharmony_ci request = VENDOR_READ_NREQUEST; 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci request = VENDOR_READ_REQUEST; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2348c2ecf20Sopenharmony_ci request, VENDOR_READ_REQUEST_TYPE, 2358c2ecf20Sopenharmony_ci value, 0, buf, 1, 100); 2368c2ecf20Sopenharmony_ci if (res != 1) { 2378c2ecf20Sopenharmony_ci dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, 2388c2ecf20Sopenharmony_ci value, res); 2398c2ecf20Sopenharmony_ci if (res >= 0) 2408c2ecf20Sopenharmony_ci res = -EIO; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return res; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 2538c2ecf20Sopenharmony_ci struct device *dev = &serial->interface->dev; 2548c2ecf20Sopenharmony_ci u8 request; 2558c2ecf20Sopenharmony_ci int res; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) 2608c2ecf20Sopenharmony_ci request = VENDOR_WRITE_NREQUEST; 2618c2ecf20Sopenharmony_ci else 2628c2ecf20Sopenharmony_ci request = VENDOR_WRITE_REQUEST; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 2658c2ecf20Sopenharmony_ci request, VENDOR_WRITE_REQUEST_TYPE, 2668c2ecf20Sopenharmony_ci value, index, NULL, 0, 100); 2678c2ecf20Sopenharmony_ci if (res) { 2688c2ecf20Sopenharmony_ci dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, 2698c2ecf20Sopenharmony_ci value, res); 2708c2ecf20Sopenharmony_ci return res; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 2798c2ecf20Sopenharmony_ci int ret = 0; 2808c2ecf20Sopenharmony_ci u8 *buf; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci buf = kmalloc(1, GFP_KERNEL); 2838c2ecf20Sopenharmony_ci if (!buf) 2848c2ecf20Sopenharmony_ci return -ENOMEM; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) 2878c2ecf20Sopenharmony_ci ret = pl2303_vendor_read(serial, reg, buf); 2888c2ecf20Sopenharmony_ci else 2898c2ecf20Sopenharmony_ci ret = pl2303_vendor_read(serial, reg | 0x80, buf); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (ret) 2928c2ecf20Sopenharmony_ci goto out_free; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci *buf &= ~mask; 2958c2ecf20Sopenharmony_ci *buf |= val & mask; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci ret = pl2303_vendor_write(serial, reg, *buf); 2988c2ecf20Sopenharmony_ciout_free: 2998c2ecf20Sopenharmony_ci kfree(buf); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return ret; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int pl2303_probe(struct usb_serial *serial, 3058c2ecf20Sopenharmony_ci const struct usb_device_id *id) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci usb_set_serial_data(serial, (void *)id->driver_info); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* 3138c2ecf20Sopenharmony_ci * Use interrupt endpoint from first interface if available. 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * This is needed due to the looney way its endpoints are set up. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic int pl2303_endpoint_hack(struct usb_serial *serial, 3188c2ecf20Sopenharmony_ci struct usb_serial_endpoints *epds) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct usb_interface *interface = serial->interface; 3218c2ecf20Sopenharmony_ci struct usb_device *dev = serial->dev; 3228c2ecf20Sopenharmony_ci struct device *ddev = &interface->dev; 3238c2ecf20Sopenharmony_ci struct usb_host_interface *iface_desc; 3248c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 3258c2ecf20Sopenharmony_ci unsigned int i; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (interface == dev->actconfig->interface[0]) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* check out the endpoints of the other interface */ 3318c2ecf20Sopenharmony_ci iface_desc = dev->actconfig->interface[0]->cur_altsetting; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 3348c2ecf20Sopenharmony_ci endpoint = &iface_desc->endpoint[i].desc; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (!usb_endpoint_is_int_in(endpoint)) 3378c2ecf20Sopenharmony_ci continue; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci dev_dbg(ddev, "found interrupt in on separate interface\n"); 3408c2ecf20Sopenharmony_ci if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in)) 3418c2ecf20Sopenharmony_ci epds->interrupt_in[epds->num_interrupt_in++] = endpoint; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int pl2303_calc_num_ports(struct usb_serial *serial, 3488c2ecf20Sopenharmony_ci struct usb_serial_endpoints *epds) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci unsigned long quirks = (unsigned long)usb_get_serial_data(serial); 3518c2ecf20Sopenharmony_ci struct device *dev = &serial->interface->dev; 3528c2ecf20Sopenharmony_ci int ret; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (quirks & PL2303_QUIRK_ENDPOINT_HACK) { 3558c2ecf20Sopenharmony_ci ret = pl2303_endpoint_hack(serial, epds); 3568c2ecf20Sopenharmony_ci if (ret) 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (epds->num_interrupt_in < 1) { 3618c2ecf20Sopenharmony_ci dev_err(dev, "required interrupt-in endpoint missing\n"); 3628c2ecf20Sopenharmony_ci return -ENODEV; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return 1; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int pl2303_startup(struct usb_serial *serial) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv; 3718c2ecf20Sopenharmony_ci enum pl2303_type type = TYPE_01; 3728c2ecf20Sopenharmony_ci unsigned char *buf; 3738c2ecf20Sopenharmony_ci int res; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); 3768c2ecf20Sopenharmony_ci if (!spriv) 3778c2ecf20Sopenharmony_ci return -ENOMEM; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci buf = kmalloc(1, GFP_KERNEL); 3808c2ecf20Sopenharmony_ci if (!buf) { 3818c2ecf20Sopenharmony_ci kfree(spriv); 3828c2ecf20Sopenharmony_ci return -ENOMEM; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (serial->dev->descriptor.bDeviceClass == 0x02) 3868c2ecf20Sopenharmony_ci type = TYPE_01; /* type 0 */ 3878c2ecf20Sopenharmony_ci else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) 3888c2ecf20Sopenharmony_ci type = TYPE_HX; 3898c2ecf20Sopenharmony_ci else if (serial->dev->descriptor.bDeviceClass == 0x00) 3908c2ecf20Sopenharmony_ci type = TYPE_01; /* type 1 */ 3918c2ecf20Sopenharmony_ci else if (serial->dev->descriptor.bDeviceClass == 0xFF) 3928c2ecf20Sopenharmony_ci type = TYPE_01; /* type 1 */ 3938c2ecf20Sopenharmony_ci dev_dbg(&serial->interface->dev, "device type: %d\n", type); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (type == TYPE_HX) { 3968c2ecf20Sopenharmony_ci res = usb_control_msg(serial->dev, 3978c2ecf20Sopenharmony_ci usb_rcvctrlpipe(serial->dev, 0), 3988c2ecf20Sopenharmony_ci VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, 3998c2ecf20Sopenharmony_ci PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100); 4008c2ecf20Sopenharmony_ci if (res != 1) 4018c2ecf20Sopenharmony_ci type = TYPE_HXN; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci spriv->type = &pl2303_type_data[type]; 4058c2ecf20Sopenharmony_ci spriv->quirks = (unsigned long)usb_get_serial_data(serial); 4068c2ecf20Sopenharmony_ci spriv->quirks |= spriv->type->quirks; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci usb_set_serial_data(serial, spriv); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (type != TYPE_HXN) { 4118c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8484, buf); 4128c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 0x0404, 0); 4138c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8484, buf); 4148c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8383, buf); 4158c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8484, buf); 4168c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 0x0404, 1); 4178c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8484, buf); 4188c2ecf20Sopenharmony_ci pl2303_vendor_read(serial, 0x8383, buf); 4198c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 0, 1); 4208c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 1, 0); 4218c2ecf20Sopenharmony_ci if (spriv->quirks & PL2303_QUIRK_LEGACY) 4228c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 2, 0x24); 4238c2ecf20Sopenharmony_ci else 4248c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 2, 0x44); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci kfree(buf); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic void pl2303_release(struct usb_serial *serial) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci kfree(spriv); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int pl2303_port_probe(struct usb_serial_port *port) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct pl2303_private *priv; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 4448c2ecf20Sopenharmony_ci if (!priv) 4458c2ecf20Sopenharmony_ci return -ENOMEM; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci usb_set_serial_port_data(port, priv); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci port->port.drain_delay = 256; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int pl2303_port_remove(struct usb_serial_port *port) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci kfree(priv); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct usb_device *dev = port->serial->dev; 4688c2ecf20Sopenharmony_ci int retval; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - %02x\n", __func__, value); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 4738c2ecf20Sopenharmony_ci SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, 4748c2ecf20Sopenharmony_ci value, 0, NULL, 0, 100); 4758c2ecf20Sopenharmony_ci if (retval) 4768c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return retval; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* 4828c2ecf20Sopenharmony_ci * Returns the nearest supported baud rate that can be set directly without 4838c2ecf20Sopenharmony_ci * using divisors. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_cistatic speed_t pl2303_get_supported_baud_rate(speed_t baud) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci static const speed_t baud_sup[] = { 4888c2ecf20Sopenharmony_ci 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 4898c2ecf20Sopenharmony_ci 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, 4908c2ecf20Sopenharmony_ci 614400, 921600, 1228800, 2457600, 3000000, 6000000 4918c2ecf20Sopenharmony_ci }; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci unsigned i; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { 4968c2ecf20Sopenharmony_ci if (baud_sup[i] > baud) 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(baud_sup)) 5018c2ecf20Sopenharmony_ci baud = baud_sup[i - 1]; 5028c2ecf20Sopenharmony_ci else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) 5038c2ecf20Sopenharmony_ci baud = baud_sup[i - 1]; 5048c2ecf20Sopenharmony_ci else 5058c2ecf20Sopenharmony_ci baud = baud_sup[i]; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return baud; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/* 5118c2ecf20Sopenharmony_ci * NOTE: If unsupported baud rates are set directly, the PL2303 seems to 5128c2ecf20Sopenharmony_ci * use 9600 baud. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_cistatic speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4], 5158c2ecf20Sopenharmony_ci speed_t baud) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci put_unaligned_le32(baud, buf); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return baud; 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], 5238c2ecf20Sopenharmony_ci speed_t baud) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci unsigned int baseline, mantissa, exponent; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * Apparently the formula is: 5298c2ecf20Sopenharmony_ci * baudrate = 12M * 32 / (mantissa * 4^exponent) 5308c2ecf20Sopenharmony_ci * where 5318c2ecf20Sopenharmony_ci * mantissa = buf[8:0] 5328c2ecf20Sopenharmony_ci * exponent = buf[11:9] 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci baseline = 12000000 * 32; 5358c2ecf20Sopenharmony_ci mantissa = baseline / baud; 5368c2ecf20Sopenharmony_ci if (mantissa == 0) 5378c2ecf20Sopenharmony_ci mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ 5388c2ecf20Sopenharmony_ci exponent = 0; 5398c2ecf20Sopenharmony_ci while (mantissa >= 512) { 5408c2ecf20Sopenharmony_ci if (exponent < 7) { 5418c2ecf20Sopenharmony_ci mantissa >>= 2; /* divide by 4 */ 5428c2ecf20Sopenharmony_ci exponent++; 5438c2ecf20Sopenharmony_ci } else { 5448c2ecf20Sopenharmony_ci /* Exponent is maxed. Trim mantissa and leave. */ 5458c2ecf20Sopenharmony_ci mantissa = 511; 5468c2ecf20Sopenharmony_ci break; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci buf[3] = 0x80; 5518c2ecf20Sopenharmony_ci buf[2] = 0; 5528c2ecf20Sopenharmony_ci buf[1] = exponent << 1 | mantissa >> 8; 5538c2ecf20Sopenharmony_ci buf[0] = mantissa & 0xff; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* Calculate and return the exact baud rate. */ 5568c2ecf20Sopenharmony_ci baud = (baseline / mantissa) >> (exponent << 1); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return baud; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic void pl2303_encode_baud_rate(struct tty_struct *tty, 5628c2ecf20Sopenharmony_ci struct usb_serial_port *port, 5638c2ecf20Sopenharmony_ci u8 buf[4]) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 5668c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 5678c2ecf20Sopenharmony_ci speed_t baud_sup; 5688c2ecf20Sopenharmony_ci speed_t baud; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci baud = tty_get_baud_rate(tty); 5718c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "baud requested = %u\n", baud); 5728c2ecf20Sopenharmony_ci if (!baud) 5738c2ecf20Sopenharmony_ci return; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (spriv->type->max_baud_rate) 5768c2ecf20Sopenharmony_ci baud = min_t(speed_t, baud, spriv->type->max_baud_rate); 5778c2ecf20Sopenharmony_ci /* 5788c2ecf20Sopenharmony_ci * Use direct method for supported baud rates, otherwise use divisors. 5798c2ecf20Sopenharmony_ci * Newer chip types do not support divisor encoding. 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci if (spriv->type->no_divisors) 5828c2ecf20Sopenharmony_ci baud_sup = baud; 5838c2ecf20Sopenharmony_ci else 5848c2ecf20Sopenharmony_ci baud_sup = pl2303_get_supported_baud_rate(baud); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (baud == baud_sup) 5878c2ecf20Sopenharmony_ci baud = pl2303_encode_baud_rate_direct(buf, baud); 5888c2ecf20Sopenharmony_ci else 5898c2ecf20Sopenharmony_ci baud = pl2303_encode_baud_rate_divisor(buf, baud); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Save resulting baud rate */ 5928c2ecf20Sopenharmony_ci tty_encode_baud_rate(tty, baud, baud); 5938c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "baud set = %u\n", baud); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int pl2303_get_line_request(struct usb_serial_port *port, 5978c2ecf20Sopenharmony_ci unsigned char buf[7]) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct usb_device *udev = port->serial->dev; 6008c2ecf20Sopenharmony_ci int ret; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 6038c2ecf20Sopenharmony_ci GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 6048c2ecf20Sopenharmony_ci 0, 0, buf, 7, 100); 6058c2ecf20Sopenharmony_ci if (ret != 7) { 6068c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (ret >= 0) 6098c2ecf20Sopenharmony_ci ret = -EIO; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic int pl2303_set_line_request(struct usb_serial_port *port, 6208c2ecf20Sopenharmony_ci unsigned char buf[7]) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct usb_device *udev = port->serial->dev; 6238c2ecf20Sopenharmony_ci int ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 6268c2ecf20Sopenharmony_ci SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 6278c2ecf20Sopenharmony_ci 0, 0, buf, 7, 100); 6288c2ecf20Sopenharmony_ci if (ret < 0) { 6298c2ecf20Sopenharmony_ci dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 6308c2ecf20Sopenharmony_ci return ret; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic bool pl2303_termios_change(const struct ktermios *a, const struct ktermios *b) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci bool ixon_change; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci ixon_change = ((a->c_iflag ^ b->c_iflag) & (IXON | IXANY)) || 6438c2ecf20Sopenharmony_ci a->c_cc[VSTART] != b->c_cc[VSTART] || 6448c2ecf20Sopenharmony_ci a->c_cc[VSTOP] != b->c_cc[VSTOP]; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return tty_termios_hw_change(a, b) || ixon_change; 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_type_data *type) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (!I_IXON(tty) || I_IXANY(tty)) 6528c2ecf20Sopenharmony_ci return false; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (START_CHAR(tty) != 0x11 || STOP_CHAR(tty) != 0x13) 6558c2ecf20Sopenharmony_ci return false; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (type->no_autoxonxoff) 6588c2ecf20Sopenharmony_ci return false; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return true; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void pl2303_set_termios(struct tty_struct *tty, 6648c2ecf20Sopenharmony_ci struct usb_serial_port *port, struct ktermios *old_termios) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 6678c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 6688c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 6698c2ecf20Sopenharmony_ci unsigned long flags; 6708c2ecf20Sopenharmony_ci unsigned char *buf; 6718c2ecf20Sopenharmony_ci int ret; 6728c2ecf20Sopenharmony_ci u8 control; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (old_termios && !pl2303_termios_change(&tty->termios, old_termios)) 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci buf = kzalloc(7, GFP_KERNEL); 6788c2ecf20Sopenharmony_ci if (!buf) { 6798c2ecf20Sopenharmony_ci /* Report back no change occurred */ 6808c2ecf20Sopenharmony_ci if (old_termios) 6818c2ecf20Sopenharmony_ci tty->termios = *old_termios; 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci pl2303_get_line_request(port, buf); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci switch (C_CSIZE(tty)) { 6888c2ecf20Sopenharmony_ci case CS5: 6898c2ecf20Sopenharmony_ci buf[6] = 5; 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case CS6: 6928c2ecf20Sopenharmony_ci buf[6] = 6; 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case CS7: 6958c2ecf20Sopenharmony_ci buf[6] = 7; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci default: 6988c2ecf20Sopenharmony_ci case CS8: 6998c2ecf20Sopenharmony_ci buf[6] = 8; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "data bits = %d\n", buf[6]); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* For reference buf[0]:buf[3] baud rate value */ 7048c2ecf20Sopenharmony_ci pl2303_encode_baud_rate(tty, port, &buf[0]); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* For reference buf[4]=0 is 1 stop bits */ 7078c2ecf20Sopenharmony_ci /* For reference buf[4]=1 is 1.5 stop bits */ 7088c2ecf20Sopenharmony_ci /* For reference buf[4]=2 is 2 stop bits */ 7098c2ecf20Sopenharmony_ci if (C_CSTOPB(tty)) { 7108c2ecf20Sopenharmony_ci /* 7118c2ecf20Sopenharmony_ci * NOTE: Comply with "real" UARTs / RS232: 7128c2ecf20Sopenharmony_ci * use 1.5 instead of 2 stop bits with 5 data bits 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_ci if (C_CSIZE(tty) == CS5) { 7158c2ecf20Sopenharmony_ci buf[4] = 1; 7168c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "stop bits = 1.5\n"); 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci buf[4] = 2; 7198c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "stop bits = 2\n"); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci } else { 7228c2ecf20Sopenharmony_ci buf[4] = 0; 7238c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "stop bits = 1\n"); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (C_PARENB(tty)) { 7278c2ecf20Sopenharmony_ci /* For reference buf[5]=0 is none parity */ 7288c2ecf20Sopenharmony_ci /* For reference buf[5]=1 is odd parity */ 7298c2ecf20Sopenharmony_ci /* For reference buf[5]=2 is even parity */ 7308c2ecf20Sopenharmony_ci /* For reference buf[5]=3 is mark parity */ 7318c2ecf20Sopenharmony_ci /* For reference buf[5]=4 is space parity */ 7328c2ecf20Sopenharmony_ci if (C_PARODD(tty)) { 7338c2ecf20Sopenharmony_ci if (C_CMSPAR(tty)) { 7348c2ecf20Sopenharmony_ci buf[5] = 3; 7358c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "parity = mark\n"); 7368c2ecf20Sopenharmony_ci } else { 7378c2ecf20Sopenharmony_ci buf[5] = 1; 7388c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "parity = odd\n"); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci } else { 7418c2ecf20Sopenharmony_ci if (C_CMSPAR(tty)) { 7428c2ecf20Sopenharmony_ci buf[5] = 4; 7438c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "parity = space\n"); 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci buf[5] = 2; 7468c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "parity = even\n"); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci } else { 7508c2ecf20Sopenharmony_ci buf[5] = 0; 7518c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "parity = none\n"); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Some PL2303 are known to lose bytes if you change serial settings 7568c2ecf20Sopenharmony_ci * even to the same values as before. Thus we actually need to filter 7578c2ecf20Sopenharmony_ci * in this specific case. 7588c2ecf20Sopenharmony_ci * 7598c2ecf20Sopenharmony_ci * Note that the tty_termios_hw_change check above is not sufficient 7608c2ecf20Sopenharmony_ci * as a previously requested baud rate may differ from the one 7618c2ecf20Sopenharmony_ci * actually used (and stored in old_termios). 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * NOTE: No additional locking needed for line_settings as it is 7648c2ecf20Sopenharmony_ci * only used in set_termios, which is serialised against itself. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci if (!old_termios || memcmp(buf, priv->line_settings, 7)) { 7678c2ecf20Sopenharmony_ci ret = pl2303_set_line_request(port, buf); 7688c2ecf20Sopenharmony_ci if (!ret) 7698c2ecf20Sopenharmony_ci memcpy(priv->line_settings, buf, 7); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* change control lines if we are switching to or from B0 */ 7738c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 7748c2ecf20Sopenharmony_ci control = priv->line_control; 7758c2ecf20Sopenharmony_ci if (C_BAUD(tty) == B0) 7768c2ecf20Sopenharmony_ci priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 7778c2ecf20Sopenharmony_ci else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 7788c2ecf20Sopenharmony_ci priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 7798c2ecf20Sopenharmony_ci if (control != priv->line_control) { 7808c2ecf20Sopenharmony_ci control = priv->line_control; 7818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 7828c2ecf20Sopenharmony_ci pl2303_set_control_lines(port, control); 7838c2ecf20Sopenharmony_ci } else { 7848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (C_CRTSCTS(tty)) { 7888c2ecf20Sopenharmony_ci if (spriv->quirks & PL2303_QUIRK_LEGACY) { 7898c2ecf20Sopenharmony_ci pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40); 7908c2ecf20Sopenharmony_ci } else if (spriv->type == &pl2303_type_data[TYPE_HXN]) { 7918c2ecf20Sopenharmony_ci pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, 7928c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_MASK, 7938c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_RTS_CTS); 7948c2ecf20Sopenharmony_ci } else { 7958c2ecf20Sopenharmony_ci pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci } else if (pl2303_enable_xonxoff(tty, spriv->type)) { 7988c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) { 7998c2ecf20Sopenharmony_ci pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, 8008c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_MASK, 8018c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_XON_XOFF); 8028c2ecf20Sopenharmony_ci } else { 8038c2ecf20Sopenharmony_ci pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0); 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } else { 8068c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) { 8078c2ecf20Sopenharmony_ci pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, 8088c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_MASK, 8098c2ecf20Sopenharmony_ci PL2303_HXN_FLOWCTRL_NONE); 8108c2ecf20Sopenharmony_ci } else { 8118c2ecf20Sopenharmony_ci pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci kfree(buf); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic void pl2303_dtr_rts(struct usb_serial_port *port, int on) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 8218c2ecf20Sopenharmony_ci unsigned long flags; 8228c2ecf20Sopenharmony_ci u8 control; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 8258c2ecf20Sopenharmony_ci if (on) 8268c2ecf20Sopenharmony_ci priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 8278c2ecf20Sopenharmony_ci else 8288c2ecf20Sopenharmony_ci priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 8298c2ecf20Sopenharmony_ci control = priv->line_control; 8308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci pl2303_set_control_lines(port, control); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic void pl2303_close(struct usb_serial_port *port) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci usb_serial_generic_close(port); 8388c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 8398c2ecf20Sopenharmony_ci pl2303_set_break(port, false); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 8458c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 8468c2ecf20Sopenharmony_ci int result; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (spriv->quirks & PL2303_QUIRK_LEGACY) { 8498c2ecf20Sopenharmony_ci usb_clear_halt(serial->dev, port->write_urb->pipe); 8508c2ecf20Sopenharmony_ci usb_clear_halt(serial->dev, port->read_urb->pipe); 8518c2ecf20Sopenharmony_ci } else { 8528c2ecf20Sopenharmony_ci /* reset upstream data pipes */ 8538c2ecf20Sopenharmony_ci if (spriv->type == &pl2303_type_data[TYPE_HXN]) { 8548c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, PL2303_HXN_RESET_REG, 8558c2ecf20Sopenharmony_ci PL2303_HXN_RESET_UPSTREAM_PIPE | 8568c2ecf20Sopenharmony_ci PL2303_HXN_RESET_DOWNSTREAM_PIPE); 8578c2ecf20Sopenharmony_ci } else { 8588c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 8, 0); 8598c2ecf20Sopenharmony_ci pl2303_vendor_write(serial, 9, 0); 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Setup termios */ 8648c2ecf20Sopenharmony_ci if (tty) 8658c2ecf20Sopenharmony_ci pl2303_set_termios(tty, port, NULL); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 8688c2ecf20Sopenharmony_ci if (result) { 8698c2ecf20Sopenharmony_ci dev_err(&port->dev, "failed to submit interrupt urb: %d\n", 8708c2ecf20Sopenharmony_ci result); 8718c2ecf20Sopenharmony_ci return result; 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci result = usb_serial_generic_open(tty, port); 8758c2ecf20Sopenharmony_ci if (result) { 8768c2ecf20Sopenharmony_ci usb_kill_urb(port->interrupt_in_urb); 8778c2ecf20Sopenharmony_ci return result; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci return 0; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int pl2303_tiocmset(struct tty_struct *tty, 8848c2ecf20Sopenharmony_ci unsigned int set, unsigned int clear) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 8878c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 8888c2ecf20Sopenharmony_ci unsigned long flags; 8898c2ecf20Sopenharmony_ci u8 control; 8908c2ecf20Sopenharmony_ci int ret; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 8938c2ecf20Sopenharmony_ci if (set & TIOCM_RTS) 8948c2ecf20Sopenharmony_ci priv->line_control |= CONTROL_RTS; 8958c2ecf20Sopenharmony_ci if (set & TIOCM_DTR) 8968c2ecf20Sopenharmony_ci priv->line_control |= CONTROL_DTR; 8978c2ecf20Sopenharmony_ci if (clear & TIOCM_RTS) 8988c2ecf20Sopenharmony_ci priv->line_control &= ~CONTROL_RTS; 8998c2ecf20Sopenharmony_ci if (clear & TIOCM_DTR) 9008c2ecf20Sopenharmony_ci priv->line_control &= ~CONTROL_DTR; 9018c2ecf20Sopenharmony_ci control = priv->line_control; 9028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci ret = pl2303_set_control_lines(port, control); 9058c2ecf20Sopenharmony_ci if (ret) 9068c2ecf20Sopenharmony_ci return usb_translate_errors(ret); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci return 0; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic int pl2303_tiocmget(struct tty_struct *tty) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 9148c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 9158c2ecf20Sopenharmony_ci unsigned long flags; 9168c2ecf20Sopenharmony_ci unsigned int mcr; 9178c2ecf20Sopenharmony_ci unsigned int status; 9188c2ecf20Sopenharmony_ci unsigned int result; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 9218c2ecf20Sopenharmony_ci mcr = priv->line_control; 9228c2ecf20Sopenharmony_ci status = priv->line_status; 9238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) 9268c2ecf20Sopenharmony_ci | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) 9278c2ecf20Sopenharmony_ci | ((status & UART_CTS) ? TIOCM_CTS : 0) 9288c2ecf20Sopenharmony_ci | ((status & UART_DSR) ? TIOCM_DSR : 0) 9298c2ecf20Sopenharmony_ci | ((status & UART_RING) ? TIOCM_RI : 0) 9308c2ecf20Sopenharmony_ci | ((status & UART_DCD) ? TIOCM_CD : 0); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return result; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int pl2303_carrier_raised(struct usb_serial_port *port) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (priv->line_status & UART_DCD) 9428c2ecf20Sopenharmony_ci return 1; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int pl2303_get_serial(struct tty_struct *tty, 9488c2ecf20Sopenharmony_ci struct serial_struct *ss) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci ss->type = PORT_16654; 9538c2ecf20Sopenharmony_ci ss->line = port->minor; 9548c2ecf20Sopenharmony_ci ss->port = port->port_number; 9558c2ecf20Sopenharmony_ci ss->baud_base = 460800; 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic void pl2303_set_break(struct usb_serial_port *port, bool enable) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 9628c2ecf20Sopenharmony_ci u16 state; 9638c2ecf20Sopenharmony_ci int result; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (enable) 9668c2ecf20Sopenharmony_ci state = BREAK_ON; 9678c2ecf20Sopenharmony_ci else 9688c2ecf20Sopenharmony_ci state = BREAK_OFF; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - turning break %s\n", __func__, 9718c2ecf20Sopenharmony_ci state == BREAK_OFF ? "off" : "on"); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 9748c2ecf20Sopenharmony_ci BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 9758c2ecf20Sopenharmony_ci 0, NULL, 0, 100); 9768c2ecf20Sopenharmony_ci if (result) 9778c2ecf20Sopenharmony_ci dev_err(&port->dev, "error sending break = %d\n", result); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic void pl2303_break_ctl(struct tty_struct *tty, int state) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci pl2303_set_break(port, state); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void pl2303_update_line_status(struct usb_serial_port *port, 9888c2ecf20Sopenharmony_ci unsigned char *data, 9898c2ecf20Sopenharmony_ci unsigned int actual_length) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct usb_serial *serial = port->serial; 9928c2ecf20Sopenharmony_ci struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 9938c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 9948c2ecf20Sopenharmony_ci struct tty_struct *tty; 9958c2ecf20Sopenharmony_ci unsigned long flags; 9968c2ecf20Sopenharmony_ci unsigned int status_idx = UART_STATE_INDEX; 9978c2ecf20Sopenharmony_ci u8 status; 9988c2ecf20Sopenharmony_ci u8 delta; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) 10018c2ecf20Sopenharmony_ci status_idx = 0; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (actual_length < status_idx + 1) 10048c2ecf20Sopenharmony_ci return; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci status = data[status_idx]; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* Save off the uart status for others to look at */ 10098c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 10108c2ecf20Sopenharmony_ci delta = priv->line_status ^ status; 10118c2ecf20Sopenharmony_ci priv->line_status = status; 10128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (status & UART_BREAK_ERROR) 10158c2ecf20Sopenharmony_ci usb_serial_handle_break(port); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (delta & UART_STATE_MSR_MASK) { 10188c2ecf20Sopenharmony_ci if (delta & UART_CTS) 10198c2ecf20Sopenharmony_ci port->icount.cts++; 10208c2ecf20Sopenharmony_ci if (delta & UART_DSR) 10218c2ecf20Sopenharmony_ci port->icount.dsr++; 10228c2ecf20Sopenharmony_ci if (delta & UART_RING) 10238c2ecf20Sopenharmony_ci port->icount.rng++; 10248c2ecf20Sopenharmony_ci if (delta & UART_DCD) { 10258c2ecf20Sopenharmony_ci port->icount.dcd++; 10268c2ecf20Sopenharmony_ci tty = tty_port_tty_get(&port->port); 10278c2ecf20Sopenharmony_ci if (tty) { 10288c2ecf20Sopenharmony_ci usb_serial_handle_dcd_change(port, tty, 10298c2ecf20Sopenharmony_ci status & UART_DCD); 10308c2ecf20Sopenharmony_ci tty_kref_put(tty); 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci wake_up_interruptible(&port->port.delta_msr_wait); 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic void pl2303_read_int_callback(struct urb *urb) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 10418c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 10428c2ecf20Sopenharmony_ci unsigned int actual_length = urb->actual_length; 10438c2ecf20Sopenharmony_ci int status = urb->status; 10448c2ecf20Sopenharmony_ci int retval; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci switch (status) { 10478c2ecf20Sopenharmony_ci case 0: 10488c2ecf20Sopenharmony_ci /* success */ 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci case -ECONNRESET: 10518c2ecf20Sopenharmony_ci case -ENOENT: 10528c2ecf20Sopenharmony_ci case -ESHUTDOWN: 10538c2ecf20Sopenharmony_ci /* this urb is terminated, clean up */ 10548c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 10558c2ecf20Sopenharmony_ci __func__, status); 10568c2ecf20Sopenharmony_ci return; 10578c2ecf20Sopenharmony_ci default: 10588c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 10598c2ecf20Sopenharmony_ci __func__, status); 10608c2ecf20Sopenharmony_ci goto exit; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci usb_serial_debug_data(&port->dev, __func__, 10648c2ecf20Sopenharmony_ci urb->actual_length, urb->transfer_buffer); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci pl2303_update_line_status(port, data, actual_length); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ciexit: 10698c2ecf20Sopenharmony_ci retval = usb_submit_urb(urb, GFP_ATOMIC); 10708c2ecf20Sopenharmony_ci if (retval) { 10718c2ecf20Sopenharmony_ci dev_err(&port->dev, 10728c2ecf20Sopenharmony_ci "%s - usb_submit_urb failed with result %d\n", 10738c2ecf20Sopenharmony_ci __func__, retval); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic void pl2303_process_read_urb(struct urb *urb) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci struct usb_serial_port *port = urb->context; 10808c2ecf20Sopenharmony_ci struct pl2303_private *priv = usb_get_serial_port_data(port); 10818c2ecf20Sopenharmony_ci unsigned char *data = urb->transfer_buffer; 10828c2ecf20Sopenharmony_ci char tty_flag = TTY_NORMAL; 10838c2ecf20Sopenharmony_ci unsigned long flags; 10848c2ecf20Sopenharmony_ci u8 line_status; 10858c2ecf20Sopenharmony_ci int i; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* update line status */ 10888c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 10898c2ecf20Sopenharmony_ci line_status = priv->line_status; 10908c2ecf20Sopenharmony_ci priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 10918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (!urb->actual_length) 10948c2ecf20Sopenharmony_ci return; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * Break takes precedence over parity, which takes precedence over 10988c2ecf20Sopenharmony_ci * framing errors. 10998c2ecf20Sopenharmony_ci */ 11008c2ecf20Sopenharmony_ci if (line_status & UART_BREAK_ERROR) 11018c2ecf20Sopenharmony_ci tty_flag = TTY_BREAK; 11028c2ecf20Sopenharmony_ci else if (line_status & UART_PARITY_ERROR) 11038c2ecf20Sopenharmony_ci tty_flag = TTY_PARITY; 11048c2ecf20Sopenharmony_ci else if (line_status & UART_FRAME_ERROR) 11058c2ecf20Sopenharmony_ci tty_flag = TTY_FRAME; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (tty_flag != TTY_NORMAL) 11088c2ecf20Sopenharmony_ci dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, 11098c2ecf20Sopenharmony_ci tty_flag); 11108c2ecf20Sopenharmony_ci /* overrun is special, not associated with a char */ 11118c2ecf20Sopenharmony_ci if (line_status & UART_OVERRUN_ERROR) 11128c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (port->sysrq) { 11158c2ecf20Sopenharmony_ci for (i = 0; i < urb->actual_length; ++i) 11168c2ecf20Sopenharmony_ci if (!usb_serial_handle_sysrq_char(port, data[i])) 11178c2ecf20Sopenharmony_ci tty_insert_flip_char(&port->port, data[i], 11188c2ecf20Sopenharmony_ci tty_flag); 11198c2ecf20Sopenharmony_ci } else { 11208c2ecf20Sopenharmony_ci tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, 11218c2ecf20Sopenharmony_ci urb->actual_length); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci tty_flip_buffer_push(&port->port); 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic struct usb_serial_driver pl2303_device = { 11288c2ecf20Sopenharmony_ci .driver = { 11298c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11308c2ecf20Sopenharmony_ci .name = "pl2303", 11318c2ecf20Sopenharmony_ci }, 11328c2ecf20Sopenharmony_ci .id_table = id_table, 11338c2ecf20Sopenharmony_ci .num_bulk_in = 1, 11348c2ecf20Sopenharmony_ci .num_bulk_out = 1, 11358c2ecf20Sopenharmony_ci .num_interrupt_in = 0, /* see pl2303_calc_num_ports */ 11368c2ecf20Sopenharmony_ci .bulk_in_size = 256, 11378c2ecf20Sopenharmony_ci .bulk_out_size = 256, 11388c2ecf20Sopenharmony_ci .open = pl2303_open, 11398c2ecf20Sopenharmony_ci .close = pl2303_close, 11408c2ecf20Sopenharmony_ci .dtr_rts = pl2303_dtr_rts, 11418c2ecf20Sopenharmony_ci .carrier_raised = pl2303_carrier_raised, 11428c2ecf20Sopenharmony_ci .get_serial = pl2303_get_serial, 11438c2ecf20Sopenharmony_ci .break_ctl = pl2303_break_ctl, 11448c2ecf20Sopenharmony_ci .set_termios = pl2303_set_termios, 11458c2ecf20Sopenharmony_ci .tiocmget = pl2303_tiocmget, 11468c2ecf20Sopenharmony_ci .tiocmset = pl2303_tiocmset, 11478c2ecf20Sopenharmony_ci .tiocmiwait = usb_serial_generic_tiocmiwait, 11488c2ecf20Sopenharmony_ci .process_read_urb = pl2303_process_read_urb, 11498c2ecf20Sopenharmony_ci .read_int_callback = pl2303_read_int_callback, 11508c2ecf20Sopenharmony_ci .probe = pl2303_probe, 11518c2ecf20Sopenharmony_ci .calc_num_ports = pl2303_calc_num_ports, 11528c2ecf20Sopenharmony_ci .attach = pl2303_startup, 11538c2ecf20Sopenharmony_ci .release = pl2303_release, 11548c2ecf20Sopenharmony_ci .port_probe = pl2303_port_probe, 11558c2ecf20Sopenharmony_ci .port_remove = pl2303_port_remove, 11568c2ecf20Sopenharmony_ci}; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 11598c2ecf20Sopenharmony_ci &pl2303_device, NULL 11608c2ecf20Sopenharmony_ci}; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver"); 11658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1166