pl2303.c revision 7f966ac7a939633ff6fa8cec58982676c243b4f8
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prolific PL2303 USB to serial adaptor driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 44d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 IBM Corp. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Original driver for 2.2.x by anonymous 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 94d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * This program is free software; you can redistribute it and/or 104d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * modify it under the terms of the GNU General Public License version 114d0dce3e0b794942407391c52f8dd2760802f391Greg Kroah-Hartman * 2 as published by the Free Software Foundation. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 133a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * See Documentation/usb/usb-serial.txt for more information on using this 143a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox * driver 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_driver.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 283a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#include <linux/uaccess.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb.h> 30a969888ce91673c7f4b86520d851a6f0d5a5fa7dGreg Kroah-Hartman#include <linux/usb/serial.h> 31b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold#include <asm/unaligned.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pl2303.h" 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 35228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define PL2303_QUIRK_UART_STATE_IDX0 BIT(0) 36228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 377d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = { 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, 403d861494729c70d9ebeb7d93caa107897925c355Peter Moulder { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, 43b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, 444be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, 45727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, 4618344a1cd5889d48dac67229fcf024ed300030d5Simone Contini { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, 4796a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, 498a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, 5558381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, 64228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), 65228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 66228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), 67228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 68228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), 69228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 70e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, 71912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ 72acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 73c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, 74c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, 756cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, 76c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, 77491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, 783b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, 79b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, 808fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, 812d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, 829e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, 83cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, 847c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, 85af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, 868540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, 87f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, 8849276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, 8935904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, 909a61d72602771906e11a5944e8571f8006387b39Manuel Jander { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, 91598f0b703506da841d3459dc0c48506be14d1778Eric Benoit { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE 0x21 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST 0x20 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE 0x21 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST 0x22 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR 0x01 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS 0x02 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE 0x21 1063a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST 0x23 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON 0xffff 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF 0x0000 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE 0xa1 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST 0x21 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE 0x40 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST 0x01 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE 0xc0 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST 0x01 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 119228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define UART_STATE_INDEX 8 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK 0x74 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD 0x01 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR 0x02 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR 0x04 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING 0x08 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR 0x10 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR 0x20 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR 0x40 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS 0x80 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type { 1327f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold TYPE_01, /* Type 0 and 1 (difference unknown) */ 1337f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold TYPE_HX, /* HX version of the pl2303 chip */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1368bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private { 1378bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold enum pl2303_type type; 138228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold unsigned long quirks; 1398bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}; 1408bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_control; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_status; 145623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold 146623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold u8 line_settings[7]; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 149362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_read(struct usb_serial *serial, u16 value, 150362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold unsigned char buf[1]) 151eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 152362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold struct device *dev = &serial->interface->dev; 153ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold int res; 154ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 155ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 156eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, 157362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, 0, buf, 1, 100); 158362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res != 1) { 159362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, 160362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, res); 161362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res >= 0) 162362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold res = -EIO; 163362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold 164362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return res; 165362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold } 166ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 167362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]); 168ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 169362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return 0; 170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 171eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 172362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) 173eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 174362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold struct device *dev = &serial->interface->dev; 175ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold int res; 176ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 177362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); 178362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold 179ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 180eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 181eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp value, index, NULL, 0, 100); 182362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res) { 183362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, 184362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, res); 185362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return res; 186362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold } 187ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 188362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return 0; 189eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 190eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 191228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovoldstatic int pl2303_probe(struct usb_serial *serial, 192228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold const struct usb_device_id *id) 193228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold{ 194228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold usb_set_serial_data(serial, (void *)id->driver_info); 195228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 196228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold return 0; 197228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold} 198228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 199372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2018bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_serial_private *spriv; 2027f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold enum pl2303_type type = TYPE_01; 2033e152505a57db6622deb1322c22551c046e33d16Sarah Sharp unsigned char *buf; 2048bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2058bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); 2068bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!spriv) 2078bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return -ENOMEM; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 209362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold buf = kmalloc(1, GFP_KERNEL); 2108bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!buf) { 2118bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(spriv); 2123e152505a57db6622deb1322c22551c046e33d16Sarah Sharp return -ENOMEM; 2138bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold } 2143e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 215b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman if (serial->dev->descriptor.bDeviceClass == 0x02) 2167f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 0 */ 217b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) 2187f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_HX; 219281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman else if (serial->dev->descriptor.bDeviceClass == 0x00) 2207f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 1 */ 221281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman else if (serial->dev->descriptor.bDeviceClass == 0xFF) 2227f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 1 */ 223b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman dev_dbg(&serial->interface->dev, "device type: %d\n", type); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold spriv->type = type; 226228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold spriv->quirks = (unsigned long)usb_get_serial_data(serial); 227228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 2288bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold usb_set_serial_data(serial, spriv); 2293e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 230362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 231362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0404, 0); 232362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 233362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8383, buf); 234362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 235362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0404, 1); 236362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 237362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8383, buf); 238362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0, 1); 239362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 1, 0); 2407f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold if (type == TYPE_01) 241362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 2, 0x24); 2427f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold else 2437f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold pl2303_vendor_write(serial, 2, 0x44); 2443e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 2453e152505a57db6622deb1322c22551c046e33d16Sarah Sharp kfree(buf); 246ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2488bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2508bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial) 2518bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 252ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 2538bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2548bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(spriv); 2558bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2568bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2578bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port) 2588bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 2598bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_private *priv; 2608bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2618bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2628bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!priv) 2638bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return -ENOMEM; 2648bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2658bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold spin_lock_init(&priv->lock); 2668bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2678bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold usb_set_serial_port_data(port, priv); 2688bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 269d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold port->port.drain_delay = 256; 270d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold 2718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return 0; 2728bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2748bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port) 2758bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 276ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 2778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(priv); 2798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2808bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return 0; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 283f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 285f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold struct usb_device *dev = port->serial->dev; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 2873a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox 288a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold dev_dbg(&port->dev, "%s - %02x\n", __func__, value); 289a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold 290372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 291372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, 292372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi value, 0, NULL, 0, 100); 293a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold if (retval) 294a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); 295ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_encode_baudrate(struct tty_struct *tty, 30015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct usb_serial_port *port, 30115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold u8 buf[4]) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 303f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold const speed_t baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, 3047e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman 4800, 7200, 9600, 14400, 19200, 28800, 38400, 3057e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman 57600, 115200, 230400, 460800, 500000, 614400, 3067e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman 921600, 1228800, 2457600, 3000000, 6000000 }; 3077e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman 308692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman struct usb_serial *serial = port->serial; 309692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 310f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold speed_t baud; 3117e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman int i; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3137e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman /* 3147e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman * NOTE: Only the values defined in baud_sup are supported! 3157e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman * => if unsupported values are set, the PL2303 seems to use 3167e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman * 9600 baud (at least my PL2303X always does) 3177e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman */ 31895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox baud = tty_get_baud_rate(tty); 319f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold dev_dbg(&port->dev, "baud requested = %u\n", baud); 320b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold if (!baud) 321b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold return; 322692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 3237e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman /* Set baudrate to nearest supported value */ 3247e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { 3257e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman if (baud_sup[i] > baud) 3267e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman break; 3277e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman } 328692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 3297e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman if (i == ARRAY_SIZE(baud_sup)) 3307e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i - 1]; 3317e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) 3327e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i - 1]; 3337e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman else 3347e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i]; 335692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 3367e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman /* type_0, type_1 only support up to 1228800 baud */ 3377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold if (spriv->type == TYPE_01) 338f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold baud = min_t(speed_t, baud, 1228800); 339692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 34054dc5792ea933a3ff8c62a1f9ea9e4e6cbdd324aGreg Kroah-Hartman if (baud <= 115200) { 341692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman put_unaligned_le32(baud, buf); 342692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman } else { 343692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman /* 3441796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman * Apparently the formula for higher speeds is: 3451796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman * baudrate = 12M * 32 / (2^buf[1]) / buf[0] 346692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman */ 3471796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman unsigned tmp = 12000000 * 32 / baud; 3481796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[3] = 0x80; 349692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman buf[2] = 0; 3501796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[1] = (tmp >= 256); 3511796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman while (tmp >= 256) { 3521796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman tmp >>= 2; 3531796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[1] <<= 1; 3541796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman } 3551796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[0] = tmp; 356692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman } 357692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 35815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold /* Save resulting baud rate */ 359b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold tty_encode_baud_rate(tty, baud, baud); 360f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold dev_dbg(&port->dev, "baud set = %u\n", baud); 36115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold} 36215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 363383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_get_line_request(struct usb_serial_port *port, 364383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold unsigned char buf[7]) 365383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{ 366383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold struct usb_device *udev = port->serial->dev; 367383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 368383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 369383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 370383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 371383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 0, 0, buf, 7, 100); 372383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret != 7) { 373383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 374383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 375383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret > 0) 376383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = -EIO; 377383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 378383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return ret; 379383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold } 380383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 381383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 382383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 383383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return 0; 384383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold} 385383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 386383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_set_line_request(struct usb_serial_port *port, 387383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold unsigned char buf[7]) 388383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{ 389383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold struct usb_device *udev = port->serial->dev; 390383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 391383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 392383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 393383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 394383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 0, 0, buf, 7, 100); 395383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret != 7) { 396383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 397383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 398383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret > 0) 399383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = -EIO; 400383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 401383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return ret; 402383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold } 403383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 404383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 405383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 406383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return 0; 407383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold} 408383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 40915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty, 41015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct usb_serial_port *port, struct ktermios *old_termios) 41115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{ 41215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct usb_serial *serial = port->serial; 41315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 41415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 41515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold unsigned long flags; 41615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold unsigned char *buf; 417383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 41815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold u8 control; 41915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 42015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 42115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold return; 42215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 42315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold buf = kzalloc(7, GFP_KERNEL); 42415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (!buf) { 42515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold /* Report back no change occurred */ 42615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (old_termios) 42715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold tty->termios = *old_termios; 42815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold return; 42915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold } 43015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 431383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold pl2303_get_line_request(port, buf); 43215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 433a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner switch (C_CSIZE(tty)) { 434a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS5: 435a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 5; 436a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 437a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS6: 438a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 6; 439a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 440a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS7: 441a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 7; 442a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 443a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner default: 444a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS8: 445a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 8; 44615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold } 447a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner dev_dbg(&port->dev, "data bits = %d\n", buf[6]); 44815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 449692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman /* For reference buf[0]:buf[3] baud rate value */ 450692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman pl2303_encode_baudrate(tty, port, &buf[0]); 45115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=0 is 1 stop bits */ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=1 is 1.5 stop bits */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=2 is 2 stop bits */ 45587265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CSTOPB(tty)) { 45687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold /* 45787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold * NOTE: Comply with "real" UARTs / RS232: 45829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer * use 1.5 instead of 2 stop bits with 5 data bits 45929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer */ 46087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CSIZE(tty) == CS5) { 46129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer buf[4] = 1; 462d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 1.5\n"); 46329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer } else { 46429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer buf[4] = 2; 465d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 2\n"); 46629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer } 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 0; 469d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 1\n"); 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_PARENB(tty)) { 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=0 is none parity */ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=1 is odd parity */ 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=2 is even parity */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=3 is mark parity */ 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=4 is space parity */ 47887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_PARODD(tty)) { 47987265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (tty->termios.c_cflag & CMSPAR) { 4806dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 3; 481d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = mark\n"); 4826dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } else { 4836dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 1; 484d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = odd\n"); 4856dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 48787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (tty->termios.c_cflag & CMSPAR) { 4886dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 4; 489d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = space\n"); 4906dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } else { 4916dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 2; 492d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = even\n"); 4936dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 0; 497d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = none\n"); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 500623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold /* 501623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * Some PL2303 are known to lose bytes if you change serial settings 502623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * even to the same values as before. Thus we actually need to filter 503623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * in this specific case. 504623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * 505623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * Note that the tty_termios_hw_change check above is not sufficient 506623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * as a previously requested baud rate may differ from the one 507623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * actually used (and stored in old_termios). 508623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * 509623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * NOTE: No additional locking needed for line_settings as it is 510623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * only used in set_termios, which is serialised against itself. 511623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold */ 512623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold if (!old_termios || memcmp(buf, priv->line_settings, 7)) { 513383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = pl2303_set_line_request(port, buf); 514383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (!ret) 515623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold memcpy(priv->line_settings, buf, 7); 516623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold } 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* change control lines if we are switching to or from B0 */ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 52187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_BAUD(tty) == B0) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 5232d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (control != priv->line_control) { 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 528f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold pl2303_set_control_lines(port, control); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 532372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 53387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CRTSCTS(tty)) { 5347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold if (spriv->type == TYPE_01) 535362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0, 0x41); 5367f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold else 5377f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold pl2303_vendor_write(serial, 0x0, 0x61); 538715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick } else { 539362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0, 0x0); 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 541572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 542572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(buf); 543572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 544572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 545335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on) 546335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 547335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 548335f8514f200e63d689113d29cb7253a5c282967Alan Cox unsigned long flags; 549335f8514f200e63d689113d29cb7253a5c282967Alan Cox u8 control; 550335f8514f200e63d689113d29cb7253a5c282967Alan Cox 551335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_lock_irqsave(&priv->lock, flags); 552335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (on) 553335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 554335f8514f200e63d689113d29cb7253a5c282967Alan Cox else 555335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 556335f8514f200e63d689113d29cb7253a5c282967Alan Cox control = priv->line_control; 557335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_unlock_irqrestore(&priv->lock, flags); 558ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 559f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold pl2303_set_control_lines(port, control); 560335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 561335f8514f200e63d689113d29cb7253a5c282967Alan Cox 562335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port) 563572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 5648b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold usb_serial_generic_close(port); 565572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->interrupt_in_urb); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 568a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 5718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5747f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold if (spriv->type == TYPE_01) { 5751694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->write_urb->pipe); 5761694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->read_urb->pipe); 5773e152505a57db6622deb1322c22551c046e33d16Sarah Sharp } else { 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset upstream data pipes */ 579362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 8, 0); 580362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 9, 0); 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup termios */ 58495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (tty) 5852d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold pl2303_set_termios(tty, port, NULL); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 587372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 589ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold dev_err(&port->dev, "failed to submit interrupt urb: %d\n", 590ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold result); 591db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold return result; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 593d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold 594f5230a53c1d551811b077ccad219105786da1becJohan Hovold result = usb_serial_generic_open(tty, port); 595d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold if (result) { 596d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold usb_kill_urb(port->interrupt_in_urb); 597d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold return result; 598d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold } 599d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60320b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty, 604372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int set, unsigned int clear) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 60695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 6106f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold int ret; 6116fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 612372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_RTS; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_DTR; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RTS; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_DTR; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 622372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6245ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold ret = pl2303_set_control_lines(port, control); 6255ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold if (ret) 6265ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold return usb_translate_errors(ret); 6276f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold 6285ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold return 0; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63160b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty) 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 63395da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mcr; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 640372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr = priv->line_control; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 643372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CTS) ? TIOCM_CTS : 0) 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DSR) ? TIOCM_DSR : 0) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_RING) ? TIOCM_RI : 0) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DCD) ? TIOCM_CD : 0); 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 652d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 657335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port) 658335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 659335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 660ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 661335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (priv->line_status & UART_DCD) 662335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 1; 663ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 664335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 0; 665335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 666335f8514f200e63d689113d29cb7253a5c282967Alan Cox 667824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovoldstatic int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg) 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 669824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold struct usb_serial_port *port = tty->driver_data; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int prevstatus; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int changed; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 676372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = priv->line_status; 678372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 6816d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold interruptible_sleep_on(&port->port.delta_msr_wait); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 685372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 68640509ca982c00c4b70fc00be887509feca0bff15Johan Hovold if (port->serial->disconnected) 68740509ca982c00c4b70fc00be887509feca0bff15Johan Hovold return -EIO; 68840509ca982c00c4b70fc00be887509feca0bff15Johan Hovold 689372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 691372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 692372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 6933a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox changed = prevstatus ^ status; 694372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (changed & UART_RING)) || 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (changed & UART_DSR)) || 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (changed & UART_DCD)) || 6983a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox ((arg & TIOCM_CTS) && (changed & UART_CTS))) { 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = status; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTREACHED */ 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70700a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty, 708372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int cmd, unsigned long arg) 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 71067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas struct serial_struct ser; 71195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 712d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 71467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas case TIOCGSERIAL: 71567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas memset(&ser, 0, sizeof ser); 71667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas ser.type = PORT_16654; 717e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman ser.line = port->minor; 7181143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman ser.port = port->port_number; 71967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas ser.baud_base = 460800; 72067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas 72167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas if (copy_to_user((void __user *)arg, &ser, sizeof ser)) 72267b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas return -EFAULT; 72367b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas 72467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas return 0; 7253a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox default: 7263a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 728ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73295da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state) 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 73495da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 state; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == 0) 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_OFF; 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_ON; 743ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 744d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - turning break %s\n", __func__, 7453a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox state == BREAK_OFF ? "off" : "on"); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 747372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 748372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 749372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, NULL, 0, 100); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 751d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_err(&port->dev, "error sending break = %d\n", result); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75497bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port, 75597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned char *data, 75697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length) 75797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{ 758228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold struct usb_serial *serial = port->serial; 759228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 76097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner struct pl2303_private *priv = usb_get_serial_port_data(port); 761d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek struct tty_struct *tty; 76297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned long flags; 763228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold unsigned int status_idx = UART_STATE_INDEX; 764d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek u8 prev_line_status; 76597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 766228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) 767228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold status_idx = 0; 76897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 769228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold if (actual_length < status_idx + 1) 770a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino return; 77197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 7723a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox /* Save off the uart status for others to look at */ 77397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_lock_irqsave(&priv->lock, flags); 774d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek prev_line_status = priv->line_status; 77597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner priv->line_status = data[status_idx]; 77697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_unlock_irqrestore(&priv->lock, flags); 777ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 778430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel if (priv->line_status & UART_BREAK_ERROR) 779430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel usb_serial_handle_break(port); 780ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 7816d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold wake_up_interruptible(&port->port.delta_msr_wait); 782d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek 783d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek tty = tty_port_tty_get(&port->port); 784d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek if (!tty) 785d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek return; 786d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek if ((priv->line_status ^ prev_line_status) & UART_DCD) 787d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek usb_serial_handle_dcd_change(port, tty, 788d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek priv->line_status & UART_DCD); 789d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek tty_kref_put(tty); 79097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner} 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7927d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb) 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 794cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 79697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length = urb->actual_length; 797461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 798461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int retval; 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 800461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 808d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 809d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman __func__, status); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 812d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 813d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman __func__, status); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81759d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman usb_serial_debug_data(&port->dev, __func__, 818372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, urb->transfer_buffer); 819372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 82097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner pl2303_update_line_status(port, data, actual_length); 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 823461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman retval = usb_submit_urb(urb, GFP_ATOMIC); 824ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold if (retval) { 825d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_err(&port->dev, 826372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi "%s - usb_submit_urb failed with result %d\n", 827441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, retval); 828ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold } 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb) 832d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{ 833f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold struct usb_serial_port *port = urb->context; 834f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 835d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox unsigned char *data = urb->transfer_buffer; 836d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox char tty_flag = TTY_NORMAL; 837f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold unsigned long flags; 838f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold u8 line_status; 839f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold int i; 840f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 841f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold /* update line status */ 842f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold spin_lock_irqsave(&priv->lock, flags); 843f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold line_status = priv->line_status; 844f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 845f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold spin_unlock_irqrestore(&priv->lock, flags); 846f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 847f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold if (!urb->actual_length) 848f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold return; 849f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 850ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold /* 851ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold * Break takes precedence over parity, which takes precedence over 852ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold * framing errors. 853ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold */ 854d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox if (line_status & UART_BREAK_ERROR) 855d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_BREAK; 856d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox else if (line_status & UART_PARITY_ERROR) 857d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_PARITY; 858d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox else if (line_status & UART_FRAME_ERROR) 859d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_FRAME; 860d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox 8613ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold if (tty_flag != TTY_NORMAL) 8623ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, 8633ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold tty_flag); 864d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox /* overrun is special, not associated with a char */ 865d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox if (line_status & UART_OVERRUN_ERROR) 86692a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); 8679388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold 868d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold if (port->port.console && port->sysrq) { 869d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox for (i = 0; i < urb->actual_length; ++i) 8706ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov if (!usb_serial_handle_sysrq_char(port, data[i])) 87192a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_insert_flip_char(&port->port, data[i], 87292a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_flag); 873d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold } else { 8742f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, 875d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold urb->actual_length); 8769388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold } 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8782e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(&port->port); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = { 882572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .driver = { 883572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .owner = THIS_MODULE, 884572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .name = "pl2303", 885572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi }, 886572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .id_table = id_table, 887572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_ports = 1, 8887919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold .bulk_in_size = 256, 8893efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold .bulk_out_size = 256, 890572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .open = pl2303_open, 891572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .close = pl2303_close, 892ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold .dtr_rts = pl2303_dtr_rts, 893335f8514f200e63d689113d29cb7253a5c282967Alan Cox .carrier_raised = pl2303_carrier_raised, 894572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .ioctl = pl2303_ioctl, 895572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .break_ctl = pl2303_break_ctl, 896572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .set_termios = pl2303_set_termios, 897572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmget = pl2303_tiocmget, 898572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmset = pl2303_tiocmset, 899824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold .tiocmiwait = pl2303_tiocmiwait, 900f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold .process_read_urb = pl2303_process_read_urb, 901572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_int_callback = pl2303_read_int_callback, 902228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .probe = pl2303_probe, 903572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .attach = pl2303_startup, 904f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = pl2303_release, 9058bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold .port_probe = pl2303_port_probe, 9068bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold .port_remove = pl2303_port_remove, 907572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 909f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 910f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern &pl2303_device, NULL 911f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern}; 912f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern 91368e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 915ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan HovoldMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver"); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 917