pl2303.c revision 871996ede12306cd1d75ed8135bed6f1fcbcd0e6
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) 3623c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold#define PL2303_QUIRK_LEGACY BIT(1) 37228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 387d40d7e85a25e01948bcb4dc3eda1355af318337Németh Mártonstatic const struct usb_device_id id_table[] = { 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, 413d861494729c70d9ebeb7d93caa107897925c355Peter Moulder { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, 44b483b6aaa56f0db72fa50e85b6499a32d82009bfMax Arnold { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, 454be2fa186d54758296d30c565d7b5111dd45b000Steve Murphy { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, 46727df3569b358ef440683787c2b9fe8cc55a0954Greg Kroah-Hartman { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, 4718344a1cd5889d48dac67229fcf024ed300030d5Simone Contini { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, 4896a3e79edff6f41b0f115a82f1a39d66218077a7Dario Lombardo { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, 508a28dea3accda319d51a1bf4d3e280771d946f78Masakazu Mokuno { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, 5658381719845d9ee19a321c2eb69cfa9b7886be9aWang Jun { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, 65228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), 66228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 67228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), 68228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 69228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), 70228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, 71e7beb667842ad0f6ec95a22e7c88e71dfbd60649Andreas Loibl { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, 72912299f6f0587bb6c221705ed9949709b36b3c56Alan Cox { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ 73acbb36f116243bed515357264ecbb6ff9c6d2a5bPeter Favrholdt { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, 74c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, 75c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, 766cceb05f8df6e28ab90f44bdeba50d33928cdee5Denis MONTERRAT { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, 77c6c27721a42b991965bb792d5c196b8331d008d5Christian Lindner { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, 78491b04ce1c9adfa0cd73f095086f3c37da81b667Dick Streefland { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, 793b92847425a98d26ad9d2b8682d3ce6020c90752Matthew Meno { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, 80b7aa94b682dc6b6dcdc01d36f8e65cef5aae81e2Kim Oldfield { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, 818fd801339350b63cbb90730ff8b2be349fb3dc67Johannes Steingraeber { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, 822d94b981c7fcb0fba4aa3442cd180066dbedbbc8YOSHIFUJI Hideaki { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, 839e3285dba5cac12d656da66fd7d420ff1bc0ecc0Magnus Damm { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, 84cc311ee7d29d96f0bf15599f4456012d6f5ea23cDamien Stuart { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, 857c99200142c04d0f1ed3f048014591f841efdaedMatthew Arnold { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, 86af4b8514aafd53d97b05a0a30b7d4cfd2cbb7b81Mike Provencher { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, 878540d66615c39010168ab97eaafb476ec2851298Gianpaolo Cugola { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, 88f36ecd5de93e4c85a9e3d25100c6e233155b12e5Jef Driesen { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, 8949276560c9004fce24c42e3c0ad75f34d956fc63Khanh-Dang Nguyen Thu Lam { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, 9035904e6b5106fda51b04c8b8080c04466865415fPawel Ludwikow { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, 919a61d72602771906e11a5944e8571f8006387b39Manuel Jander { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, 92598f0b703506da841d3459dc0c48506be14d1778Eric Benoit { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* Terminating entry */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 96372db8a780f63368c6960a167b7a19aad776d704Thiago GalesiMODULE_DEVICE_TABLE(usb, id_table); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST_TYPE 0x21 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_LINE_REQUEST 0x20 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST_TYPE 0x21 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SET_CONTROL_REQUEST 0x22 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_DTR 0x01 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONTROL_RTS 0x02 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_REQUEST_TYPE 0x21 1073a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox#define BREAK_REQUEST 0x23 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_ON 0xffff 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BREAK_OFF 0x0000 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST_TYPE 0xa1 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GET_LINE_REQUEST 0x21 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST_TYPE 0x40 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITE_REQUEST 0x01 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST_TYPE 0xc0 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_READ_REQUEST 0x01 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold#define UART_STATE_INDEX 8 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_STATE_TRANSIENT_MASK 0x74 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DCD 0x01 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_DSR 0x02 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_BREAK_ERROR 0x04 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_RING 0x08 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_FRAME_ERROR 0x10 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_PARITY_ERROR 0x20 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_OVERRUN_ERROR 0x40 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define UART_CTS 0x80 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum pl2303_type { 1337f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold TYPE_01, /* Type 0 and 1 (difference unknown) */ 1347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold TYPE_HX, /* HX version of the pl2303 chip */ 135359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold TYPE_COUNT 136359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold}; 137359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold 138359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovoldstruct pl2303_type_data { 139359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold speed_t max_baud_rate; 140359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold unsigned long quirks; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstruct pl2303_serial_private { 144359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold struct pl2303_type_data *type; 145228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold unsigned long quirks; 1468bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold}; 1478bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pl2303_private { 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_control; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 line_status; 152623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold 153623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold u8 line_settings[7]; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 156359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovoldstatic struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { 157359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold [TYPE_01] = { 158359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold .max_baud_rate = 1228800, 159359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold .quirks = PL2303_QUIRK_LEGACY, 160359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold }, 161359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold}; 162359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold 163362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_read(struct usb_serial *serial, u16 value, 164362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold unsigned char buf[1]) 165eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 166362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold struct device *dev = &serial->interface->dev; 167ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold int res; 168ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 169ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 170eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, 171362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, 0, buf, 1, 100); 172362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res != 1) { 173362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, 174362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, res); 175362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res >= 0) 176362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold res = -EIO; 177362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold 178362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return res; 179362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold } 180ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 181362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]); 182ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 183362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return 0; 184eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 185eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 186362eb02603be7bb835c47f2cf585954a5080449dJohan Hovoldstatic int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) 187eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp{ 188362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold struct device *dev = &serial->interface->dev; 189ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold int res; 190ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 191362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); 192362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold 193ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 194eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, 195eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp value, index, NULL, 0, 100); 196362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold if (res) { 197362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, 198362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold value, res); 199362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return res; 200362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold } 201ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 202362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold return 0; 203eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp} 204eb44da0b3aa0105cb38d81c5747a8feae64834beSarah Sharp 205228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovoldstatic int pl2303_probe(struct usb_serial *serial, 206228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold const struct usb_device_id *id) 207228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold{ 208228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold usb_set_serial_data(serial, (void *)id->driver_info); 209228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 210228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold return 0; 211228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold} 212228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 213372db8a780f63368c6960a167b7a19aad776d704Thiago Galesistatic int pl2303_startup(struct usb_serial *serial) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2158bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_serial_private *spriv; 2167f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold enum pl2303_type type = TYPE_01; 2173e152505a57db6622deb1322c22551c046e33d16Sarah Sharp unsigned char *buf; 2188bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2198bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); 2208bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!spriv) 2218bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return -ENOMEM; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 223362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold buf = kmalloc(1, GFP_KERNEL); 2248bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!buf) { 2258bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(spriv); 2263e152505a57db6622deb1322c22551c046e33d16Sarah Sharp return -ENOMEM; 2278bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold } 2283e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 229b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman if (serial->dev->descriptor.bDeviceClass == 0x02) 2307f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 0 */ 231b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) 2327f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_HX; 233281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman else if (serial->dev->descriptor.bDeviceClass == 0x00) 2347f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 1 */ 235281393ad0bcfc309434d2bff38abc15805c2cbc4Greg Kroah-Hartman else if (serial->dev->descriptor.bDeviceClass == 0xFF) 2367f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold type = TYPE_01; /* type 1 */ 237b52e111363e366202386f3e67f71681dbbb8e5d9Greg Kroah-Hartman dev_dbg(&serial->interface->dev, "device type: %d\n", type); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 239359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold spriv->type = &pl2303_type_data[type]; 240228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold spriv->quirks = (unsigned long)usb_get_serial_data(serial); 241359defdaa46c6ecf6a29600f3d57c663c9c35fd2Johan Hovold spriv->quirks |= spriv->type->quirks; 242228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold 2438bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold usb_set_serial_data(serial, spriv); 2443e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 245362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 246362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0404, 0); 247362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 248362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8383, buf); 249362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 250362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0404, 1); 251362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8484, buf); 252362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_read(serial, 0x8383, buf); 253362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0, 1); 254362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 1, 0); 25523c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold if (spriv->quirks & PL2303_QUIRK_LEGACY) 256362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 2, 0x24); 2577f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold else 2587f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold pl2303_vendor_write(serial, 2, 0x44); 2593e152505a57db6622deb1322c22551c046e33d16Sarah Sharp 2603e152505a57db6622deb1322c22551c046e33d16Sarah Sharp kfree(buf); 261ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2638bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2658bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic void pl2303_release(struct usb_serial *serial) 2668bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 267ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 2688bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2698bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(spriv); 2708bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2718bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2728bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_probe(struct usb_serial_port *port) 2738bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 2748bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_private *priv; 2758bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2768bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2778bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold if (!priv) 2788bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return -ENOMEM; 2798bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2808bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold spin_lock_init(&priv->lock); 2818bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2828bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold usb_set_serial_port_data(port, priv); 2838bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 284d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold port->port.drain_delay = 256; 285d7be62211125c85fa1dd796e92aadce84961a502Johan Hovold 2868bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return 0; 2878bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold} 2888bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2898bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovoldstatic int pl2303_port_remove(struct usb_serial_port *port) 2908bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold{ 291ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 2928bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2938bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold kfree(priv); 2948bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold 2958bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold return 0; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 298f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovoldstatic int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 300f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold struct usb_device *dev = port->serial->dev; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3023a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox 303a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold dev_dbg(&port->dev, "%s - %02x\n", __func__, value); 304a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold 305372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 306372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, 307372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi value, 0, NULL, 0, 100); 308a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold if (retval) 309a6ec8245bf09fd51a0561ff372a12473b48d269bJohan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); 310ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold/* 31559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * Returns the nearest supported baud rate. 31659afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold */ 31759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic speed_t pl2303_get_supported_baud_rate(speed_t baud) 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold static const speed_t baud_sup[] = { 32059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 32159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, 32259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 500000, 614400, 921600, 1228800, 2457600, 3000000, 6000000 32359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold }; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold unsigned i; 326692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 3277e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) { 3287e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman if (baud_sup[i] > baud) 3297e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman break; 3307e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman } 331692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 3327e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman if (i == ARRAY_SIZE(baud_sup)) 3337e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i - 1]; 3347e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) 3357e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i - 1]; 3367e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman else 3377e12a6fcbf266eb0d5b19761f91b2964ad18e371Greg Kroah-Hartman baud = baud_sup[i]; 338692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 33959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold return baud; 34059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold} 34159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 34259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovoldstatic void pl2303_encode_baud_rate(struct tty_struct *tty, 34359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold struct usb_serial_port *port, 34459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold u8 buf[4]) 34559afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold{ 34659afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold struct usb_serial *serial = port->serial; 34759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 34859afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold speed_t baud; 34959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 35059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold baud = tty_get_baud_rate(tty); 35159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold dev_dbg(&port->dev, "baud requested = %u\n", baud); 35259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold if (!baud) 35359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold return; 354871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold 355871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold if (spriv->type->max_baud_rate) 356871996ede12306cd1d75ed8135bed6f1fcbcd0e6Johan Hovold baud = min_t(speed_t, baud, spriv->type->max_baud_rate); 35759afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold /* 35859afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * Set baud rate to nearest supported value. 35959afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * 36059afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * NOTE: If unsupported values are set directly, the PL2303 seems to 36159afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold * use 9600 baud. 36259afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold */ 36359afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold baud = pl2303_get_supported_baud_rate(baud); 36459afe10e8dd33d26f8c2ae7572f9023044e71babJohan Hovold 36554dc5792ea933a3ff8c62a1f9ea9e4e6cbdd324aGreg Kroah-Hartman if (baud <= 115200) { 366692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman put_unaligned_le32(baud, buf); 367692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman } else { 368692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman /* 3691796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman * Apparently the formula for higher speeds is: 3701796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman * baudrate = 12M * 32 / (2^buf[1]) / buf[0] 371692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman */ 3721796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman unsigned tmp = 12000000 * 32 / baud; 3731796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[3] = 0x80; 374692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman buf[2] = 0; 3751796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[1] = (tmp >= 256); 3761796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman while (tmp >= 256) { 3771796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman tmp >>= 2; 3781796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[1] <<= 1; 3791796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman } 3801796a228762cd0b86e14d6d4a3de9ecfe65b3b8dGreg Kroah-Hartman buf[0] = tmp; 381692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman } 382692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman 38315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold /* Save resulting baud rate */ 384b2d6d98fc71bb94ada78d433f26a93498802d3f8Johan Hovold tty_encode_baud_rate(tty, baud, baud); 385f84ee3b2f5e5e39041c39268a9eab5046a050d44Johan Hovold dev_dbg(&port->dev, "baud set = %u\n", baud); 38615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold} 38715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 388383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_get_line_request(struct usb_serial_port *port, 389383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold unsigned char buf[7]) 390383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{ 391383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold struct usb_device *udev = port->serial->dev; 392383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 393383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 394383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 395383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 396383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 0, 0, buf, 7, 100); 397383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret != 7) { 398383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 399383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 400383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret > 0) 401383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = -EIO; 402383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 403383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return ret; 404383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold } 405383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 406383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 407383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 408383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return 0; 409383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold} 410383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 411383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovoldstatic int pl2303_set_line_request(struct usb_serial_port *port, 412383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold unsigned char buf[7]) 413383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold{ 414383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold struct usb_device *udev = port->serial->dev; 415383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 416383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 417383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 418383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 419383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 0, 0, buf, 7, 100); 420383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret != 7) { 421383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); 422383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 423383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (ret > 0) 424383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = -EIO; 425383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 426383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return ret; 427383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold } 428383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 429383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); 430383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 431383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold return 0; 432383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold} 433383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold 43415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovoldstatic void pl2303_set_termios(struct tty_struct *tty, 43515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct usb_serial_port *port, struct ktermios *old_termios) 43615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold{ 43715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct usb_serial *serial = port->serial; 43815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 43915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 44015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold unsigned long flags; 44115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold unsigned char *buf; 442383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold int ret; 44315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold u8 control; 44415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 44515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 44615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold return; 44715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 44815e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold buf = kzalloc(7, GFP_KERNEL); 44915e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (!buf) { 45015e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold /* Report back no change occurred */ 45115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold if (old_termios) 45215e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold tty->termios = *old_termios; 45315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold return; 45415e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold } 45515e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 456383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold pl2303_get_line_request(port, buf); 45715e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 458a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner switch (C_CSIZE(tty)) { 459a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS5: 460a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 5; 461a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 462a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS6: 463a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 6; 464a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 465a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS7: 466a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 7; 467a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner break; 468a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner default: 469a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner case CS8: 470a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner buf[6] = 8; 47115e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold } 472a313249937820f8b1996133fc285efbd6aad2c5bColin Leitner dev_dbg(&port->dev, "data bits = %d\n", buf[6]); 47315e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 474692ed4ddf0010dd643d38d6ef1a15bf64a7fbc6dGreg Kroah-Hartman /* For reference buf[0]:buf[3] baud rate value */ 47579816824c1ae73542d9523283ce353142b67563eJohan Hovold pl2303_encode_baud_rate(tty, port, &buf[0]); 47615e7cead1ed89d445cf86c75a72368e98a7a9039Johan Hovold 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=0 is 1 stop bits */ 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=1 is 1.5 stop bits */ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[4]=2 is 2 stop bits */ 48087265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CSTOPB(tty)) { 48187265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold /* 48287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold * NOTE: Comply with "real" UARTs / RS232: 48329cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer * use 1.5 instead of 2 stop bits with 5 data bits 48429cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer */ 48587265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CSIZE(tty) == CS5) { 48629cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer buf[4] = 1; 487d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 1.5\n"); 48829cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer } else { 48929cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer buf[4] = 2; 490d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 2\n"); 49129cf1b72f34519413b3fafbccc9ac776eb948edeFrank Schaefer } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 0; 494d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "stop bits = 1\n"); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49787265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_PARENB(tty)) { 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=0 is none parity */ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=1 is odd parity */ 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=2 is even parity */ 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=3 is mark parity */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For reference buf[5]=4 is space parity */ 50387265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_PARODD(tty)) { 50487265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (tty->termios.c_cflag & CMSPAR) { 5056dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 3; 506d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = mark\n"); 5076dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } else { 5086dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 1; 509d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = odd\n"); 5106dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 51287265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (tty->termios.c_cflag & CMSPAR) { 5136dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 4; 514d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = space\n"); 5156dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } else { 5166dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer buf[5] = 2; 517d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = even\n"); 5186dd81b45fd7628f3eb308f387aee696366718f25Frank Schaefer } 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[5] = 0; 522d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "parity = none\n"); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 525623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold /* 526623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * Some PL2303 are known to lose bytes if you change serial settings 527623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * even to the same values as before. Thus we actually need to filter 528623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * in this specific case. 529623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * 530623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * Note that the tty_termios_hw_change check above is not sufficient 531623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * as a previously requested baud rate may differ from the one 532623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * actually used (and stored in old_termios). 533623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * 534623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * NOTE: No additional locking needed for line_settings as it is 535623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold * only used in set_termios, which is serialised against itself. 536623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold */ 537623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold if (!old_termios || memcmp(buf, priv->line_settings, 7)) { 538383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold ret = pl2303_set_line_request(port, buf); 539383d19c58729e34b3b94e47da20aa7fe4970a577Johan Hovold if (!ret) 540623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold memcpy(priv->line_settings, buf, 7); 541623c8263376c0b8a4b0c220232e7313d762cd0ccJohan Hovold } 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* change control lines if we are switching to or from B0 */ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 54687265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_BAUD(tty) == B0) 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 5482d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (control != priv->line_control) { 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 553f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold pl2303_set_control_lines(port, control); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 557372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 55887265b4514f5a0b79efdccdcb1c6331285652640Johan Hovold if (C_CRTSCTS(tty)) { 55923c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold if (spriv->quirks & PL2303_QUIRK_LEGACY) 560362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0, 0x41); 5617f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold else 5627f966ac7a939633ff6fa8cec58982676c243b4f8Johan Hovold pl2303_vendor_write(serial, 0x0, 0x61); 563715f9527c1c1edd1a9c7a55ab4535211279c9374t.sefzick } else { 564362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 0x0, 0x0); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 566572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 567572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi kfree(buf); 568572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi} 569572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi 570335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_dtr_rts(struct usb_serial_port *port, int on) 571335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 572335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 573335f8514f200e63d689113d29cb7253a5c282967Alan Cox unsigned long flags; 574335f8514f200e63d689113d29cb7253a5c282967Alan Cox u8 control; 575335f8514f200e63d689113d29cb7253a5c282967Alan Cox 576335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_lock_irqsave(&priv->lock, flags); 577335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (on) 578335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control |= (CONTROL_DTR | CONTROL_RTS); 579335f8514f200e63d689113d29cb7253a5c282967Alan Cox else 580335f8514f200e63d689113d29cb7253a5c282967Alan Cox priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); 581335f8514f200e63d689113d29cb7253a5c282967Alan Cox control = priv->line_control; 582335f8514f200e63d689113d29cb7253a5c282967Alan Cox spin_unlock_irqrestore(&priv->lock, flags); 583ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 584f45d0a5aa593cdf48a37489fc61c145e16964288Johan Hovold pl2303_set_control_lines(port, control); 585335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 586335f8514f200e63d689113d29cb7253a5c282967Alan Cox 587335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic void pl2303_close(struct usb_serial_port *port) 588572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi{ 5898b0127b2082601e40295045414a8318f2c8ee5a0Johan Hovold usb_serial_generic_close(port); 590572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi usb_kill_urb(port->interrupt_in_urb); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 593a509a7e478e4766114d69f12d19d644ac63e9765Alan Coxstatic int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 5968bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59923c6acb9684ac87c2e752f61900c7a1a2dd543acJohan Hovold if (spriv->quirks & PL2303_QUIRK_LEGACY) { 6001694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->write_urb->pipe); 6011694899fd1af43636351aac97f415fd3c9cefb1dDariusz M usb_clear_halt(serial->dev, port->read_urb->pipe); 6023e152505a57db6622deb1322c22551c046e33d16Sarah Sharp } else { 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* reset upstream data pipes */ 604362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 8, 0); 605362eb02603be7bb835c47f2cf585954a5080449dJohan Hovold pl2303_vendor_write(serial, 9, 0); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup termios */ 60995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox if (tty) 6102d8f4447b58bba5f8cb895c07690434c02307eafJohan Hovold pl2303_set_termios(tty, port, NULL); 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 612372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) { 614ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold dev_err(&port->dev, "failed to submit interrupt urb: %d\n", 615ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold result); 616db6e9186c90188edea20aaa5161ea073440cc2a1Johan Hovold return result; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 618d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold 619f5230a53c1d551811b077ccad219105786da1becJohan Hovold result = usb_serial_generic_open(tty, port); 620d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold if (result) { 621d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold usb_kill_urb(port->interrupt_in_urb); 622d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold return result; 623d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold } 624d4691c3fa3d371835b1eacb39066ab113c4b9d8cJohan Hovold 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 62820b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int pl2303_tiocmset(struct tty_struct *tty, 629372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int set, unsigned int clear) 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 63195da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 control; 6356f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold int ret; 6366fdd8e8e33730a2abc886113bd0b6c4343f63cc9Flavio Leitner 637372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_RTS) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_RTS; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set & TIOCM_DTR) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control |= CONTROL_DTR; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_RTS) 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_RTS; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clear & TIOCM_DTR) 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->line_control &= ~CONTROL_DTR; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control = priv->line_control; 647372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6495ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold ret = pl2303_set_control_lines(port, control); 6505ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold if (ret) 6515ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold return usb_translate_errors(ret); 6526f1efd6c5aa63ddcfe1ffc60ade716f5421766f4Johan Hovold 6535ddbb26b8b571231cace9f013b2d0ae66229b316Johan Hovold return 0; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int pl2303_tiocmget(struct tty_struct *tty) 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 65895da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mcr; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int result; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 665372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr = priv->line_control; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 668372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_CTS) ? TIOCM_CTS : 0) 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DSR) ? TIOCM_DSR : 0) 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_RING) ? TIOCM_RI : 0) 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((status & UART_DCD) ? TIOCM_CD : 0); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 677d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 682335f8514f200e63d689113d29cb7253a5c282967Alan Coxstatic int pl2303_carrier_raised(struct usb_serial_port *port) 683335f8514f200e63d689113d29cb7253a5c282967Alan Cox{ 684335f8514f200e63d689113d29cb7253a5c282967Alan Cox struct pl2303_private *priv = usb_get_serial_port_data(port); 685ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 686335f8514f200e63d689113d29cb7253a5c282967Alan Cox if (priv->line_status & UART_DCD) 687335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 1; 688ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 689335f8514f200e63d689113d29cb7253a5c282967Alan Cox return 0; 690335f8514f200e63d689113d29cb7253a5c282967Alan Cox} 691335f8514f200e63d689113d29cb7253a5c282967Alan Cox 692824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovoldstatic int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 694824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold struct usb_serial_port *port = tty->driver_data; 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pl2303_private *priv = usb_get_serial_port_data(port); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int prevstatus; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int status; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int changed; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = priv->line_status; 703372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 7066d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold interruptible_sleep_on(&port->port.delta_msr_wait); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* see if a signal did it */ 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 710372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 71140509ca982c00c4b70fc00be887509feca0bff15Johan Hovold if (port->serial->disconnected) 71240509ca982c00c4b70fc00be887509feca0bff15Johan Hovold return -EIO; 71340509ca982c00c4b70fc00be887509feca0bff15Johan Hovold 714372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_lock_irqsave(&priv->lock, flags); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = priv->line_status; 716372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi spin_unlock_irqrestore(&priv->lock, flags); 717372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 7183a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox changed = prevstatus ^ status; 719372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((arg & TIOCM_RNG) && (changed & UART_RING)) || 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_DSR) && (changed & UART_DSR)) || 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((arg & TIOCM_CD) && (changed & UART_DCD)) || 7233a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox ((arg & TIOCM_CTS) && (changed & UART_CTS))) { 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevstatus = status; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTREACHED */ 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73200a0d0d65b61241a718d0aee96f46b9a2d93bf26Alan Coxstatic int pl2303_ioctl(struct tty_struct *tty, 733372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi unsigned int cmd, unsigned long arg) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 73567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas struct serial_struct ser; 73695da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 737d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 73967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas case TIOCGSERIAL: 74067b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas memset(&ser, 0, sizeof ser); 74167b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas ser.type = PORT_16654; 742e5b1e2062e0535e8ffef79bb34d857e21380d101Greg Kroah-Hartman ser.line = port->minor; 7431143832eca8f1d64da7d85642c956ae9d25c69e1Greg Kroah-Hartman ser.port = port->port_number; 74467b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas ser.baud_base = 460800; 74567b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas 74667b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas if (copy_to_user((void __user *)arg, &ser, sizeof ser)) 74767b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas return -EFAULT; 74867b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas 74967b9946dd07eeef8188e4cab816d2c370bcaa7b2John Tsiombikas return 0; 7503a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox default: 7513a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox break; 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 753ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75795da310e66ee8090119596c70ca8432e57f9a97fAlan Coxstatic void pl2303_break_ctl(struct tty_struct *tty, int break_state) 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 75995da310e66ee8090119596c70ca8432e57f9a97fAlan Cox struct usb_serial_port *port = tty->driver_data; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_serial *serial = port->serial; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 state; 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (break_state == 0) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_OFF; 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = BREAK_ON; 768ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 769d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - turning break %s\n", __func__, 7703a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox state == BREAK_OFF ? "off" : "on"); 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 772372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 773372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 774372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 0, NULL, 0, 100); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) 776d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_err(&port->dev, "error sending break = %d\n", result); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 77997bb13ec5bc156352cca8af90080597e04299a73Flavio Leitnerstatic void pl2303_update_line_status(struct usb_serial_port *port, 78097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned char *data, 78197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length) 78297bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner{ 783228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold struct usb_serial *serial = port->serial; 784228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold struct pl2303_serial_private *spriv = usb_get_serial_data(serial); 78597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner struct pl2303_private *priv = usb_get_serial_port_data(port); 786d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek struct tty_struct *tty; 78797bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned long flags; 788228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold unsigned int status_idx = UART_STATE_INDEX; 789d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek u8 prev_line_status; 79097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 791228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) 792228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold status_idx = 0; 79397bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 794228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold if (actual_length < status_idx + 1) 795a009b75aa0ed55f0bc473c8a3b3e872cbca807ecLuiz Fernando N. Capitulino return; 79697bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner 7973a0f43e9deffd9619ac34e3b6b9ba7089aa1e511Alan Cox /* Save off the uart status for others to look at */ 79897bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_lock_irqsave(&priv->lock, flags); 799d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek prev_line_status = priv->line_status; 80097bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner priv->line_status = data[status_idx]; 80197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner spin_unlock_irqrestore(&priv->lock, flags); 802ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 803430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel if (priv->line_status & UART_BREAK_ERROR) 804430eb0d27c1b36c5191c16b2472b26137673a8d4Jason Wessel usb_serial_handle_break(port); 805ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold 8066d0cad657a133818038683120fff9c5c5f8dc751Johan Hovold wake_up_interruptible(&port->port.delta_msr_wait); 807d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek 808d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek tty = tty_port_tty_get(&port->port); 809d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek if (!tty) 810d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek return; 811d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek if ((priv->line_status ^ prev_line_status) & UART_DCD) 812d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek usb_serial_handle_dcd_change(port, tty, 813d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek priv->line_status & UART_DCD); 814d14fc1a74e846d7851f24fc9519fe87dc12a1231Libor Pechacek tty_kref_put(tty); 81597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner} 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8177d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pl2303_read_int_callback(struct urb *urb) 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 819cdc97792289179974af6dda781c855696358d307Ming Lei struct usb_serial_port *port = urb->context; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *data = urb->transfer_buffer; 82197bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner unsigned int actual_length = urb->actual_length; 822461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int status = urb->status; 823461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman int retval; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 825461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman switch (status) { 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* success */ 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ECONNRESET: 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ENOENT: 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case -ESHUTDOWN: 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this urb is terminated, clean up */ 833d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", 834d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman __func__, status); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 837d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", 838d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman __func__, status); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84259d33f2fc2d63796296b1b76143e039d6e7cf532Greg Kroah-Hartman usb_serial_debug_data(&port->dev, __func__, 843372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi urb->actual_length, urb->transfer_buffer); 844372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi 84597bb13ec5bc156352cca8af90080597e04299a73Flavio Leitner pl2303_update_line_status(port, data, actual_length); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 848461d696aeeae294ad22dfcaae462d1757f955778Greg Kroah-Hartman retval = usb_submit_urb(urb, GFP_ATOMIC); 849ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold if (retval) { 850d8789b2b90aeb53ce59ac232d2ff0d8357d53893Greg Kroah-Hartman dev_err(&port->dev, 851372db8a780f63368c6960a167b7a19aad776d704Thiago Galesi "%s - usb_submit_urb failed with result %d\n", 852441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison __func__, retval); 853ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold } 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 856f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovoldstatic void pl2303_process_read_urb(struct urb *urb) 857d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox{ 858f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold struct usb_serial_port *port = urb->context; 859f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold struct pl2303_private *priv = usb_get_serial_port_data(port); 860d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox unsigned char *data = urb->transfer_buffer; 861d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox char tty_flag = TTY_NORMAL; 862f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold unsigned long flags; 863f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold u8 line_status; 864f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold int i; 865f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 866f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold /* update line status */ 867f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold spin_lock_irqsave(&priv->lock, flags); 868f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold line_status = priv->line_status; 869f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold priv->line_status &= ~UART_STATE_TRANSIENT_MASK; 870f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold spin_unlock_irqrestore(&priv->lock, flags); 871f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 872f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold if (!urb->actual_length) 873f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold return; 874f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold 875ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold /* 876ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold * Break takes precedence over parity, which takes precedence over 877ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold * framing errors. 878ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold */ 879d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox if (line_status & UART_BREAK_ERROR) 880d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_BREAK; 881d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox else if (line_status & UART_PARITY_ERROR) 882d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_PARITY; 883d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox else if (line_status & UART_FRAME_ERROR) 884d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox tty_flag = TTY_FRAME; 885d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox 8863ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold if (tty_flag != TTY_NORMAL) 8873ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, 8883ba19fe31b726371b45f91a8de9341f5625e75e4Johan Hovold tty_flag); 889d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox /* overrun is special, not associated with a char */ 890d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox if (line_status & UART_OVERRUN_ERROR) 89192a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); 8929388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold 893d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold if (port->port.console && port->sysrq) { 894d4fc4a7bfc2dee626f4fec1e209e58eaa4312de6Alan Cox for (i = 0; i < urb->actual_length; ++i) 8956ee9f4b4affe751d313d2538999aeec134d413a6Dmitry Torokhov if (!usb_serial_handle_sysrq_char(port, data[i])) 89692a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_insert_flip_char(&port->port, data[i], 89792a19f9cec9a80ad93c06e115822deb729e2c6adJiri Slaby tty_flag); 898d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold } else { 8992f69335710884ae6112fc8196ebe29b5cda7b79bJiri Slaby tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, 900d45cc8df7f59eb4db28408076ce979cd5e18f2b7Johan Hovold urb->actual_length); 9019388e2e71a51fab0aa2309bbb45e8a23d89a95a9Johan Hovold } 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9032e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(&port->port); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 906572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesistatic struct usb_serial_driver pl2303_device = { 907572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .driver = { 908572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .owner = THIS_MODULE, 909572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .name = "pl2303", 910572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi }, 911572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .id_table = id_table, 912572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .num_ports = 1, 9137919c2fd9e07276403b9a4d9ae52305e0d70f923Johan Hovold .bulk_in_size = 256, 9143efeaff6298290b36499532f0b4c87aa4bae8aefJohan Hovold .bulk_out_size = 256, 915572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .open = pl2303_open, 916572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .close = pl2303_close, 917ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan Hovold .dtr_rts = pl2303_dtr_rts, 918335f8514f200e63d689113d29cb7253a5c282967Alan Cox .carrier_raised = pl2303_carrier_raised, 919572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .ioctl = pl2303_ioctl, 920572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .break_ctl = pl2303_break_ctl, 921572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .set_termios = pl2303_set_termios, 922572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmget = pl2303_tiocmget, 923572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .tiocmset = pl2303_tiocmset, 924824d11bef5540062d17380c65ee52d4b2948ca84Johan Hovold .tiocmiwait = pl2303_tiocmiwait, 925f08e07ac8b87b1a4b8ff88a061195e99282dfbbdJohan Hovold .process_read_urb = pl2303_process_read_urb, 926572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .read_int_callback = pl2303_read_int_callback, 927228e4105374cffd5372b1dbdf1f8ec8cf1d964aeJohan Hovold .probe = pl2303_probe, 928572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi .attach = pl2303_startup, 929f9c99bb8b3a1ec81af68d484a551307326c2e933Alan Stern .release = pl2303_release, 9308bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold .port_probe = pl2303_port_probe, 9318bf769eb5f6efc33f95088850f33fcc05d28b508Johan Hovold .port_remove = pl2303_port_remove, 932572d3138eb0cf17a2bf36944cc1d2c753578862eThiago Galesi}; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 934f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Sternstatic struct usb_serial_driver * const serial_drivers[] = { 935f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern &pl2303_device, NULL 936f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern}; 937f667ddad41e303ebc2c6d5bf3105dffe2fbdd717Alan Stern 93868e24113457e437b1576670f2419b77ed0531e9eGreg Kroah-Hartmanmodule_usb_serial_driver(serial_drivers, id_table); 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 940ccfe8188a321f4039a7e52c8336bb4ff3ca35139Johan HovoldMODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver"); 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 942